由於近期 P4 官方釋出了 P416(1.2) 的規格,絕大部分的語法與 P4 1.0 都有些落差,所以在這邊打算在寫一系列的文章說明相關語法。
由於正式的 P416(1.2) 規格還沒有釋出,本系列教學會以 pre-release 版本為主。
Header
在 1.0 版中,我們必須先定義 header type 才可以定義 header,header type 裡面使用的單位則是以 bit 為主。
P4 在 1.1 版之後加入了型態,這樣能夠更方便的計算長度,也可以節省一些開發時間。
Header 定義方式如下:
header HeaderName {
fields.......
}
例如今天我們定義 Ethernet 標頭可以這樣做:
header EthernetHeader {
bit<48> dst;
bit<48> src;
bit<16> etherType;
}
接者在使用這一個 header 去產生實體即可:
EthernetHeader ethernetHeader;
相對於 1.0 與 1.1 版,1.2 版少了 field 與 header_type 這類型的關鍵字,簡化開發上的需要去記得東西。
資料型態的部份,在目前 P4 的規格中有定義的基本型態(Base types)如下:
- void
- error
- match_kind
- bool
- bit<>
- int<>
- varbit<>
除了基本型態以外,還有一些是以資料結構為主的形態,例如 Set、Tuple 等等,之後會再寫一篇說明。
Parser
與 1.0/1.1 版不同的是,原先的版本需要定義出很多個 parser,並在不同的 parser 間切換,而新版的則是定義一個 parser,並在 parser 中撰寫很多不同的狀態(state),並透過 accept 與 reject 決定 parser 是否成功解析一個封包。
表面上看起來 1.2 版與 1.0/1.1 版只是語法上不同,但是實作上面沒有什麼不同,但是實際上若深入研究 1.0/1.1 的設計會發現他有許多限制,舉例來說 1.0/1.1 版不能跳回已經用過的 parser,相同的標頭型態不能夠再被解析一次(例如 VXLAN 的外部封包內部封包)。
而 1.2 版的設計讓相同的狀態執行到多次,且 1.2 版開始將 parser 與 deparser 拆開,原先 1.0/1.1 版的 deparser 是在編譯階段時就產生好的東西,開發者無法決定 deparsing 的順序以及內容。
Parser 的寫法如下:
parser ParserName(packet_in pkt, ...) {
state start {
....
}
state state_name {
....
}
}
parser 所帶入的參數主要有:
- packet_in:執行期間所要解析的封包
- 其他輸出內容:可以是 struct 或是一般封包參照
不同的 state 切換可以透過 transition 這個關鍵字去做切換,而 transition 後面可以接 state 名稱或是 select 語法,我們以 Ethernet + IPv4 為例子。
parser MyParser(packet_in pkt, out eth, out ipv4) {
state start {
transition eth;
}
state eth {
pkt.extract(eth);
transition select(eth.ethType) {
0x800: ip;
_: reject;
}
}
state ip {
pkt.extract(ipv4);
transition accept;
}
}
除了使用 transition, select 以及 extract 以外,Parser 還有提供 verify 語法,透過 verify 檢查,決定 parser 是否要丟出 error 並跳至 reject 狀態,使用方法如下:
verify(判斷式, 錯誤類別);
另外,還有一些進階的用法會再寫一篇文章說明,像是:
- 提供 sub-parser 的寫法:可以在 parser 中建立 sub-parser去進行解析
- 提供類似迭代的方式去解析封包
以上就是 P416 有關於 Header 以及 Parser 的說明,下一篇會簡短的說明各種新增的形態(Types)