diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2017-09-05 10:13:40 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-09-17 13:37:07 +0900 |
commit | 7804cbb6f4de8d7fe9c0d3445c30833422443f8c (patch) | |
tree | ef407c15437642d2b8d41dbedb996649a49d9cc2 | |
parent | 7091523f8f769e65e95989f34ddf5c18b48d7baf (diff) |
packet/zebra: Support Neighbor Connected Address messages
This patch implements the following messages on FRRouting:
- ZEBRA_INTERFACE_NBR_ADDRESS_ADD
- ZEBRA_INTERFACE_NBR_ADDRESS_DELETE
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/packet/zebra.py | 209 |
1 files changed, 141 insertions, 68 deletions
diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py index 308b3627..cee83e9a 100644 --- a/ryu/lib/packet/zebra.py +++ b/ryu/lib/packet/zebra.py @@ -369,6 +369,71 @@ def _serialize_ip_prefix(prefix): raise ValueError('Invalid prefix: %s' % prefix) +# Family and Zebra Prefix format: +# 0 1 2 3 +# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Family | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | IPv4/v6 prefix (4 bytes or 16 bytes) | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# | Prefix len | +# +-+-+-+-+-+-+-+-+ +_ZEBRA_FAMILY_FMT = '!B' # family +_ZEBRA_FAMILY_SIZE = struct.calcsize(_ZEBRA_FAMILY_FMT) +_ZEBRA_IPV4_PREFIX_FMT = '!4sB' # prefix, prefix_len +_ZEBRA_IPV6_PREFIX_FMT = '!16sB' +_ZEBRA_IPV4_PREFIX_SIZE = struct.calcsize(_ZEBRA_IPV4_PREFIX_FMT) +_ZEBRA_IPV6_PREFIX_SIZE = struct.calcsize(_ZEBRA_IPV6_PREFIX_FMT) +_ZEBRA_FAMILY_IPV4_PREFIX_FMT = '!B4sB' # family, prefix, prefix_len +_ZEBRA_FAMILY_IPV6_PREFIX_FMT = '!B16sB' # family, prefix, prefix_len + + +def _parse_zebra_family_prefix(buf): + """ + Parses family and prefix in Zebra format. + """ + (family,) = struct.unpack_from(_ZEBRA_FAMILY_FMT, buf) + rest = buf[_ZEBRA_FAMILY_SIZE:] + + if socket.AF_INET == family: + (prefix, p_len) = struct.unpack_from(_ZEBRA_IPV4_PREFIX_FMT, rest) + prefix = '%s/%d' % (addrconv.ipv4.bin_to_text(prefix), p_len) + rest = rest[_ZEBRA_IPV4_PREFIX_SIZE:] + elif socket.AF_INET6 == family: + (prefix, p_len) = struct.unpack_from(_ZEBRA_IPV6_PREFIX_FMT, rest) + prefix = '%s/%d' % (addrconv.ipv6.bin_to_text(prefix), p_len) + rest = rest[_ZEBRA_IPV6_PREFIX_SIZE:] + else: + raise struct.error('Unsupported family: %d' % family) + + return family, prefix, rest + + +def _serialize_zebra_family_prefix(prefix): + """ + Serializes family and prefix in Zebra format. + """ + if ip.valid_ipv4(prefix): + family = socket.AF_INET # fixup + prefix_addr, prefix_num = prefix.split('/') + return family, struct.pack( + _ZEBRA_FAMILY_IPV4_PREFIX_FMT, + family, + addrconv.ipv4.text_to_bin(prefix_addr), + int(prefix_num)) + elif ip.valid_ipv6(prefix): + family = socket.AF_INET6 # fixup + prefix_addr, prefix_num = prefix.split('/') + return family, struct.pack( + _ZEBRA_FAMILY_IPV6_PREFIX_FMT, + family, + addrconv.ipv6.text_to_bin(prefix_addr), + int(prefix_num)) + + raise ValueError('Invalid prefix: %s' % prefix) + + class InterfaceLinkParams(stringify.StringifyMixin): """ Interface Link Parameters class for if_link_params structure. @@ -1333,10 +1398,8 @@ class _ZebraInterfaceAddress(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | IPv4/v6 Destination Address (Variable) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - _HEADER_FMT = '!IBB' # ifindex, ifc_flags, family + _HEADER_FMT = '!IB' # ifindex, ifc_flags HEADER_SIZE = struct.calcsize(_HEADER_FMT) - _IPV4_BODY_FMT = '!4sB4s' # prefix, prefix_len, dest - _IPV6_BODY_FMT = '!16sB16s' def __init__(self, ifindex, ifc_flags, family, prefix, dest): super(_ZebraInterfaceAddress, self).__init__() @@ -1351,51 +1414,34 @@ class _ZebraInterfaceAddress(_ZebraMessageBody): @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): - (ifindex, ifc_flags, - family) = struct.unpack_from(cls._HEADER_FMT, buf) + (ifindex, ifc_flags) = struct.unpack_from(cls._HEADER_FMT, buf) rest = buf[cls.HEADER_SIZE:] + (family, prefix, rest) = _parse_zebra_family_prefix(rest) + if socket.AF_INET == family: - (prefix, p_len, - dest) = struct.unpack_from(cls._IPV4_BODY_FMT, rest) - prefix = '%s/%d' % (addrconv.ipv4.bin_to_text(prefix), p_len) - dest = addrconv.ipv4.bin_to_text(dest) + dest = addrconv.ipv4.bin_to_text(rest) elif socket.AF_INET6 == family: - (prefix, p_len, - dest) = struct.unpack_from(cls._IPV6_BODY_FMT, rest) - prefix = '%s/%d' % (addrconv.ipv6.bin_to_text(prefix), p_len) - dest = addrconv.ipv6.bin_to_text(dest) + dest = addrconv.ipv6.bin_to_text(rest) else: raise struct.error('Unsupported family: %d' % family) return cls(ifindex, ifc_flags, family, prefix, dest) def serialize(self, version=_DEFAULT_VERSION): - if ip.valid_ipv4(self.prefix): - self.family = socket.AF_INET # fixup - prefix_addr, prefix_num = self.prefix.split('/') - body_bin = struct.pack( - self._IPV4_BODY_FMT, - addrconv.ipv4.text_to_bin(prefix_addr), - int(prefix_num), - addrconv.ipv4.text_to_bin(self.dest)) + (self.family, # fixup + body_bin) = _serialize_zebra_family_prefix(self.prefix) + + if netaddr.valid_ipv4(self.dest): + body_bin += addrconv.ipv4.text_to_bin(self.dest) elif ip.valid_ipv6(self.prefix): - self.family = socket.AF_INET6 # fixup - prefix_addr, prefix_num = self.prefix.split('/') - body_bin = struct.pack( - self._IPV6_BODY_FMT, - addrconv.ipv6.text_to_bin(prefix_addr), - int(prefix_num), - addrconv.ipv6.text_to_bin(self.dest)) + body_bin += addrconv.ipv6.text_to_bin(self.dest) else: raise ValueError( - 'Invalid address family for prefix=%s and dest=%s' - % (self.prefix, self.dest)) - - buf = struct.pack(self._HEADER_FMT, - self.ifindex, self.ifc_flags, self.family) + 'Invalid destination address: %s' % self.dest) - return buf + body_bin + return struct.pack(self._HEADER_FMT, + self.ifindex, self.ifc_flags) + body_bin @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_ADD) @@ -2162,10 +2208,6 @@ class ZebraRouterIDUpdate(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Prefix len | # +-+-+-+-+-+-+-+-+ - _FAMILY_FMT = '!B' - FAMILY_SIZE = struct.calcsize(_FAMILY_FMT) - _IPV4_BODY_FMT = '!4sB' # prefix, prefix_len - _IPV6_BODY_FMT = '!16sB' def __init__(self, family, prefix): super(ZebraRouterIDUpdate, self).__init__() @@ -2176,39 +2218,15 @@ class ZebraRouterIDUpdate(_ZebraMessageBody): @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): - (family,) = struct.unpack_from(cls._FAMILY_FMT, buf) - rest = buf[cls.FAMILY_SIZE:] - - if socket.AF_INET == family: - (prefix, p_len) = struct.unpack_from(cls._IPV4_BODY_FMT, rest) - prefix = '%s/%d' % (addrconv.ipv4.bin_to_text(prefix), p_len) - elif socket.AF_INET6 == family: - (prefix, p_len) = struct.unpack_from(cls._IPV6_BODY_FMT, rest) - prefix = '%s/%d' % (addrconv.ipv6.bin_to_text(prefix), p_len) - else: - raise struct.error('Unsupported family: %d' % family) + (family, prefix, _) = _parse_zebra_family_prefix(buf) return cls(family, prefix) def serialize(self, version=_DEFAULT_VERSION): - if ip.valid_ipv4(self.prefix): - self.family = socket.AF_INET # fixup - prefix_addr, prefix_num = self.prefix.split('/') - body_bin = struct.pack( - self._IPV4_BODY_FMT, - addrconv.ipv4.text_to_bin(prefix_addr), - int(prefix_num)) - elif ip.valid_ipv6(self.prefix): - self.family = socket.AF_INET6 # fixup - prefix_addr, prefix_num = self.prefix.split('/') - body_bin = struct.pack( - self._IPV6_BODY_FMT, - addrconv.ipv6.text_to_bin(prefix_addr), - int(prefix_num)) - else: - raise ValueError('Invalid prefix: %s' % self.prefix) + (self.family, # fixup + buf) = _serialize_zebra_family_prefix(self.prefix) - return struct.pack(self._FAMILY_FMT, self.family) + body_bin + return buf @_FrrZebraMessageBody.register_type(FRR_ZEBRA_HELLO) @@ -2500,10 +2518,65 @@ class ZebraNexthopUpdate(_ZebraMessageBody): return buf + _serialize_nexthops(self.nexthops, version=version) +class _ZebraInterfaceNbrAddress(_ZebraMessageBody): + """ + Base class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_* message body. + """ + # Zebra Interface Neighbor Address message body: + # 0 1 2 3 + # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Interface index | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Family | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | IPv4/v6 prefix | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Prefix len | + # +-+-+-+-+-+-+-+-+ + _HEADER_FMT = '!I' # ifindex + HEADER_SIZE = struct.calcsize(_HEADER_FMT) + + def __init__(self, ifindex, family, prefix): + super(_ZebraInterfaceNbrAddress, self).__init__() + self.ifindex = ifindex + self.family = family + if isinstance(prefix, (IPv4Prefix, IPv6Prefix)): + prefix = prefix.prefix + self.prefix = prefix + + @classmethod + def parse(cls, buf, version=_DEFAULT_VERSION): + (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf) + rest = buf[cls.HEADER_SIZE:] + + (family, prefix, _) = _parse_zebra_family_prefix(rest) + + return cls(ifindex, family, prefix) + + def serialize(self, version=_DEFAULT_VERSION): + (self.family, # fixup + body_bin) = _serialize_zebra_family_prefix(self.prefix) + + return struct.pack(self._HEADER_FMT, self.ifindex) + body_bin + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD) +class ZebraInterfaceNbrAddressAdd(_ZebraInterfaceNbrAddress): + """ + Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE) +class ZebraInterfaceNbrAddressDelete(_ZebraInterfaceNbrAddress): + """ + Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE. + """ + + # TODO: # Implement the following messages: -# - FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD -# - FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE # - FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE |