diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2017-09-05 10:13:36 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-09-17 13:36:40 +0900 |
commit | a5f24fe3e32ba1f8e210e77917d8dd28ad9e96b9 (patch) | |
tree | 285412bd48acec42b983164b82c5269c9a7cd73f | |
parent | b66c597fb659c314cd23c661193d160b73458b73 (diff) |
packet/zebra: Support asymmetric structure of ZEBRA_*_IMPORT_LOOKUP
The ZEBRA_IPV4_IMPORT_LOOKUP/ZEBRA_IPV6_IMPORT_LOOKUP has asymmetric
structures at when sent to Zebra daemon and when sent from Zebra daemon.
Especially, "prefix_len" field is inserted before "prefix" filed when
sent to Zebra daemon.
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 | 80 |
1 files changed, 63 insertions, 17 deletions
diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py index 25c72391..62b4d8ff 100644 --- a/ryu/lib/packet/zebra.py +++ b/ryu/lib/packet/zebra.py @@ -1629,12 +1629,29 @@ class _ZebraIPImportLookup(_ZebraMessageBody): """ Base class for ZEBRA_IPV4_IMPORT_LOOKUP and ZEBRA_IPV6_IMPORT_LOOKUP message body. + + .. Note:: + + Zebra IPv4/v6 Import Lookup message have asymmetric structure. + If the message sent from Zebra Daemon, set 'from_zebra=True' to + create an instance of this class. """ - # Zebra IPv4/v6 Import Lookup message body: + # Zebra IPv4/v6 Import Lookup message body + # (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 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | IPv4/v6 prefix | + # | Prefix Len | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | IPv4/v6 Prefix (4 bytes or 16 bytes) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Zebra IPv4/v6 Import Lookup message body + # (Zebra Daemons -> Protocol 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | IPv4/v6 Prefix (4 bytes or 16 bytes) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Metric | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -1642,6 +1659,8 @@ class _ZebraIPImportLookup(_ZebraMessageBody): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Nexthops (Variable) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + _PREFIX_LEN_FMT = '!B' # prefix_len + PREFIX_LEN_SIZE = struct.calcsize(_PREFIX_LEN_FMT) _METRIC_FMT = '!I' # metric METRIC_SIZE = struct.calcsize(_METRIC_FMT) @@ -1649,37 +1668,64 @@ class _ZebraIPImportLookup(_ZebraMessageBody): PREFIX_CLS = None # either addrconv.ipv4 or addrconv.ipv6 PREFIX_LEN = None # IP prefix length in bytes - def __init__(self, prefix, metric=None, nexthops=None): + def __init__(self, prefix, metric=None, nexthops=None, + from_zebra=False): super(_ZebraIPImportLookup, self).__init__() - assert netaddr.valid_ipv4(prefix) or netaddr.valid_ipv6(prefix) + if not from_zebra: + assert ip.valid_ipv4(prefix) or ip.valid_ipv6(prefix) + else: + if isinstance(prefix, (IPv4Prefix, IPv6Prefix)): + prefix = prefix.prefix + else: + assert netaddr.valid_ipv4(prefix) or netaddr.valid_ipv6(prefix) self.prefix = prefix self.metric = metric nexthops = nexthops or [] for nexthop in nexthops: assert isinstance(nexthop, _NextHop) self.nexthops = nexthops + self.from_zebra = from_zebra @classmethod - def parse(cls, buf, version=_DEFAULT_VERSION): + def parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False): + if not from_zebra: + (prefix_len,) = struct.unpack_from(cls._PREFIX_LEN_FMT, buf) + rest = buf[cls.PREFIX_LEN_SIZE:] + prefix = cls.PREFIX_CLS.bin_to_text(rest[:cls.PREFIX_LEN]) + return cls('%s/%d' % (prefix, prefix_len), from_zebra=False) + prefix = cls.PREFIX_CLS.bin_to_text(buf[:cls.PREFIX_LEN]) - rest = buf[cls.PREFIX_LEN:] + rest = buf[4:] - metric = None - if rest: - (metric,) = struct.unpack_from(cls._METRIC_FMT, rest) - rest = rest[cls.METRIC_SIZE:] + (metric,) = struct.unpack_from(cls._METRIC_FMT, rest) + rest = rest[cls.METRIC_SIZE:] - nexthops = None - if rest: - nexthops, rest = _parse_nexthops(rest) + nexthops, rest = _parse_nexthops(rest) + + return cls(prefix, metric, nexthops, from_zebra=True) + + @classmethod + def parse(cls, buf, version=_DEFAULT_VERSION): + return cls.parse_impl(buf, version=version, from_zebra=False) - return cls(prefix, metric, nexthops) + @classmethod + def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION): + return cls.parse_impl(buf, version=version, from_zebra=True) def serialize(self, version=_DEFAULT_VERSION): - buf = self.PREFIX_CLS.text_to_bin(self.prefix) + if not self.from_zebra: + if ip.valid_ipv4(self.prefix) or ip.valid_ipv6(self.prefix): + prefix, prefix_len = self.prefix.split('/') + return struct.pack( + self._PREFIX_LEN_FMT, + int(prefix_len)) + self.PREFIX_CLS.text_to_bin(prefix) + else: + raise ValueError('Invalid prefix: %s' % self.prefix) - if self.metric is None: - return buf + if netaddr.valid_ipv4(self.prefix) or netaddr.valid_ipv6(self.prefix): + buf = self.PREFIX_CLS.text_to_bin(self.prefix) + else: + raise ValueError('Invalid prefix: %s' % self.prefix) buf += struct.pack(self._METRIC_FMT, self.metric) |