aboutsummaryrefslogtreecommitdiffstats
path: root/test/test_dvr.py
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-10-03 08:20:21 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2017-10-05 09:50:26 +0000
commit6f6311560380d0e992f710558e213df1b098ef94 (patch)
tree237e34a2165ed5d2fc0848a1daec457ce57acc3e /test/test_dvr.py
parentd3c008d108aa2187d1a2afe2833b4de25ca2c2ab (diff)
Distributed Virtual Router Support
A distributed virtual router works by attmpeting to switch a packet, but on failing to find a local consumer (i.e. the packet is destined to a locally attached host) then the packet is sent unmodified 'upstream' to where the rest of the 'distributed' router is present. When L3 switching a packet this means the L2 header must not be modifed. This patch adds a 'l2-bridge' object to the L3 FIB which re-injects packets from the L3 path back into the L2 path - use with extreme caution. Change-Id: I069724eb45956647d7980cbe40a80a788ee6ee82 Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'test/test_dvr.py')
-rw-r--r--test/test_dvr.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/test/test_dvr.py b/test/test_dvr.py
new file mode 100644
index 00000000000..27522a54eea
--- /dev/null
+++ b/test/test_dvr.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+import random
+import socket
+import unittest
+
+from framework import VppTestCase, VppTestRunner
+from vpp_sub_interface import VppSubInterface, VppDot1QSubint
+from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_papi_provider import L2_VTR_OP
+
+from scapy.packet import Raw
+from scapy.layers.l2 import Ether, Dot1Q, ARP
+from scapy.layers.inet import IP, UDP
+from util import ppp
+
+
+class TestDVR(VppTestCase):
+ """ IPv4 Load-Balancing """
+
+ def setUp(self):
+ super(TestDVR, self).setUp()
+
+ self.create_pg_interfaces(range(4))
+ self.create_loopback_interfaces(range(1))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+
+ self.loop0.config_ip4()
+
+ def tearDown(self):
+ for i in self.pg_interfaces:
+ i.admin_down()
+ self.loop0.unconfig_ip4()
+
+ super(TestDVR, self).tearDown()
+
+ def test_dvr(self):
+ """ Distributed Virtual Router """
+
+ #
+ # A packet destined to an IP address that is L2 bridged via
+ # a non-tag interface
+ #
+ ip_non_tag_bridged = "10.10.10.10"
+ ip_tag_bridged = "10.10.10.11"
+ any_src_addr = "1.1.1.1"
+
+ pkt_no_tag = (Ether(src=self.pg0.remote_mac,
+ dst=self.loop0.local_mac) /
+ IP(src=any_src_addr,
+ dst=ip_non_tag_bridged) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ pkt_tag = (Ether(src=self.pg0.remote_mac,
+ dst=self.loop0.local_mac) /
+ IP(src=any_src_addr,
+ dst=ip_tag_bridged) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ #
+ # Two sub-interfaces so we can test VLAN tag push/pop
+ #
+ sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92)
+ sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93)
+ sub_if_on_pg2.admin_up()
+ sub_if_on_pg3.admin_up()
+
+ #
+ # Put all the interfaces into a new bridge domain
+ #
+ self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1)
+ self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1)
+ self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1)
+ self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1)
+ self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index, 1, bvi=1)
+
+ self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg2.sw_if_index,
+ L2_VTR_OP.L2_POP_1,
+ 92)
+ self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg3.sw_if_index,
+ L2_VTR_OP.L2_POP_1,
+ 93)
+
+ self.logger.error(self.vapi.ppcli("show bridge-domain 1 detail"))
+
+ #
+ # Add routes to bridge the traffic via a tagged an nontagged interface
+ #
+ route_no_tag = VppIpRoute(
+ self, ip_non_tag_bridged, 32,
+ [VppRoutePath("0.0.0.0",
+ self.pg1.sw_if_index,
+ proto=DpoProto.DPO_PROTO_ETHERNET)])
+ route_no_tag.add_vpp_config()
+
+ #
+ # Inject the packet that arrives and leaves on a non-tagged interface
+ # Since it's 'bridged' expect that the MAC headed is unchanged.
+ #
+ self.pg0.add_stream(pkt_no_tag)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(1)
+
+ self.assertEqual(rx[0][Ether].dst, pkt_no_tag[Ether].dst)
+ self.assertEqual(rx[0][Ether].src, pkt_no_tag[Ether].src)
+
+ #
+ # Add routes to bridge the traffic via a tagged interface
+ #
+ route_no_tag = VppIpRoute(
+ self, ip_tag_bridged, 32,
+ [VppRoutePath("0.0.0.0",
+ sub_if_on_pg3.sw_if_index,
+ proto=DpoProto.DPO_PROTO_ETHERNET)])
+ route_no_tag.add_vpp_config()
+
+ #
+ # Inject the packet that arrives and leaves on a non-tagged interface
+ # Since it's 'bridged' expect that the MAC headed is unchanged.
+ #
+ self.pg0.add_stream(pkt_tag)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg3.get_capture(1)
+
+ self.assertEqual(rx[0][Ether].dst, pkt_tag[Ether].dst)
+ self.assertEqual(rx[0][Ether].src, pkt_tag[Ether].src)
+ self.assertEqual(rx[0][Dot1Q].vlan, 93)
+
+ #
+ # Tag to tag
+ #
+ pkt_tag_to_tag = (Ether(src=self.pg2.remote_mac,
+ dst=self.loop0.local_mac) /
+ Dot1Q(vlan=92) /
+ IP(src=any_src_addr,
+ dst=ip_tag_bridged) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.pg2.add_stream(pkt_tag_to_tag)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ rx = self.pg3.get_capture(1)
+
+ self.assertEqual(rx[0][Ether].dst, pkt_tag_to_tag[Ether].dst)
+ self.assertEqual(rx[0][Ether].src, pkt_tag_to_tag[Ether].src)
+ self.assertEqual(rx[0][Dot1Q].vlan, 93)
+
+ #
+ # Tag to non-Tag
+ #
+ pkt_tag_to_non_tag = (Ether(src=self.pg2.remote_mac,
+ dst=self.loop0.local_mac) /
+ Dot1Q(vlan=92) /
+ IP(src=any_src_addr,
+ dst=ip_non_tag_bridged) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ self.pg2.add_stream(pkt_tag_to_non_tag)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ rx = self.pg1.get_capture(1)
+
+ self.assertEqual(rx[0][Ether].dst, pkt_tag_to_tag[Ether].dst)
+ self.assertEqual(rx[0][Ether].src, pkt_tag_to_tag[Ether].src)
+ self.assertFalse(rx[0].haslayer(Dot1Q))
+
+if __name__ == '__main__':
+ unittest.main(testRunner=VppTestRunner)