1.1 - OpenFlow statistics (Counters, Timestamps)
解决的核心问题:如何统计一个流的持续时间
- 如何实现一个操作只在数据包第一次出现的时候执行一次,之后再也不执行:设置默认操作,用于更新持续时间。第一次把时间戳从寄存器中读到元数据中,是0,设置一个流表,和元数据中相应字段的匹配key是0,然后执行的action是记录当前时间戳并修改这个字段的元数据为当前时间戳。从此以后这个元数据的相应字段就不在是0了。这个操作也就实现了只在数据包出现的第一次执行的目的。
- 如何实现记录一个流的最后一个数据包的时间戳。每个该流的数据包的时间戳来的时候都更新,那最后存的那个时间戳一定是最后一个数据包的时间戳。
mafia-sdn/p4demos/demos/1-openflow/1.1-statistics/commands.txt
table_set_default counter_table _no_op
table_add counter_table do_count 10.0.0.1 10.0.0.2 => 0
table_add counter_table do_count 10.0.0.1 10.0.0.3 => 1
table_add counter_table do_count 10.0.0.2 10.0.0.1 => 2
table_add counter_table do_count 10.0.0.2 10.0.0.3 => 3
table_add counter_table do_count 10.0.0.3 10.0.0.1 => 4
table_add counter_table do_count 10.0.0.3 10.0.0.2 => 5
table_set_default duration_table update_duration (2. 之后的每一次都执行默认的更新持续时间的操作)
table_add duration_table update_start_ts 0 => (1. 只有第一次能匹配上这个流表,然后执行存储初始时间的操作)
mafia-sdn/p4demos/demos/1-openflow/1.1-statistics/p4src/includes/counters.p4
#define TABLE_INDEX_WIDTH 3 // Number of bits to index the duration register
#define N_FLOWS_ENTRIES 8 // Number of entries for flow (2^3)
header_type my_metadata_t {
fields {
nhop_ipv4: 32;
pkt_ts: 48; // Loaded with intrinsic metadata: ingress_global_timestamp
tmp_ts: 48; // Temporary variable to load start_ts
pkt_count: 32;
byte_count: 32;
register_index: TABLE_INDEX_WIDTH;
}
}
metadata my_metadata_t my_metadata;
register my_byte_counter {
width: 32;
instance_count: N_FLOWS_ENTRIES;
}
register my_packet_counter {
width: 32;
instance_count: N_FLOWS_ENTRIES;
}
register start_ts{
width: 48;
instance_count: N_FLOWS_ENTRIES;
}
register last_ts{
width: 48;
instance_count: N_FLOWS_ENTRIES;
}
register flow_duration{ // Optional register...Duration can be derived from the two timestamp
width: 48;
static: duration_table;
instance_count: N_FLOWS_ENTRIES;
}
mafia-sdn/p4demos/demos/1-openflow/1.1-statistics/p4src/of.p4
#include "includes/headers.p4"
#include "includes/parser.p4"
#include "includes/counters.p4"
action _no_op() {
drop();
}
action _drop() {
drop();
}
// Action and table to count packets and bytes. Also load the start_ts to be matched against next table.
action do_count(entry_index) {
modify_field(my_metadata.register_index, entry_index); // Save the register index
modify_field(my_metadata.pkt_ts, intrinsic_metadata.ingress_global_timestamp); // Load packet timestamp in custom metadata
// Update packet counter (read + add + write)更新包计数器
register_read(my_metadata.pkt_count, my_packet_counter, my_metadata.register_index);
add_to_field(my_metadata.pkt_count, 1);
register_write(my_packet_counter, my_metadata.register_index, my_metadata.pkt_count);
// Update byte counter (read + add + write)更新字节计数器
register_read(my_metadata.byte_count, my_byte_counter, my_metadata.register_index);
add_to_field(my_metadata.byte_count, standard_metadata.packet_length);
register_write(my_byte_counter, my_metadata.register_index, my_metadata.byte_count);
// Cant do the following if register start_ts is associated to another table (eg: duration_table)...
// Semantic error: "static counter start_ts assigned to table duration_table cannot be referenced in an action called by table counter_table"把寄存器中的值读入到my_metadata.tmp_ts,第一次读到的是0,所以可以匹配上流表,之后的所有读的值都不是0.所以只执行默认的操。
register_read(my_metadata.tmp_ts, start_ts, entry_index); // Read the start ts for the flow
}
table counter_table {
reads {
ipv4.srcAddr : exact;
ipv4.dstAddr : exact;
}
actions {
do_count;
_no_op;
}
size : 1024;
}
// Action and table to update the start and end timestamp of the flow.
// Optionally, the duration can as well be stored in a register.
// Action is called only when start_ts=0 (value loaded in my_metadata from my_count action)
action update_start_ts(){
register_write(start_ts, my_metadata.register_index, my_metadata.pkt_ts); // Update start_ts
update_duration();
}
// Default action: only update the timestamp for the last matched packet and the duration默认操作,用于得到最后一个数据包的时间戳和当前持续时间。
action update_duration(){
register_write(last_ts, my_metadata.register_index, my_metadata.pkt_ts); // Update ts of the last seen packet
subtract_from_field(my_metadata.pkt_ts, my_metadata.tmp_ts); // Calculate duration
register_write(flow_duration, my_metadata.register_index, my_metadata.pkt_ts); // Optional: save duration in stateful register
}
table duration_table{
reads{
my_metadata.tmp_ts : exact;
}
actions{
update_start_ts;
update_duration;
}
}
control ingress {
apply(counter_table);
apply(duration_table);
}
table table_drop {
actions {
_drop;
}
}
control egress {
apply(table_drop);
}
标签:count,statistics,1.1,p4,register,ts,table,my,metadata
From: https://www.cnblogs.com/p4p4p4/p/16948557.html