summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-09-05 10:13:41 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-09-17 13:37:13 +0900
commit7baed0a100b5c29c9107c79ee0d6e26f056be536 (patch)
treedf0a8ee9313a1d5606bd4206e245d4db43b76e04
parent7804cbb6f4de8d7fe9c0d3445c30833422443f8c (diff)
packet/zebra: Support BFD Destination messages
This patch implements the following messages on FRRouting: - ZEBRA_INTERFACE_BFD_DEST_UPDATE - ZEBRA_BFD_DEST_REGISTER - ZEBRA_BFD_DEST_DEREGISTER - ZEBRA_BFD_DEST_UPDATE - ZEBRA_BFD_DEST_REPLAY 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.py379
1 files changed, 370 insertions, 9 deletions
diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py
index cee83e9a..9e46c308 100644
--- a/ryu/lib/packet/zebra.py
+++ b/ryu/lib/packet/zebra.py
@@ -340,6 +340,13 @@ ZEBRA_PTM_STATUS_DOWN = 0
ZEBRA_PTM_STATUS_UP = 1
ZEBRA_PTM_STATUS_UNKNOWN = 2
+# Constants in frr/lib/bfd.h
+
+# BFD status
+BFD_STATUS_UNKNOWN = 1 << 0
+BFD_STATUS_DOWN = 1 << 1
+BFD_STATUS_UP = 1 << 2
+
# Utility functions/classes
@@ -2575,9 +2582,80 @@ class ZebraInterfaceNbrAddressDelete(_ZebraInterfaceNbrAddress):
"""
-# TODO:
-# Implement the following messages:
-# - FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE
+@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE)
+class ZebraInterfaceBfdDestinationUpdate(_ZebraMessageBody):
+ """
+ Message body class for FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE.
+ """
+ # Zebra Interface BFD Destination Update message body:
+ # 0 1 2 3
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Interface index |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Dst Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Dst IPv4/v6 prefix |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Dst Plen |
+ # +-+-+-+-+-+-+-+-+
+ # | Status |
+ # +-+-+-+-+-+-+-+-+
+ # | Src Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Source IPv4/v6 prefix |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Src Plen |
+ # +-+-+-+-+-+-+-+-+
+ _HEADER_FMT = '!I' # ifindex
+ HEADER_SIZE = struct.calcsize(_HEADER_FMT)
+ _STATUS_FMT = '!B' # status
+ STATUS_SIZE = struct.calcsize(_STATUS_FMT)
+
+ def __init__(self, ifindex, dst_family, dst_prefix, status,
+ src_family, src_prefix):
+ super(ZebraInterfaceBfdDestinationUpdate, self).__init__()
+ self.ifindex = ifindex
+ self.dst_family = dst_family
+ if isinstance(dst_prefix, (IPv4Prefix, IPv6Prefix)):
+ dst_prefix = dst_prefix.prefix
+ self.dst_prefix = dst_prefix
+ self.status = status
+ self.src_family = src_family
+ if isinstance(src_prefix, (IPv4Prefix, IPv6Prefix)):
+ src_prefix = src_prefix.prefix
+ self.src_prefix = src_prefix
+
+ @classmethod
+ def parse(cls, buf, version=_DEFAULT_VERSION):
+ (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
+ rest = buf[cls.HEADER_SIZE:]
+
+ (dst_family, dst_prefix,
+ rest) = _parse_zebra_family_prefix(rest)
+
+ (status,) = struct.unpack_from(cls._STATUS_FMT, rest)
+ rest = rest[cls.STATUS_SIZE:]
+
+ (src_family, src_prefix,
+ _) = _parse_zebra_family_prefix(rest)
+
+ return cls(ifindex, dst_family, dst_prefix, status,
+ src_family, src_prefix)
+
+ def serialize(self, version=_DEFAULT_VERSION):
+ (self.dst_family, # fixup
+ dst_bin) = _serialize_zebra_family_prefix(self.dst_prefix)
+
+ status_bin = struct.pack(
+ self._STATUS_FMT, self.status)
+
+ (self.src_family, # fixup
+ src_bin) = _serialize_zebra_family_prefix(self.src_prefix)
+
+ return struct.pack(
+ self._HEADER_FMT,
+ self.ifindex) + dst_bin + status_bin + src_bin
@_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_REGISTER)
@@ -2601,12 +2679,295 @@ class ZebraImportCheckUpdate(ZebraNexthopUpdate):
"""
-# 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 _ZebraBfdDestination(_ZebraMessageBody):
+ """
+ Base class for FRR_ZEBRA_BFD_DEST_REGISTER and
+ FRR_ZEBRA_BFD_DEST_UPDATE message body.
+ """
+ # Zebra BFD Destination 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 |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Destination Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Destination IPv4/v6 prefix (4 bytes or 16 bytes) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Min RX Timer |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Min TX Timer |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Detect Mult |
+ # +-+-+-+-+-+-+-+-+
+ # | Multi Hop |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Source Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Source IPv4/v6 prefix (4 bytes or 16 bytes) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (MultiHopCnt) | if Multi Hop enabled
+ # +-+-+-+-+-+-+-+-+
+ # | (IFName Len) | if Multi Hop disabled
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Interface Name (Variable)) if Multi Hop disabled |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ _HEADER_FMT = '!I' # pid
+ HEADER_SIZE = struct.calcsize(_HEADER_FMT)
+ _FAMILY_FMT = '!H'
+ FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
+ _BODY_FMT = '!IIBB' # min_rx_timer, min_tx_timer, detect_mult, multi_hop
+ BODY_SIZE = struct.calcsize(_BODY_FMT)
+ _FOOTER_FMT = '!B' # multi_hop_count or ifname_len
+ FOOTER_SIZE = struct.calcsize(_FOOTER_FMT)
+
+ def __init__(self, pid, dst_family, dst_prefix,
+ min_rx_timer, min_tx_timer, detect_mult,
+ multi_hop, src_family, src_prefix,
+ multi_hop_count=None, ifname=None):
+ super(_ZebraBfdDestination, self).__init__()
+ self.pid = pid
+ self.dst_family = dst_family
+ assert (netaddr.valid_ipv4(dst_prefix) or
+ netaddr.valid_ipv6(dst_prefix))
+ self.dst_prefix = dst_prefix
+ self.min_rx_timer = min_rx_timer
+ self.min_tx_timer = min_tx_timer
+ self.detect_mult = detect_mult
+ self.multi_hop = multi_hop
+ self.src_family = src_family
+ assert (netaddr.valid_ipv4(src_prefix) or
+ netaddr.valid_ipv6(src_prefix))
+ self.src_prefix = src_prefix
+ self.multi_hop_count = multi_hop_count
+ self.ifname = ifname
+
+ @classmethod
+ def _parse_family_prefix(cls, buf):
+ (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
+ rest = buf[cls.FAMILY_SIZE:]
+
+ if socket.AF_INET == family:
+ return family, addrconv.ipv4.bin_to_text(rest[:4]), rest[4:]
+ elif socket.AF_INET6 == family:
+ return family, addrconv.ipv6.bin_to_text(rest[:16]), rest[16:]
+
+ raise struct.error('Unsupported family: %d' % family)
+
+ @classmethod
+ def parse(cls, buf, version=_DEFAULT_VERSION):
+ (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
+ rest = buf[cls.HEADER_SIZE:]
+
+ (dst_family, dst_prefix,
+ rest) = cls._parse_family_prefix(rest)
+
+ (min_rx_timer, min_tx_timer, detect_mult,
+ multi_hop) = struct.unpack_from(cls._BODY_FMT, rest)
+ rest = rest[cls.BODY_SIZE:]
+
+ (src_family, src_prefix,
+ rest) = cls._parse_family_prefix(rest)
+
+ multi_hop_count = None
+ ifname = None
+ if multi_hop:
+ (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
+ else:
+ (ifname_len,) = struct.unpack_from(cls._FOOTER_FMT, rest)
+ ifname_bin = rest[cls.FOOTER_SIZE:cls.FOOTER_SIZE + ifname_len]
+ ifname = str(six.text_type(ifname_bin.strip(b'\x00'), 'ascii'))
+
+ return cls(pid, dst_family, dst_prefix,
+ min_rx_timer, min_tx_timer, detect_mult,
+ multi_hop, src_family, src_prefix,
+ multi_hop_count, ifname)
+
+ def _serialize_family_prefix(self, prefix):
+ if netaddr.valid_ipv4(prefix):
+ family = socket.AF_INET
+ return (family,
+ struct.pack(self._FAMILY_FMT, family)
+ + addrconv.ipv4.text_to_bin(prefix))
+ elif netaddr.valid_ipv6(prefix):
+ family = socket.AF_INET6
+ return (family,
+ struct.pack(self._FAMILY_FMT, family)
+ + addrconv.ipv6.text_to_bin(prefix))
+
+ raise ValueError('Invalid prefix: %s' % prefix)
+
+ def serialize(self, version=_DEFAULT_VERSION):
+ (self.dst_family, # fixup
+ dst_bin) = self._serialize_family_prefix(self.dst_prefix)
+
+ body_bin = struct.pack(
+ self._BODY_FMT,
+ self.min_rx_timer, self.min_tx_timer, self.detect_mult,
+ self.multi_hop)
+
+ (self.src_family, # fixup
+ src_bin) = self._serialize_family_prefix(self.src_prefix)
+
+ if self.multi_hop:
+ footer_bin = struct.pack(
+ self._FOOTER_FMT, self.multi_hop_count)
+ else:
+ ifname_bin = self.ifname.encode('ascii')
+ footer_bin = struct.pack(
+ self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
+
+ return struct.pack(
+ self._HEADER_FMT,
+ self.pid) + dst_bin + body_bin + src_bin + footer_bin
+
+
+@_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REGISTER)
+class ZebraBfdDestinationRegister(_ZebraBfdDestination):
+ """
+ Message body class for FRR_ZEBRA_BFD_DEST_REGISTER.
+ """
+
+
+@_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_DEREGISTER)
+class ZebraBfdDestinationDeregister(_ZebraMessageBody):
+ """
+ Message body class for FRR_ZEBRA_BFD_DEST_DEREGISTER.
+ """
+ # 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 |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Destination IPv4/v6 prefix (4 bytes or 16 bytes) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Multi Hop |
+ # +-+-+-+-+-+-+-+-+
+ # | Family |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Source IPv4/v6 prefix (4 bytes or 16 bytes) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (MultiHopCnt) | if Multi Hop enabled
+ # +-+-+-+-+-+-+-+-+
+ # | (IF Name Len) | if Multi Hop disabled
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (IF Name (Variable)) if Multi Hop disabled |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ _HEADER_FMT = '!I' # pid
+ HEADER_SIZE = struct.calcsize(_HEADER_FMT)
+ _FAMILY_FMT = '!H'
+ FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
+ _BODY_FMT = '!B' # multi_hop
+ BODY_SIZE = struct.calcsize(_BODY_FMT)
+ _FOOTER_FMT = '!B' # multi_hop_count or ifname_len
+ FOOTER_SIZE = struct.calcsize(_FOOTER_FMT)
+
+ def __init__(self, pid, dst_family, dst_prefix,
+ multi_hop, src_family, src_prefix,
+ multi_hop_count=None, ifname=None):
+ super(ZebraBfdDestinationDeregister, self).__init__()
+ self.pid = pid
+ self.dst_family = dst_family
+ assert (netaddr.valid_ipv4(dst_prefix) or
+ netaddr.valid_ipv6(dst_prefix))
+ self.dst_prefix = dst_prefix
+ self.multi_hop = multi_hop
+ self.src_family = src_family
+ assert (netaddr.valid_ipv4(src_prefix) or
+ netaddr.valid_ipv6(src_prefix))
+ self.src_prefix = src_prefix
+ self.multi_hop_count = multi_hop_count
+ self.ifname = ifname
+
+ @classmethod
+ def _parse_family_prefix(cls, buf):
+ (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
+ rest = buf[cls.FAMILY_SIZE:]
+
+ if socket.AF_INET == family:
+ return family, addrconv.ipv4.bin_to_text(rest[:4]), rest[4:]
+ elif socket.AF_INET6 == family:
+ return family, addrconv.ipv6.bin_to_text(rest[:16]), rest[16:]
+
+ raise struct.error('Unsupported family: %d' % family)
+
+ @classmethod
+ def parse(cls, buf, version=_DEFAULT_VERSION):
+ (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
+ rest = buf[cls.HEADER_SIZE:]
+
+ (dst_family, dst_prefix,
+ rest) = cls._parse_family_prefix(rest)
+
+ (multi_hop,) = struct.unpack_from(cls._BODY_FMT, rest)
+ rest = rest[cls.BODY_SIZE:]
+
+ (src_family, src_prefix,
+ rest) = cls._parse_family_prefix(rest)
+
+ multi_hop_count = None
+ ifname = None
+ if multi_hop:
+ (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
+ else:
+ (ifname_len,) = struct.unpack_from(cls._FOOTER_FMT, rest)
+ ifname_bin = rest[cls.FOOTER_SIZE:cls.FOOTER_SIZE + ifname_len]
+ ifname = str(six.text_type(ifname_bin.strip(b'\x00'), 'ascii'))
+
+ return cls(pid, dst_family, dst_prefix,
+ multi_hop, src_family, src_prefix,
+ multi_hop_count, ifname)
+
+ def _serialize_family_prefix(self, prefix):
+ if netaddr.valid_ipv4(prefix):
+ family = socket.AF_INET
+ return (family,
+ struct.pack(self._FAMILY_FMT, family)
+ + addrconv.ipv4.text_to_bin(prefix))
+ elif netaddr.valid_ipv6(prefix):
+ family = socket.AF_INET6
+ return (family,
+ struct.pack(self._FAMILY_FMT, family)
+ + addrconv.ipv6.text_to_bin(prefix))
+
+ raise ValueError('Invalid prefix: %s' % prefix)
+
+ def serialize(self, version=_DEFAULT_VERSION):
+ (self.dst_family, # fixup
+ dst_bin) = self._serialize_family_prefix(self.dst_prefix)
+
+ body_bin = struct.pack(self._BODY_FMT, self.multi_hop)
+
+ (self.src_family, # fixup
+ src_bin) = self._serialize_family_prefix(self.src_prefix)
+
+ if self.multi_hop:
+ footer_bin = struct.pack(
+ self._FOOTER_FMT, self.multi_hop_count)
+ else:
+ ifname_bin = self.ifname.encode('ascii')
+ footer_bin = struct.pack(
+ self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
+
+ return struct.pack(
+ self._HEADER_FMT,
+ self.pid) + dst_bin + body_bin + src_bin + footer_bin
+
+
+@_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_UPDATE)
+class ZebraBfdDestinationUpdate(_ZebraBfdDestination):
+ """
+ Message body class for FRR_ZEBRA_BFD_DEST_UPDATE.
+ """
+
+
+@_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REPLAY)
+class ZebraBfdDestinationReply(_ZebraMessageBody):
+ """
+ Message body class for FRR_ZEBRA_BFD_DEST_REPLAY.
+ """
class _ZebraRedistributeIPv4(_ZebraIPRoute):