前幾篇介紹了 Header、Parser、Action 跟 Table,而這些東西並不能讓一台 Switch 活起來,他需要一個名為 Control 的區塊。

簡單回顧一下 P4 的 Model:

螢幕快照 2015-11-27 下午10.07.13

可以看到上方有一個 Control Program 這一塊,Control Program 最主要的目的是協調一個 Packet 應該要經過哪一些 Table,舉例來說,一個需要被導向的封包,需要先經過 mac learning table,然後再來是檢查他的目的位址,如果存在的話就送到 Forwarding table,否則送到 Flooding table。

Control flow


Control flow 寫起來也跟 function 很相似,在 P4 裡面有兩個主要的 control flow,ingress 以及 egress,這兩個 control flow 分別代表了一個封包的進入以及離開。

當 Parser 處理完封包之後,會將相關的資料,例如解析出來的 header 以及 metadata 儲存,然後交由 ingress 處理,ingress 會將封包送往不同的 table、更改封包 header 內容、設定封包輸出的 port 等等,最後再丟到一個 queue 中。

Egress 則是會將 Queue 的資料拿出來,在一次的處理並且將封包送出、丟棄、複製或是重新處理(recirculate)。

control 的寫法如下:

control control_function_name {

    /* statements */

}

其中中間的 statements 可以是下面幾種:

  1. 將 packet 扔到 table 測試:
    此時會依據該 table 中的 entry 去做出相對應的動作。
    用法:

    apply(table_name);
  2. apply and select with result action:
    這個用法比較特殊,他會依據該 table 選到的 action 去決定要執行哪一段 control block,舉例來說:

    apply(check_dmac) {
    
        ipv4_route {
            apply(ipv4_rpf);
            apply(ipv4_acl);
        }
    
        default {
            apply(ipv6_rpf);
            apply(ipv6_acl);
        }
    
    }

    執行其他沒有些出來的 action 時,會去呼叫 default 這個 block 中的東西。
    諸如此類的作法可以讓程式更有彈性。

  3. apply and select with table hit/miss:
    跟上一個很像,只是他這邊是將 action 的名稱更改成 hit 或是 miss,用來表示在有 match 到東西或是沒有 match 到東西時的行為。
  4. if/else/else if:
    跟一般的 C 語言一樣,這邊也是可以使用 if/else/else if 來決定應該要做什麼事情,舉例來說:

    if(valid(vlan)) {
        apply(vlan);
    } else {
        my_metadata.vlan = 0;
    }

    在 if 括號當中可以是:

    • valid(header_ref):表示該 packet header 是存在/合法取出
    • 一般的布林預算:例如 (eth.type == 0x800) and (ipv4.mask == 65535)
    • true 以及 false
  5. 其他 control 名稱:例如「flood();」,直接把其他 control flow 當做ˋ一般的 function 來呼叫即可。

一般來說,一個 ingress 執行完畢之後,會將處理過的封包資料傳送到 queue 當中等待 egress 階段,但如果在 action 當中呼叫了像是 resubmit 或是 recirculate 等 API,則會在階段完成之後將封包送回 ingress 重新處理,或是呼叫 clone_e2i 之類的 API 也會複製一份封包,在處理階段完成後送到指定的地方。

Egress spec/port


除了封包處理以外,封包的轉送也是網路設備相當重要的功能,要設定封包送出去的 port,只需要在 ingress 階段中設定 standard  的 egress_spec 即可:

modify_field(standard_metadata.egress_spec, 1);

egress_spec 不一定只是一個 port 而已,他可以是一個 route、VLAN fllod group 或是 multicast group,而這些東西都會事先於 switch 中先定義好。

而在 egress 階段可以透過 standard_metadata 取得 egress_port 這一個值(唯讀)來判斷要做什麼事情。

 

下篇將會說明有關於 standard_metadata 的詳細資訊。

Share Your Thought