# P4 lab
## Part 1
將目前使用者加到docker群組裡面,當docker service起來時,會以這個群組的成員來初始化相關服務
```
sudo chmod 777 /var/run/docker.sock
```
進入獨立的venv python環境
```
python -m venv venv && . ./venv/bin/activate
```
查詢ASCII
```
python -c "print(hex(ord('+')))"
```
### Get P4 code
Get the basic p4 codebase from ONOS.

### Compile first P4 code
```
$ p4c-bm2-ss --arch v1model \
-o build/bmv2.json --p4runtime-files build/p4info.txt \
src/basic.p4
```
完成後會在build資料夾中生成以下檔案

接著建立一python檔(topo.py),執行並建立基本網路拓樸。

### Network Topology
Set up switches with p4runtime-shell, and then add flow rules to the switch through p4 program.
上圖可以看到所建立的拓樸有兩台switch,所以我們需要用p4 language去控制每一台switch。
```
$ python -m p4runtime_sh --election-id 0,1 \
--grpc-addr localhost:50001 \
--config "build/p4info.txt,build/bmv2.json"
```

接著輸入以下指令為讓封包進入這台switch由port 1進、port 2出。
```
te = table_entry["ingress.table0_control.table0"](
action="ingress.table0_control.set_egress_port"
)
te.priority = 1
te.match["standard_metadata.ingress_port"] = "2"
te.action["port"] = "1"
te.insert()
te = table_entry["ingress.table0_control.table0"](
action="ingress.table0_control.set_egress_port"
)
te.priority = 1
te.match["standard_metadata.ingress_port"] = "1"
te.action["port"] = "2"
te.insert()
```

兩台switch設定完成後,回到mininet即可以讓h1與h2互通。

## Part 2
### P4 architecture

**Parser $\rightarrow$ Control Pipeline $\rightarrow$ Control Deparser**
### Parser & Deparser
開啟mininet

發送UDP封包
```
$ docker exec -it p4mn_01 m h2 bash
$ nc -u 10.0.1.1 3000
1 + 1
```
開啟wireshark
(若遇到wireshark權限問題,待補)


**實驗目標:**
Parser:如果UDP port是3000,解析內容(兩個數字+一個運算符號)。
透過**header stack**來儲存內容。
**步驟**
編輯parsers.p4、headers.p4、custom_headers.p4
在parse_udp底下可以透過transition select來轉換到不同的state,在此預設的情況是不會往下送,當滿足以下條件則進行parse_math_udp
$\cdot$ UDP data length > 0
$\cdot$ UDP port = 3000
### Step 1 - 1:

從維基百科上面的資料可以得知udp協定中的header為8個bytes,從剛剛wireshark的封包可以看到他的length為14也就是整體的長度,因此可以得知data length為6 bytes。所以我們要定義一個UDP data length,且他必須大於0。在header.p4中可以看到他定義的UDP整體長度為length_,所以我們在定義UDP data length為:
**headers**

這個length_是指udp封包的整個length。
**custom headers**

local_metadata主要是定義、儲存在parser.p4得出的結果
**parser**

### Step 1 - 2:
接著需要寫buffer來儲存num1、space1、num2、operator、space2。要注意的是,它的結構是由struct包著header,再由header包著field才比較不會有bug。
**headers**

**custom headers**


(打錯字,已更正)
**parser**

建立header stack來暫存數字及運算符號。需要注意的是定義的udp_buffer裡面的元素是char,-CHAR_0是為了將字元轉為數字。

**define**

定義字元0的ASCII為0X30。
### Control Pipeline
**實驗目標:**
Table entry具有三個欄位:Key、Action、Action Data

將前面的數字及運算符號進行運算,並把結果資料寫回UDP封包。
**步驟**
### Step 2 - 1:
basic.p4



define.p4
