/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_IPV4 = 0x800;
/*instance_type指的是数据包实例类型:正常(Normal)、入端口复制(ingress clone)、出端口复制(egress clone)、再循环(recirculated),此处TYPE_EGRESS_CLONE:在出端口复制指定的数据.*/
const bit<32> TYPE_EGRESS_CLONE = 2;
//常规数据包instance_type=0,此处用于判断数据包是否是需要在出端口复制packet
#define IS_E2E_CLONE(std_meta) (std_meta.instance_type == TYPE_EGRESS_CLONE)
const bit<32> E2E_CLONE_SESSION_ID = 11;
/*联系后续代码及论文的目的,MAX_ENTRIES实则指的是环形缓冲区长度(类似于C语言的数组长度,如ring_buffer[MAX_ENTRIES])*/
const bit<32> MAX_ENTRIES = 26;
//设置阈值的大小
#define THRESHOLD 6000
#define SIZE_OF_ENTRY 238
#define TYPE_TELEMETRY 31
/*************************************************************************
*********************** 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 {//以太网首部存储的是mac源、mac目的地址
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 ipv4_option_t {
bit<1> copyFlag;
bit<2> optClass;
bit<5> option;
bit<8> optionLength;
}
header telemetry_t{
bit<32> ipv4_srcAddr;
bit<32> ipv4_dstAddr;
bit<16> tcp_sport;
bit<16> tcp_dport;
bit<8> protocol;
bit<48> ingress_timestamp;
bit<48> egress_timestamp;
bit<19> enqQdepth;
bit<19> deqQdepth;
bit<2> padding; // 238 bits of telemetry data + 2 bits of padding + 16 bits of IPOption header = 256 bits (multiple of 32)
}
header tcp_t {
bit<16> srcPort;
bit<16> dstPort;
bit<32> seqNo;
bit<32> ackNo;
bit<4> dataOffset;
bit<3> res;
bit<3> ecn;
bit<6> ctrl;
bit<16> window;
bit<16> checksum;
bit<16> urgentPtr;
}
struct metadata {//对每个被标记的数据包都嵌入元数据,以区分该数据包是否被标记过。
bit<1> flag; // metadata for each packet,flag用来区分
bit<7> index;
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
ipv4_option_t ipv4_option;
telemetry_t telemetry;
tcp_t tcp;
}
/*************************************************************************
*********************** 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) {
6: parse_tcp;
default: accept;
}
}
state parse_tcp {
packet.extract(hdr.tcp);
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) {
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
hdr.ethernet.dstAddr = dstAddr;
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
standard_metadata.egress_spec = port;
}
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = NoAction();
}
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) {
/*
Values of bytesRemaining, index, ring_buffer variables need to be maintained between
all incoming data packets. Thus, these variables are implemented using registers.
*/
/*
将数据存储在寄存器中,对数据的读写操作可参考如下的代码:
extern Register<T>
{
Register(bit<32> size);//类似于指定数组的长度
T read(bit<32> index);//根据数组的下标index(从C语言的角度),从寄存器的具体位置中读取数据。
void write(bit<32> index, T value); //根据下标index,向寄存器的具体位置写入数据value
}
*/
register<bit<19>>(1) bytesRemaining; // bytes count stored in a register
bit<19> bytes; // temporary bytes count in bit<> format
int<19> bytes_int; // temporary bytes count in int<> format
int<19> deqQdepth;//出队的数据包个数
register<bit<32>>(1) index; // index stored in a register
bit<32> id; // temporary index in bit<> format 与register<bit<32>> index合作,register保存的时间更长久。
register<bit<SIZE_OF_ENTRY>>(MAX_ENTRIES) ring_buffer; //环形缓冲区ring_buffer[26]
bit<SIZE_OF_ENTRY> data; // to move data to register
bit<SIZE_OF_ENTRY> data_clone; // to extract data from register and transfer it to cloned packet
action do_clone_e2e(){
clone3(CloneType.E2E,E2E_CLONE_SESSION_ID,meta);//出端口复制常规的数据包,然后再次传回出口流水线
}
action mark_packet(){//标记涉及微突发的所有数据包
meta.flag = 1;
//data:收集的遥测信息
data = hdr.ipv4.srcAddr ++ hdr.ipv4.dstAddr ++ hdr.tcp.srcPort ++ hdr.tcp.dstPort ++
hdr.ipv4.protocol ++ standard_metadata.ingress_global_timestamp ++
standard_metadata.egress_global_timestamp ++ standard_metadata.enq_qdepth ++
standard_metadata.deq_qdepth; // concatenate all required fields into one bitstring
ring_buffer.write(id, data);//刚开始时id=0,ring_buffer[0].value=data,向环形缓冲区写入遥测信息,id==26时,id重置为0
meta.index = (bit<7>)id;
id = id + 1;//当前环形缓冲区ring_buffer[id]已有数据写入,下次写入的数据将存储在ring_buffer[id+1].
if(id==MAX_ENTRIES){
id=0;
}
index.write(0, id);//与下文的index.read(id,0)对应
}
table generate_clone{
actions = {
do_clone_e2e;
NoAction;
}
default_action = NoAction();
}
apply { // index and bytesRemaining register values are initialized to 0 from the control plane (simple_switch_CLI)
index.read(id, 0);
bytesRemaining.read(bytes, 0);
bytes_int = (int<19>)bytes;
if(!IS_E2E_CLONE(standard_metadata)){//对正常操作的数据包进行操作
deqQdepth = (int<19>)(standard_metadata.deq_qdepth * 19w1500); //deq_adepth出队时的数据包个数
if(deqQdepth > THRESHOLD){
bytes_int = (deqQdepth - (int<19>(bit<19>)standard_metadata.packet_length);//byte_int使用有符号类型是因为进行减的计算有可能出现负数(bit<19>)standard_metadata.packet_length);//packet_length数据包大小
mark_packet();//标记
}
else{
if(bytes_int > 0){
bytes_int = bytes_int - (int<19>)(bit<19>)standard_metadata.packet_length;
mark_packet();
}
}
if(bytes_int < 0){
bytes_int = 0;
}
bytes = (bit<19>)bytes_int;
bytesRemaining.write(0, bytes);
if(meta.flag == 1){//有数据包被标记即数据包涉及微突发,对应的在镜像出端口生成自定义数据包
generate_clone.apply();
}
}
else{//环形缓冲区的遥测信息复制(即写入)一份给镜像出端口的自定义数据包
ring_buffer.read(data_clone, (bit<32>)meta.index);
hdr.ipv4.ihl = hdr.ipv4.ihl + 8; // 32 bit word * 8 = 256 bits
hdr.ipv4.totalLen = hdr.ipv4.totalLen + 32;
hdr.ipv4_option.setValid(); // add IPOption header
hdr.ipv4_option.optionLength = 32; // telemetry(240) + IPOption(16) = 256 bytes ==> 256/8 = 32 octets
hdr.ipv4_option.option = TYPE_TELEMETRY;
hdr.telemetry.setValid(); // add telemetry header
hdr.telemetry.ipv4_srcAddr[31:0] = data_clone[237:206];// extract in the same sequence in which it was concatenated
hdr.telemetry.ipv4_dstAddr[31:0] = data_clone[205:174];
hdr.telemetry.tcp_sport[15:0] = data_clone[173:158];
hdr.telemetry.tcp_dport[15:0] = data_clone[157:142];
hdr.telemetry.protocol[7:0] = data_clone[141: 134];
hdr.telemetry.ingress_timestamp[47:0] = data_clone[133:86];
hdr.telemetry.egress_timestamp[47:0] = data_clone[85:38];
hdr.telemetry.enqQdepth[18:0] = data_clone[37:19];
hdr.telemetry.deqQdepth[18:0] = data_clone[18:0];
hdr.telemetry.padding = (bit<2>)0;
truncate(86); // Ether(14) + IP (20) + IP Option (32) + TCP (20) = 86 bytes,被嵌入遥测信息后,截断常规数据包的原有负载(这些数据不被需要)
}
}
}
/*************************************************************************
************* 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);
update_checksum(
hdr.ipv4_option.isValid(),
{ hdr.ipv4_option.copyFlag,
hdr.ipv4_option.optClass, // update checksum for IP Option header
hdr.ipv4_option.option,
hdr.ipv4_option.optionLength},
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
update_checksum(
hdr.telemetry.isValid(),
{ hdr.telemetry.ipv4_srcAddr,
hdr.telemetry.ipv4_dstAddr,
hdr.telemetry.tcp_sport,
hdr.telemetry.tcp_dport,
hdr.telemetry.protocol, // update checksum for telemetry header
hdr.telemetry.ingress_timestamp,
hdr.telemetry.egress_timestamp,
hdr.telemetry.enqQdepth,
hdr.telemetry.deqQdepth,
hdr.telemetry.padding},
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
/* TODO: add deparser logic */
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
packet.emit(hdr.ipv4_option);
packet.emit(hdr.telemetry);
packet.emit(hdr.tcp);
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
Burstradar.p4个人注释
于 2022-09-23 10:02:15 首次发布