diff options
author | HIYAMA Manabu <hiyama.manabu@po.ntts.co.jp> | 2013-02-21 11:29:24 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2013-02-24 12:50:14 +0900 |
commit | 4c666748776fddc85e823b8bc39d3f7cb147a944 (patch) | |
tree | f8b365dff2ed0c61aa56b613962e468d7bf18676 | |
parent | a3cc10b8ec2fec40b72d95a6276d6ec719711086 (diff) |
packet lib: fix icmpv6.nd_s.parser() and support NDP option type
This patch fixes parser error if there is no NDP option, and support
the class to handle the NDP option.
I have implemented only the option type = 1 and 2. We also need to
implement other type, but this is enough in mininet for now.
> Traceback (most recent call last):
> (...)
> File "/usr/local/lib/python2.7/dist-packages/ryu-1.6-py2.7.egg/ryu/lib/packet/icmpv6.py", line 87, in parser
> msg.data = cls_.parser(buf, offset)
> File "/usr/local/lib/python2.7/dist-packages/ryu-1.6-py2.7.egg/ryu/lib/packet/icmpv6.py", line 134, in parser
> buf, offset)
> error: unpack_from requires a buffer of at least 28 bytes
Signed-off-by: HIYAMA Manabu <hiyama.manabu@po.ntts.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/packet/icmpv6.py | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/ryu/lib/packet/icmpv6.py b/ryu/lib/packet/icmpv6.py index 3f8ab2fe..eef450fe 100644 --- a/ryu/lib/packet/icmpv6.py +++ b/ryu/lib/packet/icmpv6.py @@ -116,23 +116,74 @@ class icmpv6(packet_base.PacketBase): @icmpv6.register_icmpv6_type(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT) -class nd_s(object): - _PACK_STR = '!I16sBB6s' +class nd_neighbor(object): + _PACK_STR = '!I16s' _MIN_LEN = struct.calcsize(_PACK_STR) + _ND_OPTION_TYPES = {} - def __init__(self, res, dst, type_, length, hw_src, data=None): + # ND option type + ND_OPTION_SLA = 1 # Source Link-Layer Address + ND_OPTION_TLA = 2 # Target Link-Layer Address + ND_OPTION_PI = 3 # Prefix Information + ND_OPTION_RH = 4 # Redirected Header + ND_OPTION_MTU = 5 # MTU + + @staticmethod + def register_nd_option_type(*args): + def _register_nd_option_type(cls): + for type_ in args: + nd_neighbor._ND_OPTION_TYPES[type_] = cls + return cls + return _register_nd_option_type + + def __init__(self, res, dst, type_=None, length=None, data=None): self.res = res << 29 self.dst = dst self.type_ = type_ self.length = length + self.data = data + + @classmethod + def parser(cls, buf, offset): + (res, dst) = struct.unpack_from(cls._PACK_STR, buf, offset) + msg = cls(res, dst) + offset += cls._MIN_LEN + if len(buf) > offset: + (msg.type_, msg.length) = struct.unpack_from('!BB', buf, offset) + cls_ = cls._ND_OPTION_TYPES.get(msg.type_, None) + if cls_: + msg.data = cls_.parser(buf, offset) + else: + msg.data = buf[offset:] + + return msg + + def serialize(self): + hdr = bytearray(struct.pack(nd_neighbor._PACK_STR, self.res, self.dst)) + + if self.type_ is not None: + hdr += bytearray(struct.pack('!BB', self.type_, self.length)) + if self.type_ in nd_neighbor._ND_OPTION_TYPES: + hdr += self.data.serialize() + elif self.data is not None: + hdr += bytearray(self.data) + + return hdr + + +@nd_neighbor.register_nd_option_type(nd_neighbor.ND_OPTION_SLA, nd_neighbor.ND_OPTION_TLA) +class nd_option_la(object): + _PACK_STR = '!6s' + _MIN_LEN = struct.calcsize(_PACK_STR) + + def __init__(self, hw_src, data=None): self.hw_src = hw_src self.data = data @classmethod def parser(cls, buf, offset): - (res, dst, type_, length, hw_src) = struct.unpack_from(cls._PACK_STR, - buf, offset) - msg = cls(res, dst, type_, length, hw_src) + (hw_src, ) = struct.unpack_from(cls._PACK_STR, buf, offset) + msg = cls(hw_src) offset += cls._MIN_LEN if len(buf) > offset: msg.data = buf[offset:] @@ -140,11 +191,10 @@ class nd_s(object): return msg def serialize(self): - hdr = bytearray(struct.pack(nd_s._PACK_STR, self.res, self.dst, - self.type_, self.length, self.hw_src)) + hdr = bytearray(struct.pack(self._PACK_STR, self.hw_src)) if self.data is not None: - hdr += self.data + hdr += bytearray(self.data) return hdr |