From c84162890a8aa2459a003066113fc3577de45429 Mon Sep 17 00:00:00 2001 From: Rayyan Hussain Date: Thu, 1 May 2025 12:42:26 +0500 Subject: [PATCH] latest uptade --- .gitignore | 68 +++- .../tutorial/pipeconf/InterpreterImpl.java | 4 +- app/src/main/resources/p4info.txt | 321 ++++++++++++++++++ mininet/netcfg-sr.json | 12 +- mininet/netcfg.json | 143 +------- mininet/topo-gtp.py | 19 +- mininet/topo-v4.py | 43 +-- mininet/topo-v6.py | 111 ++---- net | 0 p4src/main.p4 | 124 +++++-- packet-logger-app/pom.xml | 93 +++++ .../org/packetlogger/app/AppComponent.java | 126 +++++++ .../org/packetlogger/app/package-info.java | 20 ++ ping_script.py | 9 + send_test_traffic.py | 44 +++ 15 files changed, 851 insertions(+), 286 deletions(-) create mode 100644 app/src/main/resources/p4info.txt create mode 100644 net create mode 100644 packet-logger-app/pom.xml create mode 100644 packet-logger-app/src/main/java/org/packetlogger/app/AppComponent.java create mode 100644 packet-logger-app/src/main/java/org/packetlogger/app/package-info.java create mode 100644 ping_script.py create mode 100755 send_test_traffic.py diff --git a/.gitignore b/.gitignore index f435287..3fce49b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,54 @@ +# Compiled class file +*.class + +# Log files +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# virtual machine crash logs +hs_err_pid* + +# IDE Files .idea/ +*.iml +.vscode/ +*.swp +*.swo +.project +.classpath +.settings/ + +# P4 build artifacts +p4src/build/ +*.json +!mininet/*.json + +# Temporary files tmp/ -p4src/build -app/target -app/src/main/resources/p4info.txt -app/src/main/resources/bmv2.json -ptf/stratum_bmv2.log -ptf/p4rt_write.log -ptf/ptf.log -ptf/ptf.pcap -**/*.iml -**/*.pyc -**/*.bak -**/.classpath -**/.project -**/.settings -**/.factorypath -util/.pipe_cfg +*~ +.DS_Store diff --git a/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java b/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java index edf5bfa..2570a3b 100644 --- a/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java +++ b/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java @@ -154,7 +154,7 @@ private PiPacketOperation buildPacketOut(ByteBuffer pktData, long portNumber) // Create metadata instance for egress port. // *** TODO EXERCISE 4: modify metadata names to match P4 program // ---- START SOLUTION ---- - final String outPortMetadataName = "ADD HERE METADATA NAME FOR THE EGRESS PORT"; + final String outPortMetadataName = "egress_port"; // ---- END SOLUTION ---- final PiPacketMetadata outPortMetadata = PiPacketMetadata.builder() .withId(PiPacketMetadataId.of(outPortMetadataName)) @@ -186,7 +186,7 @@ public InboundPacket mapInboundPacket(PiPacketOperation packetIn, DeviceId devic // Find the ingress_port metadata. // *** TODO EXERCISE 4: modify metadata names to match P4Info // ---- START SOLUTION ---- - final String inportMetadataName = "ADD HERE METADATA NAME FOR THE INGRESS PORT"; + final String inportMetadataName = "ingress_port"; // ---- END SOLUTION ---- Optional inportMetadata = packetIn.metadatas() .stream() diff --git a/app/src/main/resources/p4info.txt b/app/src/main/resources/p4info.txt new file mode 100644 index 0000000..07f2780 --- /dev/null +++ b/app/src/main/resources/p4info.txt @@ -0,0 +1,321 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33605373 + name: "IngressPipeImpl.l2_exact_table" + alias: "l2_exact_table" + } + match_fields { + id: 1 + name: "hdr.ethernet.dst_addr" + bitwidth: 48 + match_type: EXACT + } + action_refs { + id: 16812802 + } + action_refs { + id: 16796182 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + const_default_action_id: 16796182 + direct_resource_ids: 318813612 + size: 1024 +} +tables { + preamble { + id: 33573501 + name: "IngressPipeImpl.l2_ternary_table" + alias: "l2_ternary_table" + } + match_fields { + id: 1 + name: "hdr.ethernet.dst_addr" + bitwidth: 48 + match_type: TERNARY + } + action_refs { + id: 16841371 + } + action_refs { + id: 16796182 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + const_default_action_id: 16796182 + direct_resource_ids: 318768597 + size: 1024 +} +tables { + preamble { + id: 33589516 + name: "IngressPipeImpl.ipv4_routing_table" + alias: "ipv4_routing_table" + } + match_fields { + id: 1 + name: "hdr.ipv4.dst_addr" + bitwidth: 32 + match_type: LPM + } + action_refs { + id: 16796784 + } + action_refs { + id: 16796182 + } + direct_resource_ids: 318808852 + size: 1024 +} +tables { + preamble { + id: 33557865 + name: "IngressPipeImpl.acl_table" + alias: "acl_table" + } + match_fields { + id: 1 + name: "standard_metadata.ingress_port" + bitwidth: 9 + match_type: TERNARY + } + match_fields { + id: 2 + name: "hdr.ethernet.dst_addr" + bitwidth: 48 + match_type: TERNARY + } + match_fields { + id: 3 + name: "hdr.ethernet.src_addr" + bitwidth: 48 + match_type: TERNARY + } + match_fields { + id: 4 + name: "hdr.ethernet.ether_type" + bitwidth: 16 + match_type: TERNARY + } + match_fields { + id: 5 + name: "local_metadata.ip_proto" + bitwidth: 8 + match_type: TERNARY + } + match_fields { + id: 6 + name: "local_metadata.icmp_type" + bitwidth: 8 + match_type: TERNARY + } + match_fields { + id: 7 + name: "local_metadata.l4_src_port" + bitwidth: 16 + match_type: TERNARY + } + match_fields { + id: 8 + name: "local_metadata.l4_dst_port" + bitwidth: 16 + match_type: TERNARY + } + match_fields { + id: 9 + name: "hdr.arp.$valid$" + bitwidth: 1 + match_type: TERNARY + } + match_fields { + id: 10 + name: "local_metadata.arp_opcode" + bitwidth: 16 + match_type: TERNARY + } + action_refs { + id: 16833331 + } + action_refs { + id: 16782152 + } + action_refs { + id: 16840287 + } + action_refs { + id: 16796182 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + direct_resource_ids: 318773822 + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16796182 + name: "IngressPipeImpl.drop" + alias: "drop" + } +} +actions { + preamble { + id: 16812802 + name: "IngressPipeImpl.set_egress_port" + alias: "set_egress_port" + } + params { + id: 1 + name: "port_num" + bitwidth: 9 + } +} +actions { + preamble { + id: 16841371 + name: "IngressPipeImpl.set_multicast_group" + alias: "set_multicast_group" + } + params { + id: 1 + name: "gid" + bitwidth: 16 + } +} +actions { + preamble { + id: 16796784 + name: "IngressPipeImpl.ipv4_forward" + alias: "ipv4_forward" + } + params { + id: 1 + name: "dst_mac" + bitwidth: 48 + } + params { + id: 2 + name: "src_mac" + bitwidth: 48 + } + params { + id: 3 + name: "port" + bitwidth: 9 + } +} +actions { + preamble { + id: 16833331 + name: "IngressPipeImpl.send_to_cpu" + alias: "send_to_cpu" + } +} +actions { + preamble { + id: 16782152 + name: "IngressPipeImpl.clone_to_cpu" + alias: "clone_to_cpu" + } +} +actions { + preamble { + id: 16840287 + name: "IngressPipeImpl.permit" + alias: "permit" + } +} +direct_counters { + preamble { + id: 318813612 + name: "l2_exact_table_counter" + alias: "l2_exact_table_counter" + } + spec { + unit: BOTH + } + direct_table_id: 33605373 +} +direct_counters { + preamble { + id: 318768597 + name: "l2_ternary_table_counter" + alias: "l2_ternary_table_counter" + } + spec { + unit: BOTH + } + direct_table_id: 33573501 +} +direct_counters { + preamble { + id: 318808852 + name: "ipv4_routing_table_counter" + alias: "ipv4_routing_table_counter" + } + spec { + unit: BOTH + } + direct_table_id: 33589516 +} +direct_counters { + preamble { + id: 318773822 + name: "acl_table_counter" + alias: "acl_table_counter" + } + spec { + unit: BOTH + } + direct_table_id: 33557865 +} +controller_packet_metadata { + preamble { + id: 67132047 + name: "packet_in" + alias: "packet_in" + annotations: "@controller_header(\"packet_in\")" + } + metadata { + id: 1 + name: "ingress_port" + bitwidth: 9 + } + metadata { + id: 2 + name: "_pad" + bitwidth: 7 + } +} +controller_packet_metadata { + preamble { + id: 67111875 + name: "packet_out" + alias: "packet_out" + annotations: "@controller_header(\"packet_out\")" + } + metadata { + id: 1 + name: "egress_port" + bitwidth: 9 + } + metadata { + id: 2 + name: "_pad" + bitwidth: 7 + } +} +type_info { +} diff --git a/mininet/netcfg-sr.json b/mininet/netcfg-sr.json index 1856cb1..85e0730 100644 --- a/mininet/netcfg-sr.json +++ b/mininet/netcfg-sr.json @@ -126,7 +126,7 @@ "hosts": { "00:00:00:00:00:1A/None": { "basic": { - "name": "h1a", + "name": "h1", "locType": "grid", "gridX": 100, "gridY": 700 @@ -134,7 +134,7 @@ }, "00:00:00:00:00:1B/None": { "basic": { - "name": "h1b", + "name": "h2", "locType": "grid", "gridX": 100, "gridY": 800 @@ -142,7 +142,7 @@ }, "00:00:00:00:00:1C/100": { "basic": { - "name": "h1c", + "name": "h3", "locType": "grid", "gridX": 250, "gridY": 800 @@ -150,7 +150,7 @@ }, "00:00:00:00:00:20/200": { "basic": { - "name": "h2", + "name": "h4", "locType": "grid", "gridX": 400, "gridY": 700 @@ -158,7 +158,7 @@ }, "00:00:00:00:00:30/300": { "basic": { - "name": "h3", + "name": "h5", "locType": "grid", "gridX": 750, "gridY": 700 @@ -166,7 +166,7 @@ }, "00:00:00:00:00:40/None": { "basic": { - "name": "h4", + "name": "h6", "locType": "grid", "gridX": 850, "gridY": 700 diff --git a/mininet/netcfg.json b/mininet/netcfg.json index 35aa8ea..82f8a13 100644 --- a/mininet/netcfg.json +++ b/mininet/netcfg.json @@ -1,163 +1,54 @@ { "devices": { - "device:leaf1": { + "device:s1": { "basic": { "managementAddress": "grpc://mininet:50001?device_id=1", "driver": "stratum-bmv2", "pipeconf": "org.onosproject.ngsdn-tutorial", "locType": "grid", - "gridX": 200, - "gridY": 600 - }, - "fabricDeviceConfig": { - "myStationMac": "00:aa:00:00:00:01", - "mySid": "3:101:2::", - "isSpine": false - } - }, - "device:leaf2": { - "basic": { - "managementAddress": "grpc://mininet:50002?device_id=1", - "driver": "stratum-bmv2", - "pipeconf": "org.onosproject.ngsdn-tutorial", - "locType": "grid", - "gridX": 800, - "gridY": 600 - }, - "fabricDeviceConfig": { - "myStationMac": "00:aa:00:00:00:02", - "mySid": "3:102:2::", - "isSpine": false - } - }, - "device:spine1": { - "basic": { - "managementAddress": "grpc://mininet:50003?device_id=1", - "driver": "stratum-bmv2", - "pipeconf": "org.onosproject.ngsdn-tutorial", - "locType": "grid", "gridX": 400, "gridY": 400 }, "fabricDeviceConfig": { - "myStationMac": "00:bb:00:00:00:01", - "mySid": "3:201:2::", - "isSpine": true - } - }, - "device:spine2": { - "basic": { - "managementAddress": "grpc://mininet:50004?device_id=1", - "driver": "stratum-bmv2", - "pipeconf": "org.onosproject.ngsdn-tutorial", - "locType": "grid", - "gridX": 600, - "gridY": 400 - }, - "fabricDeviceConfig": { - "myStationMac": "00:bb:00:00:00:02", - "mySid": "3:202:2::", - "isSpine": true + "myStationMac": "00:00:00:00:00:ff", + "mySid": "3:1:2::", + "isSpine": false } } }, "ports": { - "device:leaf1/3": { - "interfaces": [ - { - "name": "leaf1-3", - "ips": ["2001:1:1::ff/64"] - } - ] - }, - "device:leaf1/4": { + "device:s1/1": { "interfaces": [ { - "name": "leaf1-4", - "ips": ["2001:1:1::ff/64"] + "name": "s1-eth1", + "ips": ["10.0.0.254/24"] } ] }, - "device:leaf1/5": { + "device:s1/2": { "interfaces": [ { - "name": "leaf1-5", - "ips": ["2001:1:1::ff/64"] - } - ] - }, - "device:leaf1/6": { - "interfaces": [ - { - "name": "leaf1-6", - "ips": ["2001:1:2::ff/64"] - } - ] - }, - "device:leaf2/3": { - "interfaces": [ - { - "name": "leaf2-3", - "ips": ["2001:2:3::ff/64"] - } - ] - }, - "device:leaf2/4": { - "interfaces": [ - { - "name": "leaf2-4", - "ips": ["2001:2:4::ff/64"] + "name": "s1-eth2", + "ips": ["10.0.0.254/24"] } ] } }, "hosts": { - "00:00:00:00:00:1A/None": { - "basic": { - "name": "h1a", - "locType": "grid", - "gridX": 100, - "gridY": 700 - } - }, - "00:00:00:00:00:1B/None": { - "basic": { - "name": "h1b", - "locType": "grid", - "gridX": 100, - "gridY": 800 - } - }, - "00:00:00:00:00:1C/None": { + "00:00:00:00:00:01/None": { "basic": { - "name": "h1c", + "name": "h1", "locType": "grid", - "gridX": 250, - "gridY": 800 + "gridX": 300, + "gridY": 500 } }, - "00:00:00:00:00:20/None": { + "00:00:00:00:00:02/None": { "basic": { "name": "h2", "locType": "grid", - "gridX": 400, - "gridY": 700 - } - }, - "00:00:00:00:00:30/None": { - "basic": { - "name": "h3", - "locType": "grid", - "gridX": 750, - "gridY": 700 - } - }, - "00:00:00:00:00:40/None": { - "basic": { - "name": "h4", - "locType": "grid", - "gridX": 850, - "gridY": 700 + "gridX": 500, + "gridY": 500 } } } diff --git a/mininet/topo-gtp.py b/mininet/topo-gtp.py index e67d8f6..8f919ec 100755 --- a/mininet/topo-gtp.py +++ b/mininet/topo-gtp.py @@ -19,7 +19,7 @@ from mininet.cli import CLI from mininet.log import setLogLevel from mininet.net import Mininet -from mininet.node import Host +from mininet.node import Host, RemoteController from mininet.topo import Topo from stratum import StratumBmv2Switch @@ -90,17 +90,17 @@ def __init__(self, *args, **kwargs): def main(): - net = Mininet(topo=TutorialTopo(), controller=None) + net = Mininet(topo=TutorialTopo(), controller=RemoteController('c0', ip='10.3.12.140')) net.start() CLI(net) net.stop() - print '#' * 80 - print 'ATTENTION: Mininet was stopped! Perhaps accidentally?' - print 'No worries, it will restart automatically in a few seconds...' - print 'To access again the Mininet CLI, use `make mn-cli`' - print 'To detach from the CLI (without stopping), press Ctrl-D' - print 'To permanently quit Mininet, use `make stop`' - print '#' * 80 + print('#' * 80) + print('ATTENTION: Mininet was stopped! Perhaps accidentally?') + print('No worries, it will restart automatically in a few seconds...') + print('To access again the Mininet CLI, use `make mn-cli`') + print('To detach from the CLI (without stopping), press Ctrl-D') + print('To permanently quit Mininet, use `make stop`') + print('#' * 80) if __name__ == "__main__": @@ -110,3 +110,4 @@ def main(): setLogLevel('info') main() + diff --git a/mininet/topo-v4.py b/mininet/topo-v4.py index 08c5205..7ce696b 100755 --- a/mininet/topo-v4.py +++ b/mininet/topo-v4.py @@ -19,7 +19,7 @@ from mininet.cli import CLI from mininet.log import setLogLevel from mininet.net import Mininet -from mininet.node import Host +from mininet.node import Host, RemoteController from mininet.topo import Topo from stratum import StratumBmv2Switch @@ -115,40 +115,40 @@ def __init__(self, *args, **kwargs): self.addLink(spine2, leaf2) # IPv4 hosts attached to leaf 1 - h1a = self.addHost('h1a', cls=IPv4Host, mac="00:00:00:00:00:1A", + h1 = self.addHost('h1', cls=IPv4Host, mac="00:00:00:00:00:1A", ip='172.16.1.1/24', gw='172.16.1.254') - h1b = self.addHost('h1b', cls=IPv4Host, mac="00:00:00:00:00:1B", + h2 = self.addHost('h2', cls=IPv4Host, mac="00:00:00:00:00:1B", ip='172.16.1.2/24', gw='172.16.1.254') - h1c = self.addHost('h1c', cls=TaggedIPv4Host, mac="00:00:00:00:00:1C", + h3 = self.addHost('h3', cls=TaggedIPv4Host, mac="00:00:00:00:00:1C", ip='172.16.1.3/24', gw='172.16.1.254', vlan=100) - h2 = self.addHost('h2', cls=TaggedIPv4Host, mac="00:00:00:00:00:20", + h4 = self.addHost('h4', cls=TaggedIPv4Host, mac="00:00:00:00:00:20", ip='172.16.2.1/24', gw='172.16.2.254', vlan=200) - self.addLink(h1a, leaf1) # port 3 - self.addLink(h1b, leaf1) # port 4 - self.addLink(h1c, leaf1) # port 5 - self.addLink(h2, leaf1) # port 6 + self.addLink(h1, leaf1) # port 3 + self.addLink(h2, leaf1) # port 4 + self.addLink(h3, leaf1) # port 5 + self.addLink(h4, leaf1) # port 6 # IPv4 hosts attached to leaf 2 - h3 = self.addHost('h3', cls=TaggedIPv4Host, mac="00:00:00:00:00:30", + h5 = self.addHost('h5', cls=TaggedIPv4Host, mac="00:00:00:00:00:30", ip='172.16.3.1/24', gw='172.16.3.254', vlan=300) - h4 = self.addHost('h4', cls=IPv4Host, mac="00:00:00:00:00:40", + h6 = self.addHost('h6', cls=IPv4Host, mac="00:00:00:00:00:40", ip='172.16.4.1/24', gw='172.16.4.254') - self.addLink(h3, leaf2) # port 3 - self.addLink(h4, leaf2) # port 4 + self.addLink(h5, leaf2) # port 3 + self.addLink(h6, leaf2) # port 4 def main(): - net = Mininet(topo=TutorialTopo(), controller=None) + net = Mininet(topo=TutorialTopo(), controller=RemoteController('c0', ip='10.3.12.140')) net.start() CLI(net) net.stop() - print '#' * 80 - print 'ATTENTION: Mininet was stopped! Perhaps accidentally?' - print 'No worries, it will restart automatically in a few seconds...' - print 'To access again the Mininet CLI, use `make mn-cli`' - print 'To detach from the CLI (without stopping), press Ctrl-D' - print 'To permanently quit Mininet, use `make stop`' - print '#' * 80 + print('#' * 80) + print('ATTENTION: Mininet was stopped! Perhaps accidentally?') + print('No worries, it will restart automatically in a few seconds...') + print('To access again the Mininet CLI, use `make mn-cli`') + print('To detach from the CLI (without stopping), press Ctrl-D') + print('To permanently quit Mininet, use `make stop`') + print('#' * 80) if __name__ == "__main__": @@ -158,3 +158,4 @@ def main(): setLogLevel('info') main() + diff --git a/mininet/topo-v6.py b/mininet/topo-v6.py index 03390ae..2342768 100755 --- a/mininet/topo-v6.py +++ b/mininet/topo-v6.py @@ -1,121 +1,80 @@ #!/usr/bin/python -# Copyright 2019-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. - import argparse from mininet.cli import CLI from mininet.log import setLogLevel from mininet.net import Mininet -from mininet.node import Host +from mininet.node import Host, RemoteController from mininet.topo import Topo from stratum import StratumBmv2Switch CPU_PORT = 255 -class IPv6Host(Host): - """Host that can be configured with an IPv6 gateway (default route). - """ +class IPv4Host(Host): + """Host that can be configured with an IPv4 gateway (default route).""" - def config(self, ipv6, ipv6_gw=None, **params): - super(IPv6Host, self).config(**params) - self.cmd('ip -4 addr flush dev %s' % self.defaultIntf()) + def config(self, ipv4, ipv4_gw=None, **params): + super(IPv4Host, self).config(**params) self.cmd('ip -6 addr flush dev %s' % self.defaultIntf()) - self.cmd('ip -6 addr add %s dev %s' % (ipv6, self.defaultIntf())) - if ipv6_gw: - self.cmd('ip -6 route add default via %s' % ipv6_gw) + self.cmd('ip -4 addr flush dev %s' % self.defaultIntf()) + self.cmd('ip addr add %s dev %s' % (ipv4, self.defaultIntf())) + if ipv4_gw: + self.cmd('ip route add default via %s' % ipv4_gw) # Disable offload for attr in ["rx", "tx", "sg"]: cmd = "/sbin/ethtool --offload %s %s off" % (self.defaultIntf(), attr) self.cmd(cmd) def updateIP(): - return ipv6.split('/')[0] + return ipv4.split('/')[0] self.defaultIntf().updateIP = updateIP def terminate(self): - super(IPv6Host, self).terminate() + super(IPv4Host, self).terminate() -class TutorialTopo(Topo): - """2x2 fabric topology with IPv6 hosts""" +class OneSwitchTwoHostTopo(Topo): + """Topology with 1 switch and 2 IPv4 hosts""" def __init__(self, *args, **kwargs): Topo.__init__(self, *args, **kwargs) - # Leaves - # gRPC port 50001 - leaf1 = self.addSwitch('leaf1', cls=StratumBmv2Switch, cpuport=CPU_PORT) - # gRPC port 50002 - leaf2 = self.addSwitch('leaf2', cls=StratumBmv2Switch, cpuport=CPU_PORT) - - # Spines - # gRPC port 50003 - spine1 = self.addSwitch('spine1', cls=StratumBmv2Switch, cpuport=CPU_PORT) - # gRPC port 50004 - spine2 = self.addSwitch('spine2', cls=StratumBmv2Switch, cpuport=CPU_PORT) - - # Switch Links - self.addLink(spine1, leaf1) - self.addLink(spine1, leaf2) - self.addLink(spine2, leaf1) - self.addLink(spine2, leaf2) - - # IPv6 hosts attached to leaf 1 - h1a = self.addHost('h1a', cls=IPv6Host, mac="00:00:00:00:00:1A", - ipv6='2001:1:1::a/64', ipv6_gw='2001:1:1::ff') - h1b = self.addHost('h1b', cls=IPv6Host, mac="00:00:00:00:00:1B", - ipv6='2001:1:1::b/64', ipv6_gw='2001:1:1::ff') - h1c = self.addHost('h1c', cls=IPv6Host, mac="00:00:00:00:00:1C", - ipv6='2001:1:1::c/64', ipv6_gw='2001:1:1::ff') - h2 = self.addHost('h2', cls=IPv6Host, mac="00:00:00:00:00:20", - ipv6='2001:1:2::1/64', ipv6_gw='2001:1:2::ff') - self.addLink(h1a, leaf1) # port 3 - self.addLink(h1b, leaf1) # port 4 - self.addLink(h1c, leaf1) # port 5 - self.addLink(h2, leaf1) # port 6 - - # IPv6 hosts attached to leaf 2 - h3 = self.addHost('h3', cls=IPv6Host, mac="00:00:00:00:00:30", - ipv6='2001:2:3::1/64', ipv6_gw='2001:2:3::ff') - h4 = self.addHost('h4', cls=IPv6Host, mac="00:00:00:00:00:40", - ipv6='2001:2:4::1/64', ipv6_gw='2001:2:4::ff') - self.addLink(h3, leaf2) # port 3 - self.addLink(h4, leaf2) # port 4 + # Single switch + switch = self.addSwitch('s1', cls=StratumBmv2Switch, cpuport=CPU_PORT) + + # Hosts + h1 = self.addHost('h1', cls=IPv4Host, mac="00:00:00:00:00:01", + ipv4='10.0.0.1/24', ipv4_gw='10.0.0.254') + h2 = self.addHost('h2', cls=IPv4Host, mac="00:00:00:00:00:02", + ipv4='10.0.0.2/24', ipv4_gw='10.0.0.254') + + # Links + self.addLink(h1, switch) + self.addLink(h2, switch) def main(): - net = Mininet(topo=TutorialTopo(), controller=None) + net = Mininet(topo=OneSwitchTwoHostTopo(), controller=RemoteController('c0', ip='10.3.12.140')) net.start() CLI(net) net.stop() - print '#' * 80 - print 'ATTENTION: Mininet was stopped! Perhaps accidentally?' - print 'No worries, it will restart automatically in a few seconds...' - print 'To access again the Mininet CLI, use `make mn-cli`' - print 'To detach from the CLI (without stopping), press Ctrl-D' - print 'To permanently quit Mininet, use `make stop`' - print '#' * 80 + print('#' * 80) + print('ATTENTION: Mininet was stopped! Perhaps accidentally?') + print('No worries, it will restart automatically in a few seconds...') + print('To access again the Mininet CLI, use `make mn-cli`') + print('To detach from the CLI (without stopping), press Ctrl-D') + print('To permanently quit Mininet, use `make stop`') + print('#' * 80) if __name__ == "__main__": parser = argparse.ArgumentParser( - description='Mininet topology script for 2x2 fabric with stratum_bmv2 and IPv6 hosts') + description='Mininet topology script for 1 switch 2 hosts with stratum_bmv2 and IPv4 hosts') args = parser.parse_args() setLogLevel('info') main() + diff --git a/net b/net new file mode 100644 index 0000000..e69de29 diff --git a/p4src/main.p4 b/p4src/main.p4 index 3bcd2d1..b099a43 100644 --- a/p4src/main.p4 +++ b/p4src/main.p4 @@ -45,6 +45,7 @@ typedef bit<16> l4_port_t; const bit<16> ETHERTYPE_IPV4 = 0x0800; const bit<16> ETHERTYPE_IPV6 = 0x86dd; +const bit<16> ETHERTYPE_ARP = 0x0806; const bit<8> IP_PROTO_ICMP = 1; const bit<8> IP_PROTO_TCP = 6; @@ -57,6 +58,12 @@ const mac_addr_t IPV6_MCAST_01 = 0x33_33_00_00_00_01; const bit<8> ICMP6_TYPE_NS = 135; const bit<8> ICMP6_TYPE_NA = 136; +const bit<8> ICMP_ECHO_REQUEST = 8; +const bit<8> ICMP_ECHO_REPLY = 0; + +const bit<16> ARP_REQUEST = 1; +const bit<16> ARP_REPLY = 2; + const bit<8> NDP_OPT_TARGET_LL_ADDR = 2; const bit<32> NDP_FLAG_ROUTER = 0x80000000; @@ -160,6 +167,18 @@ header ndp_t { bit<48> target_mac_addr; } +header arp_t { + bit<16> hw_type; + bit<16> proto_type; + bit<8> hw_addr_len; + bit<8> proto_addr_len; + bit<16> opcode; + mac_addr_t sender_hw_addr; + bit<32> sender_proto_addr; + mac_addr_t target_hw_addr; + bit<32> target_proto_addr; +} + // Packet-in header. Prepended to packets sent to the CPU_PORT and used by the // P4Runtime server (Stratum) to populate the PacketIn message metadata fields. // Here we use it to carry the original ingress port where the packet was @@ -193,6 +212,7 @@ struct parsed_headers_t { icmp_t icmp; icmpv6_t icmpv6; ndp_t ndp; + arp_t arp; } struct local_metadata_t { @@ -202,6 +222,7 @@ struct local_metadata_t { ipv6_addr_t next_srv6_sid; bit<8> ip_proto; bit<8> icmp_type; + bit<16> arp_opcode; } @@ -231,6 +252,7 @@ parser ParserImpl (packet_in packet, transition select(hdr.ethernet.ether_type){ ETHERTYPE_IPV4: parse_ipv4; ETHERTYPE_IPV6: parse_ipv6; + ETHERTYPE_ARP: parse_arp; default: accept; } } @@ -330,6 +352,12 @@ parser ParserImpl (packet_in packet, default: accept; } } + + state parse_arp { + packet.extract(hdr.arp); + local_metadata.arp_opcode = hdr.arp.opcode; + transition accept; + } } @@ -423,6 +451,27 @@ control IngressPipeImpl (inout parsed_headers_t hdr, counters = direct_counter(CounterType.packets_and_bytes); } + // IPv4 routing table - for basic IPv4 forwarding + action ipv4_forward(mac_addr_t dst_mac, mac_addr_t src_mac, port_num_t port) { + standard_metadata.egress_spec = port; + hdr.ethernet.dst_addr = dst_mac; + hdr.ethernet.src_addr = src_mac; + hdr.ipv4.ttl = hdr.ipv4.ttl - 1; + } + + table ipv4_routing_table { + key = { + hdr.ipv4.dst_addr: lpm; + } + actions = { + ipv4_forward; + drop; + } + default_action = drop(); + @name("ipv4_routing_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + // *** TODO EXERCISE 5 (IPV6 ROUTING) // @@ -474,6 +523,11 @@ control IngressPipeImpl (inout parsed_headers_t hdr, clone3(CloneType.I2E, CPU_CLONE_SESSION_ID, { standard_metadata.ingress_port }); } + // Allow IPv4 ARP broadcast traffic + action permit() { + // No special action, just permit the packet to continue through the pipeline + } + table acl_table { key = { standard_metadata.ingress_port: ternary; @@ -484,10 +538,13 @@ control IngressPipeImpl (inout parsed_headers_t hdr, local_metadata.icmp_type: ternary; local_metadata.l4_src_port: ternary; local_metadata.l4_dst_port: ternary; + hdr.arp.isValid(): ternary; + local_metadata.arp_opcode: ternary; } actions = { send_to_cpu; clone_to_cpu; + permit; drop; } @name("acl_table_counter") @@ -497,16 +554,26 @@ control IngressPipeImpl (inout parsed_headers_t hdr, apply { if (hdr.cpu_out.isValid()) { - // *** TODO EXERCISE 4 - // Implement logic such that if this is a packet-out from the - // controller: - // 1. Set the packet egress port to that found in the cpu_out header - // 2. Remove (set invalid) the cpu_out header - // 3. Exit the pipeline here (no need to go through other tables + // Implement packet-out logic + standard_metadata.egress_spec = hdr.cpu_out.egress_port; + hdr.cpu_out.setInvalid(); + exit; } bool do_l3_l2 = true; + // Handle ARP requests by redirecting to the controller + if (hdr.arp.isValid() && hdr.arp.opcode == ARP_REQUEST) { + // Send ARP requests to the controller for processing + clone_to_cpu(); + } + + // Handle ICMP Echo requests (ping) by redirecting to the controller + if (hdr.icmp.isValid() && hdr.icmp.type == ICMP_ECHO_REQUEST) { + // Send ICMP echo requests to the controller for processing + clone_to_cpu(); + } + if (hdr.icmpv6.isValid() && hdr.icmpv6.type == ICMP6_TYPE_NS) { // *** TODO EXERCISE 5 // Insert logic to handle NDP messages to resolve the MAC address of the @@ -517,23 +584,23 @@ control IngressPipeImpl (inout parsed_headers_t hdr, } if (do_l3_l2) { - - // *** TODO EXERCISE 5 - // Insert logic to match the My Station table and upon hit, the - // routing table. You should also add a conditional to drop the - // packet if the hop_limit reaches 0. - - // *** TODO EXERCISE 6 - // Insert logic to match the SRv6 My SID and Transit tables as well - // as logic to perform PSP behavior. HINT: This logic belongs - // somewhere between checking the switch's my station table and - // applying the routing table. - - // L2 bridging logic. Apply the exact table first... - if (!l2_exact_table.apply().hit) { - // ...if an entry is NOT found, apply the ternary one in case - // this is a multicast/broadcast NDP NS packet. - l2_ternary_table.apply(); + // For IPv4 packets, ensure we have basic routing capabilities + if (hdr.ipv4.isValid()) { + // Drop packet if TTL is 0 + if (hdr.ipv4.ttl == 0) { + drop(); + return; + } + + // Apply IPv4 routing + ipv4_routing_table.apply(); + } else { + // L2 bridging logic. Apply the exact table first... + if (!l2_exact_table.apply().hit) { + // ...if an entry is NOT found, apply the ternary one in case + // this is a multicast/broadcast NDP NS packet. + l2_ternary_table.apply(); + } } } @@ -549,13 +616,9 @@ control EgressPipeImpl (inout parsed_headers_t hdr, apply { if (standard_metadata.egress_port == CPU_PORT) { - // *** TODO EXERCISE 4 - // Implement logic such that if the packet is to be forwarded to the - // CPU port, e.g., if in ingress we matched on the ACL table with - // action send/clone_to_cpu... - // 1. Set cpu_in header as valid - // 2. Set the cpu_in.ingress_port field to the original packet's - // ingress port (standard_metadata.ingress_port). + // Implement packet-in logic + hdr.cpu_in.setValid(); + hdr.cpu_in.ingress_port = standard_metadata.ingress_port; } // If this is a multicast packet (flag set by l2_ternary_table), make @@ -612,6 +675,7 @@ control DeparserImpl(packet_out packet, in parsed_headers_t hdr) { packet.emit(hdr.icmp); packet.emit(hdr.icmpv6); packet.emit(hdr.ndp); + packet.emit(hdr.arp); } } diff --git a/packet-logger-app/pom.xml b/packet-logger-app/pom.xml new file mode 100644 index 0000000..b938e3a --- /dev/null +++ b/packet-logger-app/pom.xml @@ -0,0 +1,93 @@ + + + + 4.0.0 + + + org.onosproject + onos-dependencies + 2.2.2 + + + org.packetlogger.app + packet-logger-app + 1.0-SNAPSHOT + bundle + + ONOS Packet Logger Application + http://onosproject.org + + + org.packetlogger.app + Packet Logger App + Packet Logger, Inc. + default + http://onosproject.org + ONOS application for logging packet-in events. + 11 + 11 + + + + + org.onosproject + onos-api + ${onos.version} + provided + + + + org.onosproject + onlab-osgi + ${onos.version} + provided + + + + org.onosproject + onlab-misc + ${onos.version} + provided + + + + org.onosproject + onos-api + ${onos.version} + test + tests + + + + + + + org.onosproject + onos-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + + \ No newline at end of file diff --git a/packet-logger-app/src/main/java/org/packetlogger/app/AppComponent.java b/packet-logger-app/src/main/java/org/packetlogger/app/AppComponent.java new file mode 100644 index 0000000..5c63712 --- /dev/null +++ b/packet-logger-app/src/main/java/org/packetlogger/app/AppComponent.java @@ -0,0 +1,126 @@ +/* + * Copyright 2023-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. + */ +package org.packetlogger.app; + +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Application component that continuously sends "hello world" messages to an HTTP endpoint. + */ +@Component(immediate = true) +public class AppComponent { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + protected CoreService coreService; + + private ApplicationId appId; + private HttpClient httpClient; + private ScheduledExecutorService scheduledExecutor; + private static final String BASE_URL = "http://10.3.12.140:8000/url/"; + private static final int MESSAGE_INTERVAL_SECONDS = 1; // Send message every second + + @Activate + protected void activate() { + appId = coreService.registerApplication("org.packetlogger.app"); + + // Initialize HTTP client + httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(5)) + .build(); + + // Start scheduled task to send hello world messages + scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); + scheduledExecutor.scheduleAtFixedRate( + this::sendHelloWorld, + 0, // start immediately + MESSAGE_INTERVAL_SECONDS, + TimeUnit.SECONDS + ); + + log.info("Started hello world sender application - sending messages every {} second(s)", + MESSAGE_INTERVAL_SECONDS); + } + + @Deactivate + protected void deactivate() { + // Shutdown the scheduled executor + if (scheduledExecutor != null) { + scheduledExecutor.shutdown(); + scheduledExecutor = null; + } + + log.info("Stopped hello world sender application"); + } + + /** + * Sends a hello world message to the HTTP endpoint. + */ + private void sendHelloWorld() { + String jsonData = "{\"test\":\"hello world\"}"; + try { + // URL encode the JSON data to be part of the URL path + String encodedJson = URLEncoder.encode(jsonData, StandardCharsets.UTF_8.toString()); + String fullUrl = BASE_URL + encodedJson; + + log.info("Sending hello world to endpoint: {}", fullUrl); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(fullUrl)) + .GET() // Use GET instead of POST since data is in URL + .timeout(Duration.ofSeconds(5)) + .build(); + + CompletableFuture> response = httpClient.sendAsync( + request, HttpResponse.BodyHandlers.ofString()); + + response.thenAccept(res -> { + if (res.statusCode() == 200) { + log.info("Successfully sent hello world message. Response: {}", res.body()); + } else { + log.warn("Failed to send hello world message. Status code: {}, Response: {}", + res.statusCode(), res.body()); + } + }).exceptionally(ex -> { + log.error("Error sending HTTP request: {}", ex.getMessage()); + return null; + }); + } catch (Exception e) { + log.error("Error preparing HTTP request: {}", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/packet-logger-app/src/main/java/org/packetlogger/app/package-info.java b/packet-logger-app/src/main/java/org/packetlogger/app/package-info.java new file mode 100644 index 0000000..661746f --- /dev/null +++ b/packet-logger-app/src/main/java/org/packetlogger/app/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2023-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. + */ + +/** + * ONOS application for logging all packet-in metadata from switch packet interrupts. + */ +package org.packetlogger.app; \ No newline at end of file diff --git a/ping_script.py b/ping_script.py new file mode 100644 index 0000000..edac2a0 --- /dev/null +++ b/ping_script.py @@ -0,0 +1,9 @@ +#!/usr/bin/python +import os +import time + +# Generate some IPv4 traffic +for i in range(5): + os.system("ping -c 3 8.8.8.8") + time.sleep(1) + print("Ping iteration", i+1, "complete") \ No newline at end of file diff --git a/send_test_traffic.py b/send_test_traffic.py new file mode 100755 index 0000000..ae7bd4b --- /dev/null +++ b/send_test_traffic.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +from mininet.net import Mininet +from mininet.node import Controller, RemoteController +from mininet.topo import SingleSwitchTopo +import time + +def generate_traffic(net): + h1, h2 = net.get('h1', 'h2') + + # TCP traffic + print("Generating TCP traffic...") + h1.cmd('nc -w 1 %s 80