# VPP 學習筆記 --- ## VPP Plugins >[nDPI Example](https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=f4b90660f1ef4b52752a6eeb95cae768a800f898) --- ### VPP 封包處理流程架構 ![](https://i.imgur.com/lWPqO9f.png) * 由多個 `node` 串接成一連串的資料處理流程 * 透過在不同位置上新增不同節點,決定封包在何時該做何種動作 ### VPP 軟體架構 ![](https://i.imgur.com/w2d3WfL.png) ### 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}]"}
    1248 views