diff options
-rw-r--r-- | ryu/lib/packet/zebra.py | 649 |
1 files changed, 554 insertions, 95 deletions
diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py index 71d8947b..308b3627 100644 --- a/ryu/lib/packet/zebra.py +++ b/ryu/lib/packet/zebra.py @@ -515,8 +515,6 @@ class _NextHop(type_desc.TypeDisp, stringify.StringifyMixin): self.ifindex = ifindex self.ifname = ifname self.addr = addr - if type_ is None: - type_ = self._rev_lookup_type(self.__class__) self.type = type_ @classmethod @@ -529,33 +527,60 @@ class _NextHop(type_desc.TypeDisp, stringify.StringifyMixin): if subcls is None: raise struct.error('unsupported Nexthop type: %d' % type_) - return subcls.parse(rest) + nexthop, rest = subcls.parse(rest) + nexthop.type = type_ + return nexthop, rest @abc.abstractmethod def _serialize(self): return b'' - def serialize(self): + def serialize(self, version=_DEFAULT_VERSION): + if self.type is None: + if version <= 3: + nh_cls = _NextHop + elif version == 4: + nh_cls = _FrrNextHop + else: + raise ValueError( + 'Unsupported Zebra protocol version: %d' % version) + self.type = nh_cls._rev_lookup_type(self.__class__) return struct.pack(self._HEADER_FMT, self.type) + self._serialize() +@six.add_metaclass(abc.ABCMeta) +class _FrrNextHop(_NextHop): + """ + Base class for Zebra Nexthop structure for translating nexthop types + on FRRouting. + """ + + _NEXTHOP_COUNT_FMT = '!B' # nexthop_count _NEXTHOP_COUNT_SIZE = struct.calcsize(_NEXTHOP_COUNT_FMT) -def _parse_nexthops(buf): +def _parse_nexthops(buf, version=_DEFAULT_VERSION): (nexthop_count,) = struct.unpack_from(_NEXTHOP_COUNT_FMT, buf) rest = buf[_NEXTHOP_COUNT_SIZE:] + if version <= 3: + nh_cls = _NextHop + elif version == 4: + nh_cls = _FrrNextHop + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' % version) + nexthops = [] for _ in range(nexthop_count): - nexthop, rest = _NextHop.parse(rest) + nexthop, rest = nh_cls.parse(rest) nexthops.append(nexthop) return nexthops, rest -def _serialize_nexthops(nexthops): +def _serialize_nexthops(nexthops, version=_DEFAULT_VERSION): nexthop_count = len(nexthops) buf = struct.pack(_NEXTHOP_COUNT_FMT, nexthop_count) @@ -563,11 +588,12 @@ def _serialize_nexthops(nexthops): return buf for nexthop in nexthops: - buf += nexthop.serialize() + buf += nexthop.serialize(version=version) return buf +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IFINDEX) @_NextHop.register_type(ZEBRA_NEXTHOP_IFINDEX) class NextHopIFIndex(_NextHop): """ @@ -606,6 +632,7 @@ class NextHopIFName(_NextHop): return struct.pack(self._BODY_FMT, self.ifindex) +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4) @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4) class NextHopIPv4(_NextHop): """ @@ -625,6 +652,7 @@ class NextHopIPv4(_NextHop): return addrconv.ipv4.text_to_bin(self.addr) +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4_IFINDEX) @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4_IFINDEX) class NextHopIPv4IFIndex(_NextHop): """ @@ -669,6 +697,7 @@ class NextHopIPv4IFName(_NextHop): return struct.pack(self._BODY_FMT, addr, self.ifindex) +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6) @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6) class NextHopIPv6(_NextHop): """ @@ -688,6 +717,7 @@ class NextHopIPv6(_NextHop): return addrconv.ipv6.text_to_bin(self.addr) +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6_IFINDEX) @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6_IFINDEX) class NextHopIPv6IFIndex(_NextHop): """ @@ -732,6 +762,7 @@ class NextHopIPv6IFName(_NextHop): return struct.pack(self._BODY_FMT, addr, self.ifindex) +@_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_BLACKHOLE) @_NextHop.register_type(ZEBRA_NEXTHOP_BLACKHOLE) class NextHopBlackhole(_NextHop): """ @@ -760,6 +791,7 @@ class RegisteredNexthop(stringify.StringifyMixin): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _HEADER_FMT = '!?H' HEADER_SIZE = struct.calcsize(_HEADER_FMT) + # Note: connected is renamed to flags on FRRouting. def __init__(self, connected, family, prefix): super(RegisteredNexthop, self).__init__() @@ -769,6 +801,14 @@ class RegisteredNexthop(stringify.StringifyMixin): prefix = prefix.prefix self.prefix = prefix + @property + def flags(self): + return self.connected + + @flags.setter + def flags(self, v): + self.connected = v + @classmethod def parse(cls, buf): (connected, family) = struct.unpack_from(cls._HEADER_FMT, buf) @@ -868,7 +908,9 @@ class ZebraMessage(packet_base.PacketBase): V3_HEADER_SIZE = struct.calcsize(_V3_HEADER_FMT) # Note: Marker should be 0xff(=255) in the version>=1 header. + # Also, FRRouting uses the different marker value. _MARKER = 0xff + _LT_MARKER = 0xfe def __init__(self, length=None, version=_DEFAULT_VERSION, vrf_id=0, command=None, body=None): @@ -876,22 +918,23 @@ class ZebraMessage(packet_base.PacketBase): self.length = length self.version = version self.vrf_id = vrf_id - if body is None: - assert command is not None - else: - assert isinstance(body, _ZebraMessageBody) - if command is None: - command = _ZebraMessageBody.rev_lookup_command(body.__class__) self.command = command self.body = body + def _fill_command(self): + assert isinstance(self.body, _ZebraMessageBody) + body_base_cls = _ZebraMessageBody + if self.version == 4: + body_base_cls = _FrrZebraMessageBody + self.command = body_base_cls.rev_lookup_command(self.body.__class__) + @classmethod def get_header_size(cls, version): if version == 0: return cls.V0_HEADER_SIZE elif version in [1, 2]: return cls.V1_HEADER_SIZE - elif version == 3: + elif version in [3, 4]: return cls.V3_HEADER_SIZE else: raise ValueError( @@ -901,7 +944,7 @@ class ZebraMessage(packet_base.PacketBase): @classmethod def parse_header(cls, buf): (length, marker) = struct.unpack_from(cls._V0_HEADER_FMT, buf) - if marker != cls._MARKER: + if marker not in [cls._MARKER, cls._LT_MARKER]: command = marker body_buf = buf[cls.V0_HEADER_SIZE:length] # version=0, vrf_id=0 @@ -916,7 +959,7 @@ class ZebraMessage(packet_base.PacketBase): (length, marker, version, vrf_id, command) = struct.unpack_from( cls._V3_HEADER_FMT, buf) - if version == 3: + if version == 3 or (version == 4 and marker == cls._LT_MARKER): body_buf = buf[cls.V3_HEADER_SIZE:length] return length, version, vrf_id, command, body_buf @@ -925,20 +968,33 @@ class ZebraMessage(packet_base.PacketBase): 'marker=%d, version=%d' % (marker, version)) @classmethod - def _parser_impl(cls, buf, body_parser='parse'): + def get_body_class(cls, version, command): + if version == 4: + return _FrrZebraMessageBody.lookup_command(command) + else: + return _ZebraMessageBody.lookup_command(command) + + @classmethod + def _parser_impl(cls, buf, from_zebra=False): buf = six.binary_type(buf) (length, version, vrf_id, command, body_buf) = cls.parse_header(buf) if body_buf: - body_cls = _ZebraMessageBody.lookup_command(command) - _parser = getattr(body_cls, body_parser) - body = _parser(body_buf, version=version) + body_cls = cls.get_body_class(version, command) + if from_zebra: + body = body_cls.parse_from_zebra(body_buf, version=version) + else: + body = body_cls.parse(body_buf, version=version) else: body = None rest = buf[length:] + if from_zebra: + return (cls(length, version, vrf_id, command, body), + _ZebraMessageFromZebra, rest) + return cls(length, version, vrf_id, command, body), cls, rest @classmethod @@ -957,11 +1013,15 @@ class ZebraMessage(packet_base.PacketBase): self._V1_HEADER_FMT, self.length, self._MARKER, self.version, self.command) - elif self.version == 3: + elif self.version in [3, 4]: + if self.version == 3: + _marker = self._MARKER + else: # self.version == 4 + _marker = self._LT_MARKER self.length = self.V3_HEADER_SIZE + body_len # fixup return struct.pack( self._V3_HEADER_FMT, - self.length, self._MARKER, self.version, + self.length, _marker, self.version, self.vrf_id, self.command) else: raise ValueError( @@ -969,10 +1029,13 @@ class ZebraMessage(packet_base.PacketBase): % self.version) def serialize(self, _payload=None, _prev=None): - if isinstance(self.body, _ZebraMessageBody): - body = self.body.serialize(version=self.version) - else: + if self.body is None: + assert self.command is not None body = b'' + else: + assert isinstance(self.body, _ZebraMessageBody) + self._fill_command() # fixup + body = self.body.serialize(version=self.version) return self.serialize_header(len(body)) + body @@ -984,7 +1047,7 @@ class _ZebraMessageFromZebra(ZebraMessage): @classmethod def parser(cls, buf): - return ZebraMessage._parser_impl(buf, body_parser='parse_from_zebra') + return ZebraMessage._parser_impl(buf, from_zebra=True) # Alias @@ -1018,6 +1081,13 @@ class _ZebraMessageBody(type_desc.TypeDisp, stringify.StringifyMixin): return b'' +class _FrrZebraMessageBody(_ZebraMessageBody): + """ + Pseudo message body class for translating message types on FRRouting. + """ + + +@_FrrZebraMessageBody.register_unknown_type() @_ZebraMessageBody.register_unknown_type() class ZebraUnknownMessage(_ZebraMessageBody): """ @@ -1059,6 +1129,8 @@ class _ZebraInterface(_ZebraMessageBody): # | Interface flags | # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (PTM Enable) | (PTM Status) | v4(FRRouting) + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Metric | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Interface's MTU for IPv4 | @@ -1087,14 +1159,19 @@ class _ZebraInterface(_ZebraMessageBody): # ll_type, hw_addr_len _V3_HEADER_FMT = '!%dsIBQIIIIII' % INTERFACE_NAMSIZE V3_HEADER_SIZE = struct.calcsize(_V3_HEADER_FMT) + # ifname, ifindex, status, if_flags, ptm_enable, ptm_status, metric, + # ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len + _V4_HEADER_FMT = '!%dsIBQBBIIIIII' % INTERFACE_NAMSIZE + V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT) # link_params_state (whether a link-params follows) _LP_STATE_FMT = '!?' LP_STATE_SIZE = struct.calcsize(_LP_STATE_FMT) # See InterfaceLinkParams class for Link params structure - def __init__(self, ifname, ifindex, status, if_flags, - metric, ifmtu, ifmtu6, bandwidth, + def __init__(self, ifname=None, ifindex=None, status=None, if_flags=None, + ptm_enable=None, ptm_status=None, + metric=None, ifmtu=None, ifmtu6=None, bandwidth=None, ll_type=None, hw_addr_len=0, hw_addr=None, link_params=None): super(_ZebraInterface, self).__init__() @@ -1102,6 +1179,8 @@ class _ZebraInterface(_ZebraMessageBody): self.ifindex = ifindex self.status = status self.if_flags = if_flags + self.ptm_enable = ptm_enable + self.ptm_status = ptm_status self.metric = metric self.ifmtu = ifmtu self.ifmtu6 = ifmtu6 @@ -1116,17 +1195,28 @@ class _ZebraInterface(_ZebraMessageBody): @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): + ptm_enable = None + ptm_status = None ll_type = None if version <= 2: (ifname, ifindex, status, if_flags, metric, ifmtu, ifmtu6, bandwidth, hw_addr_len) = struct.unpack_from(cls._HEADER_FMT, buf) rest = buf[cls.HEADER_SIZE:] - else: + elif version == 3: (ifname, ifindex, status, if_flags, metric, ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len) = struct.unpack_from(cls._V3_HEADER_FMT, buf) rest = buf[cls.V3_HEADER_SIZE:] + elif version == 4: + (ifname, ifindex, status, if_flags, ptm_enable, ptm_status, + metric, ifmtu, ifmtu6, bandwidth, ll_type, + hw_addr_len) = struct.unpack_from(cls._V4_HEADER_FMT, buf) + rest = buf[cls.V4_HEADER_SIZE:] + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' + % version) ifname = str(six.text_type(ifname.strip(b'\x00'), 'ascii')) hw_addr_len = min(hw_addr_len, INTERFACE_HWADDR_MAX) @@ -1141,9 +1231,9 @@ class _ZebraInterface(_ZebraMessageBody): hw_addr = hw_addr_bin if not rest: - return cls(ifname, ifindex, status, if_flags, metric, - ifmtu, ifmtu6, bandwidth, ll_type, - hw_addr_len, hw_addr) + return cls(ifname, ifindex, status, if_flags, + ptm_enable, ptm_status, metric, ifmtu, ifmtu6, + bandwidth, ll_type, hw_addr_len, hw_addr) (link_param_state,) = struct.unpack_from(cls._LP_STATE_FMT, rest) rest = rest[cls.LP_STATE_SIZE:] @@ -1153,10 +1243,15 @@ class _ZebraInterface(_ZebraMessageBody): else: link_params = None - return cls(ifname, ifindex, status, if_flags, metric, ifmtu, ifmtu6, - bandwidth, ll_type, hw_addr_len, hw_addr, link_params) + return cls(ifname, ifindex, status, if_flags, + ptm_enable, ptm_status, metric, ifmtu, ifmtu6, + bandwidth, ll_type, hw_addr_len, hw_addr, + link_params) def serialize(self, version=_DEFAULT_VERSION): + if self.ifname is None: + # Case for sending message to Zebra + return b'' # fixup if netaddr.valid_mac(self.hw_addr): # MAC address @@ -1173,12 +1268,23 @@ class _ZebraInterface(_ZebraMessageBody): self.ifname.encode('ascii'), self.ifindex, self.status, self.if_flags, self.metric, self.ifmtu, self.ifmtu6, self.bandwidth, hw_addr_len) + hw_addr - else: + elif version == 3: buf = struct.pack( self._V3_HEADER_FMT, self.ifname.encode('ascii'), self.ifindex, self.status, self.if_flags, self.metric, self.ifmtu, self.ifmtu6, self.bandwidth, self.ll_type, hw_addr_len) + hw_addr + elif version == 4: + buf = struct.pack( + self._V4_HEADER_FMT, + self.ifname.encode('ascii'), self.ifindex, self.status, + self.if_flags, self.ptm_enable, self.ptm_status, self.metric, + self.ifmtu, self.ifmtu6, + self.bandwidth, self.ll_type, hw_addr_len) + hw_addr + else: + raise ValueError( + 'Unsupported Zebra protocol version: %d' + % version) if isinstance(self.link_params, InterfaceLinkParams): buf += struct.pack(self._LP_STATE_FMT, True) @@ -1189,6 +1295,7 @@ class _ZebraInterface(_ZebraMessageBody): return buf +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADD) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADD) class ZebraInterfaceAdd(_ZebraInterface): """ @@ -1196,6 +1303,7 @@ class ZebraInterfaceAdd(_ZebraInterface): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DELETE) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DELETE) class ZebraInterfaceDelete(_ZebraInterface): """ @@ -1290,6 +1398,7 @@ class _ZebraInterfaceAddress(_ZebraMessageBody): return buf + body_bin +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_ADD) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_ADD) class ZebraInterfaceAddressAdd(_ZebraInterfaceAddress): """ @@ -1297,6 +1406,7 @@ class ZebraInterfaceAddressAdd(_ZebraInterfaceAddress): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_DELETE) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_DELETE) class ZebraInterfaceAddressDelete(_ZebraInterfaceAddress): """ @@ -1304,6 +1414,7 @@ class ZebraInterfaceAddressDelete(_ZebraInterfaceAddress): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_UP) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_UP) class ZebraInterfaceUp(_ZebraInterface): """ @@ -1311,6 +1422,7 @@ class ZebraInterfaceUp(_ZebraInterface): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DOWN) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DOWN) class ZebraInterfaceDown(_ZebraInterface): """ @@ -1353,6 +1465,32 @@ class _ZebraIPRoute(_ZebraMessageBody): # | (TAG) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # + # Zebra IPv4/IPv6 Route message body on FRRouting + # (Protocol Daemons -> Zebra Daemon): + # 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Route Type | Instance | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Flags | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Message | SAFI | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | IPv4/v6 Prefix (Variable) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Nexthop Num | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Nexthops (Variable) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Distance) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Metric) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (TAG) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (MTU) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # # Zebra IPv4/IPv6 Route message body (Zebra Daemon -> Protocol Daemons): # 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 @@ -1377,8 +1515,38 @@ class _ZebraIPRoute(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | (TAG) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Zebra IPv4/IPv6 Route message body on FRRouting + # (Zebra Daemon -> Protocol Daemons): + # 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Route Type | Instance | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Flags | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Message | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | IPv4/v6 Prefix (Variable) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Nexthop Num) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Nexthops (Variable)) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (IFIndex Num) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Interface indexes) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Distance) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Metric) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (TAG) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _HEADER_FMT = '!BBB' # type, flags, message HEADER_SIZE = struct.calcsize(_HEADER_FMT) + _V4_HEADER_FMT = '!BHIB' # type, instance, flags, message + V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT) _SAFI_FMT = '!H' # safi SAFI_SIZE = struct.calcsize(_SAFI_FMT) _NUM_FMT = '!B' # nexthop_num or ifindex_num @@ -1392,9 +1560,10 @@ class _ZebraIPRoute(_ZebraMessageBody): def __init__(self, route_type, flags, message, safi=None, prefix=None, nexthops=None, ifindexes=None, distance=None, metric=None, mtu=None, tag=None, - from_zebra=False): + instance=None, from_zebra=False): super(_ZebraIPRoute, self).__init__() self.route_type = route_type + self.instance = instance self.flags = flags self.message = message @@ -1445,14 +1614,24 @@ class _ZebraIPRoute(_ZebraMessageBody): if message & flag: (option,) = struct.unpack_from(fmt, buf) return option, buf[struct.calcsize(fmt):] - else: - return None, buf + + return None, buf @classmethod def _parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False): - (route_type, flags, message,) = struct.unpack_from( - cls._HEADER_FMT, buf) - rest = buf[cls.HEADER_SIZE:] + instance = None + if version <= 3: + (route_type, flags, message,) = struct.unpack_from( + cls._HEADER_FMT, buf) + rest = buf[cls.HEADER_SIZE:] + elif version == 4: + (route_type, instance, flags, message,) = struct.unpack_from( + cls._V4_HEADER_FMT, buf) + rest = buf[cls.V4_HEADER_SIZE:] + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' + % version) if from_zebra: safi = None @@ -1477,7 +1656,7 @@ class _ZebraIPRoute(_ZebraMessageBody): nexthops.append(nexthop) rest = rest[16:] else: - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest, version) ifindexes = [] if from_zebra and message & ZAPI_MESSAGE_IFINDEX: @@ -1488,19 +1667,33 @@ class _ZebraIPRoute(_ZebraMessageBody): ifindexes.append(ifindex) rest = rest[cls.IFINDEX_SIZE:] - distance, rest = cls._parse_message_option( - message, ZAPI_MESSAGE_DISTANCE, '!B', rest) - metric, rest = cls._parse_message_option( - message, ZAPI_MESSAGE_METRIC, '!I', rest) - mtu, rest = cls._parse_message_option( - message, ZAPI_MESSAGE_MTU, '!I', rest) - tag, rest = cls._parse_message_option( - message, ZAPI_MESSAGE_TAG, '!I', rest) + if version <= 3: + distance, rest = cls._parse_message_option( + message, ZAPI_MESSAGE_DISTANCE, '!B', rest) + metric, rest = cls._parse_message_option( + message, ZAPI_MESSAGE_METRIC, '!I', rest) + mtu, rest = cls._parse_message_option( + message, ZAPI_MESSAGE_MTU, '!I', rest) + tag, rest = cls._parse_message_option( + message, ZAPI_MESSAGE_TAG, '!I', rest) + elif version == 4: + distance, rest = cls._parse_message_option( + message, FRR_ZAPI_MESSAGE_DISTANCE, '!B', rest) + metric, rest = cls._parse_message_option( + message, FRR_ZAPI_MESSAGE_METRIC, '!I', rest) + tag, rest = cls._parse_message_option( + message, FRR_ZAPI_MESSAGE_TAG, '!I', rest) + mtu, rest = cls._parse_message_option( + message, FRR_ZAPI_MESSAGE_MTU, '!I', rest) + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' + % version) return cls(route_type, flags, message, safi, prefix, nexthops, ifindexes, distance, metric, mtu, tag, - from_zebra=from_zebra) + instance, from_zebra=from_zebra) @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): @@ -1523,14 +1716,14 @@ class _ZebraIPRoute(_ZebraMessageBody): prefix = _serialize_ip_prefix(self.prefix) nexthops = b'' - if self.nexthops: + if self.from_zebra and self.nexthops: self.message |= ZAPI_MESSAGE_NEXTHOP # fixup - if self.from_zebra: - nexthops += struct.pack(self._NUM_FMT, len(self.nexthops)) - for nexthop in self.nexthops: - nexthops += ip.text_to_bin(nexthop) - else: - nexthops = _serialize_nexthops(self.nexthops) + nexthops += struct.pack(self._NUM_FMT, len(self.nexthops)) + for nexthop in self.nexthops: + nexthops += ip.text_to_bin(nexthop) + else: + self.message |= ZAPI_MESSAGE_NEXTHOP # fixup + nexthops = _serialize_nexthops(self.nexthops, version=version) ifindexes = b'' if self.ifindexes and self.from_zebra: @@ -1539,17 +1732,35 @@ class _ZebraIPRoute(_ZebraMessageBody): for ifindex in self.ifindexes: ifindexes += struct.pack(self._IFINDEX_FMT, ifindex) - options = self._serialize_message_option( - self.distance, ZAPI_MESSAGE_DISTANCE, '!B') - options += self._serialize_message_option( - self.metric, ZAPI_MESSAGE_METRIC, '!I') - options += self._serialize_message_option( - self.mtu, ZAPI_MESSAGE_MTU, '!I') - options += self._serialize_message_option( - self.tag, ZAPI_MESSAGE_TAG, '!I') - - header = struct.pack( - self._HEADER_FMT, self.route_type, self.flags, self.message) + if version <= 3: + options = self._serialize_message_option( + self.distance, ZAPI_MESSAGE_DISTANCE, '!B') + options += self._serialize_message_option( + self.metric, ZAPI_MESSAGE_METRIC, '!I') + options += self._serialize_message_option( + self.mtu, ZAPI_MESSAGE_MTU, '!I') + options += self._serialize_message_option( + self.tag, ZAPI_MESSAGE_TAG, '!I') + header = struct.pack( + self._HEADER_FMT, + self.route_type, self.flags, self.message) + elif version == 4: + options = self._serialize_message_option( + self.distance, FRR_ZAPI_MESSAGE_DISTANCE, '!B') + options += self._serialize_message_option( + self.metric, FRR_ZAPI_MESSAGE_METRIC, '!I') + options += self._serialize_message_option( + self.tag, FRR_ZAPI_MESSAGE_TAG, '!I') + options += self._serialize_message_option( + self.mtu, FRR_ZAPI_MESSAGE_MTU, '!I') + header = struct.pack( + self._V4_HEADER_FMT, + self.route_type, self.instance, self.flags, self.message) + else: + raise ValueError( + 'Unsupported Zebra protocol version: %d' + % version) + if not self.from_zebra: header += struct.pack(self._SAFI_FMT, self.safi) @@ -1563,6 +1774,7 @@ class _ZebraIPv4Route(_ZebraIPRoute): _FAMILY = socket.AF_INET +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_ADD) @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_ADD) class ZebraIPv4RouteAdd(_ZebraIPv4Route): """ @@ -1570,6 +1782,7 @@ class ZebraIPv4RouteAdd(_ZebraIPv4Route): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_DELETE) @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_DELETE) class ZebraIPv4RouteDelete(_ZebraIPv4Route): """ @@ -1584,6 +1797,7 @@ class _ZebraIPv6Route(_ZebraIPRoute): _FAMILY = socket.AF_INET6 +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_ADD) @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_ADD) class ZebraIPv6RouteAdd(_ZebraIPv6Route): """ @@ -1591,6 +1805,7 @@ class ZebraIPv6RouteAdd(_ZebraIPv6Route): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_DELETE) @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_DELETE) class ZebraIPv6RouteDelete(_ZebraIPv6Route): """ @@ -1598,6 +1813,13 @@ class ZebraIPv6RouteDelete(_ZebraIPv6Route): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD) +class ZebraIPv4RouteIPv6NexthopAdd(_ZebraIPv4Route): + """ + Message body class for FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD. + """ + + @six.add_metaclass(abc.ABCMeta) class _ZebraRedistribute(_ZebraMessageBody): """ @@ -1610,23 +1832,53 @@ class _ZebraRedistribute(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Route Type | # +-+-+-+-+-+-+-+-+ - _HEADER_FMT = '!B' + # + # Zebra Redistribute message body on FRRouting: + # 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | AFI | Route Type | Instance | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-++-+-+-+-+-+-+ + _HEADER_FMT = '!B' # route_type HEADER_SIZE = struct.calcsize(_HEADER_FMT) + _V4_HEADER_FMT = '!BBH' # afi, route_type, instance + V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT) - def __init__(self, route_type): + def __init__(self, route_type, afi=None, instance=None): super(_ZebraRedistribute, self).__init__() + self.afi = afi self.route_type = route_type + self.instance = instance @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): - (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf) + afi = None + instance = None + if version <= 3: + (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf) + elif version == 4: + (afi, route_type, + instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf) + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' + % version) - return cls(route_type) + return cls(route_type, afi, instance) def serialize(self, version=_DEFAULT_VERSION): - return struct.pack(self._HEADER_FMT, self.route_type) + if version <= 3: + return struct.pack(self._HEADER_FMT, self.route_type) + elif version == 4: + return struct.pack(self._V4_HEADER_FMT, + self.afi, self.route_type, self.instance) + else: + raise ValueError( + 'Unsupported Zebra protocol version: %d' + % version) +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_ADD) @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_ADD) class ZebraRedistributeAdd(_ZebraRedistribute): """ @@ -1634,6 +1886,7 @@ class ZebraRedistributeAdd(_ZebraRedistribute): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DELETE) @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DELETE) class ZebraRedistributeDelete(_ZebraRedistribute): """ @@ -1649,6 +1902,7 @@ class _ZebraRedistributeDefault(_ZebraMessageBody): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_ADD) @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_ADD) class ZebraRedistributeDefaultAdd(_ZebraRedistribute): """ @@ -1656,6 +1910,7 @@ class ZebraRedistributeDefaultAdd(_ZebraRedistribute): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_DELETE) @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE) class ZebraRedistributeDefaultDelete(_ZebraRedistribute): """ @@ -1711,7 +1966,7 @@ class _ZebraIPNexthopLookup(_ZebraMessageBody): nexthops = None if rest: - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest, version) return cls(addr, metric, nexthops) @@ -1723,7 +1978,7 @@ class _ZebraIPNexthopLookup(_ZebraMessageBody): buf += struct.pack(self._METRIC_FMT, self.metric) - return buf + _serialize_nexthops(self.nexthops) + return buf + _serialize_nexthops(self.nexthops, version=version) @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP) @@ -1820,7 +2075,7 @@ class _ZebraIPImportLookup(_ZebraMessageBody): (metric,) = struct.unpack_from(cls._METRIC_FMT, rest) rest = rest[cls.METRIC_SIZE:] - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest, version) return cls(prefix, metric, nexthops, from_zebra=True) @@ -1849,7 +2104,7 @@ class _ZebraIPImportLookup(_ZebraMessageBody): buf += struct.pack(self._METRIC_FMT, self.metric) - return buf + _serialize_nexthops(self.nexthops) + return buf + _serialize_nexthops(self.nexthops, version=version) @_ZebraMessageBody.register_type(ZEBRA_IPV4_IMPORT_LOOKUP) @@ -1875,6 +2130,7 @@ class ZebraIPv6ImportLookup(_ZebraIPImportLookup): # class ZebraInterfaceRename(_ZebraMessageBody): +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_ADD) @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_ADD) class ZebraRouterIDAdd(_ZebraMessageBody): """ @@ -1882,6 +2138,7 @@ class ZebraRouterIDAdd(_ZebraMessageBody): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_DELETE) @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_DELETE) class ZebraRouterIDDelete(_ZebraMessageBody): """ @@ -1889,6 +2146,7 @@ class ZebraRouterIDDelete(_ZebraMessageBody): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_UPDATE) @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_UPDATE) class ZebraRouterIDUpdate(_ZebraMessageBody): """ @@ -1953,6 +2211,7 @@ class ZebraRouterIDUpdate(_ZebraMessageBody): return struct.pack(self._FAMILY_FMT, self.family) + body_bin +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_HELLO) @_ZebraMessageBody.register_type(ZEBRA_HELLO) class ZebraHello(_ZebraMessageBody): """ @@ -1962,25 +2221,43 @@ class ZebraHello(_ZebraMessageBody): # 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 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Route Type | - # +-+-+-+-+-+-+-+-+ - _HEADER_FMT = '!B' + # | Route Type | (Instance): v4(FRRouting) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + _HEADER_FMT = '!B' # route_type HEADER_SIZE = struct.calcsize(_HEADER_FMT) + _V4_HEADER_FMT = '!BH' # route_type, instance + V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT) - def __init__(self, route_type=ZEBRA_ROUTE_MAX): + def __init__(self, route_type, instance=None): super(ZebraHello, self).__init__() self.route_type = route_type + self.instance = instance @classmethod def parse(cls, buf, version=_DEFAULT_VERSION): - route_type = None - if buf: + instance = None + if version <= 3: (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf) + elif version == 4: + (route_type, + instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf) + else: + raise struct.error( + 'Unsupported Zebra protocol version: %d' + % version) - return cls(route_type) + return cls(route_type, instance) def serialize(self, version=_DEFAULT_VERSION): - return struct.pack(self._HEADER_FMT, self.route_type) + if version <= 3: + return struct.pack(self._HEADER_FMT, self.route_type) + elif version == 4: + return struct.pack(self._V4_HEADER_FMT, + self.route_type, self.instance) + else: + raise ValueError( + 'Unsupported Zebra protocol version: %d' + % version) @six.add_metaclass(abc.ABCMeta) @@ -2003,14 +2280,14 @@ class _ZebraIPNexthopLookupMRib(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Nexthops (Variable) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - _DISTANCE_METRIC_FMT = '!I' # metric + _DISTANCE_METRIC_FMT = '!BI' # distance, metric DISTANCE_METRIC_SIZE = struct.calcsize(_DISTANCE_METRIC_FMT) # Message type specific constants ADDR_CLS = None # either addrconv.ipv4 or addrconv.ipv6 ADDR_LEN = None # IP address length in bytes - def __init__(self, addr, distance, metric, nexthops=None): + def __init__(self, addr, distance=None, metric=None, nexthops=None): super(_ZebraIPNexthopLookupMRib, self).__init__() assert netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr) self.addr = addr @@ -2026,22 +2303,30 @@ class _ZebraIPNexthopLookupMRib(_ZebraMessageBody): addr = cls.ADDR_CLS.bin_to_text(buf[:cls.ADDR_LEN]) rest = buf[cls.ADDR_LEN:] - (metric,) = struct.unpack_from(cls._DISTANCE_METRIC_FMT, rest) + if not rest: + return cls(addr) + + (distance, + metric) = struct.unpack_from(cls._DISTANCE_METRIC_FMT, rest) rest = rest[cls.DISTANCE_METRIC_SIZE:] - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest, version) - return cls(addr, metric, nexthops) + return cls(addr, distance, metric, nexthops) def serialize(self, version=_DEFAULT_VERSION): buf = self.ADDR_CLS.text_to_bin(self.addr) + if self.distance is None or self.metric is None: + return buf + buf += struct.pack( self._DISTANCE_METRIC_FMT, self.distance, self.metric) - return buf + _serialize_nexthops(self.nexthops) + return buf + _serialize_nexthops(self.nexthops, version=version) +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) class ZebraIPv4NexthopLookupMRib(_ZebraIPNexthopLookupMRib): """ @@ -2051,6 +2336,7 @@ class ZebraIPv4NexthopLookupMRib(_ZebraIPNexthopLookupMRib): ADDR_LEN = 4 +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_UNREGISTER) @_ZebraMessageBody.register_type(ZEBRA_VRF_UNREGISTER) class ZebraVrfUnregister(_ZebraMessageBody): """ @@ -2058,6 +2344,7 @@ class ZebraVrfUnregister(_ZebraMessageBody): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_LINK_PARAMS) @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_LINK_PARAMS) class ZebraInterfaceLinkParams(_ZebraMessageBody): """ @@ -2128,6 +2415,7 @@ class _ZebraNexthopRegister(_ZebraMessageBody): return buf +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_REGISTER) @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_REGISTER) class ZebraNexthopRegister(_ZebraNexthopRegister): """ @@ -2135,6 +2423,7 @@ class ZebraNexthopRegister(_ZebraNexthopRegister): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UNREGISTER) @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UNREGISTER) class ZebraNexthopUnregister(_ZebraNexthopRegister): """ @@ -2142,6 +2431,7 @@ class ZebraNexthopUnregister(_ZebraNexthopRegister): """ +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UPDATE) @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UPDATE) class ZebraNexthopUpdate(_ZebraMessageBody): """ @@ -2188,7 +2478,7 @@ class ZebraNexthopUpdate(_ZebraMessageBody): (metric,) = struct.unpack_from(cls._METRIC_FMT, rest) rest = rest[cls.METRIC_SIZE:] - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest, version) return cls(family, prefix, metric, nexthops) @@ -2207,4 +2497,173 @@ class ZebraNexthopUpdate(_ZebraMessageBody): buf += struct.pack(self._METRIC_FMT, self.metric) - return buf + _serialize_nexthops(self.nexthops) + return buf + _serialize_nexthops(self.nexthops, version=version) + + +# TODO: +# Implement the following messages: +# - FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD +# - FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE +# - FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_REGISTER) +class ZebraImportRouteRegister(_ZebraNexthopRegister): + """ + Message body class for FRR_ZEBRA_IMPORT_ROUTE_REGISTER. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER) +class ZebraImportRouteUnregister(_ZebraNexthopRegister): + """ + Message body class for FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_CHECK_UPDATE) +class ZebraImportCheckUpdate(ZebraNexthopUpdate): + """ + Message body class for FRR_ZEBRA_IMPORT_CHECK_UPDATE. + """ + + +# TODO: +# Implement the following messages: +# - FRR_ZEBRA_BFD_DEST_REGISTER +# - FRR_ZEBRA_BFD_DEST_DEREGISTER +# - FRR_ZEBRA_BFD_DEST_UPDATE +# - FRR_ZEBRA_BFD_DEST_REPLAY + + +class _ZebraRedistributeIPv4(_ZebraIPRoute): + """ + Base class for FRR_ZEBRA_REDISTRIBUTE_IPV4_* message body. + """ + _FAMILY = socket.AF_INET + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_ADD) +class ZebraRedistributeIPv4Add(_ZebraRedistributeIPv4): + """ + Message body class for FRR_ZEBRA_IPV4_ROUTE_ADD. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_DEL) +class ZebraRedistributeIPv4Delete(_ZebraRedistributeIPv4): + """ + Message body class for FRR_ZEBRA_IPV4_ROUTE_DELETE. + """ + + +class _ZebraRedistributeIPv6(_ZebraIPRoute): + """ + Base class for FRR_ZEBRA_REDISTRIBUTE_IPV6_* message body. + """ + _FAMILY = socket.AF_INET6 + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD) +class ZebraRedistributeIPv6Add(_ZebraRedistributeIPv6): + """ + Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL) +class ZebraRedistributeIPv6Delete(_ZebraRedistributeIPv6): + """ + Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL. + """ + + +# TODO: +# Implement the following messages: +# - FRR_ZEBRA_VRF_ADD +# - FRR_ZEBRA_VRF_DELETE +# - FRR_ZEBRA_INTERFACE_VRF_UPDATE + + +class _ZebraBfdClient(_ZebraMessageBody): + """ + Base class for FRR_ZEBRA_BFD_CLIENT_*. + """ + # Zebra BFD Client 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | PID | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + _HEADER_FMT = '!I' # pid + HEADER_SIZE = struct.calcsize(_HEADER_FMT) + + def __init__(self, pid): + super(_ZebraBfdClient, self).__init__() + self.pid = pid + + @classmethod + def parse(cls, buf, version=_DEFAULT_FRR_VERSION): + (pid,) = struct.unpack_from(cls._HEADER_FMT, buf) + + return cls(pid) + + def serialize(self, version=_DEFAULT_FRR_VERSION): + return struct.pack(self._HEADER_FMT, self.pid) + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_CLIENT_REGISTER) +class ZebraBfdClientRegister(_ZebraBfdClient): + """ + Message body class for FRR_ZEBRA_BFD_CLIENT_REGISTER. + """ + + +# TODO: +# Implement the following messages: +# - FRR_ZEBRA_INTERFACE_ENABLE_RADV +# - FRR_ZEBRA_INTERFACE_DISABLE_RADV +# - FRR_ZEBRA_MPLS_LABELS_ADD +# - FRR_ZEBRA_MPLS_LABELS_DELETE + + +class _ZebraIPv4Nexthop(_ZebraIPRoute): + """ + Base class for FRR_ZEBRA_IPV4_NEXTHOP_* message body. + """ + _FAMILY = socket.AF_INET + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_ADD) +class ZebraIPv4NexthopAdd(_ZebraIPv4Nexthop): + """ + Message body class for FRR_ZEBRA_IPV4_NEXTHOP_ADD. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_DELETE) +class ZebraIPv4NexthopDelete(_ZebraIPv4Nexthop): + """ + Message body class for FRR_ZEBRA_IPV4_NEXTHOP_DELETE. + """ + + +class _ZebraIPv6Nexthop(_ZebraIPRoute): + """ + Base class for FRR_ZEBRA_IPV6_NEXTHOP_* message body. + """ + _FAMILY = socket.AF_INET6 + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_ADD) +class ZebraIPv6NexthopAdd(_ZebraIPv6Nexthop): + """ + Message body class for FRR_ZEBRA_IPV6_NEXTHOP_ADD. + """ + + +@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_DELETE) +class ZebraIPv6NexthopDelete(_ZebraIPv6Nexthop): + """ + Message body class for FRR_ZEBRA_IPV6_NEXTHOP_DELETE. + """ |