summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ryu/lib/packet/bgp.py90
-rw-r--r--ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcapbin217 -> 273 bytes
-rw-r--r--ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcapbin217 -> 289 bytes
-rw-r--r--ryu/tests/unit/packet/test_bgp.py3
4 files changed, 78 insertions, 15 deletions
diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 47feeb39..d22bb0ed 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -1997,7 +1997,7 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
# +-----------------------------------+
# | NLRI value (variable) |
# +-----------------------------------+
-
+ ROUTE_FAMILY = None
_LENGTH_SHORT_FMT = '!B'
LENGTH_SHORT_SIZE = struct.calcsize(_LENGTH_SHORT_FMT)
_LENGTH_LONG_FMT = '!H'
@@ -2013,7 +2013,7 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
@classmethod
def parser(cls, buf):
- (length, ) = struct.unpack_from(
+ (length,) = struct.unpack_from(
cls._LENGTH_LONG_FMT, six.binary_type(buf))
if length < cls._LENGTH_THRESHOLD:
@@ -2022,7 +2022,14 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
else:
offset = cls.LENGTH_LONG_SIZE
+ kwargs = {'length': length}
rest = buf[offset:offset + length]
+
+ if cls.ROUTE_FAMILY.safi == subaddr_family.VPN_FLOW_SPEC:
+ route_dist = _RouteDistinguisher.parser(rest[:8])
+ kwargs['route_dist'] = route_dist.formatted_str
+ rest = rest[8:]
+
rules = []
while rest:
@@ -2036,10 +2043,17 @@ class _FlowSpecNLRIBase(StringifyMixin, TypeDisp):
rule.operator & rule.END_OF_LIST):
break
- return cls(length, rules), rest
+ kwargs['rules'] = rules
+
+ return cls(**kwargs), rest
def serialize(self):
- rules_bin = bytearray()
+ rules_bin = b''
+
+ if self.ROUTE_FAMILY.safi == subaddr_family.VPN_FLOW_SPEC:
+ route_dist = _RouteDistinguisher.from_str(self.route_dist)
+ rules_bin += route_dist.serialize()
+
self.rules.sort(key=lambda x: x.type)
for _, rules in itertools.groupby(self.rules, key=lambda x: x.type):
rules = list(rules)
@@ -2114,18 +2128,19 @@ class FlowSpecIPv4NLRI(_FlowSpecNLRIBase):
=========== ============= ========= ==============================
Example::
+
>>> msg = bgp.FlowSpecIPv4NLRI.from_user(
... dst_prefix='10.0.0.0/24',
... src_prefix='20.0.0.1/24',
- ... ip_proto='==6',
- ... port='==80 | ==8000',
+ ... ip_proto=6,
+ ... port='80 | 8000',
... dst_port='>9000 & <9050',
... src_port='>=8500 & <=9000',
- ... icmp_type='==0',
- ... icmp_code='==6',
+ ... icmp_type=0,
+ ... icmp_code=6,
... tcp_flags='SYN+ACK & !=URGENT',
- ... packet_len='==1000',
- ... dscp='==22 | ==24',
+ ... packet_len=1000,
+ ... dscp='22 | 24',
... fragment='LF | ==FF')
>>>
@@ -2173,15 +2188,62 @@ class FlowSpecIPv4NLRI(_FlowSpecNLRIBase):
class FlowSpecVPNv4NLRI(_FlowSpecNLRIBase):
"""
Flow Specification NLRI class for VPNv4 [RFC 5575]
-
- See :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI`
"""
+
+ # flow-spec NLRI:
+ # +-----------------------------------+
+ # | length (0xnn or 0xfn nn) |
+ # +-----------------------------------+
+ # | RD (8 octets) |
+ # +-----------------------------------+
+ # | NLRI value (variable) |
+ # +-----------------------------------+
ROUTE_FAMILY = RF_VPNv4_FLOW_SPEC
+ def __init__(self, length=0, route_dist=None, rules=None):
+ super(FlowSpecVPNv4NLRI, self).__init__(length, rules)
+ assert route_dist is not None
+ self.route_dist = route_dist
+
@classmethod
- def from_user(cls, **kwargs):
+ def _from_user(cls, route_dist, **kwargs):
+ rules = []
+ for k, v in kwargs.items():
+ subcls = _FlowSpecComponentBase.lookup_type_name(k)
+ rule = subcls.from_str(str(v))
+ rules.extend(rule)
+ rules.sort(key=lambda x: x.type)
+ return cls(route_dist=route_dist, rules=rules)
- return cls._from_user(**kwargs)
+ @classmethod
+ def from_user(cls, route_dist, **kwargs):
+ """
+ Utility method for creating a NLRI instance.
+
+ This function returns a NLRI instance from human readable format value.
+
+ :param route_dist: Route Distinguisher.
+ :param kwargs: See :py:mod:`ryu.lib.packet.bgp.FlowSpecIPv4NLRI`
+
+ Example::
+
+ >>> msg = bgp.FlowSpecIPv4NLRI.from_user(
+ ... route_dist='65000:1000',
+ ... dst_prefix='10.0.0.0/24',
+ ... src_prefix='20.0.0.1/24',
+ ... ip_proto=6,
+ ... port='80 | 8000',
+ ... dst_port='>9000 & <9050',
+ ... src_port='>=8500 & <=9000',
+ ... icmp_type=0,
+ ... icmp_code=6,
+ ... tcp_flags='SYN+ACK & !=URGENT',
+ ... packet_len=1000,
+ ... dscp='22 | 24',
+ ... fragment='LF | ==FF')
+ >>>
+ """
+ return cls._from_user(route_dist, **kwargs)
class _FlowSpecComponentBase(StringifyMixin, TypeDisp):
diff --git a/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap b/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap
index c7953484..885a106a 100644
--- a/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap
+++ b/ryu/tests/packet_data/bgp4/flowspec_nlri_ipv4.pcap
Binary files differ
diff --git a/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap b/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap
index 74a7d174..236110db 100644
--- a/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap
+++ b/ryu/tests/packet_data/bgp4/flowspec_nlri_vpn4.pcap
Binary files differ
diff --git a/ryu/tests/unit/packet/test_bgp.py b/ryu/tests/unit/packet/test_bgp.py
index dec1dae6..a3b7a68f 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -561,6 +561,7 @@ class Test_bgp(unittest.TestCase):
eq_(rest, b'')
msg = bgp.FlowSpecVPNv4NLRI.from_user(
+ route_dist='65001:250',
dst_prefix='10.0.0.0/24',
src_prefix='20.0.0.0/24',
ip_proto='6',
@@ -573,7 +574,7 @@ class Test_bgp(unittest.TestCase):
packet_len='1000 & 1100',
dscp='22 24',
fragment='LF ==FF&==ISF | !=DF')
- msg2 = bgp.FlowSpecVPNv4NLRI(rules=rules)
+ msg2 = bgp.FlowSpecVPNv4NLRI(route_dist='65001:250', rules=rules)
binmsg = msg.serialize()
binmsg2 = msg2.serialize()
eq_(str(msg), str(msg2))