# VPP 學習筆記
---
## VPP Plugins
>[nDPI Example](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f4b90660f1ef4b52752a6eeb95cae768a800f898)
---
### VPP 封包處理流程架構

* 由多個 `node` 串接成一連串的資料處理流程
* 透過在不同位置上新增不同節點,決定封包在何時該做何種動作
### VPP 軟體架構

### Adding a plugin
> [VPP - Adding a plugin](https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/add_plugin.html)
* 使用腳本建立一個新的 plugin
```
$ cd ./src/plugins
$ ../../extras/emacs/make-plugin.sh
...
```
* 確認是否產生文件
```
$ cd ./myplugin
$ ls
CMakeLists.txt myplugin.c myplugin_periodic.c setup.pg
myplugin_all_api_h.h myplugin.h myplugin_test.c
myplugin.api myplugin_msg_enum.h node.c
```
* 重建工作區
```
$ cd <top-of-workspace>
$ make rebuild [or rebuild-release]
```
* Run VPP
```
$ cd <top-of-workspace>
$ make run
<snip>
load_one_plugin:189: Loaded plugin: myplugin_plugin.so (myplugin description goes here)
<snip>
load_one_vat_plugin:67: Loaded plugin: myplugin_test_plugin.so
<snip>
DBGvpp#
```
---
## VPP Python API
---
## 製造測試用封包
* `scapy` 提供網路封包處理的 `API` ,包含製造封包、檢視封包
* 製造 `packet` 步驟如下:
導入 `scapy` 必要 `Library` ,包含 `L2` 、 `TCP/IP Protocol`
```python=
from scapy.layers.l2 import Ether
from scapy.packet import Raw
from scapy.layers.inet import IP, UDP
```
根據 `packet` 需要,在各個 `layer` 加入對應的 `header`
```python=4
p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
UDP(sport=randint(1000, 2000), dport=5678) /
Raw(payload))
```
透過 `pythone` 的 `append` ,使大量 `packet` 變成 `stream`
```python=
def create_stream(src_if, dst_if, count):
packets = []
for i in range(count):
# create the packet itself
p = create_packet()
# append the packet to the list
packets.append(p)
# return the created packet list
return packets
```
---
## 建立 PG_interface 模擬網路接口
### 必要 Library
* `framework.VppTestCase` 模組
>[framework module](https://docs.fd.io/vpp/17.01/vpp_make_test/html/framework.html)
* 必須先 `Setup` 才可以使用 `module`
> `setUp()`
> * Clear trace before running each test
>
> classmethod `setUpClass()`
> * Perform class setup before running the testcase Remove shared memory files, start vpp and connect the vpp-api
>
> classmethod `tearDownClass()`
> * Perform final cleanup after running all tests in this test-case
---
### SetUp 範例
```python=
from framework import VppTestCase
class PGinterface(VppTestCase):
def setUpClass(cls):
super(PGinterface, cls).setUpClass()
def tearDownClass(cls):
super(PGinterface, cls).tearDownClass()
def setUp(self):
super(PGinterface, self).setUp()
if __name__ == '__main__':
test = PGinterface()
test.setUpClass()
test.setUp()
```
---
### 建立 PG_interface
* 使用 `VppTestCase` 中的 `create_pg_interfaces()`
```python=
class PGinterface(VppTestCase):
...
def setUp(self):
super(PGinterface, self).setUp()
# create 2 pg interfaces
self.create_pg_interfaces(range(2))
# setup interfaces
# assign them different tables
table_id = 0
self.tables = []
for i in self.pg_interfaces:
i.admin_up()
if table_id != 0:
tbl = VppIpTable(self, table_id)
tbl.add_vpp_config()
self.tables.append(tbl)
tbl = VppIpTable(self, table_id, is_ip6=1)
tbl.add_vpp_config()
self.tables.append(tbl)
i.set_table_ip4(table_id)
i.set_table_ip6(table_id)
i.config_ip4()
i.config_ip6()
table_id += 1
```
* 每個 `interface` 為 `1` 個 `object` ,擁有自己的 `mac` 、 `IPv4 Address` 、 `IPv6 Address` 等
* `pg_interface.local_ip4` : 回傳 `IPv4 address`
* `pg_interface.local_ip6` : 回傳 `IPv6 address`
* `pg_interface.local_mac` : 回傳 `interface 的 mac address`
---
### 透過 ARP 測試 PG_interface
* 主要使用 `vpp_pg_interface.VppPGInterface` 中的 `API`
* 建立 `ARP Request` 封包
```python=
class VppPGInterface(VppInterface):
...
def create_arp_req(self):
"""Create ARP request applicable for this interface"""
return (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.remote_mac) /
ARP(op="who-has", pdst=self.local_ip4,
psrc=self.remote_ip4, hwsrc=self.remote_mac))
```
* 主要目的是測試 `PG_interface` 是否正常運作,封包 `header` 如下:
* `ARP_Req.op` : `0x0001` ,代表 `Request`
* `ARP_Req.hwsrc` : `src` 的 `mac address`
* `ARP_Req.pdst` : `dst` 的 `IPv4 address`
* `ARP_Req.psrc` : `src` 的 `IPv4 address`
* 使用範例:
```python=
PG_interface.create_arp_req()
```
---
* 啟動 `PG_interface` 接收封包的功能,並將 `ARP` 加入 `interface` ,模擬封包傳入
> classmethod `pg_enable_capture(interfaces)`
> * Enable capture on packet-generator interfaces
>
> `add_stream(pkts)`
> * Add a stream of packets to this packet-generator
>
> classmethod `pg_start()`
> * Remove any zombie captures and enable the packet generator
```python=
PG_interface.enable_capture()
PG_interface.add_stream( ARP_Req_Pkt )
self.pg_start()
```
---
* 嘗試從 `PG_interface` 接收封包
* 根據封包種類,自動將封包轉型,如接收 `ARP Request` ,自動將收到的封包轉成 `ARP Response`
> `wait_for_packet(timeout)`
> * Wait for next packet captured with a timeout
> * Parameters:
> * timeout – How long to wait for the packet
> * Returns:
> * Captured packet if no packet arrived within timeout
> * Raises:
> * Exception – if no packet arrives within timeout
```python=
captured_packet = interface.wait_for_packet(1)
```
> `get_capture(remark=None, filter_fn=<function is_ipv6_misc>)`
> * Get captured packets
> * Parameters
> * remark – remark printed into debug logs
> * filter_fn – filter applied to each packet, packets for which the filter returns True are removed from capture
> * Returns:
> * iterable packets
```python=
captured_packet = interface.get_capture()
```
---
{"metaMigratedAt":"2023-06-15T15:39:04.359Z","metaMigratedFrom":"Content","title":"VPP 學習筆記","breaks":true,"contributors":"[{\"id\":\"8d3dbdbd-0e3e-4b19-a505-4e54323d5318\",\"add\":6271,\"del\":258}]"}