20210531 Programming Protocol-independent Packet Processors ( P4 ) - 4
課堂資料
範例程式
Copy to CPU
Send to CPU
Send to CPU2
課堂作業附件

課堂練習
cd Downloads
mkdir copy-to-cpu send-to-cpu send-to-cpu2
mv -f copy-to-cpu.zip copy-to-cpu/
mv -f send_to_cpu.zip send-to-cpu/
mv -f send_to_cpu2.zip send-to-cpu2/
cd copy-to-cpu
unzip copy-to-cpu.zip
cd ..

cd send-to-cpu
unzip send_to_cpu.zip
cd ..
cd send-to-cpu2
unzip send_to_cpu2.zip

cd ..
Copy to CPU

cd copy-to-cpu
gedit p4app.json basic.p4 receive.py cmd.txt &

sed -i '/^$/d' p4app.json
p4run

s1 ifconfig

監聽後進行
h1 ping h2
h1 ping h2 -c 5

xterm h2 h1
p4app.json
{
"program": "basic.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": true,
"enable_log": true,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopoStrategies"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"assignment_strategy": "l2",
"links": [["h1", "s1"], ["h2", "s1"]],
"hosts": {
"h1": {
},
"h2": {
}
},
"switches": {
"s1": {
"cli_input": "cmd.txt",
"program": "basic.p4",
"cpu_port": true
}
}
}
}
basic.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
struct metadata {
/* empty */
}
struct headers {
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
transition accept;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action forward(bit<9> port) {
standard_metadata.egress_spec = port;
}
table phy_forward {
key = {
standard_metadata.ingress_port: exact;
}
actions = {
forward;
drop;
}
size = 1024;
default_action = drop();
}
apply {
phy_forward.apply();
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply {
if (standard_metadata.instance_type == 0 ){
clone(CloneType.E2E,100);
}
}
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
receive.py
#!/usr/bin/env python
import sys
import struct
import os
from scapy.all import sniff, sendp, hexdump, get_if_list, get_if_hwaddr, bind_layers
from scapy.all import Packet, IPOption, Ether
from scapy.all import ShortField, IntField, LongField, BitField, FieldListField, FieldLenField
from scapy.all import IP, UDP, Raw, ls
from scapy.layers.inet import _IPOption_HDR
class CpuHeader(Packet):
name = 'CpuPacket'
fields_desc = [BitField("device_id",0,16), BitField('reason',0,16), BitField('counter', 0, 80)]
bind_layers(CpuHeader, Ether)
def handle_pkt(pkt):
print "Controller got a packet"
print pkt.summary()
def main():
if len(sys.argv) < 2:
iface = 's1-cpu-eth1'
else:
iface = sys.argv[1]
print "sniffing on %s" % iface
sys.stdout.flush()
sniff(iface = iface,
prn = lambda x: handle_pkt(x))
if __name__ == '__main__':
main()
cmd.txt
table_add phy_forward forward 1 => 2
table_add phy_forward forward 2 => 1
mirroring_add 100 3
cd Downloads/copy-to-cpu
進行監聽
python receive.py

python receive.py

python server.py

python client.py

cd Downloads/copy-to-cpu
gedit client.py server.py
rm -rf socket.pyc
server.py
import socket
import sys
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = ('10.0.0.2', 10000)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)
# Listen for incoming connections
sock.listen(1)
connection, client_address = sock.accept()
print >>sys.stderr, 'connection from', client_address
data = connection.recv(1024)
print >>sys.stderr, 'received "%s"' % data
connection.close()
client.py
import socket
import sys
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('10.0.0.2', 10000)
print >>sys.stderr, 'connecting to %s port %s' % server_address
sock.connect(server_address)
# Send data
message = 'hello world'
print >>sys.stderr, 'sending "%s"' % message
sock.sendall(message)
sock.close()
cd ..
Send to CPU

cd send-to-cpu
sed -i '/^$/d' p4app.json
gedit p4app.json send_to_cpu.p4 s1-commands.txt s2-commands.txt s3-commands.txt controller.py &

p4run

h1 ping h2 -c 5

p4app.json
{
"program": "send_to_cpu.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": true,
"enable_log": true,
"cpu_port": true,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopo"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"links": [["h1","s1"], ["s3","h2"], ["s1","s2"], ["s2","s3"]],
"hosts": {
"h1": {
},
"h2": {
}
},
"switches": {
"s1": {
"cli_input": "s1-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
},
"s2": {
"cli_input": "s2-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
},
"s3": {
"cli_input": "s3-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
}
}
}
}
send_to_cpu.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_IPV4 = 0x800;
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> tos;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct metadata {
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType){
TYPE_IPV4: ipv4;
default: accept;
}
}
state ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
//set the src mac address as the previous dst, this is not correct right?
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
//set the destination mac address that we got from the match in the table
hdr.ethernet.dstAddr = dstAddr;
//set the output port that we also get from the table
standard_metadata.egress_spec = port;
//decrease ttl by 1
hdr.ipv4.ttl = hdr.ipv4.ttl -1;
}
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = NoAction();
}
apply {
//only if IPV4 the rule is applied. Therefore other packets will not be forwarded.
if (hdr.ipv4.isValid()){
ipv4_lpm.apply();
}
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply {
if (standard_metadata.instance_type == 0 ){
clone3(CloneType.E2E,100, meta);
}
//handle the cloned packet
if (standard_metadata.instance_type != 0){
truncate((bit<32>)34); //ether+ip header
}
}
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
update_checksum(
hdr.ipv4.isValid(),
{ hdr.ipv4.version,
hdr.ipv4.ihl,
hdr.ipv4.tos,
hdr.ipv4.totalLen,
hdr.ipv4.identification,
hdr.ipv4.flags,
hdr.ipv4.fragOffset,
hdr.ipv4.ttl,
hdr.ipv4.protocol,
hdr.ipv4.srcAddr,
hdr.ipv4.dstAddr },
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
//parsed headers have to be added again into the packet.
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
//switch architecture
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
s1-commands.txt
table_set_default ipv4_lpm drop
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:00:0a:00:01:01 1
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.3.0/24 => 00:00:00:02:01:00 2
//creates a mirroring ID 100 to output port 3
mirroring_add 100 3
s2-commands.txt
table_set_default ipv4_lpm drop
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:00:00:01:01:00 1
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.3.0/24 => 00:00:00:03:01:00 2
//creates a mirroring ID 100 to output port 3
//mirroring_add 100 3
s3-commands.txt
table_set_default ipv4_lpm drop
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:00:00:02:01:00 2
table_add MyIngress.ipv4_lpm ipv4_forward 10.0.3.2/32 => 00:00:0a:00:03:02 1
//creates a mirroring ID 100 to output port 3
mirroring_add 100 3
controller.py
import nnpy
import struct
from p4utils.utils.topology import Topology
from p4utils.utils.sswitch_API import SimpleSwitchAPI
from scapy.all import Ether, sniff, Packet, BitField
class myController(object):
def __init__(self):
self.topo = Topology(db="topology.db")
self.controllers = {}
self.connect_to_switches()
def connect_to_switches(self):
for p4switch in self.topo.get_p4switches():
thrift_port = self.topo.get_thrift_port(p4switch)
#print "p4switch:", p4switch, "thrift_port:", thrift_port
self.controllers[p4switch] = SimpleSwitchAPI(thrift_port)
def recv_msg_cpu(self, pkt):
print "interface:", pkt.sniffed_on
print "summary:", pkt.summary()
def run_cpu_port_loop(self):
cpu_interfaces = [str(self.topo.get_cpu_port_intf(sw_name).replace("eth0", "eth1")) for sw_name in self.controllers]
sniff(iface=cpu_interfaces, prn=self.recv_msg_cpu)
if __name__ == "__main__":
controller = myController()
controller.run_cpu_port_loop()
cd send-to-cpu
python controller.py

cd ..
Send to CPU2
cd send-to-cpu2
sed -i '/^$/d' p4app.json
gedit p4app.json send_to_cpu.p4 s1-commands.txt s2-commands.txt s3-commands.txt controller.py &

p4run
xterm h1 h2
p4app.json
{
"program": "send_to_cpu.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": true,
"enable_log": true,
"cpu_port": true,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopo"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"links": [["h1","s1"], ["s3","h2"], ["s1","s2"], ["s2","s3"]],
"hosts": {
"h1": {
},
"h2": {
}
},
"switches": {
"s1": {
"cli_input": "s1-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
},
"s2": {
"cli_input": "s2-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
},
"s3": {
"cli_input": "s3-commands.txt",
"program": "send_to_cpu.p4",
"cpu_port": true
}
}
}
}
send_to_cpu.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_IPV4 = 0x800;
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> tos;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct metadata {
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType){
TYPE_IPV4: ipv4;
default: accept;
}
}
state ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
//set the src mac address as the previous dst, this is not correct right?
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
//set the destination mac address that we got from the match in the table
hdr.ethernet.dstAddr = dstAddr;
//set the output port that we also get from the table
standard_metadata.egress_spec = port;
//decrease ttl by 1
hdr.ipv4.ttl = hdr.ipv4.ttl -1;
}
action to_cpu(egressSpec_t port) {
standard_metadata.egress_spec = port;
}
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
to_cpu;
drop;
}
size = 1024;
}
apply {
//only if IPV4 the rule is applied. Therefore other packets will not be forwarded.
if (hdr.ipv4.isValid()){
ipv4_lpm.apply();
}
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply {
}
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
update_checksum(
hdr.ipv4.isValid(),
{ hdr.ipv4.version,
hdr.ipv4.ihl,
hdr.ipv4.tos,
hdr.ipv4.totalLen,
hdr.ipv4.identification,
hdr.ipv4.flags,
hdr.ipv4.fragOffset,
hdr.ipv4.ttl,
hdr.ipv4.protocol,
hdr.ipv4.srcAddr,
hdr.ipv4.dstAddr },
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
//parsed headers have to be added again into the packet.
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
//switch architecture
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
s1-commands.txt
table_set_default ipv4_lpm to_cpu 3
s2-commands.txt
s3-commands.txt
table_set_default ipv4_lpm to_cpu 3
controller.py
import nnpy
import struct
from p4utils.utils.topology import Topology
from p4utils.utils.sswitch_API import SimpleSwitchAPI
#from scapy.all import Ether, sniff, Packet, BitField
from scapy.all import *
rules=[]
class myController(object):
def __init__(self):
self.topo = Topology(db="topology.db")
self.controllers = {}
self.connect_to_switches()
def connect_to_switches(self):
for p4switch in self.topo.get_p4switches():
thrift_port = self.topo.get_thrift_port(p4switch)
#print "p4switch:", p4switch, "thrift_port:", thrift_port
self.controllers[p4switch] = SimpleSwitchAPI(thrift_port)
def recv_msg_cpu(self, pkt):
print "-------------------------------------------------------------------"
global rules
print "interface:", pkt.sniffed_on
print "summary:", pkt.summary()
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
print "ip_src:", ip_src, " ip_dst:", ip_dst
if (ip_src, ip_dst) not in rules:
rules.append((ip_src, ip_dst))
print "rules:", rules
else:
return
switches = {sw_name:{} for sw_name in self.topo.get_p4switches().keys()}
#print "switches:", switches
for sw_name, controller in self.controllers.items():
for host in self.topo.get_hosts_connected_to(sw_name):
host_ip_addr = self.topo.get_host_ip(host)
if ip_src == host_ip_addr:
sw_src = sw_name
if ip_dst == host_ip_addr:
sw_dst = sw_name
sw_port = self.topo.node_to_node_port_num(sw_name, host)
host_ip = self.topo.get_host_ip(host) + "/32"
host_mac = self.topo.get_host_mac(host)
#print host, "(", host_ip, host_mac, ")", "-->", sw_name, "with port:", sw_port
#add rule
print "table_add at {}:".format(sw_name)
self.controllers[sw_name].table_add("ipv4_lpm", "ipv4_forward", [str(host_ip)], [str(host_mac), str(sw_port)])
print "sw_src:", sw_src, "sw_dst:", sw_dst
paths = self.topo.get_shortest_paths_between_nodes(sw_src, sw_dst)
sw_1=sw_src
for next_hop in paths[0][1:]:
host_ip = ip_dst + "/32"
sw_port = self.topo.node_to_node_port_num(sw_1, next_hop)
dst_sw_mac = self.topo.node_to_node_mac(next_hop, sw_1)
#add rule
print "table_add at {}:".format(sw_1)
self.controllers[sw_1].table_add("ipv4_lpm", "ipv4_forward", [str(host_ip)],
[str(dst_sw_mac), str(sw_port)])
sw_1=next_hop
print "send original packet back from ", pkt.sniffed_on
sendp(pkt, iface=pkt.sniffed_on, verbose=False)
def run_cpu_port_loop(self):
cpu_interfaces = [str(self.topo.get_cpu_port_intf(sw_name).replace("eth0", "eth1")) for sw_name in self.controllers]
sniff(iface=cpu_interfaces, prn=self.recv_msg_cpu)
if __name__ == "__main__":
controller = myController()
controller.run_cpu_port_loop()
cd send-to-cpu2
simple_switch_CLI --thrift-port 9090
table_dump ipv4_lpm

simple_switch_CLI --thrift-port 9091
table_dump ipv4_lpm

simple_switch_CLI --thrift-port 9092
table_dump ipv4_lpm

python controller.py

ping 10.0.3.2 -c 5

Broadcast / Multicast

cd p4-test/test-broadcast
p4run
xterm h1 h2 h3
接收
h1
傳送
python receive.py
進行傳送,由
h1
、h3
接收
python send.py
接收
h3
傳送
python receive.py

接收
h1
傳送
python receive.py
接收
h2
傳送
python receive.py
進行傳送,由
h1
、h2
接收
python send.py

進行傳送,由
h2
、h3
接收
python send.py
接收
h2
傳送
python receive.py
接收
h3
傳送
python receive.py

延伸

Broadcast
:當接收封包時,廣播至所有節點Multicast
:針對有興趣的節點傳送封包
課堂作業
Multicast

cd p4-test
cp -r test-broadcast/ multicast
cd multicast
gedit basic.p4 p4app.json cmd.txt

gedit send.py receive.py

p4run
xterm h1 h2 h3 h4
p4app.json
{
"program": "basic.p4",
"switch": "simple_switch",
"compiler": "p4c",
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": false,
"enable_log": true,
"topo_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.apptopo",
"object_name": "AppTopoStrategies"
},
"controller_module": null,
"topodb_module": {
"file_path": "",
"module_name": "p4utils.utils.topology",
"object_name": "Topology"
},
"mininet_module": {
"file_path": "",
"module_name": "p4utils.mininetlib.p4net",
"object_name": "P4Mininet"
},
"topology": {
"links": [["h1", "s1"], ["h2", "s1"], ["h3", "s1"], ["h4", "s1"]],
"hosts": {
"h1": {
},
"h2": {
},
"h3": {
},
"h4": {
}
},
"switches": {
"s1": {
"cli_input": "cmd.txt",
"program": "basic.p4"
}
}
}
}
basic.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
bit<32> srcAddr;
bit<32> dstAddr;
}
struct metadata {
/* empty */
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state parse_ethernet {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
16w0x800: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
state start {
transition parse_ethernet;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action forward(bit<9> port) {
standard_metadata.egress_spec = port;
}
table mac_forward {
key = {
hdr.ethernet.dstAddr: exact;
}
actions = {
forward;
drop;
}
size = 1024;
default_action = drop();
}
action broadcast(bit<16> mcast_grp_id) {
standard_metadata.mcast_grp = mcast_grp_id;
}
table ip_broadcast {
key = {
hdr.ipv4.dstAddr: exact;
standard_metadata.ingress_port: exact;
}
actions = {
broadcast;
NoAction;
}
size = 1024;
default_action = NoAction();
}
apply {
if (!ip_broadcast.apply().hit){
mac_forward.apply();
}
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply { }
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
cmd.txt
table_add mac_forward forward 00:00:0a:00:01:01 => 1
table_add mac_forward forward 00:00:0a:00:01:02 => 2
table_add mac_forward forward 00:00:0a:00:01:03 => 3
table_add ip_broadcast broadcast 224.0.0.10 1 => 1
mc_mgrp_create 1
mc_node_create 0 2 4
mc_node_associate 1 0
send.py
#!/usr/bin/env python
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.sendto('hello everyone', ('224.0.0.10', 1234))
receive.py
import socket
import struct
MCAST_GRP = '224.0.0.10'
MCAST_PORT = 1234
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
# For Python 3, change next line to "print(sock.recv(10240))"
print sock.recv(10240)
wireshark

python receive.py

wireshark

python receive.py

wireshark

python receive.py

進行傳送,由
h2
、h3
、h4
進行wireshark
監測
python send.py
再次傳送,由
h2
、h3
、h4
進行監測
python send.py
Previous20210524 Programming Protocol-independent Packet Processors ( P4 ) - 3Next20210607 Programming Protocol-independent Packet Processors ( P4 ) - Finish
Last updated
Was this helpful?