Notes - Network Simulation and Analysis
  • 網路模擬與分析
  • 期中
    • 20210222 Ubuntu 與 Mininet 的安裝
    • 20210308 Iperf
    • 20210315 Gnuplot
    • 20210322 Bridge ( 一 )
    • 20210329 Bridge ( 二 )
    • 20210412 Openvswitch ( 一 )
    • 20210419 期中週
  • 期末
    • 20210426 Group Table
    • 20210503 Containernet / Mininet-Wifi ( Miniedit )
    • 20210510 Programming Protocol-independent Packet Processors ( P4 ) - 1
    • 20210517 Programming Protocol-independent Packet Processors ( P4 ) - 2
    • 20210524 Programming Protocol-independent Packet Processors ( P4 ) - 3
    • 20210531 Programming Protocol-independent Packet Processors ( P4 ) - 4
    • 20210607 Programming Protocol-independent Packet Processors ( P4 ) - Finish
Powered by GitBook
On this page
  • 課堂資料
  • Copy to CPU
  • Send to CPU
  • Send to CPU2
  • 課堂作業附件
  • 課堂練習
  • Copy to CPU
  • Send to CPU
  • Send to CPU2
  • Broadcast / Multicast
  • 課堂作業
  • Multicast

Was this helpful?

  1. 期末

20210531 Programming Protocol-independent Packet Processors ( P4 ) - 4

Previous20210524 Programming Protocol-independent Packet Processors ( P4 ) - 3Next20210607 Programming Protocol-independent Packet Processors ( P4 ) - Finish

Last updated 3 years ago

Was this helpful?

課堂資料

範例程式

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

TCP/IP Client and Server - Python Module of the Week
copy-to-cpuDropbox
send_to_cpuDropbox
send_to_cpu2Dropbox
How do you UDP multicast in Python?Stack Overflow
test-multicastDropbox
Logo
Logo
Logo
Logo
Logo