From 50a94e81759cbcc43a8b010cf877f086f2f326d2 Mon Sep 17 00:00:00 2001 From: Ahmed Karic Date: Fri, 2 May 2025 19:54:06 +0200 Subject: [PATCH] test: Verify ieee-group-forward LLDP --- test/case/infix_services/Readme.adoc | 2 + test/case/infix_services/lldp.yaml | 3 + .../lldp_ieee_group_forward/Readme.adoc | 1 + .../lldp_ieee_group_forward.adoc | 28 ++++ .../lldp_ieee_group_forward/test.py | 145 ++++++++++++++++++ .../lldp_ieee_group_forward/topology.dot | 24 +++ .../lldp_ieee_group_forward/topology.svg | 51 ++++++ 7 files changed, 254 insertions(+) create mode 120000 test/case/infix_services/lldp_ieee_group_forward/Readme.adoc create mode 100644 test/case/infix_services/lldp_ieee_group_forward/lldp_ieee_group_forward.adoc create mode 100755 test/case/infix_services/lldp_ieee_group_forward/test.py create mode 100644 test/case/infix_services/lldp_ieee_group_forward/topology.dot create mode 100644 test/case/infix_services/lldp_ieee_group_forward/topology.svg diff --git a/test/case/infix_services/Readme.adoc b/test/case/infix_services/Readme.adoc index a0bdab82..be8577d0 100644 --- a/test/case/infix_services/Readme.adoc +++ b/test/case/infix_services/Readme.adoc @@ -11,6 +11,8 @@ include::lldp_enable_disable/Readme.adoc[] include::lldp_admin_status/Readme.adoc[] +include::lldp_ieee_group_forward/Readme.adoc[] + include::ssh_server_config/Readme.adoc[] include::ssh_key_authentication/Readme.adoc[] diff --git a/test/case/infix_services/lldp.yaml b/test/case/infix_services/lldp.yaml index 4f0c30e6..af3ce73b 100644 --- a/test/case/infix_services/lldp.yaml +++ b/test/case/infix_services/lldp.yaml @@ -4,3 +4,6 @@ - name: lldp_admin_status case: lldp_admin_status/test.py + +- name: lldp_ieee_group_forward + case: lldp_ieee_group_forward/test.py diff --git a/test/case/infix_services/lldp_ieee_group_forward/Readme.adoc b/test/case/infix_services/lldp_ieee_group_forward/Readme.adoc new file mode 120000 index 00000000..f718858e --- /dev/null +++ b/test/case/infix_services/lldp_ieee_group_forward/Readme.adoc @@ -0,0 +1 @@ +lldp_ieee_group_forward.adoc \ No newline at end of file diff --git a/test/case/infix_services/lldp_ieee_group_forward/lldp_ieee_group_forward.adoc b/test/case/infix_services/lldp_ieee_group_forward/lldp_ieee_group_forward.adoc new file mode 100644 index 00000000..d7d5c266 --- /dev/null +++ b/test/case/infix_services/lldp_ieee_group_forward/lldp_ieee_group_forward.adoc @@ -0,0 +1,28 @@ +=== LLDP IEEE Group Forward +==== Description +Verify that LLDP packets can be flooded to all ports on a bridge. +Operation and non-operation are confirmed using tcpdump. + +==== Topology +ifdef::topdoc[] +image::{topdoc}../../test/case/infix_services/lldp_ieee_group_forward/topology.svg[LLDP IEEE Group Forward topology] +endif::topdoc[] +ifndef::topdoc[] +ifdef::testgroup[] +image::lldp_ieee_group_forward/topology.svg[LLDP IEEE Group Forward topology] +endif::testgroup[] +ifndef::testgroup[] +image::topology.svg[LLDP IEEE Group Forward topology] +endif::testgroup[] +endif::topdoc[] +==== Test sequence +. Set up topology and attach to target DUT +. Enable target interfaces and create bridge +. Disable LLDP on target +. Verify LLDP absence on host:data2 +. Enable LLDP flooding by setting group forward +. Verify LLDP arrival on host:data2 + + +<<< + diff --git a/test/case/infix_services/lldp_ieee_group_forward/test.py b/test/case/infix_services/lldp_ieee_group_forward/test.py new file mode 100755 index 00000000..3e20017b --- /dev/null +++ b/test/case/infix_services/lldp_ieee_group_forward/test.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +"""LLDP IEEE Group Forward + +Verify that LLDP packets can be flooded to all ports on a bridge. +Operation and non-operation are confirmed using tcpdump. +""" + +import time +import threading +import infamy + +from scapy.all import Ether, sendp +from scapy.contrib.lldp import ( + LLDPDU, LLDPDUChassisID, LLDPDUPortID, + LLDPDUTimeToLive, LLDPDUEndOfLLDPDU +) + +SNIFFING_DURATION = 3 + +LLDP_INTERVAL = 1 +LLDP_TTL = 3 +LLDP_MULTICAST_MAC = "01:80:C2:00:00:0E" +LLDP_ETHERTYPE = 0x88cc + +CHASSIS_ID = "Chassis-Test" +SRC_MAC = "02:01:02:03:04:05" + +BRIDGE = "br0" + +def send_lldp_packet(iface): + eth = Ether(src=SRC_MAC, dst=LLDP_MULTICAST_MAC, type=LLDP_ETHERTYPE) + lldpdu = eth / LLDPDU() + lldpdu /= LLDPDUChassisID(subtype=7, id=CHASSIS_ID) + lldpdu /= LLDPDUPortID(subtype=5, id=iface) + lldpdu /= LLDPDUTimeToLive(ttl=LLDP_TTL) + lldpdu /= LLDPDUEndOfLLDPDU() + sendp(lldpdu, iface=iface, verbose=False) + +def send_lldp_packets_continuously(iface, stop_event): + time.sleep(LLDP_INTERVAL/2) + while not stop_event.is_set(): + send_lldp_packet(iface) + time.sleep(LLDP_INTERVAL) + +def capture_traffic(iface): + with infamy.IsolatedMacVlan(iface) as netns: + sniffer = infamy.Sniffer(netns, f"ether proto {LLDP_ETHERTYPE}") + with sniffer: + time.sleep(SNIFFING_DURATION) + return sniffer.output() + +def start_lldp_sender_thread(iface): + stop = threading.Event() + thread = threading.Thread( + target=send_lldp_packets_continuously, + args=(iface, stop) + ) + thread.start() + return stop, thread + +with infamy.Test() as test: + with test.step("Set up topology and attach to target DUT"): + env = infamy.Env() + target = env.attach("target", "mgmt") + _, hdata1 = env.ltop.xlate("host", "data1") + _, hdata2 = env.ltop.xlate("host", "data2") + + with test.step("Configure interfaces and disable LLDP daemon"): + target.put_config_dicts({ + "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": BRIDGE, + "type": "infix-if-type:bridge", + "enabled": True, + }, + { + "name": target["data1"], + "enabled": True, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": target["data2"], + "enabled": True, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + } + ] + } + }, + "ieee802-dot1ab-lldp": { + "lldp": { + "enabled": False + } + } + }) + + stop_event, sender_thread = start_lldp_sender_thread(hdata1) + + try: + with test.step("Verify LLDP absence on host:data2"): + captured_traffic = capture_traffic(hdata2) + if "LLDP" in captured_traffic.stdout: + test.fail() + + finally: + stop_event.set() + sender_thread.join() + + with test.step("Enable LLDP flooding by setting group forward"): + target.put_config_dicts({ + "ietf-interfaces": { + "interfaces": { + "interface": [ + { + "name": BRIDGE, + "infix-interfaces:bridge": { + "ieee-group-forward": [ + "lldp" + ] + } + } + ] + } + } + }) + + stop_event, sender_thread = start_lldp_sender_thread(hdata1) + + try: + with test.step("Verify LLDP arrival on host:data2"): + captured_traffic = capture_traffic(hdata2) + if "LLDP" not in captured_traffic.stdout: + test.fail() + + finally: + stop_event.set() + sender_thread.join() + + test.succeed() diff --git a/test/case/infix_services/lldp_ieee_group_forward/topology.dot b/test/case/infix_services/lldp_ieee_group_forward/topology.dot new file mode 100644 index 00000000..3db4cf17 --- /dev/null +++ b/test/case/infix_services/lldp_ieee_group_forward/topology.dot @@ -0,0 +1,24 @@ +graph "1x3" { + layout="neato"; + overlap="false"; + esep="+80"; + + node [shape=record, fontname="DejaVu Sans Mono, Book"]; + edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"]; + + host [ + label="host | { mgmt | data1 | data2 }", + pos="0,12!", + requires="controller", + ]; + + target [ + label="{ mgmt | data1 | data2 } | target", + pos="10,12!", + requires="infix", + ]; + + host:mgmt -- target:mgmt [requires="mgmt", color="lightgray"] + host:data1 -- target:data1 [color="black", requires="ieee-mc"] + host:data2 -- target:data2 [color="black", requires="ieee-mc"] +} diff --git a/test/case/infix_services/lldp_ieee_group_forward/topology.svg b/test/case/infix_services/lldp_ieee_group_forward/topology.svg new file mode 100644 index 00000000..9517e639 --- /dev/null +++ b/test/case/infix_services/lldp_ieee_group_forward/topology.svg @@ -0,0 +1,51 @@ + + + + + + +1x3 + + + +host + +host + +mgmt + +data1 + +data2 + + + +target + +mgmt + +data1 + +data2 + +target + + + +host:mgmt--target:mgmt + + + + +host:data1--target:data1 + + + + +host:data2--target:data2 + + + +