Mininet-Wifi (P4): Roaming
[topology]
Initially, sta1 and sta3 are connecting to ap1. Later, sta3 will disconnect with ap1 and then connect to ap2. There is a local controller running in ap1. This controller will monitor the status of connected stations. When the station is disconnected from h1. The controller will remove the rule from ap1 for this station. When the station is connected to ap1, the controller will add rule for this station. Similarly, there is another local controller for ap2.
Later, when sta3 is disconnected with ap1 and connected to ap2.
Note. You need to install the mininet-wifi with p4 first.
[p4.py]
#!/usr/bin/python """ You need to activate the following apps
if you want to run this code with ONOS: onos> app activate fwd drivers.bmv2
drivers.mellanox pipelines.fabric proxyarp lldpprovider hostprovider segmentrouting """ import os import sys from mininet.log import setLogLevel, info from mn_wifi.cli
import CLI from mn_wifi.net import Mininet_wifi from mn_wifi.bmv2
import P4AP, P4Host from mininet.node import RemoteController def topology(remote_controller): 'Create a network.' net = Mininet_wifi() info('***
Adding stations/hosts\n') h1 = net.addHost('h1', ip='10.0.0.1/24',
mac="00:00:00:00:00:01") h2 = net.addHost('h2', ip='10.0.0.2/24',
mac="00:00:00:00:00:02") br
= net.addHost('br') sta1 = net.addStation('sta1', ip='10.0.0.3/24',
mac="00:00:00:00:00:03") sta2 = net.addStation('sta2', ip='10.0.0.4/24',
mac="00:00:00:00:00:04") sta3 = net.addStation('sta3', ip='10.0.0.5/24',
mac="00:00:00:00:00:05") args1 = dict() args2 = dict() if not remote_controller:
path = os.path.dirname(os.path.abspath(__file__)) json_file = path + '/ap-runtime.json'
config1 = path + '/commands_ap1.txt'
config2 = path + '/commands_ap2.txt'
args1 = {'json': json_file, 'switch_config': config1}
args2 = {'json': json_file, 'switch_config': config2} info('***
Adding P4APs\n') ap1 = net.addAccessPoint('ap1', ssid='ssid-ap1',
cls=P4AP, netcfg=True,
**args1) ap2 = net.addAccessPoint('ap2', ssid='ssid-ap2',
cls=P4AP, netcfg=True,
**args2) if remote_controller: info('*** Adding Controller\n') net.addController('c0',
controller=RemoteController) net.configureWifiNodes() info('***
Creating links\n') net.addLink(sta1, ap1) net.addLink(sta2, ap2) net.addLink(sta3, ap1) #net.addLink(h1,
ap1) #net.addLink(h2,
ap2) net.addLink(ap1, br) net.addLink(ap2, br) net.addLink(br, h1) net.addLink(br, h2) info('***
Starting network\n') net.start() ap1,ap2,br,h1=net.get('ap1','ap2','br', 'h1') #ap1.cmd("python
get-stations.py &") br.cmd("brctl addbr mybr") br.cmd("ifconfig
br-eth0 0") br.cmd("ifconfig
br-eth1 0") br.cmd("ifconfig
br-eth2 0") br.cmd("ifconfig
br-eth3 0") br.cmd("brctl addif mybr
br-eth0") br.cmd("brctl addif mybr
br-eth1") br.cmd("brctl addif mybr
br-eth2") br.cmd("brctl addif mybr
br-eth3") br.cmd("ifconfig
mybr up") br.cmd("brctl setageing mybr 1") if not remote_controller: net.staticArp() h1.cmd("arp -s 10.0.0.3 00:00:00:00:00:03") h2.cmd("arp -s 10.0.0.3 00:00:00:00:00:03") sta2.cmd("arp -s 10.0.0.3 00:00:00:00:00:03") sta3.cmd("arp -s 10.0.0.3 00:00:00:00:00:03") info('***
Running CLI\n') CLI(net) info('***
Stopping network\n') net.stop() if __name__ == '__main__': #setLogLevel('debug') setLogLevel('info') remote_controller
= True if '-r' in sys.argv
else False topology(remote_controller) |
[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; 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; } 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 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(egressSpec_t port) { standard_metadata.egress_spec =
port; } table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: exact; }
actions = {
ipv4_forward;
drop;
NoAction; }
size = 1024; default_action = drop(); } apply { 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.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 {
//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; |
[commands_ap1.txt]
table_set_default ipv4_lpm drop table_add ipv4_lpm ipv4_forward 10.0.0.1 => 2 table_add ipv4_lpm ipv4_forward 10.0.0.2 => 2 table_add ipv4_lpm ipv4_forward 10.0.0.3 => 1 table_add ipv4_lpm ipv4_forward 10.0.0.4 => 2 table_add ipv4_lpm ipv4_forward 10.0.0.5 => 1 |
[commands_ap2.txt]
table_set_default ipv4_lpm drop table_add MyIngress.ipv4_lpm ipv4_forward 10.0.0.1 => 2 table_add MyIngress.ipv4_lpm ipv4_forward 10.0.0.2 => 2 table_add MyIngress.ipv4_lpm ipv4_forward 10.0.0.3 => 2 table_add MyIngress.ipv4_lpm ipv4_forward 10.0.0.4 => 1 table_add MyIngress.ipv4_lpm ipv4_forward 10.0.0.5 => 2 |
[run1.py]
from subprocess import check_output import time ap1_sta=['00:00:00:00:00:03',
'00:00:00:00:00:05'] f=open("/tmp/bmv2-ap1-thrift-port", "r") port=f.read() print(port) f.close while True:
out = check_output(['./get-stations1.sh', ''])
x=out.split( )
y = [item for item in ap1_sta if not item in x]
z = [item for item in x if not item in ap1_sta]
print "x=", x
#print "y=", y, "z=", z, "ap1_sta=",
ap1_sta
if y and y[0] in ap1_sta: print y," is moving
out of ap1" ap1_sta.remove(y[0]) tmp=y[0].split(':') tmp2="0a0000"+tmp[5] out2 = check_output(['./rm_rules1.sh',
tmp2]) print out2
if z: print z," is
connected to ap2" ap1_sta.extend(z) tmp=z[0].split(':') tmp2="0a0000"+tmp[5] out2 = check_output(['./add_rules1.sh',
tmp2]) print out2 time.sleep(1) |
[run2.py]
from subprocess import check_output import time ap2_sta=['00:00:00:00:00:04'] while True:
out = check_output(['./get-stations2.sh', ''])
x=out.split( )
y = [item for item in ap2_sta if not item in x]
z = [item for item in x if not item in ap2_sta]
print "x=", x
if y and y[0] in ap2_sta: print y," is moving
out of ap2" ap2_sta.remove(y[0]) tmp=y[0].split(':') tmp2="0a0000"+tmp[5] out2 = check_output(['./rm_rules2.sh',
tmp2]) print out2
if z: print z," is
connected to ap2" ap2_sta.extend(z) tmp=z[0].split(':') tmp2="0a0000"+tmp[5] out2 = check_output(['./add_rules2.sh',
tmp2]) print out2 time.sleep(1) |
[get-station1.sh]
#!/bin/bash result=`iw dev
ap1-wlan1 station dump|grep Station|awk
'{print $2}'` echo $result |
[get-station2.sh]
#!/bin/bash result=`iw dev
ap2-wlan1 station dump|grep Station|awk
'{print $2}'` echo $result |
[add_rules1.sh]
#!/bin/bash port=`cat /tmp/bmv2-ap1-thrift-port` no=$(echo "table_dump
ipv4_lpm" | simple_switch_CLI --thrift-port
$port | grep -B 3 "$1" | grep Dumping | awk '{print $3}' |awk -F"x" '{print $2}'| xargs
echo "ibase=16; $2" | bc) echo "table_delete
ipv4_lpm $no" | simple_switch_CLI
--thrift-port $port tmp=`echo $1 | cut -c 8` echo "table_add ipv4_lpm ipv4_forward 10.0.0.$tmp => 1"| simple_switch_CLI --thrift-port $port |
[add_rules2.sh]
#!/bin/bash port=`cat /tmp/bmv2-ap2-thrift-port` no=$(echo "table_dump
ipv4_lpm" | simple_switch_CLI --thrift-port
$port | grep -B 3 "$1" | grep Dumping | awk '{print $3}' | awk -F"x" '{print $2}'| xargs
echo "ibase=16; $2" | bc) echo "table_delete
ipv4_lpm $no" | simple_switch_CLI
--thrift-port $port tmp=`echo $1 | cut -c 8` echo "table_add ipv4_lpm ipv4_forward 10.0.0.$tmp => 1"| simple_switch_CLI --thrift-port $port |
[rm_rules1.sh]
#!/bin/bash port=`cat /tmp/bmv2-ap1-thrift-port` no=$(echo "table_dump
ipv4_lpm" | simple_switch_CLI --thrift-port
$port | grep -B 3 "$1" | grep Dumping | awk '{print $3}' | awk -F"x" '{print $2}'| xargs
echo "ibase=16; $2" | bc) #echo $no echo "table_delete ipv4_lpm $no" | simple_switch_CLI --thrift-port $port |
[rm_rules2.sh]
#!/bin/bash port=`cat /tmp/bmv2-ap2-thrift-port` no=$(echo "table_dump
ipv4_lpm" | simple_switch_CLI --thrift-port
$port | grep -B 3 "$1" | grep Dumping | awk '{print $3}' | awk -F"x" '{print $2}' | xargs
echo "ibase=16; $2" | bc) #echo $no echo "table_delete ipv4_lpm $no" | simple_switch_CLI --thrift-port $port |
[execution]
Before running the example, please stop NetworkManager.
Compile the p4 program.
Running p4.py
Open terminal for sta3, ap1, and ap2.
Running run1.py at ap1, run2.py at ap2, and ping at sta3.
Sta3 disconnected with ap1. Ping does not work. We can also see that 00:00:00:00:00:05 (sta3) is moving out of ap1
Sta3 connects with ap2. We can see the rule has been added in ap2. Ping works again.
Dr. Chih-Heng Ke
Department of Computer Science and
Information Engineering, National Quemoy University, Kinmen, Taiwan
Email: smallko@gmail.com