d9b0c6fbf7
Drop pycodestyle for code style checking in favor of black. Black is much faster, stable PEP8 compliant code style checker offering also automatic formatting. It aims to be very stable and produce smallest diffs. It's used by many small and big projects. Running checkstyle with black takes a few seconds with a terse output. Thus, test-checkstyle-diff is no longer necessary. Expand scope of checkstyle to all python files in the repo, replacing test-checkstyle with checkstyle-python. Also, fixstyle-python is now available for automatic style formatting. Note: python virtualenv has been consolidated in test/Makefile, test/requirements*.txt which will eventually be moved to a central location. This is required to simply the automated generation of docker executor images in the CI. Type: improvement Change-Id: I022a326603485f58585e879ac0f697fceefbc9c8 Signed-off-by: Klement Sekera <klement.sekera@gmail.com> Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
286 lines
9.5 KiB
Python
286 lines
9.5 KiB
Python
#!/usr/bin/env python3
|
|
"""IRB Test Case HLD:
|
|
|
|
**config**
|
|
- L2 MAC learning enabled in l2bd
|
|
- 2 routed interfaces untagged, bvi (Bridge Virtual Interface)
|
|
- 2 bridged interfaces in l2bd with bvi
|
|
|
|
**test**
|
|
- sending ip4 eth pkts between routed interfaces
|
|
- 2 routed interfaces
|
|
- 2 bridged interfaces
|
|
|
|
- 64B, 512B, 1518B, 9200B (ether_size)
|
|
|
|
- burst of pkts per interface
|
|
- 257pkts per burst
|
|
- routed pkts hitting different FIB entries
|
|
- bridged pkts hitting different MAC entries
|
|
|
|
**verify**
|
|
- all packets received correctly
|
|
|
|
"""
|
|
|
|
import unittest
|
|
from random import choice
|
|
|
|
from scapy.packet import Raw
|
|
from scapy.layers.l2 import Ether
|
|
from scapy.layers.inet import IP, UDP
|
|
|
|
from framework import VppTestCase, VppTestRunner
|
|
from vpp_papi import MACAddress
|
|
from vpp_l2 import L2_PORT_TYPE
|
|
|
|
|
|
class TestIpIrb(VppTestCase):
|
|
"""IRB Test Case"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
"""
|
|
#. Create BD with MAC learning enabled and put interfaces to this BD.
|
|
#. Configure IPv4 addresses on BVI interface and routed interface.
|
|
#. Configure MAC address binding to IPv4 neighbors on bvi0.
|
|
#. Configure MAC address on pg2.
|
|
#. BVI interface has remote hosts, one half of hosts are
|
|
behind pg0 second behind pg1.
|
|
"""
|
|
super(TestIpIrb, cls).setUpClass()
|
|
|
|
cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # packet sizes
|
|
cls.bd_id = 10
|
|
cls.remote_hosts_count = 250
|
|
|
|
# create 3 pg interfaces, 1 BVI interface
|
|
cls.create_pg_interfaces(range(3))
|
|
cls.create_bvi_interfaces(1)
|
|
|
|
cls.interfaces = list(cls.pg_interfaces)
|
|
cls.interfaces.extend(cls.bvi_interfaces)
|
|
|
|
for i in cls.interfaces:
|
|
i.admin_up()
|
|
|
|
# Create BD with MAC learning enabled and put interfaces to this BD
|
|
cls.vapi.sw_interface_set_l2_bridge(
|
|
rx_sw_if_index=cls.bvi0.sw_if_index,
|
|
bd_id=cls.bd_id,
|
|
port_type=L2_PORT_TYPE.BVI,
|
|
)
|
|
cls.vapi.sw_interface_set_l2_bridge(
|
|
rx_sw_if_index=cls.pg0.sw_if_index, bd_id=cls.bd_id
|
|
)
|
|
cls.vapi.sw_interface_set_l2_bridge(
|
|
rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.bd_id
|
|
)
|
|
|
|
# Configure IPv4 addresses on BVI interface and routed interface
|
|
cls.bvi0.config_ip4()
|
|
cls.pg2.config_ip4()
|
|
|
|
# Configure MAC address binding to IPv4 neighbors on bvi0
|
|
cls.bvi0.generate_remote_hosts(cls.remote_hosts_count)
|
|
cls.bvi0.configure_ipv4_neighbors()
|
|
# configure MAC address on pg2
|
|
cls.pg2.resolve_arp()
|
|
|
|
# BVI interface has remote hosts, one half of hosts are behind
|
|
# pg0 second behind pg1
|
|
half = cls.remote_hosts_count // 2
|
|
cls.pg0.remote_hosts = cls.bvi0.remote_hosts[:half]
|
|
cls.pg1.remote_hosts = cls.bvi0.remote_hosts[half:]
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
super(TestIpIrb, cls).tearDownClass()
|
|
|
|
def tearDown(self):
|
|
"""Run standard test teardown and log ``show l2patch``,
|
|
``show l2fib verbose``,``show bridge-domain <bd_id> detail``,
|
|
``show ip neighbors``.
|
|
"""
|
|
super(TestIpIrb, self).tearDown()
|
|
|
|
def show_commands_at_teardown(self):
|
|
self.logger.info(self.vapi.cli("show l2patch"))
|
|
self.logger.info(self.vapi.cli("show l2fib verbose"))
|
|
self.logger.info(self.vapi.cli("show bridge-domain %s detail" % self.bd_id))
|
|
self.logger.info(self.vapi.cli("show ip neighbors"))
|
|
|
|
def create_stream(self, src_ip_if, dst_ip_if, packet_sizes):
|
|
pkts = []
|
|
for i in range(0, 257):
|
|
remote_dst_host = choice(dst_ip_if.remote_hosts)
|
|
info = self.create_packet_info(src_ip_if, dst_ip_if)
|
|
payload = self.info_to_payload(info)
|
|
p = (
|
|
Ether(dst=src_ip_if.local_mac, src=src_ip_if.remote_mac)
|
|
/ IP(src=src_ip_if.remote_ip4, dst=remote_dst_host.ip4)
|
|
/ UDP(sport=1234, dport=1234)
|
|
/ Raw(payload)
|
|
)
|
|
info.data = p.copy()
|
|
size = packet_sizes[(i // 2) % len(packet_sizes)]
|
|
self.extend_packet(p, size)
|
|
pkts.append(p)
|
|
return pkts
|
|
|
|
def create_stream_l2_to_ip(self, src_l2_if, src_ip_if, dst_ip_if, packet_sizes):
|
|
pkts = []
|
|
for i in range(0, 257):
|
|
info = self.create_packet_info(src_ip_if, dst_ip_if)
|
|
payload = self.info_to_payload(info)
|
|
|
|
host = choice(src_l2_if.remote_hosts)
|
|
|
|
p = (
|
|
Ether(src=host.mac, dst=src_ip_if.local_mac)
|
|
/ IP(src=host.ip4, dst=dst_ip_if.remote_ip4)
|
|
/ UDP(sport=1234, dport=1234)
|
|
/ Raw(payload)
|
|
)
|
|
|
|
info.data = p.copy()
|
|
size = packet_sizes[(i // 2) % len(packet_sizes)]
|
|
self.extend_packet(p, size)
|
|
|
|
pkts.append(p)
|
|
return pkts
|
|
|
|
def verify_capture_l2_to_ip(self, dst_ip_if, src_ip_if, capture):
|
|
last_info = dict()
|
|
for i in self.interfaces:
|
|
last_info[i.sw_if_index] = None
|
|
|
|
dst_ip_sw_if_index = dst_ip_if.sw_if_index
|
|
|
|
for packet in capture:
|
|
ip = packet[IP]
|
|
udp = packet[IP][UDP]
|
|
payload_info = self.payload_to_info(packet[IP][UDP][Raw])
|
|
|
|
self.assertEqual(payload_info.dst, dst_ip_sw_if_index)
|
|
|
|
next_info = self.get_next_packet_info_for_interface2(
|
|
payload_info.src, dst_ip_sw_if_index, last_info[payload_info.src]
|
|
)
|
|
last_info[payload_info.src] = next_info
|
|
self.assertTrue(next_info is not None)
|
|
saved_packet = next_info.data
|
|
self.assertTrue(next_info is not None)
|
|
|
|
# MAC: src, dst
|
|
self.assertEqual(packet.src, dst_ip_if.local_mac)
|
|
self.assertEqual(packet.dst, dst_ip_if.remote_mac)
|
|
|
|
# IP: src, dst
|
|
host = src_ip_if.host_by_ip4(ip.src)
|
|
self.assertIsNotNone(host)
|
|
self.assertEqual(ip.dst, saved_packet[IP].dst)
|
|
self.assertEqual(ip.dst, dst_ip_if.remote_ip4)
|
|
|
|
# UDP:
|
|
self.assertEqual(udp.sport, saved_packet[UDP].sport)
|
|
self.assertEqual(udp.dport, saved_packet[UDP].dport)
|
|
|
|
def verify_capture(self, dst_ip_if, src_ip_if, capture):
|
|
last_info = dict()
|
|
for i in self.interfaces:
|
|
last_info[i.sw_if_index] = None
|
|
|
|
dst_ip_sw_if_index = dst_ip_if.sw_if_index
|
|
|
|
for packet in capture:
|
|
ip = packet[IP]
|
|
udp = packet[IP][UDP]
|
|
payload_info = self.payload_to_info(packet[IP][UDP][Raw])
|
|
packet_index = payload_info.index
|
|
|
|
self.assertEqual(payload_info.dst, dst_ip_sw_if_index)
|
|
|
|
next_info = self.get_next_packet_info_for_interface2(
|
|
payload_info.src, dst_ip_sw_if_index, last_info[payload_info.src]
|
|
)
|
|
last_info[payload_info.src] = next_info
|
|
self.assertTrue(next_info is not None)
|
|
self.assertEqual(packet_index, next_info.index)
|
|
saved_packet = next_info.data
|
|
self.assertTrue(next_info is not None)
|
|
|
|
# MAC: src, dst
|
|
self.assertEqual(packet.src, dst_ip_if.local_mac)
|
|
host = dst_ip_if.host_by_mac(packet.dst)
|
|
|
|
# IP: src, dst
|
|
self.assertEqual(ip.src, src_ip_if.remote_ip4)
|
|
self.assertEqual(ip.dst, saved_packet[IP].dst)
|
|
self.assertEqual(ip.dst, host.ip4)
|
|
|
|
# UDP:
|
|
self.assertEqual(udp.sport, saved_packet[UDP].sport)
|
|
self.assertEqual(udp.dport, saved_packet[UDP].dport)
|
|
|
|
def test_ip4_irb_1(self):
|
|
"""IPv4 IRB test 1
|
|
|
|
Test scenario:
|
|
- ip traffic from pg2 interface must ends in both pg0 and pg1
|
|
- arp entry present in bvi0 interface for destination IP
|
|
- no l2 entry configured, pg0 and pg1 are same
|
|
"""
|
|
|
|
stream = self.create_stream(self.pg2, self.bvi0, self.pg_if_packet_sizes)
|
|
self.pg2.add_stream(stream)
|
|
|
|
self.pg_enable_capture(self.pg_interfaces)
|
|
self.pg_start()
|
|
|
|
packet_count = self.get_packet_count_for_if_idx(self.bvi0.sw_if_index)
|
|
|
|
rcvd1 = self.pg0.get_capture(packet_count)
|
|
rcvd2 = self.pg1.get_capture(packet_count)
|
|
|
|
self.verify_capture(self.bvi0, self.pg2, rcvd1)
|
|
self.verify_capture(self.bvi0, self.pg2, rcvd2)
|
|
|
|
self.assertListEqual(rcvd1.res, rcvd2.res)
|
|
|
|
def send_and_verify_l2_to_ip(self):
|
|
stream1 = self.create_stream_l2_to_ip(
|
|
self.pg0, self.bvi0, self.pg2, self.pg_if_packet_sizes
|
|
)
|
|
stream2 = self.create_stream_l2_to_ip(
|
|
self.pg1, self.bvi0, self.pg2, self.pg_if_packet_sizes
|
|
)
|
|
self.vapi.cli("clear trace")
|
|
self.pg0.add_stream(stream1)
|
|
self.pg1.add_stream(stream2)
|
|
|
|
self.pg_enable_capture(self.pg_interfaces)
|
|
self.pg_start()
|
|
|
|
rcvd = self.pg2.get_capture(514)
|
|
self.verify_capture_l2_to_ip(self.pg2, self.bvi0, rcvd)
|
|
|
|
def test_ip4_irb_2(self):
|
|
"""IPv4 IRB test 2
|
|
|
|
Test scenario:
|
|
- ip traffic from pg0 and pg1 ends on pg2
|
|
"""
|
|
self.send_and_verify_l2_to_ip()
|
|
|
|
# change the BVI's mac and resed traffic
|
|
self.bvi0.set_mac(MACAddress("00:00:00:11:11:33"))
|
|
|
|
self.send_and_verify_l2_to_ip()
|
|
# check it wasn't flooded
|
|
self.pg1.assert_nothing_captured(remark="UU Flood")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(testRunner=VppTestRunner)
|