My Implementation for “High-Speed Data-Plane Packet Aggregation and Disaggregation by P4 Switches”

Based on “High-Speed Data-Plane Packet Aggregation and Disaggregation by P4 Switches” published by Shie-Yuan Wang et al., I try to implement the idea in this lab.

 

H1(10.0.0.1)---(port 1)S1(port2)---(port2)S2(port1)---H2 (10.0.0.2)

 

H1 will send the IOT packets to S1. At S1, 8 packets will be aggregated into a big packet and be sent to S2. At S2, the aggregated packets will be disaggregated into 8 small packets and then be sent to the H2.

 

[cmd.txt] rules for S1 (for packets sent to 10.0.0.2, the switch will perform aggregation task (0); for packets sent to 10.0.0.1, the switch will perform disaggregation task (1))

table_add setAction set_action 10.0.0.2 => 0

table_add setAction set_action 10.0.0.1 => 1

table_add phyforward forward 1 => 2

table_add phyforward forward 2 => 1

 

[cmd2.txt] rules for s2 (the aggregated packet will be set to a multicast group 1. Then the aggregated packet will be duplicated 8 times and be sent to the same output port 1.)

table_add setAction set_action 10.0.0.2 => 1

table_add setAction set_action 10.0.0.1 => 0

table_add phyforward forward 2 => 1

table_add phyforward forward 1 => 2

mc_mgrp_create 1

mc_node_create 0 1

mc_node_create 1 1

mc_node_create 2 1

mc_node_create 3 1

mc_node_create 4 1

mc_node_create 5 1

mc_node_create 6 1

mc_node_create 7 1

mc_node_associate 1 0

mc_node_associate 1 1

mc_node_associate 1 2

mc_node_associate 1 3

mc_node_associate 1 4

mc_node_associate 1 5

mc_node_associate 1 6

mc_node_associate 1 7

 

[cmd_add.py] Put the rules into S1 and S2

import os

 

os.system('sudo /home/vagrant/behavioral-model/targets/simple_switch/simple_switch_CLI --thrift-port=9090 < cmd.txt')

os.system('sudo /home/vagrant/behavioral-model/targets/simple_switch/simple_switch_CLI --thrift-port=9091 < cmd2.txt')

 

[basic.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;

 

register<bit<128>>(8) buffer;

register<bit<1>>(1) is_buffer_empty;

register<bit<3>>(1) cnt;

 

header ethernet_t {

    macAddr_t dstAddr;

    macAddr_t 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;

    ip4Addr_t srcAddr;

    ip4Addr_t dstAddr;

}

 

header udp_t {

    bit<16> srcPort;

    bit<16> dstPort;

    bit<16> udplength;

    bit<16> checksum;

}

 

header flag_t {

    bit<8> type;

    bit<40> padding;

}

 

header msg_t {

    bit<128> msg;

}

 

header agg_t {

    bit<128> msg;

}

 

struct metadata {

    bit<1>   saved;

    bit<1>   empty;

    bit<3>   cnt;

    bit<1>   myaction; //0:aggregate 1:disaggregate

}

 

struct headers {

    ethernet_t   ethernet;

    ipv4_t       ipv4;

    udp_t       udp;

    flag_t       flag;

    msg_t      msg;

    agg_t[8]     agg; 

}

 

/*************************************************************************

*********************** 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 parse_ethernet;

    }

 

    state parse_ethernet {

        packet.extract(hdr.ethernet);

        transition select(hdr.ethernet.etherType) {

            TYPE_IPV4: parse_ipv4;

            default: accept;

        }

    }

 

    state parse_ipv4 {

        packet.extract(hdr.ipv4);

        transition select(hdr.ipv4.protocol) {

            0x11: parse_udp;

            default: accept;

        }

    }

 

    state parse_udp {

        packet.extract(hdr.udp);

        transition parse_flag;

    }

  

    state parse_flag {

        packet.extract(hdr.flag);

        transition select(hdr.flag.type) {

            0x1: parse_msg;

            0x2: parse_agg;

            default: accept;

        }

    }

 

    state parse_msg {

        meta.saved=0;

        packet.extract(hdr.msg);

        transition accept;

    }

 

    state parse_agg {

        packet.extract(hdr.agg[0]);

        packet.extract(hdr.agg[1]);

        packet.extract(hdr.agg[2]);

        packet.extract(hdr.agg[3]);

        packet.extract(hdr.agg[4]);

        packet.extract(hdr.agg[5]);

        packet.extract(hdr.agg[6]);

        packet.extract(hdr.agg[7]);             

        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();

    }

   

    action check_cnt() {

        cnt.read(meta.cnt,(bit<32>)0);

    }

 

    action check_buffer_empty() {

        is_buffer_empty.read(meta.empty,(bit<32>)0);

    }

 

    action set_buffer_not_empty() {

        is_buffer_empty.write((bit<32>)0, 1);

    }

 

    action set_buffer_empty() {

        is_buffer_empty.write((bit<32>)0, 0);

    }

 

    action to_buffer() {

        buffer.write((bit<32>)meta.cnt,(bit<128>)hdr.msg.msg);

        meta.saved=1;

    }     

 

    action add_counter() {

        meta.cnt = meta.cnt + 1;

        cnt.write((bit<32>)0,(bit<3>)meta.cnt);

    }

 

    action set_Npkt() {

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)7);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)6);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();   

        buffer.read(hdr.agg[0].msg, (bit<32>)5);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)4);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)3);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)2);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)1);

        hdr.agg.push_front(1);

        hdr.agg[0].setValid();

        buffer.read(hdr.agg[0].msg, (bit<32>)0);

        hdr.udp.udplength =  (bit<16>) 142;

        hdr.ipv4.totalLen =  (bit<16>) 162;

    }

 

    action multicast_method() {

        standard_metadata.mcast_grp=1;

    }

 

    action forward(egressSpec_t port) {

        standard_metadata.egress_spec = port;

    }

 

    table phyforward {

        key = {

            standard_metadata.ingress_port: exact;

        }

        actions = {

            forward;

            drop;

        }

        size = 1024;

        default_action = drop();

    }     

 

    action set_action(bit<1> myaction) {

        meta.myaction=myaction;

    }

 

    table setAction {

        key = {

            hdr.ipv4.dstAddr: exact;

        }

        actions = {

            set_action();

        }

        size = 1024;

    }               

    

    apply {

        setAction.apply();

 

        if(hdr.flag.type==1 && meta.myaction==0) {

           check_cnt();

           check_buffer_empty();

           if(meta.empty!=0 && meta.cnt==0) {

             set_Npkt();

             hdr.flag.type=2; //aggregated N-pkt

             set_buffer_empty();

             to_buffer();

             add_counter();

             hdr.msg.setInvalid();

           }

 

           if(meta.saved==0) {

             to_buffer();

             add_counter();

             set_buffer_not_empty();

             drop();

           }

        }

       

        if(hdr.flag.type==2 && meta.myaction==0) {

       phyforward.apply();

        }

 

        if(hdr.flag.type==2 && meta.myaction==1) {      

           multicast_method();

        }

    }

}

 

/*************************************************************************

****************  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(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==0) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[0].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;   

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      } 

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==1) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[1].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      }

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==2) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[2].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      } 

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==3) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[3].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      }  

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==4) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[4].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      }  

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==5) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[5].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      } 

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==6) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[6].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      }  

 

      if(hdr.flag.type==2 && meta.myaction==1 && standard_metadata.egress_rid==7) {

         hdr.msg.setValid();

         hdr.msg.msg=hdr.agg[7].msg;

         hdr.agg[0].setInvalid();

         hdr.agg[1].setInvalid();

         hdr.agg[2].setInvalid();

         hdr.agg[3].setInvalid();

         hdr.agg[4].setInvalid();

         hdr.agg[5].setInvalid();

         hdr.agg[6].setInvalid();

         hdr.agg[7].setInvalid(); 

         hdr.flag.type=1;

         hdr.ipv4.totalLen=50;

         hdr.udp.udplength=30;

      }  

    }

}

 

/*************************************************************************

*************   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.diffserv,

              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 {

        packet.emit(hdr.ethernet);

        packet.emit(hdr.ipv4);

        packet.emit(hdr.udp);

        packet.emit(hdr.flag);

        packet.emit(hdr.msg);

        packet.emit(hdr.agg);     

    }

}

 

/*************************************************************************

***********************  S W I T C H  *******************************

*************************************************************************/

 

V1Switch(

MyParser(),

MyVerifyChecksum(),

MyIngress(),

MyEgress(),

MyComputeChecksum(),

MyDeparser()

) main;

 

[test_topo.py] network topology

import os

from mininet.net import Mininet

from mininet.topo import Topo

from mininet.log import setLogLevel, info

from mininet.cli import CLI

from mininet.node import RemoteController

 

from p4_mininet import P4Switch, P4Host

 

import argparse

from time import sleep

 

parser = argparse.ArgumentParser(description='Mininet demo')

parser.add_argument('--behavioral-exe', help='Path to behavioral executable',

                    type=str, action="store", required=False, default='simple_switch' )

parser.add_argument('--thrift-port', help='Thrift server port for table updates',

                    type=int, action="store", default=9090)

parser.add_argument('--num-hosts', help='Number of hosts to connect to switch',

                    type=int, action="store", default=2)

parser.add_argument('--mode', choices=['l2', 'l3'], type=str, default='l3')

parser.add_argument('--json', help='Path to JSON config file',

                    type=str, action="store", required=True)

parser.add_argument('--pcap-dump', help='Dump packets on interfaces to pcap files',

                    type=str, action="store", required=False, default=False)

 

args = parser.parse_args()

 

class SingleSwitchTopo(Topo):

    def __init__(self, sw_path, json_path, thrift_port, pcap_dump, **opts):

        Topo.__init__(self, **opts)

 

        switch1 = self.addSwitch('s1', sw_path = sw_path, json_path = json_path, thrift_port = thrift_port,cls = P4Switch ,pcap_dump = pcap_dump)

        switch2 = self.addSwitch('s2', sw_path = sw_path, json_path = json_path, thrift_port = thrift_port + 1,cls = P4Switch ,pcap_dump = pcap_dump)

               

        host1 = self.addHost('h1', mac = '00:00:00:00:00:01')

        host2 = self.addHost('h2', mac = '00:00:00:00:00:02')

      

        self.addLink(host1, switch1, port1 = 0, port2 = 1)

        self.addLink(host2, switch2, port1 = 0, port2 = 1)

        self.addLink(switch1, switch2)

       

def main():

    topo = SingleSwitchTopo(args.behavioral_exe, args.json, args.thrift_port, args.pcap_dump)

    #controller1 = RemoteController('controller1', ip = '10.108.148.148')

    net = Mininet(topo = topo, host = P4Host, controller = None)

    net.start()

 

    sleep(1)

 

    print('\033[0;32m'),

    print "Gotcha!"

    print('\033[0m')

 

    CLI(net)

    try:

        net.stop()

    except:

        print('\033[0;31m'),

        print('Stop error! Trying sudo mn -c')

        print('\033[0m')

        os.system('sudo mn -c')

        print('\033[0;32m'),

        print ('Stop successfully!')

        print('\033[0m')

 

if __name__ == '__main__':

    setLogLevel('info')

    main()

 

[start_test_topo.py]

import os

 

os.system("sudo python test_topo.py --behavioral-exe /home/vagrant/behavioral-model/targets/simple_switch/simple_switch --json basic.json")

 

[p4_mininet.py]

# Copyright 2013-present Barefoot Networks, Inc.

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#   http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

#

 

from mininet.net import Mininet

from mininet.node import Switch, Host

from mininet.log import setLogLevel, info, error, debug

from mininet.moduledeps import pathCheck

from sys import exit

import os

import tempfile

import socket

 

class P4Host(Host):

    def config(self, **params):

        r = super(Host, self).config(**params)

 

        self.defaultIntf().rename("eth0")

 

        for off in ["rx", "tx", "sg"]:

            cmd = "/sbin/ethtool --offload eth0 %s off" % off

            self.cmd(cmd)

 

        # disable IPv6

        self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")

        self.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")

        self.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")

 

        return r

 

    def describe(self):

        print "**********"

        print self.name

        print "default interface: %s\t%s\t%s" %(

            self.defaultIntf().name,

            self.defaultIntf().IP(),

            self.defaultIntf().MAC()

        )

        print "**********"

 

class P4Switch(Switch):

    """P4 virtual switch"""

    device_id = 0

 

    def __init__(self, name, sw_path = None, json_path = None,

                 thrift_port = None,

                 pcap_dump = False,

                 log_console = True,

                 verbose = True,

                 device_id = None,

                 enable_debugger = False,

                 **kwargs):

        Switch.__init__(self, name, **kwargs)

        assert(sw_path)

        assert(json_path)

        # make sure that the provided sw_path is valid

        pathCheck(sw_path)

        # make sure that the provided JSON file exists

        if not os.path.isfile(json_path):

            error("Invalid JSON file.\n")

            exit(1)

        self.sw_path = sw_path

        self.json_path = json_path

        self.verbose = verbose

        logfile = "/tmp/p4s.{}.log".format(self.name)

        self.output = open(logfile, 'w')

        self.thrift_port = thrift_port

        self.pcap_dump = pcap_dump

        self.enable_debugger = enable_debugger

        self.log_console = log_console

        if device_id is not None:

            self.device_id = device_id

            P4Switch.device_id = max(P4Switch.device_id, device_id)

        else:

            self.device_id = P4Switch.device_id

            P4Switch.device_id += 1

        self.nanomsg = "ipc:///tmp/bm-{}-log.ipc".format(self.device_id)

 

    @classmethod

    def setup(cls):

        pass

 

    def check_switch_started(self, pid):

        """While the process is running (pid exists), we check if the Thrift

        server has been started. If the Thrift server is ready, we assume that

        the switch was started successfully. This is only reliable if the Thrift

        server is started at the end of the init process"""

        while True:

            if not os.path.exists(os.path.join("/proc", str(pid))):

                return False

            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            sock.settimeout(0.5)

            result = sock.connect_ex(("localhost", self.thrift_port))

            if result == 0:

                return  True

 

    def start(self, controllers):

        "Start up a new P4 switch"

        info("Starting P4 switch {}.\n".format(self.name))

        args = [self.sw_path]

        for port, intf in self.intfs.items():

            if not intf.IP():

                args.extend(['-i', str(port) + "@" + intf.name])

 

        #wuwzhs edit in 2017/11/10

        #args.extend(['-i 3@veth1'])

 

        if self.pcap_dump:

            args.append("--pcap")

            # args.append("--useFiles")

        if self.thrift_port:

            args.extend(['--thrift-port', str(self.thrift_port)])

        if self.nanomsg:

            args.extend(['--nanolog', self.nanomsg])

        args.extend(['--device-id', str(self.device_id)])

        P4Switch.device_id += 1

        args.append(self.json_path)

        if self.enable_debugger:

            args.append("--debugger")

        if self.log_console:

            args.append("--log-console")

        logfile = "/tmp/p4s.{}.log".format(self.name)

        info(' '.join(args) + "\n")

 

        pid = None

        with tempfile.NamedTemporaryFile() as f:

            # self.cmd(' '.join(args) + ' > /dev/null 2>&1 &')

            self.cmd(' '.join(args) + ' >' + logfile + ' 2>&1 & echo $! >> ' + f.name)

            pid = int(f.read())

        debug("P4 switch {} PID is {}.\n".format(self.name, pid))

        if not self.check_switch_started(pid):

            error("P4 switch {} did not start correctly.\n".format(self.name))

            exit(1)

        info("P4 switch {} has been started.\n".format(self.name))

 

    def stop(self):

        "Terminate P4 switch."

        self.output.flush()

        self.cmd('kill %' + self.sw_path)

        self.cmd('wait')

        self.deleteIntfs()

 

    def attach(self, intf):

        "Connect a data port"

        assert(0)

 

    def detach(self, intf):

        "Disconnect a data port"

        assert(0)

 

[send.py] sender program (generate small IOT packets)

#!/usr/bin/env python

import argparse

import sys

import socket

import random

import struct

 

from scapy.utils import *

from scapy.all import *

import readline

 

def get_if():

    ifs=get_if_list()

    iface=None

    for i in get_if_list():

        if "eth0" in i:

            iface=i

            break;

    if not iface:

        print "Cannot find eth0 interface"

        exit(1)

    return iface

 

def main():

 

    if len(sys.argv)<2:

        print 'pass 2 arguments: <destination>'

        exit(1)

 

    addr = socket.gethostbyname(sys.argv[1])

    iface = get_if()

    print "sending on interface %s to %s" % (iface, str(addr))

    k=1

    while k<20:

        print

        data = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + struct.pack('!I', k)

        pkt =  Ether(src=get_if_hwaddr(iface), dst='00:00:00:00:00:02')

        data = "\x01" + "\x00\x00\x00\x00\x00" + data

        a=Raw(load=data)

        pkt = pkt / IP(dst=addr) / UDP(dport=4321, sport=1234)/a

        pkt.show2()

        sendp(pkt, iface=iface, verbose=False)

        k+=1

        print "send out:" + str(k) + "th packet"

 

 

if __name__ == '__main__':

    main()

 

[receive.py]

#!/usr/bin/env python

import sys

import struct

 

from scapy.utils import *

from scapy.all import *

from scapy.layers.inet import _IPOption_HDR

i=0

 

def get_if():

    ifs=get_if_list()

    iface=None

    for i in get_if_list():

        if "eth0" in i:

            iface=i

            break;

    if not iface:

        print "Cannot find eth0 interface"

        exit(1)

    return iface

 

def handle_pkt(pkt):

    global i

    i+=1

    print "got a packet:" + str(i)

    pkt.show2()

    sys.stdout.flush()

 

def main():

    iface = 'eth0'

    print "sniffing on %s" % iface

    sys.stdout.flush()

    sniff(filter="udp and port 4321", iface = iface,

          prn = lambda x: handle_pkt(x))

 

if __name__ == '__main__':

    main()

 

[Execution]

1.      Compile the p4 program and start experiment

2.      Set the rules for s1 and s2

 

3.      Open three terminals for h1, s1, and h2

 

4.      Open wireshark for h2 (listen on eth0 interface) : check the disaggregated pkts

5.      Open wireshark for s1 (listen on s1-eth2 interface): check the aggregated pkts

6.      Start transmission at h1

7.      The captured pkts at s1-eth2

 

8.      The captured pkts at eth0 (h2)

 

 

Dr. Chih-Heng Ke (smallko@gmail.com)

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.