# Copyright (C) 2011, 2012 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2011 Isaku Yamahata # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import struct from ryu import exception from . import ofproto_common LOG = logging.getLogger('ryu.ofproto.ofproto_parser') def header(buf): assert len(buf) >= ofproto_common.OFP_HEADER_SIZE #LOG.debug('len %d bufsize %d', len(buf), ofproto.OFP_HEADER_SIZE) return struct.unpack_from(ofproto_common.OFP_HEADER_PACK_STR, buffer(buf)) _MSG_PARSERS = {} def register_msg_parser(version): def register(msg_parser): _MSG_PARSERS[version] = msg_parser return msg_parser return register def msg(datapath, version, msg_type, msg_len, xid, buf): assert len(buf) >= msg_len msg_parser = _MSG_PARSERS.get(version) if msg_parser is None: raise exception.OFPUnknownVersion(version=version) return msg_parser(datapath, version, msg_type, msg_len, xid, buf) class MsgBase(object): def __init__(self, datapath): self.datapath = datapath self.version = None self.msg_type = None self.msg_len = None self.xid = None self.buf = None def set_headers(self, version, msg_type, msg_len, xid): assert msg_type == self.cls_msg_type self.version = version self.msg_type = msg_type self.msg_len = msg_len self.xid = xid def set_xid(self, xid): assert self.xid is None self.xid = xid def set_buf(self, buf): self.buf = buffer(buf) def __str__(self): return 'version: 0x%x msg_type 0x%x xid 0x%x' % (self.version, self.msg_type, self.xid) @classmethod def parser(cls, datapath, version, msg_type, msg_len, xid, buf): msg = cls(datapath) msg.set_headers(version, msg_type, msg_len, xid) msg.set_buf(buf) return msg def _serialize_pre(self): assert self.version is None assert self.msg_type is None assert self.buf is None self.version = self.datapath.ofproto.OFP_VERSION self.msg_type = self.cls_msg_type self.buf = bytearray().zfill(self.datapath.ofproto.OFP_HEADER_SIZE) def _serialize_header(self): # buffer length is determined after trailing data is formated. assert self.version is not None assert self.msg_type is not None assert self.msg_len is None assert self.buf is not None assert len(self.buf) >= self.datapath.ofproto.OFP_HEADER_SIZE self.msg_len = len(self.buf) if self.xid is None: self.xid = 0 struct.pack_into(self.datapath.ofproto.OFP_HEADER_PACK_STR, self.buf, 0, self.version, self.msg_type, self.msg_len, self.xid) def _serialize_body(self): pass def serialize(self): self._serialize_pre() self._serialize_body() self._serialize_header() def msg_pack_into(fmt, buf, offset, *args): if len(buf) < offset: buf += bytearray().zfill(offset - len(buf)) if len(buf) == offset: buf += struct.pack(fmt, *args) return needed_len = offset + struct.calcsize(fmt) if len(buf) < needed_len: buf += bytearray().zfill(needed_len - len(buf)) struct.pack_into(fmt, buf, offset, *args) def msg_str_attr(msg, buf, attr_list): for attr in attr_list: val = getattr(msg, attr, None) if val is not None: buf += ' %s %s' % (attr, val) return buf