diff --git a/backends/ebpf/psa/examples/simple.p4 b/backends/ebpf/psa/examples/simple.p4 new file mode 100644 index 0000000000..0012f95510 --- /dev/null +++ b/backends/ebpf/psa/examples/simple.p4 @@ -0,0 +1,107 @@ +/* +Copyright 2022-present Orange +Copyright 2022-present Open Networking Foundation + +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. +*/ + +/* + * This P4 program implements following functionality: + * - VLAN tagging + * - L2 forwarding + * - L3 routing with ECMP + * - checksum verification & re-calculation + * - MAC learning + * - ACL based on 5-tuple + * - port counters + */ + +#include +#include + +typedef bit<48> ethernet_addr_t; + +struct empty_metadata_t { +} + +header ethernet_t { + ethernet_addr_t dst_addr; + ethernet_addr_t src_addr; + bit<16> ether_type; +} +struct headers_t { + ethernet_t ethernet; +} + +struct local_metadata_t { +} + +parser packet_parser(packet_in packet, out headers_t headers, inout local_metadata_t local_metadata, in psa_ingress_parser_input_metadata_t standard_metadata, in empty_metadata_t resub_meta, in empty_metadata_t recirc_meta) { + state start { + packet.extract(headers.ethernet); + transition accept; + } +} + +control packet_deparser(packet_out packet, out empty_metadata_t clone_i2e_meta, out empty_metadata_t resubmit_meta, out empty_metadata_t normal_meta, inout headers_t headers, in local_metadata_t local_metadata, in psa_ingress_output_metadata_t istd) { + apply { + packet.emit(headers.ethernet); + } +} + +control ingress(inout headers_t headers, inout local_metadata_t local_metadata, in psa_ingress_input_metadata_t standard_metadata, + inout psa_ingress_output_metadata_t ostd) { + + action forward(PortId_t output_port) { + send_to_port(ostd, output_port); + } + + table tbl_switching { + key = { + headers.ethernet.dst_addr : exact; + } + + actions = { + forward; + } + } + + apply { + // tbl_switching.apply(); + } + +} + +control egress(inout headers_t headers, inout local_metadata_t local_metadata, in psa_egress_input_metadata_t istd, inout psa_egress_output_metadata_t ostd) { + apply { + } +} + +parser egress_parser(packet_in buffer, out headers_t headers, inout local_metadata_t local_metadata, in psa_egress_parser_input_metadata_t istd, in empty_metadata_t normal_meta, in empty_metadata_t clone_i2e_meta, in empty_metadata_t clone_e2e_meta) { + state start { + transition accept; + } + +} + +control egress_deparser(packet_out packet, out empty_metadata_t clone_e2e_meta, out empty_metadata_t recirculate_meta, inout headers_t headers, in local_metadata_t local_metadata, in psa_egress_output_metadata_t istd, in psa_egress_deparser_input_metadata_t edstd) { + apply { + } +} + + +IngressPipeline(packet_parser(), ingress(), packet_deparser()) ip; + +EgressPipeline(egress_parser(), egress(), egress_deparser()) ep; + +PSA_Switch(ip, PacketReplicationEngine(), ep, BufferingQueueingEngine()) main; diff --git a/backends/ebpf/psa/examples/simple.p4info.txtpb b/backends/ebpf/psa/examples/simple.p4info.txtpb new file mode 100644 index 0000000000..cfbdc3d692 --- /dev/null +++ b/backends/ebpf/psa/examples/simple.p4info.txtpb @@ -0,0 +1,6 @@ +# proto-file: p4/config/v1/p4info.proto +# proto-message: p4.config.v1.P4Info + +pkg_info { + arch: "psa" +} diff --git a/backends/ebpf/tests/ptf/simple.py b/backends/ebpf/tests/ptf/simple.py new file mode 100644 index 0000000000..8cca7266f9 --- /dev/null +++ b/backends/ebpf/tests/ptf/simple.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright 2022-present Orange +# Copyright 2022-present Open Networking Foundation +# +# 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. + +from pathlib import Path +from typing import Optional +from ptf.mask import Mask +from ptf import testutils +from common import P4EbpfTest, DP_PORTS + +FILE_DIR = Path(__file__).resolve().parent + +PORT0 = 0 +PORT1 = 1 +PORT2 = 2 +PORT3 = 3 +PORT4 = 4 +PORT5 = 5 +ALL_PORTS = [PORT0, PORT1, PORT2, PORT3] + + +class SimpleTest(P4EbpfTest): + p4_file_path = FILE_DIR.joinpath("../../psa/examples/simple.p4") + p4info_reference_file_path = FILE_DIR.joinpath("../../psa/examples/simple.p4info.txtpb") + + def configure_port(self, port_id: int, vlan_id: Optional[int] = None) -> None: + if vlan_id is None: + self.table_add(table="ingress_tbl_ingress_vlan", key=[port_id, 0], action=1) + self.table_add(table="egress_tbl_vlan_egress", key=[port_id], action=1) + else: + self.table_add(table="ingress_tbl_ingress_vlan", key=[port_id, 1], action=0) + self.table_add(table="egress_tbl_vlan_egress", key=[port_id], action=2, data=[vlan_id]) + + def setUp(self) -> None: + super(SimpleTest, self).setUp() + # self.configure_port(port_id=DP_PORTS[0]) + # self.configure_port(port_id=DP_PORTS[5]) + # self.configure_port(port_id=DP_PORTS[1], vlan_id=1) + # self.configure_port(port_id=DP_PORTS[2], vlan_id=1) + # self.configure_port(port_id=DP_PORTS[4], vlan_id=1) + # self.configure_port(port_id=DP_PORTS[3], vlan_id=2) + + def runTest(self) -> None: + # check no connectivity if switching rules are not installed + pkt = testutils.simple_udp_packet(eth_dst="00:00:00:00:00:03") + testutils.send_packet(self, PORT0, pkt) + # testutils.verify_packet(self, pkt, PORT0) + testutils.verify_any_packet_any_port(self, [pkt], ALL_PORTS) diff --git a/requirements.txt b/requirements.txt index fb5216d030..c1d1b4e5df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # Install with pip3 install --user -r requirements.txt pyroute2==0.7.3 ply==3.11 -ptf==0.9.4 +ptf==0.10.0 scapy==2.5.0 clang-format==18.1.0 isort==5.13.2; python_version > '3.6'