diff options
author | Henkel, Michael <michael.henkel@hp.com> | 2013-02-05 23:23:32 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2013-02-05 23:34:43 +0900 |
commit | e91758277c902bf11ecb1ae8b68200f290ab49cb (patch) | |
tree | 03160c68d639e98f2e710f0cfc83317a21212a6a | |
parent | bed275ec1babab43c8c790c9ad8ba1ae4b8406a2 (diff) |
packet lib: add ipv6 ICMP support
Signed-off-by: "Henkel, Michael" <michael.henkel@hp.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/packet/icmp6.py | 179 | ||||
-rw-r--r-- | ryu/lib/packet/ipv6.py | 2 |
2 files changed, 181 insertions, 0 deletions
diff --git a/ryu/lib/packet/icmp6.py b/ryu/lib/packet/icmp6.py new file mode 100644 index 00000000..72e12482 --- /dev/null +++ b/ryu/lib/packet/icmp6.py @@ -0,0 +1,179 @@ +# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation. +# +# 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 struct +import socket +import sys +import array +import binascii +from . import packet_base +from . import packet_utils +from ryu.lib.mac import haddr_to_bin, haddr_to_str + +ICMP6_DST_UNREACH = 1 # dest unreachable, codes: +ICMP6_PACKET_TOO_BIG = 2 # packet too big +ICMP6_TIME_EXCEEDED = 3 # time exceeded, code: +ICMP6_PARAM_PROB = 4 # ip6 header bad + +ICMP6_ECHO_REQUEST = 128 # echo service +ICMP6_ECHO_REPLY = 129 # echo reply +MLD_LISTENER_QUERY = 130 # multicast listener query +MLD_LISTENER_REPOR = 131 # multicast listener report +MLD_LISTENER_DONE = 132 # multicast listener done + +# RFC2292 decls +ICMP6_MEMBERSHIP_QUERY = 130 # group membership query +ICMP6_MEMBERSHIP_REPORT = 131 # group membership report +ICMP6_MEMBERSHIP_REDUCTION = 132 # group membership termination + +ND_ROUTER_SOLICIT = 133 # router solicitation +ND_ROUTER_ADVERT = 134 # router advertisment +ND_NEIGHBOR_SOLICIT = 135 # neighbor solicitation +ND_NEIGHBOR_ADVERT = 136 # neighbor advertisment +ND_REDIREC = 137 # redirect + +ICMP6_ROUTER_RENUMBERING = 138 # router renumbering + +ICMP6_WRUREQUEST = 139 # who are you request +ICMP6_WRUREPLY = 140 # who are you reply +ICMP6_FQDN_QUERY = 139 # FQDN query +ICMP6_FQDN_REPLY = 140 # FQDN reply +ICMP6_NI_QUERY = 139 # node information request +ICMP6_NI_REPLY = 140 # node information reply + +ICMP6_MAXTYPE = 201 + + +class icmp6(packet_base.PacketBase): + _PACK_STR = '!BBH' + _MIN_LEN = struct.calcsize(_PACK_STR) + _ICMP6_TYPES = {} + + @staticmethod + def register_icmp6_type(*args): + def _register_icmp6_type(cls): + for type_ in args: + icmp6._ICMP6_TYPES[type_] = cls + return cls + return _register_icmp6_type + + def __init__(self, type_, code, csum, data=None): + super(icmp6, self).__init__() + self.type_ = type_ + self.code = code + self.csum = csum + self.data = data + + @classmethod + def parser(cls, buf): + (type_, code, csum) = struct.unpack_from(cls._PACK_STR, buf) + msg = cls(type_, code, csum) + offset = cls._MIN_LEN + if len(buf) > offset: + cls_ = cls._ICMP6_TYPES.get(type_, None) + if cls_: + msg.data = cls_.parser(buf, offset) + else: + msg.data = buf[offset:] + + return msg, None + + def serialize(self, payload, prev): + hdr = bytearray(struct.pack(icmp6._PACK_STR, self.type_, + self.code, self.csum)) + + if self.data is not None: + if self.type_ in icmp6._ICMP6_TYPES: + hdr += self.data.serialize() + else: + hdr += self.data + src = prev.src + dst = prev.dst + nxt = prev.nxt + if self.csum == 0: + length = len(str(hdr)) + ph = struct.pack('!16s16sBBH', prev.src, prev.dst, 0, prev.nxt, + length) + f = ph + hdr + payload + if len(f) % 2: + f += '\x00' + self.csum = socket.htons(packet_utils.checksum(f)) + struct.pack_into('!H', hdr, 2, self.csum) + + return hdr + + +@icmp6.register_icmp6_type(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT) +class nd_s(object): + _PACK_STR = '!I16sBB6s' + _MIN_LEN = struct.calcsize(_PACK_STR) + + def __init__(self, res, dst, type_, length, hw_src, data=None): + self.res = res << 29 + self.dst = dst + self.type_ = type_ + self.length = length + 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) + offset += cls._MIN_LEN + if len(buf) > offset: + msg.data = buf[offset:] + + return msg + + def serialize(self): + hdr = bytearray(struct.pack(nd_s._PACK_STR, self.res, self.dst, + self.type_, self.length, self.hw_src)) + + if self.data is not None: + hdr += self.data + + return hdr + + +@icmp6.register_icmp6_type(ICMP6_ECHO_REPLY, ICMP6_ECHO_REQUEST) +class echo(object): + _PACK_STR = '!HH' + _MIN_LEN = struct.calcsize(_PACK_STR) + + def __init__(self, id_, seq, data=None): + self.id = id_ + self.seq = seq + self.data = data + + @classmethod + def parser(cls, buf, offset): + (id_, seq) = struct.unpack_from(cls._PACK_STR, buf, offset) + msg = cls(id_, seq) + offset += cls._MIN_LEN + + if len(buf) > offset: + msg.data = buf[offset:] + + return msg + + def serialize(self): + hdr = bytearray(struct.pack(echo._PACK_STR, self.id, + self.seq)) + if self.data is not None: + hdr += bytearray(self.data) + + return hdr diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py index 8fc9d0de..4f1325ea 100644 --- a/ryu/lib/packet/ipv6.py +++ b/ryu/lib/packet/ipv6.py @@ -17,6 +17,7 @@ import struct import socket from . import packet_base from . import packet_utils +from . import icmp6 from . import tcp from ryu.ofproto import inet @@ -64,4 +65,5 @@ class ipv6(packet_base.PacketBase): self.src, self.dst) return hdr +ipv6.register_packet_type(icmp6.icmp6, inet.IPPROTO_ICMP6) ipv6.register_packet_type(tcp.tcp, inet.IPPROTO_TCP) |