summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-04-04 14:21:03 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-05-09 10:20:16 +0900
commit2354bd7df38b67992408bb6bb357a31a934d844d (patch)
treef6df742efeb6ebdb1bbb03faa989f85fde63e011
parent6d35bb8d0198900de0ae418d966112bb8ab4a09b (diff)
packet/zebra: Support IP_ROUTE message from Zebra
Zebra IPv4/IPv6 route message have asymmetric structure, in other words, the message structure from Zebra to the protocol daemons and that from the protocol daemons to Zebra have the different structures. This patch introduces _ZebraMessageFromZebra in order to distinguish which daemon sent the message and fixes _ZebraIPRoute to decode IPv4/IPv6 route message from Zebra. 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/tcp.py4
-rw-r--r--ryu/lib/packet/zebra.py181
-rw-r--r--ryu/services/protocols/zebra/client/zclient.py2
3 files changed, 164 insertions, 23 deletions
diff --git a/ryu/lib/packet/tcp.py b/ryu/lib/packet/tcp.py
index e264f6db..4b7dfe2e 100644
--- a/ryu/lib/packet/tcp.py
+++ b/ryu/lib/packet/tcp.py
@@ -120,7 +120,9 @@ class tcp(packet_base.PacketBase):
elif(src_port in [OFP_TCP_PORT, OFP_SSL_PORT_OLD] or
dst_port in [OFP_TCP_PORT, OFP_SSL_PORT_OLD]):
return openflow.openflow
- elif zebra.ZEBRA_PORT in [src_port, dst_port]:
+ elif src_port == zebra.ZEBRA_PORT:
+ return zebra._ZebraMessageFromZebra
+ elif dst_port == zebra.ZEBRA_PORT:
return zebra.ZebraMessage
else:
return None
diff --git a/ryu/lib/packet/zebra.py b/ryu/lib/packet/zebra.py
index fec37b42..2858e053 100644
--- a/ryu/lib/packet/zebra.py
+++ b/ryu/lib/packet/zebra.py
@@ -33,6 +33,7 @@ from ryu.lib import stringify
from ryu.lib import type_desc
from . import packet_base
from . import bgp
+from . import safi as packet_safi
LOG = logging.getLogger(__name__)
@@ -774,14 +775,15 @@ class ZebraMessage(packet_base.PacketBase):
'marker=%d, version=%d' % (marker, version))
@classmethod
- def parser(cls, buf):
+ def _parser_impl(cls, buf, body_parser='parse'):
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)
- body = body_cls.parse(body_buf)
+ _parser = getattr(body_cls, body_parser)
+ body = _parser(body_buf)
else:
body = None
@@ -789,6 +791,10 @@ class ZebraMessage(packet_base.PacketBase):
return cls(length, version, vrf_id, command, body), cls, rest
+ @classmethod
+ def parser(cls, buf):
+ return cls._parser_impl(buf)
+
def serialize_header(self, body_len):
if self.version == 0:
self.length = self.V0_HEADER_SIZE + body_len # fixup
@@ -821,6 +827,16 @@ class ZebraMessage(packet_base.PacketBase):
return self.serialize_header(len(body)) + body
+class _ZebraMessageFromZebra(ZebraMessage):
+ """
+ This class is corresponding to the message sent from Zebra daemon.
+ """
+
+ @classmethod
+ def parser(cls, buf):
+ return cls._parser_impl(buf, body_parser='parse_from_zebra')
+
+
# Alias
zebra = ZebraMessage
@@ -844,6 +860,10 @@ class _ZebraMessageBody(type_desc.TypeDisp, stringify.StringifyMixin):
def parse(cls, buf):
return cls()
+ @classmethod
+ def parse_from_zebra(cls, buf):
+ return cls.parse(buf)
+
def serialize(self):
return b''
@@ -1155,8 +1175,14 @@ class _ZebraIPRoute(_ZebraMessageBody):
"""
Base class for ZEBRA_IPV4_ROUTE_* and ZEBRA_IPV6_ROUTE_*
message body.
+
+ .. Note::
+
+ Zebra IPv4/IPv6 Route message have asymmetric structure.
+ If the message sent from Zebra Daemon, set 'from_zebra=True' to
+ create an instance of this class.
"""
- # Zebra IPv4/IPv6 Route message body:
+ # Zebra IPv4/IPv6 Route 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
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -1178,33 +1204,93 @@ class _ZebraIPRoute(_ZebraMessageBody):
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | (TAG) |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- _HEADER_FMT = '!BBBH' # type, flags, message, safi
+ #
+ # 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
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Route Type | Flags | Message |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | IPv4/v6 Prefix (Variable) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Nexthop Num) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Nexthops (Variable)) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (IFIndex Num) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Interface indexes) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Distance) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (Metric) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (MTU) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | (TAG) |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ _HEADER_FMT = '!BBB' # type, flags, message
HEADER_SIZE = struct.calcsize(_HEADER_FMT)
+ _SAFI_FMT = '!H' # safi
+ SAFI_SIZE = struct.calcsize(_SAFI_FMT)
+ _NUM_FMT = '!B' # nexthop_num or ifindex_num
+ NUM_SIZE = struct.calcsize(_NUM_FMT)
+ _IFINDEX_FMT = '!I' # ifindex
+ IFINDEX_SIZE = struct.calcsize(_IFINDEX_FMT)
# API type specific constants
_FAMILY = None # either socket.AF_INET or socket.AF_INET6
- def __init__(self, route_type, flags, message, safi, prefix,
- nexthops=None,
+ def __init__(self, route_type, flags, message, safi=None, prefix=None,
+ nexthops=None, ifindexes=None,
distance=None, metric=None, mtu=None, tag=None,
- _tail=None):
+ from_zebra=False):
super(_ZebraIPRoute, self).__init__()
self.route_type = route_type
self.flags = flags
self.message = message
- self.safi = safi
+
+ # SAFI should be included if this message sent to Zebra.
+ if from_zebra:
+ self.safi = None
+ else:
+ self.safi = safi or packet_safi.UNICAST
+
+ assert prefix is not None
if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
prefix = prefix.prefix
self.prefix = prefix
+
+ # Nexthops should be a list of str representations of IP address
+ # if this message sent from Zebra, otherwise a list of _Nexthop
+ # subclasses.
nexthops = nexthops or []
- for nexthop in nexthops:
- assert isinstance(nexthop, _NextHop)
+ if from_zebra:
+ for nexthop in nexthops:
+ assert (netaddr.valid_ipv4(nexthop)
+ or netaddr.valid_ipv6(nexthop))
+ else:
+ for nexthop in nexthops:
+ assert isinstance(nexthop, _NextHop)
self.nexthops = nexthops
+
+ # Interface indexes should be included if this message sent from
+ # Zebra.
+ if from_zebra:
+ ifindexes = ifindexes or []
+ for ifindex in ifindexes:
+ assert isinstance(ifindex, six.integer_types)
+ self.ifindexes = ifindexes
+ else:
+ self.ifindexes = None
+
self.distance = distance
self.metric = metric
self.mtu = mtu
self.tag = tag
- self._tail = _tail or b''
+
+ # is this message sent from Zebra message or not.
+ self.from_zebra = from_zebra
@classmethod
def _parse_message_option(cls, message, flag, fmt, buf):
@@ -1215,14 +1301,44 @@ class _ZebraIPRoute(_ZebraMessageBody):
return None, buf
@classmethod
- def parse(cls, buf):
- (route_type, flags, message, safi) = struct.unpack_from(
+ def _parse_impl(cls, buf, from_zebra=False):
+ (route_type, flags, message,) = struct.unpack_from(
cls._HEADER_FMT, buf)
rest = buf[cls.HEADER_SIZE:]
+ if from_zebra:
+ safi = None
+ else:
+ (safi,) = struct.unpack_from(cls._SAFI_FMT, rest)
+ rest = rest[cls.SAFI_SIZE:]
+
prefix, rest = _parse_ip_prefix(cls._FAMILY, rest)
- nexthops, rest = _parse_nexthops(rest)
+ if from_zebra and message & ZAPI_MESSAGE_NEXTHOP:
+ nexthops = []
+ (nexthop_num,) = struct.unpack_from(cls._NUM_FMT, rest)
+ rest = rest[cls.NUM_SIZE:]
+ if cls._FAMILY == socket.AF_INET:
+ for _ in range(nexthop_num):
+ nexthop = addrconv.ipv4.bin_to_text(rest[:4])
+ nexthops.append(nexthop)
+ rest = rest[4:]
+ else: # cls._FAMILY == socket.AF_INET6:
+ for _ in range(nexthop_num):
+ nexthop = addrconv.ipv6.bin_to_text(rest[:16])
+ nexthops.append(nexthop)
+ rest = rest[16:]
+ else:
+ nexthops, rest = _parse_nexthops(rest)
+
+ ifindexes = []
+ if from_zebra and message & ZAPI_MESSAGE_IFINDEX:
+ (ifindex_num,) = struct.unpack_from(cls._NUM_FMT, rest)
+ rest = rest[cls.NUM_SIZE:]
+ for _ in range(ifindex_num):
+ (ifindex,) = struct.unpack_from(cls._IFINDEX_FMT, rest)
+ ifindexes.append(ifindex)
+ rest = rest[cls.IFINDEX_SIZE:]
distance, rest = cls._parse_message_option(
message, ZAPI_MESSAGE_DISTANCE, '!B', rest)
@@ -1233,9 +1349,18 @@ class _ZebraIPRoute(_ZebraMessageBody):
tag, rest = cls._parse_message_option(
message, ZAPI_MESSAGE_TAG, '!I', rest)
- return cls(route_type, flags, message, safi,
- prefix, nexthops,
- distance, metric, mtu, tag, _tail=rest)
+ return cls(route_type, flags, message, safi, prefix,
+ nexthops, ifindexes,
+ distance, metric, mtu, tag,
+ from_zebra=from_zebra)
+
+ @classmethod
+ def parse(cls, buf):
+ return cls._parse_impl(buf)
+
+ @classmethod
+ def parse_from_zebra(cls, buf):
+ return cls._parse_impl(buf, from_zebra=True)
def _serialize_message_option(self, option, flag, fmt):
if option is None:
@@ -1249,9 +1374,22 @@ class _ZebraIPRoute(_ZebraMessageBody):
def serialize(self):
prefix = _serialize_ip_prefix(self.prefix)
- nexthops = _serialize_nexthops(self.nexthops)
+ nexthops = b''
if 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)
+
+ ifindexes = b''
+ if self.ifindexes and self.from_zebra:
+ self.message |= ZAPI_MESSAGE_IFINDEX # fixup
+ ifindexes += struct.pack(self._NUM_FMT, len(self.ifindexes))
+ for ifindex in self.ifindexes:
+ ifindexes += struct.pack(self._IFINDEX_FMT, ifindex)
options = self._serialize_message_option(
self.distance, ZAPI_MESSAGE_DISTANCE, '!B')
@@ -1263,10 +1401,11 @@ class _ZebraIPRoute(_ZebraMessageBody):
self.tag, ZAPI_MESSAGE_TAG, '!I')
header = struct.pack(
- self._HEADER_FMT,
- self.route_type, self.flags, self.message, self.safi)
+ self._HEADER_FMT, self.route_type, self.flags, self.message)
+ if not self.from_zebra:
+ header += struct.pack(self._SAFI_FMT, self.safi)
- return header + prefix + nexthops + options + self._tail
+ return header + prefix + nexthops + ifindexes + options
class _ZebraIPv4Route(_ZebraIPRoute):
diff --git a/ryu/services/protocols/zebra/client/zclient.py b/ryu/services/protocols/zebra/client/zclient.py
index 59d659d3..570a42c8 100644
--- a/ryu/services/protocols/zebra/client/zclient.py
+++ b/ryu/services/protocols/zebra/client/zclient.py
@@ -171,7 +171,7 @@ class ZServer(object):
recv_len = length - len(buf)
break
- msg, _, buf = zebra.ZebraMessage.parser(buf)
+ msg, _, buf = zebra._ZebraMessageFromZebra.parser(buf)
ev = event.message_to_event(self.client, msg)
if ev: