diff options
-rw-r--r-- | ryu/cfg.py | 1 | ||||
-rw-r--r-- | ryu/flags.py | 8 | ||||
-rw-r--r-- | ryu/lib/packet/zebra.py | 164 | ||||
-rw-r--r-- | ryu/tests/unit/packet/test_zebra.py | 73 |
4 files changed, 203 insertions, 43 deletions
@@ -36,6 +36,7 @@ CONF = oslo_config.cfg.ConfigOpts() from oslo_config.cfg import ConfigOpts +from oslo_config.cfg import Opt from oslo_config.cfg import BoolOpt from oslo_config.cfg import IntOpt from oslo_config.cfg import ListOpt diff --git a/ryu/flags.py b/ryu/flags.py index 69eb3d22..b63b9b5e 100644 --- a/ryu/flags.py +++ b/ryu/flags.py @@ -17,6 +17,8 @@ global flags """ +from distutils.version import LooseVersion + from ryu import cfg CONF = cfg.CONF @@ -80,6 +82,9 @@ DEFAULT_ZSERV_CLIENT_ROUTE_TYPE = 'BGP' DEFAULT_ZSERV_INTERVAL = 10 DEFAULT_ZSERV_DATABASE = 'sqlite:///zebra.db' DEFAULT_ZSERV_ROUTER_ID = '1.1.1.1' +# For the backward compatibility with Quagga, the default FRRouting version +# should be None. +DEFAULT_ZSERV_FRR_VERSION = '0.0' CONF.register_cli_opts([ cfg.StrOpt( @@ -111,4 +116,7 @@ CONF.register_cli_opts([ 'router-id', default=DEFAULT_ZSERV_ROUTER_ID, help='Initial Router ID used by Zebra protocol service ' '(default: %s)' % DEFAULT_ZSERV_ROUTER_ID), + cfg.Opt( + 'frr-version', LooseVersion, default=DEFAULT_ZSERV_FRR_VERSION, + help='FRRouting version when integrated with FRRouting (e.g., 3.0)'), ], group='zapi') diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py index 8e5b5129..ad8b4f07 100644 --- a/ryu/lib/packet/zebra.py +++ b/ryu/lib/packet/zebra.py @@ -23,10 +23,13 @@ import abc import socket import struct import logging +from distutils.version import LooseVersion import netaddr import six +from ryu import flags as cfg_flags # For loading 'zapi' option definition +from ryu.cfg import CONF from ryu.lib import addrconv from ryu.lib import ip from ryu.lib import stringify @@ -42,6 +45,9 @@ LOG = logging.getLogger(__name__) _DEFAULT_VERSION = 3 _DEFAULT_FRR_VERSION = 4 +_FRR_VERSION_2_0 = LooseVersion('2.0') +_FRR_VERSION_3_0 = LooseVersion('3.0') + # Constants in quagga/lib/zebra.h # Default Zebra TCP port @@ -462,6 +468,10 @@ def _serialize_zebra_family_prefix(prefix): raise ValueError('Invalid prefix: %s' % prefix) +def _is_frr_version_ge(compared_version): + return CONF['zapi'].frr_version >= compared_version + + class InterfaceLinkParams(stringify.StringifyMixin): """ Interface Link Parameters class for if_link_params structure. @@ -733,15 +743,27 @@ class NextHopIPv4(_NextHop): """ _BODY_FMT = '!4s' # addr(IPv4) BODY_SIZE = struct.calcsize(_BODY_FMT) + _BODY_FMT_FRR_V3 = '!4sI' # addr(IPv4), ifindex + BODY_SIZE_FRR_V3 = struct.calcsize(_BODY_FMT_FRR_V3) @classmethod def parse(cls, buf): + if _is_frr_version_ge(_FRR_VERSION_3_0): + (addr, ifindex) = struct.unpack_from(cls._BODY_FMT_FRR_V3, buf) + addr = addrconv.ipv4.bin_to_text(addr) + rest = buf[cls.BODY_SIZE_FRR_V3:] + return cls(ifindex=ifindex, addr=addr), rest + addr = addrconv.ipv4.bin_to_text(buf[:cls.BODY_SIZE]) rest = buf[cls.BODY_SIZE:] return cls(addr=addr), rest def _serialize(self): + if _is_frr_version_ge(_FRR_VERSION_3_0) and self.ifindex: + addr = addrconv.ipv4.text_to_bin(self.addr) + return struct.pack(self._BODY_FMT_FRR_V3, addr, self.ifindex) + return addrconv.ipv4.text_to_bin(self.addr) @@ -798,15 +820,27 @@ class NextHopIPv6(_NextHop): """ _BODY_FMT = '!16s' # addr(IPv6) BODY_SIZE = struct.calcsize(_BODY_FMT) + _BODY_FMT_FRR_V3 = '!16sI' # addr(IPv6), ifindex + BODY_SIZE_FRR_V3 = struct.calcsize(_BODY_FMT_FRR_V3) @classmethod def parse(cls, buf): + if _is_frr_version_ge(_FRR_VERSION_3_0): + (addr, ifindex) = struct.unpack_from(cls._BODY_FMT_FRR_V3, buf) + addr = addrconv.ipv4.bin_to_text(addr) + rest = buf[cls.BODY_SIZE_FRR_V3:] + return cls(ifindex=ifindex, addr=addr), rest + addr = addrconv.ipv6.bin_to_text(buf[:cls.BODY_SIZE]) rest = buf[cls.BODY_SIZE:] return cls(addr=addr), rest def _serialize(self): + if _is_frr_version_ge(_FRR_VERSION_3_0) and self.ifindex: + addr = addrconv.ipv4.text_to_bin(self.addr) + return struct.pack(self._BODY_FMT_FRR_V3, addr, self.ifindex) + return addrconv.ipv6.text_to_bin(self.addr) @@ -1226,6 +1260,8 @@ class _ZebraInterface(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Metric | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Speed): v4(FRRouting v3.0 or later) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Interface's MTU for IPv4 | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Interface's MTU for IPv6 | @@ -1254,8 +1290,12 @@ class _ZebraInterface(_ZebraMessageBody): 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) + _V4_HEADER_FMT_2_0 = '!%dsIBQBBIIIIII' % INTERFACE_NAMSIZE + V4_HEADER_SIZE_2_0 = struct.calcsize(_V4_HEADER_FMT_2_0) + # ifname, ifindex, status, if_flags, ptm_enable, ptm_status, metric, + # speed, ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len + _V4_HEADER_FMT_3_0 = '!%dsIBQBBIIIIIII' % INTERFACE_NAMSIZE + V4_HEADER_SIZE_3_0 = struct.calcsize(_V4_HEADER_FMT_3_0) # link_params_state (whether a link-params follows) _LP_STATE_FMT = '!?' @@ -1264,8 +1304,8 @@ class _ZebraInterface(_ZebraMessageBody): 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, + metric=None, speed=None, ifmtu=None, ifmtu6=None, + bandwidth=None, ll_type=None, hw_addr_len=0, hw_addr=None, link_params=None): super(_ZebraInterface, self).__init__() self.ifname = ifname @@ -1275,6 +1315,7 @@ class _ZebraInterface(_ZebraMessageBody): self.ptm_enable = ptm_enable self.ptm_status = ptm_status self.metric = metric + self.speed = speed self.ifmtu = ifmtu self.ifmtu6 = ifmtu6 self.bandwidth = bandwidth @@ -1290,6 +1331,7 @@ class _ZebraInterface(_ZebraMessageBody): def parse(cls, buf, version=_DEFAULT_VERSION): ptm_enable = None ptm_status = None + speed = None ll_type = None if version <= 2: (ifname, ifindex, status, if_flags, metric, @@ -1302,10 +1344,20 @@ class _ZebraInterface(_ZebraMessageBody): 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:] + if _is_frr_version_ge(_FRR_VERSION_3_0): + (ifname, ifindex, status, if_flags, ptm_enable, ptm_status, + metric, speed, ifmtu, ifmtu6, bandwidth, ll_type, + hw_addr_len) = struct.unpack_from(cls._V4_HEADER_FMT_3_0, buf) + rest = buf[cls.V4_HEADER_SIZE_3_0:] + elif _is_frr_version_ge(_FRR_VERSION_2_0): + (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_2_0, buf) + rest = buf[cls.V4_HEADER_SIZE_2_0:] + else: + raise struct.error( + 'Unsupported FRRouting version: %s' + % CONF['zapi'].frr_version) else: raise struct.error( 'Unsupported Zebra protocol version: %d' @@ -1325,7 +1377,7 @@ class _ZebraInterface(_ZebraMessageBody): if not rest: return cls(ifname, ifindex, status, if_flags, - ptm_enable, ptm_status, metric, ifmtu, ifmtu6, + ptm_enable, ptm_status, metric, speed, ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len, hw_addr) (link_param_state,) = struct.unpack_from(cls._LP_STATE_FMT, rest) @@ -1337,7 +1389,7 @@ class _ZebraInterface(_ZebraMessageBody): link_params = None return cls(ifname, ifindex, status, if_flags, - ptm_enable, ptm_status, metric, ifmtu, ifmtu6, + ptm_enable, ptm_status, metric, speed, ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len, hw_addr, link_params) @@ -1368,12 +1420,24 @@ class _ZebraInterface(_ZebraMessageBody): 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 + if _is_frr_version_ge(_FRR_VERSION_3_0): + buf = struct.pack( + self._V4_HEADER_FMT_3_0, + self.ifname.encode('ascii'), self.ifindex, self.status, + self.if_flags, self.ptm_enable, self.ptm_status, + self.metric, self.speed, self.ifmtu, self.ifmtu6, + self.bandwidth, self.ll_type, hw_addr_len) + hw_addr + elif _is_frr_version_ge(_FRR_VERSION_2_0): + buf = struct.pack( + self._V4_HEADER_FMT_2_0, + 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 FRRouting version: %s' + % CONF['zapi'].frr_version) else: raise ValueError( 'Unsupported Zebra protocol version: %d' @@ -1552,6 +1616,8 @@ class _ZebraIPRoute(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | IPv4/v6 Prefix (Variable) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Nexthop Num | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Nexthops (Variable) | @@ -1603,6 +1669,8 @@ class _ZebraIPRoute(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | IPv4/v6 Prefix (Variable) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | (Nexthop Num) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | (Nexthops (Variable)) | @@ -1631,7 +1699,8 @@ class _ZebraIPRoute(_ZebraMessageBody): # API type specific constants _FAMILY = None # either socket.AF_INET or socket.AF_INET6 - def __init__(self, route_type, flags, message, safi=None, prefix=None, + def __init__(self, route_type, flags, message, safi=None, + prefix=None, src_prefix=None, nexthops=None, ifindexes=None, distance=None, metric=None, mtu=None, tag=None, instance=None, from_zebra=False): @@ -1652,6 +1721,10 @@ class _ZebraIPRoute(_ZebraMessageBody): prefix = prefix.prefix self.prefix = prefix + if isinstance(src_prefix, (IPv4Prefix, IPv6Prefix)): + src_prefix = src_prefix.prefix + self.src_prefix = src_prefix + # Nexthops should be a list of str representations of IP address # if this message sent from Zebra, otherwise a list of _Nexthop # subclasses. @@ -1715,6 +1788,10 @@ class _ZebraIPRoute(_ZebraMessageBody): prefix, rest = _parse_ip_prefix(cls._FAMILY, rest) + src_prefix = None + if version == 4 and message & FRR_ZAPI_MESSAGE_SRCPFX: + src_prefix, rest = _parse_ip_prefix(cls._FAMILY, rest) + if from_zebra and message & ZAPI_MESSAGE_NEXTHOP: nexthops = [] (nexthop_num,) = struct.unpack_from(cls._NUM_FMT, rest) @@ -1764,7 +1841,7 @@ class _ZebraIPRoute(_ZebraMessageBody): 'Unsupported Zebra protocol version: %d' % version) - return cls(route_type, flags, message, safi, prefix, + return cls(route_type, flags, message, safi, prefix, src_prefix, nexthops, ifindexes, distance, metric, mtu, tag, instance, from_zebra=from_zebra) @@ -1788,6 +1865,9 @@ class _ZebraIPRoute(_ZebraMessageBody): def serialize(self, version=_DEFAULT_VERSION): prefix = _serialize_ip_prefix(self.prefix) + if version == 4 and self.src_prefix: + self.message |= FRR_ZAPI_MESSAGE_SRCPFX # fixup + prefix += _serialize_ip_prefix(self.src_prefix) nexthops = b'' if self.from_zebra and self.nexthops: @@ -2491,6 +2571,8 @@ class ZebraNexthopUpdate(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | IPv4/v6 prefix | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Distance) | v4(FRRouting v3.0 or later) + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Metric | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Nexthop Num | @@ -2499,15 +2581,22 @@ class ZebraNexthopUpdate(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _FAMILY_FMT = '!H' # family FAMILY_SIZE = struct.calcsize(_FAMILY_FMT) + _DISTANCE_FMT = '!B' # metric + DISTANCE_SIZE = struct.calcsize(_DISTANCE_FMT) _METRIC_FMT = '!I' # metric METRIC_SIZE = struct.calcsize(_METRIC_FMT) - def __init__(self, family, prefix, metric, nexthops=None): + def __init__(self, family, prefix, distance=None, metric=None, + nexthops=None): super(ZebraNexthopUpdate, self).__init__() self.family = family if isinstance(prefix, (IPv4Prefix, IPv6Prefix)): prefix = prefix.prefix self.prefix = prefix + if _is_frr_version_ge(_FRR_VERSION_3_0): + assert distance is not None + self.distance = distance + assert metric is not None self.metric = metric nexthops = nexthops or [] for nexthop in nexthops: @@ -2521,12 +2610,17 @@ class ZebraNexthopUpdate(_ZebraMessageBody): prefix, rest = _parse_ip_prefix(family, rest) + distance = None + if _is_frr_version_ge(_FRR_VERSION_3_0): + (distance,) = struct.unpack_from(cls._DISTANCE_FMT, rest) + rest = rest[cls.DISTANCE_SIZE:] + (metric,) = struct.unpack_from(cls._METRIC_FMT, rest) rest = rest[cls.METRIC_SIZE:] nexthops, rest = _parse_nexthops(rest, version) - return cls(family, prefix, metric, nexthops) + return cls(family, prefix, distance, metric, nexthops) def serialize(self, version=_DEFAULT_VERSION): # fixup @@ -2541,6 +2635,9 @@ class ZebraNexthopUpdate(_ZebraMessageBody): buf += _serialize_ip_prefix(self.prefix) + if _is_frr_version_ge(_FRR_VERSION_3_0): + buf += struct.pack(self._DISTANCE_FMT, self.distance) + buf += struct.pack(self._METRIC_FMT, self.metric) return buf + _serialize_nexthops(self.nexthops, version=version) @@ -3200,6 +3297,8 @@ class _ZebraMplsLabels(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Gate IPv4/v6 Address (4 bytes/16 bytes) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Interface Index: v4(FRRouting v3.0 or later) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Distance | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | In Label | @@ -3216,10 +3315,12 @@ class _ZebraMplsLabels(_ZebraMessageBody): IPV6_PREFIX_SIZE = struct.calcsize(_IPV6_PREFIX_FMT) _FAMILY_IPV4_PREFIX_FMT = '!I4sB' _FAMILY_IPV6_PREFIX_FMT = '!I16sB' + _IFINDEX_FMT = '!I' + IFINDEX_SIZE = struct.calcsize(_IFINDEX_FMT) _BODY_FMT = '!BII' # distance, in_label, out_label - def __init__(self, route_type, family, prefix, gate_addr, - distance, in_label, out_label): + def __init__(self, route_type, family, prefix, gate_addr, ifindex=None, + distance=None, in_label=None, out_label=None): super(_ZebraMplsLabels, self).__init__() self.route_type = route_type self.family = family @@ -3228,8 +3329,14 @@ class _ZebraMplsLabels(_ZebraMessageBody): self.prefix = prefix assert netaddr.valid_ipv4(gate_addr) or netaddr.valid_ipv6(gate_addr) self.gate_addr = gate_addr + if _is_frr_version_ge(_FRR_VERSION_3_0): + assert ifindex is not None + self.ifindex = ifindex + assert distance is not None self.distance = distance + assert in_label is not None self.in_label = in_label + assert out_label is not None self.out_label = out_label @classmethod @@ -3266,10 +3373,15 @@ class _ZebraMplsLabels(_ZebraMessageBody): else: raise struct.error('Unsupported family: %d' % family) + ifindex = None + if _is_frr_version_ge(_FRR_VERSION_3_0): + (ifindex,) = struct.unpack_from(cls._IFINDEX_FMT, rest) + rest = rest[cls.IFINDEX_SIZE:] + (distance, in_label, out_label) = struct.unpack_from(cls._BODY_FMT, rest) - return cls(route_type, family, prefix, gate_addr, + return cls(route_type, family, prefix, gate_addr, ifindex, distance, in_label, out_label) def _serialize_family_prefix(self, prefix): @@ -3303,7 +3415,11 @@ class _ZebraMplsLabels(_ZebraMessageBody): else: raise ValueError('Unsupported family: %d' % self.family) - body_bin = struct.pack( + body_bin = b'' + if _is_frr_version_ge(_FRR_VERSION_3_0): + body_bin = struct.pack(self._IFINDEX_FMT, self.ifindex) + + body_bin += struct.pack( self._BODY_FMT, self.distance, self.in_label, self.out_label) return struct.pack( diff --git a/ryu/tests/unit/packet/test_zebra.py b/ryu/tests/unit/packet/test_zebra.py index b5fb9c5d..4ea76b55 100644 --- a/ryu/tests/unit/packet/test_zebra.py +++ b/ryu/tests/unit/packet/test_zebra.py @@ -15,6 +15,11 @@ from __future__ import print_function +try: + import mock # Python 2 +except ImportError: + from unittest import mock # Python 3 + import os import socket import sys @@ -36,37 +41,53 @@ PCAP_DATA_DIR = os.path.join( '../../packet_data/pcap/') +_patch_frr_v2 = mock.patch( + 'ryu.lib.packet.zebra._is_frr_version_ge', + mock.MagicMock(side_effect=lambda x: x == zebra._FRR_VERSION_2_0)) + + class Test_zebra(unittest.TestCase): """ Test case for ryu.lib.packet.zebra. """ - def test_pcap(self): + @staticmethod + def _test_pcap_single(f): + zebra_pcap_file = os.path.join(PCAP_DATA_DIR, f + '.pcap') + # print('*** testing %s' % zebra_pcap_file) + + for _, buf in pcaplib.Reader(open(zebra_pcap_file, 'rb')): + # Checks if Zebra message can be parsed as expected. + pkt = packet.Packet(buf) + zebra_pkts = pkt.get_protocols(zebra.ZebraMessage) + for zebra_pkt in zebra_pkts: + ok_(isinstance(zebra_pkt, zebra.ZebraMessage), + 'Failed to parse Zebra message: %s' % pkt) + ok_(not isinstance(pkt.protocols[-1], + (six.binary_type, bytearray)), + 'Some messages could not be parsed in %s: %s' % (f, pkt)) + + # Checks if Zebra message can be serialized as expected. + pkt.serialize() + eq_(binary_str(buf), binary_str(pkt.data)) + + def test_pcap_quagga(self): files = [ 'zebra_v2', 'zebra_v3', + ] + + for f in files: + self._test_pcap_single(f) + + @_patch_frr_v2 + def test_pcap_frr_v2(self): + files = [ 'zebra_v4_frr_v2', # API version 4 on FRRouting v2.0 ] for f in files: - zebra_pcap_file = os.path.join(PCAP_DATA_DIR, f + '.pcap') - # print('*** testing %s' % zebra_pcap_file) - - for _, buf in pcaplib.Reader(open(zebra_pcap_file, 'rb')): - # Checks if Zebra message can be parsed as expected. - pkt = packet.Packet(buf) - zebra_pkts = pkt.get_protocols(zebra.ZebraMessage) - for zebra_pkt in zebra_pkts: - ok_(isinstance(zebra_pkt, zebra.ZebraMessage), - 'Failed to parse Zebra message: %s' % pkt) - ok_(not isinstance(pkt.protocols[-1], - (six.binary_type, bytearray)), - 'Some messages could not be parsed: %s' % pkt) - - # Checks if Zebra message can be serialized as expected. - pkt.serialize() - eq_(buf, pkt.data, - "b'%s' != b'%s'" % (binary_str(buf), binary_str(pkt.data))) + self._test_pcap_single(f) class TestZebraMessage(unittest.TestCase): @@ -227,6 +248,7 @@ class TestZebraNexthopUpdateIPv6(unittest.TestCase): nexthop_type = zebra.ZEBRA_NEXTHOP_IFINDEX ifindex = 2 + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraNexthopUpdate.parse(self.buf) @@ -253,6 +275,7 @@ class TestZebraInterfaceNbrAddressAdd(unittest.TestCase): family = socket.AF_INET prefix = '192.168.1.0/24' + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraInterfaceNbrAddressAdd.parse(self.buf) @@ -283,6 +306,7 @@ class TestZebraInterfaceBfdDestinationUpdate(unittest.TestCase): src_family = socket.AF_INET src_prefix = '192.168.1.2/24' + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraInterfaceBfdDestinationUpdate.parse(self.buf) @@ -323,6 +347,7 @@ class TestZebraBfdDestinationRegisterMultiHopEnabled(unittest.TestCase): multi_hop_count = 5 ifname = None + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationRegister.parse(self.buf) @@ -369,6 +394,7 @@ class TestZebraBfdDestinationRegisterMultiHopDisabled(unittest.TestCase): multi_hop_count = None ifname = 'eth0' + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationRegister.parse(self.buf) @@ -420,6 +446,7 @@ class TestZebraBfdDestinationRegisterMultiHopEnabledIPv6(unittest.TestCase): multi_hop_count = 5 ifname = None + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationRegister.parse(self.buf) @@ -459,6 +486,7 @@ class TestZebraBfdDestinationDeregisterMultiHopEnabled(unittest.TestCase): multi_hop_count = 5 ifname = None + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationDeregister.parse(self.buf) @@ -496,6 +524,7 @@ class TestZebraBfdDestinationDeregisterMultiHopDisabled(unittest.TestCase): multi_hop_count = None ifname = 'eth0' + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationDeregister.parse(self.buf) @@ -538,6 +567,7 @@ class TestZebraBfdDestinationDeregisterMultiHopEnabledIPv6(unittest.TestCase): multi_hop_count = 5 ifname = None + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraBfdDestinationDeregister.parse(self.buf) @@ -569,6 +599,7 @@ class TestZebraVrfAdd(unittest.TestCase): ) vrf_name = 'VRF1' + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraVrfAdd.parse(self.buf) @@ -587,6 +618,7 @@ class TestZebraInterfaceVrfUpdate(unittest.TestCase): ifindex = 1 vrf_id = 2 + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraInterfaceVrfUpdate.parse(self.buf) @@ -606,6 +638,7 @@ class TestZebraInterfaceEnableRadv(unittest.TestCase): ifindex = 1 interval = 0x100 + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraInterfaceEnableRadv.parse(self.buf) @@ -636,6 +669,7 @@ class TestZebraMplsLabelsAddIPv4(unittest.TestCase): in_label = 100 out_label = zebra.MPLS_IMP_NULL_LABEL + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraMplsLabelsAdd.parse(self.buf) @@ -677,6 +711,7 @@ class TestZebraMplsLabelsAddIPv6(unittest.TestCase): in_label = 100 out_label = zebra.MPLS_IMP_NULL_LABEL + @_patch_frr_v2 def test_parser(self): body = zebra.ZebraMplsLabelsAdd.parse(self.buf) |