H.264 RTP video streaming over P4 networks
[topology]
Note. The video traffic sent by h1 (10.0.1.1) will be mapped to the highest priority 7.
[ip_forward.p4]
#include <core.p4> #include <v1model.p4> typedef bit<48> macAddr_t; typedef bit<9> egressSpec_t; header arp_t { bit<16> htype; bit<16> ptype; bit<8> hlen; bit<8> plen; bit<16> opcode; bit<48> hwSrcAddr; bit<32> protoSrcAddr; bit<48> hwDstAddr; bit<32> protoDstAddr; } 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 { } struct headers { @name(".arp") arp_t arp;
@name(".ethernet") ethernet_t
ethernet; @name(".ipv4") ipv4_t ipv4; } parser ParserImpl(packet_in packet, out headers hdr,
inout metadata meta, inout
standard_metadata_t standard_metadata)
{
@name(".parse_arp") state parse_arp
{ packet.extract(hdr.arp);
transition accept; }
@name(".parse_ethernet") state parse_ethernet
{ packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
16w0x800: parse_ipv4;
16w0x806: parse_arp;
default: accept; } }
@name(".parse_ipv4") state parse_ipv4 { packet.extract(hdr.ipv4);
transition accept; } @name(".start")
state start {
transition parse_ethernet; } } control egress(inout
headers hdr, inout
metadata meta, inout standard_metadata_t
standard_metadata) {
register<bit<19>>(10) qdepth; action do_add_qdepth()
{ qdepth.write((bit<32>)standard_metadata.egress_port,
standard_metadata.deq_qdepth); } apply { do_add_qdepth(); } } control ingress(inout
headers hdr, inout
metadata meta, inout standard_metadata_t
standard_metadata) {
@name(".set_nhop") action set_nhop(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; } @name("._drop")
action _drop() { mark_to_drop(standard_metadata); }
@name(".ipv4_lpm") table ipv4_lpm {
actions = {
set_nhop;
_drop; }
key = {
hdr.ipv4.dstAddr: lpm; }
size = 512;
const default_action = _drop(); } apply {
ipv4_lpm.apply(); if
(hdr.ipv4.srcAddr == 0x0a000101){
standard_metadata.priority =
(bit<3>)7;
}
} } control DeparserImpl(packet_out packet, in headers hdr)
{ apply { packet.emit(hdr.ethernet); packet.emit(hdr.arp); packet.emit(hdr.ipv4); } } control verifyChecksum(inout headers hdr, inout metadata meta) { apply { verify_checksum(true, { 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); } } control computeChecksum(inout headers hdr, inout metadata meta) { apply { update_checksum(true, { 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); } } V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; |
[p4app.json]
{
"program": "ip_forward.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":
"manual", "auto_arp_tables":
"true", "auto_gw_arp":
"true", "default_bw":10,
"default_delay":"1ms", "links":
[["h1", "s1"], ["h2", "s1"],
["h3", "s1"]], "hosts": {
"h1": {
"ip": "10.0.1.1/24",
"gw": "10.0.1.254" },
"h2": {
"ip": "10.0.2.1/24", "gw": "10.0.2.254" },
"h3": {
"ip": "10.0.3.1/24", "gw": "10.0.3.254" } }, "switches": {
"s1": {
"cli_input": "cmd.txt",
"program": "ip_forward.p4" } }
} } |
[cmd.txt]
table_add ipv4_lpm set_nhop 10.0.1.1/32 =>
00:00:0a:00:01:01 1 table_add ipv4_lpm set_nhop 10.0.2.1/32 =>
00:00:0a:00:02:01 2 table_add ipv4_lpm set_nhop 10.0.3.1/32 => 00:00:0a:00:03:01 3 |
[execution]
Open another terminal and connect to s1 to do some settings for queues
Open terminal for h1, h2, and h3
Generate the background packet traffic (h2-h3). We can also see the queue is full for port 3. (we set the queue depth to 50.)
H.264 RTP video streaming (h1->h3)
We can see the video. Video can be played out smoothly. Because the video packet are mapping to highest priority.
Now change the following code in ip_forward.p4. (change 7 to 0)
if (hdr.ipv4.srcAddr ==
0x0a000101){
standard_metadata.priority = (bit<3>)0;
}
Re-run the program again. No video can be played out. Because video and background traffic are mapped to the same priority. And all background traffic seizes almost all bandwidth.
[references]
https://github.com/nsg-ethz/p4-learning/blob/master/vm/bin/update-bmv2.sh
Dr. Chih-Heng Ke
Department of Computer Science and Information
Engineering, National Quemoy University, Kinmen, Taiwan
Email: smallko@gmail.com / smallko@nqu.edu.tw