From 839bf3269effc4c8285fb010fc5fa42b2c945c6a Mon Sep 17 00:00:00 2001 From: aqn96 Date: Sat, 14 Mar 2026 21:05:33 +0000 Subject: [PATCH 1/7] Add PTF test file for basic forwarding exercise Signed-off-by: aqn96 Signed-off-by: An --- exercises/basic/ptf/basic_fwd.py | 147 +++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 exercises/basic/ptf/basic_fwd.py diff --git a/exercises/basic/ptf/basic_fwd.py b/exercises/basic/ptf/basic_fwd.py new file mode 100644 index 00000000..80e0a029 --- /dev/null +++ b/exercises/basic/ptf/basic_fwd.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 + +# Copyright 2026 Andrew Nguyen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +import ptf +import ptf.testutils as tu +from ptf.base_tests import BaseTest +import p4runtime_sh.shell as sh +import p4runtime_shell_utils as shu + + +# Configure logging +logger = logging.getLogger(None) +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + + +class BasicFwdTest(BaseTest): + def setUp(self): + self.dataplane = ptf.dataplane_instance + self.dataplane.flush() + + logging.debug("BasicFwdTest.setUp()") + grpc_addr = tu.test_param_get("grpcaddr") + if grpc_addr is None: + grpc_addr = 'localhost:9559' + p4info_txt_fname = tu.test_param_get("p4info") + p4prog_binary_fname = tu.test_param_get("config") + sh.setup(device_id=0, + grpc_addr=grpc_addr, + election_id=(0, 1), + config=sh.FwdPipeConfig(p4info_txt_fname, p4prog_binary_fname), + verbose=False) + + def tearDown(self): + logging.debug("BasicFwdTest.tearDown()") + sh.teardown() + + +###################################################################### +# Helper function to add entries to ipv4_lpm table +###################################################################### + +def add_ipv4_lpm_entry(ipv4_addr_str, prefix_len, dst_mac_str, port): + te = sh.TableEntry('MyIngress.ipv4_lpm')(action='MyIngress.ipv4_forward') + te.match['hdr.ipv4.dstAddr'] = '%s/%d' % (ipv4_addr_str, prefix_len) + te.action['dstAddr'] = dst_mac_str + te.action['port'] = '%d' % port + te.insert() + + +class DropTest(BasicFwdTest): + """Test that packets are dropped when no table entries are installed.""" + def runTest(self): + in_dmac = 'ee:30:ca:9d:1e:00' + in_smac = 'ee:cd:00:7e:70:00' + ip_dst = '10.0.1.1' + ig_port = 1 + + pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, + ip_dst=ip_dst, ip_ttl=64) + tu.send_packet(self, ig_port, pkt) + tu.verify_no_other_packets(self) + + +class FwdTest(BasicFwdTest): + """Test that a packet is forwarded correctly with one table entry.""" + def runTest(self): + in_dmac = 'ee:30:ca:9d:1e:00' + in_smac = 'ee:cd:00:7e:70:00' + ip_dst = '10.0.1.1' + ig_port = 1 + + eg_port = 2 + out_dmac = '08:00:00:00:02:22' + + # Add a forwarding entry + add_ipv4_lpm_entry(ip_dst, 32, out_dmac, eg_port) + + # Send packet + pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, + ip_dst=ip_dst, ip_ttl=64) + + # Expected: srcAddr = old dstAddr, dstAddr = new MAC, TTL decremented + exp_pkt = tu.simple_tcp_packet(eth_src=in_dmac, eth_dst=out_dmac, + ip_dst=ip_dst, ip_ttl=63) + tu.send_packet(self, ig_port, pkt) + tu.verify_packets(self, exp_pkt, [eg_port]) + + +class MultiEntryTest(BasicFwdTest): + """Test multiple LPM entries route to different ports correctly.""" + def runTest(self): + in_dmac = 'ee:30:ca:9d:1e:00' + in_smac = 'ee:cd:00:7e:70:00' + ig_port = 0 + + entries = [] + entries.append({'ip_dst': '10.0.1.1', + 'prefix_len': 32, + 'pkt_dst': '10.0.1.1', + 'eg_port': 1, + 'out_dmac': '08:00:00:00:01:11'}) + entries.append({'ip_dst': '10.0.2.0', + 'prefix_len': 24, + 'pkt_dst': '10.0.2.99', + 'eg_port': 2, + 'out_dmac': '08:00:00:00:02:22'}) + entries.append({'ip_dst': '10.0.3.0', + 'prefix_len': 24, + 'pkt_dst': '10.0.3.1', + 'eg_port': 3, + 'out_dmac': '08:00:00:00:03:33'}) + + # Add all entries + for e in entries: + add_ipv4_lpm_entry(e['ip_dst'], e['prefix_len'], + e['out_dmac'], e['eg_port']) + + # Test each entry + ttl_in = 64 + for e in entries: + pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, + ip_dst=e['pkt_dst'], ip_ttl=ttl_in) + exp_pkt = tu.simple_tcp_packet(eth_src=in_dmac, eth_dst=e['out_dmac'], + ip_dst=e['pkt_dst'], + ip_ttl=ttl_in - 1) + tu.send_packet(self, ig_port, pkt) + tu.verify_packets(self, exp_pkt, [e['eg_port']]) + ttl_in -= 10 From 07b3c5cf6eb93dc360651fc9182deea006032282 Mon Sep 17 00:00:00 2001 From: aqn96 Date: Sat, 14 Mar 2026 23:00:38 +0000 Subject: [PATCH 2/7] Add runptf.sh script for basic forwarding PTF tests Signed-off-by: aqn96 Signed-off-by: An --- exercises/basic/.gitignore | 4 +++ exercises/basic/runptf.sh | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 exercises/basic/.gitignore create mode 100755 exercises/basic/runptf.sh diff --git a/exercises/basic/.gitignore b/exercises/basic/.gitignore new file mode 100644 index 00000000..8d1d7f89 --- /dev/null +++ b/exercises/basic/.gitignore @@ -0,0 +1,4 @@ +build/ +ptf.log +ptf.pcap +ss-log.txt diff --git a/exercises/basic/runptf.sh b/exercises/basic/runptf.sh new file mode 100755 index 00000000..aee1257c --- /dev/null +++ b/exercises/basic/runptf.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# Run PTF tests for the basic forwarding exercise. +# Tests run against the solution P4 program. + +# Path to p4runtime_shell_utils and testlib +T="`realpath ~/p4-guide/testlib`" +if [ x"${PYTHONPATH}" == "x" ] +then + P="${T}" +else + P="${T}:${PYTHONPATH}" +fi + +set -x + +# Compile the solution P4 program into build directory +mkdir -p build +p4c --target bmv2 \ + --arch v1model \ + --p4runtime-files build/basic.p4info.txtpb \ + -o build \ + solution/basic.p4 + +/bin/rm -f ss-log.txt + +# Start simple_switch_grpc with no P4 program loaded (loaded via P4Runtime) +sudo simple_switch_grpc \ + --log-file ss-log \ + --log-flush \ + --dump-packet-data 10000 \ + -i 0@veth0 \ + -i 1@veth2 \ + -i 2@veth4 \ + -i 3@veth6 \ + -i 4@veth8 \ + -i 5@veth10 \ + -i 6@veth12 \ + -i 7@veth14 \ + --no-p4 & + +echo "" +echo "Started simple_switch_grpc. Waiting 2 seconds before starting PTF test ..." +sleep 2 + +# Run PTF tests +sudo ${P4_EXTRA_SUDO_OPTS} `which ptf` \ + --pypath "$P" \ + -i 0@veth1 \ + -i 1@veth3 \ + -i 2@veth5 \ + -i 3@veth7 \ + -i 4@veth9 \ + -i 5@veth11 \ + -i 6@veth13 \ + -i 7@veth15 \ + --test-params="grpcaddr='localhost:9559';p4info='build/basic.p4info.txtpb';config='build/basic.json'" \ + --test-dir ptf + +echo "" +echo "PTF test finished. Waiting 2 seconds before killing simple_switch_grpc ..." +sleep 2 +sudo pkill --signal 9 --list-name simple_switch +echo "" +echo "Verifying that there are no simple_switch_grpc processes running any longer in 4 seconds ..." +sleep 4 +ps axguwww | grep simple_switch From ec5d91a2edf4f6f35cc7105d05d136429543c620 Mon Sep 17 00:00:00 2001 From: aqn96 Date: Sat, 14 Mar 2026 23:12:51 +0000 Subject: [PATCH 3/7] Add testing section to basic forwarding README Signed-off-by: aqn96 Signed-off-by: An --- exercises/basic/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/exercises/basic/README.md b/exercises/basic/README.md index 1cf62e74..a8490287 100644 --- a/exercises/basic/README.md +++ b/exercises/basic/README.md @@ -189,6 +189,21 @@ make stop Congratulations, your implementation works! Move onto the next assignment [Basic Tunneling](../basic_tunnel) +## Automated Tests + +PTF (Packet Test Framework) tests are available to verify the solution +program works correctly. These tests run against `solution/basic.p4` +and check forwarding behavior, including drop on miss, single entry +forwarding, and multi-entry LPM routing. + +To run the tests: +```bash +./runptf.sh +``` + +Note: The `veth` interfaces must be set up before running. If you see +a "No such device" error, run the `veth_setup.sh` script from +[p4-guide](https://github.com/jafingerhut/p4-guide/blob/master/bin/veth_setup.sh). ## Relevant Documentation From 8a2b90e5c51027ceabf4418d4f030299c9d6955f Mon Sep 17 00:00:00 2001 From: aqn96 Date: Sun, 15 Mar 2026 18:57:27 +0000 Subject: [PATCH 4/7] Refactor: use p4runtime_lib instead of external dependency, self-contained veth setup, add make test target to the Makerfile, updated the README.md to reflect changes Signed-off-by: aqn96 Signed-off-by: An --- exercises/basic/Makefile | 3 ++ exercises/basic/README.md | 7 ++-- exercises/basic/ptf/basic_fwd.py | 63 +++++++++++++++++++++++--------- exercises/basic/runptf.sh | 50 +++++++++++++++++-------- 4 files changed, 86 insertions(+), 37 deletions(-) diff --git a/exercises/basic/Makefile b/exercises/basic/Makefile index da31be2f..b61b2468 100644 --- a/exercises/basic/Makefile +++ b/exercises/basic/Makefile @@ -3,3 +3,6 @@ BMV2_SWITCH_EXE = simple_switch_grpc TOPO = pod-topo/topology.json include ../../utils/Makefile + +test: + ./runptf.sh diff --git a/exercises/basic/README.md b/exercises/basic/README.md index a8490287..87a0808e 100644 --- a/exercises/basic/README.md +++ b/exercises/basic/README.md @@ -198,12 +198,11 @@ forwarding, and multi-entry LPM routing. To run the tests: ```bash -./runptf.sh +make test ``` -Note: The `veth` interfaces must be set up before running. If you see -a "No such device" error, run the `veth_setup.sh` script from -[p4-guide](https://github.com/jafingerhut/p4-guide/blob/master/bin/veth_setup.sh). +This handles veth interface creation, P4 compilation, switch startup, +test execution, and cleanup automatically. ## Relevant Documentation diff --git a/exercises/basic/ptf/basic_fwd.py b/exercises/basic/ptf/basic_fwd.py index 80e0a029..0f5ffc8c 100644 --- a/exercises/basic/ptf/basic_fwd.py +++ b/exercises/basic/ptf/basic_fwd.py @@ -15,12 +15,20 @@ # limitations under the License. import logging +import os +import sys import ptf import ptf.testutils as tu from ptf.base_tests import BaseTest -import p4runtime_sh.shell as sh -import p4runtime_shell_utils as shu + +# Import p4runtime_lib from the tutorials repo utils directory +sys.path.append( + os.path.join(os.path.dirname(os.path.abspath(__file__)), + '../../../utils/')) +import p4runtime_lib.bmv2 +import p4runtime_lib.helper +from p4runtime_lib.switch import ShutdownAllSwitchConnections # Configure logging @@ -38,32 +46,53 @@ def setUp(self): self.dataplane.flush() logging.debug("BasicFwdTest.setUp()") + + # Get test parameters grpc_addr = tu.test_param_get("grpcaddr") if grpc_addr is None: grpc_addr = 'localhost:9559' p4info_txt_fname = tu.test_param_get("p4info") p4prog_binary_fname = tu.test_param_get("config") - sh.setup(device_id=0, - grpc_addr=grpc_addr, - election_id=(0, 1), - config=sh.FwdPipeConfig(p4info_txt_fname, p4prog_binary_fname), - verbose=False) + + # Create P4Info helper for building table entries + self.p4info_helper = p4runtime_lib.helper.P4InfoHelper(p4info_txt_fname) + + # Connect to the switch via gRPC + self.sw = p4runtime_lib.bmv2.Bmv2SwitchConnection( + name='s1', + address=grpc_addr, + device_id=0, + proto_dump_file='logs/s1-p4runtime-requests.txt') + + # Establish as master controller + self.sw.MasterArbitrationUpdate() + + # Load the P4 program onto the switch + self.sw.SetForwardingPipelineConfig( + p4info=self.p4info_helper.p4info, + bmv2_json_file_path=p4prog_binary_fname) def tearDown(self): logging.debug("BasicFwdTest.tearDown()") - sh.teardown() + ShutdownAllSwitchConnections() ###################################################################### # Helper function to add entries to ipv4_lpm table ###################################################################### -def add_ipv4_lpm_entry(ipv4_addr_str, prefix_len, dst_mac_str, port): - te = sh.TableEntry('MyIngress.ipv4_lpm')(action='MyIngress.ipv4_forward') - te.match['hdr.ipv4.dstAddr'] = '%s/%d' % (ipv4_addr_str, prefix_len) - te.action['dstAddr'] = dst_mac_str - te.action['port'] = '%d' % port - te.insert() + def add_ipv4_lpm_entry(self, ipv4_addr_str, prefix_len, dst_mac_str, port): + table_entry = self.p4info_helper.buildTableEntry( + table_name='MyIngress.ipv4_lpm', + match_fields={ + 'hdr.ipv4.dstAddr': (ipv4_addr_str, prefix_len) + }, + action_name='MyIngress.ipv4_forward', + action_params={ + 'dstAddr': dst_mac_str, + 'port': port + }) + self.sw.WriteTableEntry(table_entry) class DropTest(BasicFwdTest): @@ -92,7 +121,7 @@ def runTest(self): out_dmac = '08:00:00:00:02:22' # Add a forwarding entry - add_ipv4_lpm_entry(ip_dst, 32, out_dmac, eg_port) + self.add_ipv4_lpm_entry(ip_dst, 32, out_dmac, eg_port) # Send packet pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, @@ -131,8 +160,8 @@ def runTest(self): # Add all entries for e in entries: - add_ipv4_lpm_entry(e['ip_dst'], e['prefix_len'], - e['out_dmac'], e['eg_port']) + self.add_ipv4_lpm_entry(e['ip_dst'], e['prefix_len'], + e['out_dmac'], e['eg_port']) # Test each entry ttl_in = 64 diff --git a/exercises/basic/runptf.sh b/exercises/basic/runptf.sh index aee1257c..8602db53 100755 --- a/exercises/basic/runptf.sh +++ b/exercises/basic/runptf.sh @@ -2,18 +2,25 @@ # Run PTF tests for the basic forwarding exercise. # Tests run against the solution P4 program. -# Path to p4runtime_shell_utils and testlib -T="`realpath ~/p4-guide/testlib`" -if [ x"${PYTHONPATH}" == "x" ] -then - P="${T}" -else - P="${T}:${PYTHONPATH}" -fi +set -e + +# ---- veth setup ---- +echo "Creating veth interfaces..." +for i in 0 1 2 3 4 5 6 7; do + intf0="veth$(( i * 2 ))" + intf1="veth$(( i * 2 + 1 ))" + if ! ip link show $intf0 &>/dev/null; then + sudo ip link add name $intf0 type veth peer name $intf1 + sudo ip link set dev $intf0 up + sudo ip link set dev $intf1 up + sudo sysctl -q net.ipv6.conf.$intf0.disable_ipv6=1 + sudo sysctl -q net.ipv6.conf.$intf1.disable_ipv6=1 + fi +done set -x -# Compile the solution P4 program into build directory +# ---- compile ---- mkdir -p build p4c --target bmv2 \ --arch v1model \ @@ -23,7 +30,7 @@ p4c --target bmv2 \ /bin/rm -f ss-log.txt -# Start simple_switch_grpc with no P4 program loaded (loaded via P4Runtime) +# ---- start switch ---- sudo simple_switch_grpc \ --log-file ss-log \ --log-flush \ @@ -39,12 +46,11 @@ sudo simple_switch_grpc \ --no-p4 & echo "" -echo "Started simple_switch_grpc. Waiting 2 seconds before starting PTF test ..." +echo "Started simple_switch_grpc. Waiting 2 seconds before starting PTF test..." sleep 2 -# Run PTF tests +# ---- run tests ---- sudo ${P4_EXTRA_SUDO_OPTS} `which ptf` \ - --pypath "$P" \ -i 0@veth1 \ -i 1@veth3 \ -i 2@veth5 \ @@ -57,10 +63,22 @@ sudo ${P4_EXTRA_SUDO_OPTS} `which ptf` \ --test-dir ptf echo "" -echo "PTF test finished. Waiting 2 seconds before killing simple_switch_grpc ..." +echo "PTF test finished. Waiting 2 seconds before killing simple_switch_grpc..." sleep 2 + +# ---- cleanup ---- sudo pkill --signal 9 --list-name simple_switch + echo "" -echo "Verifying that there are no simple_switch_grpc processes running any longer in 4 seconds ..." -sleep 4 +echo "Cleaning up veth interfaces..." +for i in 0 1 2 3 4 5 6 7; do + intf0="veth$(( i * 2 ))" + if ip link show $intf0 &>/dev/null; then + sudo ip link del $intf0 + fi +done + +echo "" +echo "Verifying no simple_switch_grpc processes remain..." +sleep 2 ps axguwww | grep simple_switch From b58388e4b7ff88a2d131d3e7a8a0abc7db9e7971 Mon Sep 17 00:00:00 2001 From: An Date: Mon, 16 Mar 2026 18:16:22 -0700 Subject: [PATCH 5/7] ci: add automated ptf testing for tutorial exercises Signed-off-by: An --- .github/workflows/test-exercises.yml | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/test-exercises.yml diff --git a/.github/workflows/test-exercises.yml b/.github/workflows/test-exercises.yml new file mode 100644 index 00000000..4035ab3c --- /dev/null +++ b/.github/workflows/test-exercises.yml @@ -0,0 +1,42 @@ +name: P4 Tutorials CI + +on: + pull_request: + branches: [ master ] + push: + branches: [ master ] + +jobs: + test-basic-exercise: + runs-on: ubuntu-latest + # We use need a privileged container because P4 tests need to create veth interfaces + container: + image: p4lang/p4c:latest + options: --privileged + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + apt-get update + apt-get install -y make python3-pip sudo libboost-iostreams-dev libboost-graph-devs + pip3 install protobuf==3.20.3 grpcio grpcio-tools googleapis-common-protos scapy + + - name: Ensure scripts are executable + run: | + chmod +x exercises/basic/runptf.sh + + - name: Run PTF Tests + run: | + cd exercises/basic + mkdir -p logs + make test + # Retain logs in case runs fail + - name: Upload Logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: p4-logs + path: exercises/basic/logs/ From 8c916d8db4f7430ea7ebad78f89d9c2db5530c81 Mon Sep 17 00:00:00 2001 From: An Date: Mon, 16 Mar 2026 18:28:10 -0700 Subject: [PATCH 6/7] ci: fix typo in the boost package name Signed-off-by: An --- .github/workflows/test-exercises.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-exercises.yml b/.github/workflows/test-exercises.yml index 4035ab3c..0a38a440 100644 --- a/.github/workflows/test-exercises.yml +++ b/.github/workflows/test-exercises.yml @@ -21,7 +21,7 @@ jobs: - name: Install build dependencies run: | apt-get update - apt-get install -y make python3-pip sudo libboost-iostreams-dev libboost-graph-devs + apt-get install -y make python3-pip sudo libboost-iostreams-dev libboost-graph-dev pip3 install protobuf==3.20.3 grpcio grpcio-tools googleapis-common-protos scapy - name: Ensure scripts are executable From 444bffe239ec236bdd9767f31fc121d0ed15f68a Mon Sep 17 00:00:00 2001 From: An Date: Tue, 17 Mar 2026 00:27:30 -0700 Subject: [PATCH 7/7] feat: add LPM Tiebreaker, TTL, and NonIpv4Drop tests; update license header Signed-off-by: An --- exercises/basic/ptf/basic_fwd.py | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/exercises/basic/ptf/basic_fwd.py b/exercises/basic/ptf/basic_fwd.py index 0f5ffc8c..04add256 100644 --- a/exercises/basic/ptf/basic_fwd.py +++ b/exercises/basic/ptf/basic_fwd.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 # Copyright 2026 Andrew Nguyen # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,6 +14,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# import logging import os @@ -174,3 +176,69 @@ def runTest(self): tu.send_packet(self, ig_port, pkt) tu.verify_packets(self, exp_pkt, [e['eg_port']]) ttl_in -= 10 + + +class LpmTiebreakerTest(BasicFwdTest): + """Test that longest-prefix match wins for overlapping routes.""" + def runTest(self): + in_dmac = 'ee:30:ca:9d:1e:00' + in_smac = 'ee:cd:00:7e:70:00' + ig_port = 0 + + less_specific_out_dmac = '08:00:00:00:11:11' + less_specific_eg_port = 1 + more_specific_out_dmac = '08:00:00:00:22:22' + more_specific_eg_port = 2 + + # Two overlapping routes: /16 and /24. Packet should match /24. + self.add_ipv4_lpm_entry('10.0.0.0', 16, + less_specific_out_dmac, less_specific_eg_port) + self.add_ipv4_lpm_entry('10.0.1.0', 24, + more_specific_out_dmac, more_specific_eg_port) + + pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, + ip_dst='10.0.1.99', ip_ttl=64) + exp_pkt = tu.simple_tcp_packet(eth_src=in_dmac, eth_dst=more_specific_out_dmac, + ip_dst='10.0.1.99', ip_ttl=63) + + tu.send_packet(self, ig_port, pkt) + tu.verify_packets(self, exp_pkt, [more_specific_eg_port]) + + +class TtlBoundaryTest(BasicFwdTest): + """Test forwarding behavior when input IPv4 TTL is at boundary value 1.""" + def runTest(self): + in_dmac = 'ee:30:ca:9d:1e:00' + in_smac = 'ee:cd:00:7e:70:00' + ip_dst = '10.0.9.9' + ig_port = 1 + + eg_port = 3 + out_dmac = '08:00:00:00:09:99' + + self.add_ipv4_lpm_entry(ip_dst, 32, out_dmac, eg_port) + + pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, + ip_dst=ip_dst, ip_ttl=1) + exp_pkt = tu.simple_tcp_packet(eth_src=in_dmac, eth_dst=out_dmac, + ip_dst=ip_dst, ip_ttl=0) + + tu.send_packet(self, ig_port, pkt) + tu.verify_packets(self, exp_pkt, [eg_port]) + + +class NonIpv4DropTest(BasicFwdTest): + """Test non-IPv4 traffic bypasses IPv4 LPM forwarding logic.""" + def runTest(self): + ig_port = 1 + pkt = tu.simple_arp_packet( + eth_dst='ff:ff:ff:ff:ff:ff', + eth_src='00:de:ad:be:ef:01', + arp_op=1, + ip_snd='10.0.1.10', + ip_tgt='10.0.1.1', + hw_snd='00:de:ad:be:ef:01', + hw_tgt='00:00:00:00:00:00') + + tu.send_packet(self, ig_port, pkt) + tu.verify_packets(self, pkt, [0])