P4勉強録
金沢工業大学のAdvent Calendar 2023 12日目の内容です。
P4とは
オープンソースのプログラミング言語です。ネットワーク機器のデータプレーン部分をプログラミングすることができます。
P4.org(https://p4.org/)
コントロールプレーンとデータプレーン
ネットワークの「プレーン」は、特定の処理が行われる場所に関する抽象的なものになります。
コントロールプレーン
コントロールプレーンは、パケットをどの経路で送受信するのかを制御します。ルーティングテーブルなどはコントロールプレーンの一部です。
データプレーン
データプレーンは、実際にパケットの転送処理を行います。
P4サンドボックス
P4.orgにブラウザ上でP4を動かすことができる、P4サンドボックスというものがあります。
今回はそのサンドボックスに例として書かれているプログラムの挙動を見たいと思います。
P4サンドボックス:https://p4.org/sandbox-page/
プログラムの全体像
#include <core.p4>
#include <v1model.p4>
const int MAX_HOPS = 10;
const int STANDARD = 0x00;
const int HOPS = 0x01;
typedef standard_metadata_t std_meta_t;
header type_t {
bit<8> tag;
}
header hop_t {
bit<8> port;
bit<8> bos;
}
header standard_t {
bit<8> src;
bit<8> dst;
}
struct headers_t {
type_t type;
hop_t[MAX_HOPS] hops;
standard_t standard;
}
struct meta_t { }
parser MyParser(packet_in pkt, out headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
state start {
pkt.extract(hdr.type);
transition select(hdr.type.tag) {
HOPS: parse_hops;
STANDARD: parse_standard;
default: accept;
}
}
state parse_hops {
pkt.extract(hdr.hops.next);
transition select(hdr.hops.last.bos) {
1: parse_standard;
default: parse_hops;
}
}
state parse_standard {
pkt.extract(hdr.standard);
transition accept;
}
}
control MyVerifyChecksum(inout headers_t hdr, inout meta_t meta) {
apply { }
}
control MyComputeChecksum(inout headers_t hdr, inout meta_t meta) {
apply { }
}
control MyIngress(inout headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
action allow() { }
action deny() { std_meta.egress_spec = 9w511; }
table acl {
key = { hdr.standard.src : exact; hdr.standard.dst : exact; }
actions = { allow; deny; }
const entries = { (0xCC, 0xDD) : deny(); }
default_action = allow();
}
apply {
std_meta.egress_spec = (bit<9>) hdr.hops[0].port;
hdr.hops.pop_front(1);
if (!hdr.hops[0].isValid()) {
hdr.type.tag = 0x00;
}
acl.apply();
}
}
control MyEgress(inout headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
apply { }
}
control MyDeparser(packet_out pkt, in headers_t hdr) {
apply {
pkt.emit(hdr.type);
pkt.emit(hdr.hops);
pkt.emit(hdr.standard);
}
}
V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main;
入力パケット
先程のP4プログラムに対する入力は以下のものとします。
01
0200 0300 0401
AA BB
4f 48 20 4d 59 59 20 49 20 4b 4e 4f 57 20 57 48 59
出力パケット
上記の入力を行った場合の出力パケットは以下になります。
01 03 00 04 01 AA BB 4F 48 20 4D 59 59 20 49 20 4B 4E 4F 57 20 57 48 59 port: 2
プログラムの挙動
入力の最初の8ビットである「01」はtagフィールドとして認識されます。
「AA」はsrc, 「BB」はdstとなります。
そして、ペイロードが「4F 48 20 4D 59 59 20 49 20 4B 4E 4F 57 20 57 48 59」となります。