packet/zebra: Support FRRouting version 3.0
This patch enables to support Zebra messages of FRRouting version 3.0 and introduces a flag to switch FRRouting version. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
parent
6e51b2a41d
commit
66bdeaa7b5
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue