6.報文緩沖區(qū)庫
報文緩沖區(qū)庫(Mbuf)提供了申請和釋放緩沖區(qū)的功能谷醉,DPDK應(yīng)用程序使用這些buffer存儲消息緩沖嗅榕。消息緩沖存儲在mempool中澡匪,使用內(nèi)存池庫 蒂秘。
數(shù)據(jù)結(jié)構(gòu)rte_mbuf可以承載網(wǎng)絡(luò)數(shù)據(jù)包buffer或者通用控制消息buffer(由CTRL_MBUF_FLAG指示)减江。也可以擴(kuò)展到其他類型染突。rte_mbuf頭部結(jié)構(gòu)盡可能小,目前只使用兩個緩存行辈灼,最常用的字段位于第一個緩存行中份企。
6.1.報文緩沖區(qū)設(shè)計
為了存儲數(shù)據(jù)包數(shù)據(jù)(包括協(xié)議頭部),考慮了兩種方法:
- 在單個存儲buffer中嵌入metadata巡莹,后面跟著數(shù)據(jù)包數(shù)據(jù)固定大小區(qū)域
- 為metadata和報文數(shù)據(jù)分別使用獨(dú)立的存儲buffer司志。
第一種方法的優(yōu)點是他只需要一個操作來分配/釋放數(shù)據(jù)包的整個存儲表示。但是降宅,第二種方法更加靈活骂远,并允許將元數(shù)據(jù)的分配與報文數(shù)據(jù)緩沖區(qū)的分配完全分離。
DPDK選擇了第一種方法腰根。Metadata包含諸如消息類型激才,長度,到數(shù)據(jù)開頭的偏移量等控制信息额嘿,以及允許緩沖鏈接的附加mbuf結(jié)構(gòu)指針瘸恼。
用于承載網(wǎng)絡(luò)數(shù)據(jù)包buffer的消息緩沖可以處理需要多個緩沖區(qū)來保存完整數(shù)據(jù)包的情況。許多通過下一個字段鏈接在一起的mbuf組成的jumbo幀册养,就是這種情況钞脂。
對于新分配的mbuf,數(shù)據(jù)開始的區(qū)域是buffer之后 RTE_PKTMBUF_HEADROOM 字節(jié)的位置捕儒,這是緩存對齊的冰啃。 Message buffers可以在系統(tǒng)中的不同實體中攜帶控制信息邓夕,報文,事件等阎毅。 Message buffers也可以使用起buffer指針來指向其他消息緩沖的數(shù)據(jù)字段或其他數(shù)據(jù)結(jié)構(gòu)焚刚。
Buffer Manager實現(xiàn)了一組相當(dāng)標(biāo)準(zhǔn)的buffer訪問操作來操縱網(wǎng)絡(luò)數(shù)據(jù)包。
6.2.存儲在內(nèi)存池中的緩沖區(qū)
Buffer Manager使用內(nèi)存池庫來申請buffer扇调。因此確保了數(shù)據(jù)包頭部均衡分布到信道上矿咕,有利于L3處理。mbuf中包含一個字段狼钮,用于表示它從哪個池中申請出來碳柱。當(dāng)調(diào)用 rte_ctrlmbuf_free(m) 或 rte_pktmbuf_free(m),mbuf被釋放到原來的池中熬芜。
6.3.構(gòu)造函數(shù)
Packet及control mbuf構(gòu)造函數(shù)由API提供莲镣。接口rte_pktmbuf_init()及rte_ctrlmbuf_init()初始化mbuf結(jié)構(gòu)中的某些字段,這些字段一旦創(chuàng)建將不會被用戶修改(如mbuf類型涎拉、源池瑞侮、緩沖區(qū)起始地址等)。此函數(shù)在池創(chuàng)建時作為rte_mempool_create()函數(shù)的回掉函數(shù)給出鼓拧。
6.4.緩沖區(qū)申請及釋放
分配一個新mbuf需要用戶指定從哪個池中申請半火。對于任意新分配的mbuf,它包含一個段季俩,長度為0钮糖。 緩沖區(qū)到數(shù)據(jù)的偏移量被初始化,以便使得buffer具有一些字節(jié)(RTE_PKTMBUF_HEADROOM)的headroom酌住。
釋放mbuf意味著將其返回到原始的mempool藐鹤。當(dāng)mbuf的內(nèi)容存儲在一個池中(作為一個空閑的mbuf)時,mbuf的內(nèi)容不會被修改赂韵。由構(gòu)造函數(shù)初始化的字段不需要在mbuf分配時重新初始化娱节。
當(dāng)釋放包含多個段的數(shù)據(jù)包mbuf時,他們都被釋放祭示,并返回到原始mempool肄满。
6.5.緩沖區(qū)操作
這個庫提供了一些操作數(shù)據(jù)包mbuf中的數(shù)據(jù)的功能。例如:
- 獲取數(shù)據(jù)長度
- 獲取指向數(shù)據(jù)開始位置的指針
- 數(shù)據(jù)前插入數(shù)據(jù)
- 數(shù)據(jù)之后添加數(shù)據(jù)
- 刪除緩沖區(qū)開頭的數(shù)據(jù)(rte_pktmbuf_adj())
- 刪除緩沖區(qū)末尾的數(shù)據(jù)(rte_pktmbuf_trim())詳細(xì)信息請參閱 DPDK API Reference
6.6.元數(shù)據(jù)信息
數(shù)據(jù)包的一些信息由網(wǎng)絡(luò)驅(qū)動程序檢索并存儲在mbuf中使得處理更簡單质涛。例如稠歉,VLAN、RSS哈希結(jié)果(參見 Poll Mode Driver)及校驗和由硬件計算的標(biāo)志等汇陆。
一個報文緩沖區(qū)中還包含數(shù)據(jù)源端口和報文鏈中mbuf數(shù)目怒炸。對于鏈接的mbuf,只有鏈的第一個mbuf存儲這個元信息毡代。
例如阅羹,對于IEEE1588數(shù)據(jù)包勺疼,RX側(cè)就是這種情況,時間戳機(jī)制捏鱼,VLAN標(biāo)記和IP校驗和計算执庐。
在TX端,應(yīng)用程序還可以將一些處理委托給硬件导梆。 例如轨淌,PKT_TX_IP_CKSUM標(biāo)志允許卸載IPv4校驗和的計算。
以下示例說明如何在vxlan封裝的tcp數(shù)據(jù)包上配置不同的TX offloads:out_eth/out_ip/out_udp/vxlan/in_eth/in_ip/in_tcp/payload
-
計算out_ip的校驗和:
mb->l2_len = len(out_eth) mb->l3_len = len(out_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM set out_ip checksum to 0 in the packet
配置DEV_TX_OFFLOAD_IPV4_CKSUM支持在硬件計算看尼。
-
計算out_ip 和 out_udp的校驗和:
mb->l2_len = len(out_eth) mb->l3_len = len(out_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_UDP_CKSUM set out_ip checksum to 0 in the packet set out_udp checksum to pseudo header using rte_ipv4_phdr_cksum()
配置DEV_TX_OFFLOAD_IPV4_CKSUM 和 DEV_TX_OFFLOAD_UDP_CKSUM支持在硬件上計算递鹉。
-
計算in_ip的校驗和:
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM set in_ip checksum to 0 in the packet
這以情況1類似,但是l2_len不同藏斩。 配置DEV_TX_OFFLOAD_IPV4_CKSUM支持硬件計算躏结。 注意,只有外部L4校驗和為0時才可以工作灾茁。
-
計算in_ip 和 in_tcp的校驗和:
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_TCP_CKSUM 在報文中設(shè)置in_ip校驗和為0 使用rte_ipv4_phdr_cksum()將in_tcp校驗和設(shè)置為偽頭
這與情況2類似,但是l2_len不同谷炸。 配置DEV_TX_OFFLOAD_IPV4_CKSUM 和 DEV_TX_OFFLOAD_TCP_CKSUM支持硬件實現(xiàn)北专。 注意,只有外部L4校驗和為0才能工作旬陡。
-
segment inner TCP:
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->l4_len = len(in_tcp) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_TCP_SEG; 在報文中設(shè)置in_ip校驗和為0 將in_tcp校驗和設(shè)置為偽頭部拓颓,而不使用IP載荷長度 配置DEV_TX_OFFLOAD_TCP_TSO支持硬件實現(xiàn)。 注意描孟,只有L4校驗和為0時才能工作驶睦。
-
計算out_ip, in_ip, in_tcp的校驗和:
mb->outer_l2_len = len(out_eth) mb->outer_l3_len = len(out_ip) mb->l2_len = len(out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags|=PKT_TX_OUTER_IPV4|PKT_TX_OUTER_IP_CKSUM | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM; 設(shè)置 out_ip 校驗和為0 設(shè)置 in_ip 校驗和為0 使用rte_ipv4_phdr_cksum()設(shè)置in_tcp校驗和為偽頭部
配置DEV_TX_OFFLOAD_IPV4_CKSUM、DEV_TX_OFFLOAD_UDP_CKSUM匿醒、 DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM支持硬件實現(xiàn)场航。
Flage標(biāo)記的意義在mbuf API文檔(rte_mbuf.h)中有詳細(xì)描述。 更多詳細(xì)信息還可以參閱testpmd 源碼(特別是csumonly.c)廉羔。
6.7.直接緩沖區(qū)和間接緩沖區(qū)
直接緩沖區(qū)是指緩沖區(qū)完全獨(dú)立溉痢。間接緩沖區(qū)的行為類似于直接緩沖區(qū),但緩沖區(qū)的指針和數(shù)據(jù)偏移量指的是另一個直接緩沖區(qū)的數(shù)據(jù)憋他。這在數(shù)據(jù)包需要復(fù)制或分段的情況下是很有用的孩饼,因為間接緩沖區(qū)提供跨越多個緩沖區(qū)重用相同數(shù)據(jù)包數(shù)據(jù)的手段。
當(dāng)使用接口 rte_pktmbuf_attach() 函數(shù)將緩沖區(qū)附加到直接緩沖區(qū)時竹挡,該緩沖區(qū)變成間接緩沖區(qū)镀娶。每個緩沖區(qū)有一個引用計數(shù)器字段,每當(dāng)直接緩沖區(qū)附加一個間接緩沖區(qū)時揪罕,直接緩沖區(qū)上的引用計數(shù)器遞增梯码。類似的宝泵,每當(dāng)間接緩沖區(qū)被分裂時,直接緩沖區(qū)上的引用計數(shù)器遞減忍些。如果生成的引用計數(shù)器為0鲁猩,則直接緩沖區(qū)將被釋放,因為它不再使用罢坝。
處理間接緩沖區(qū)時需要注意幾件事情廓握。首先,間接緩沖區(qū)從不附加到另一個間接緩沖區(qū)嘁酿。嘗試將緩沖區(qū)A附加到間接緩沖區(qū)B(且B附加到C上了)隙券,將使得rte_pktmbuf_attach() 自動將A附加到C上。其次闹司,為了使緩沖區(qū)變成間接緩沖區(qū)娱仔,其引用計數(shù)必須等于1,也就是說它不能被另一個間接緩沖區(qū)引用游桩。最后牲迫,不可能將間接緩沖區(qū)重新鏈接到直接緩沖區(qū)(除非它已經(jīng)被分離了)。
雖然可以使用推薦的rte_pktmbuf_attach()和rte_pktmbuf_detach()函數(shù)直接調(diào)用附加/分離操作借卧,但建議使用更高級的rte_pktmbuf_clone()函數(shù)盹憎,該函數(shù)負(fù)責(zé)間接緩沖區(qū)的正確初始化,并可以克隆具有多個段的緩沖區(qū)铐刘。
由于間接緩沖區(qū)不應(yīng)該實際保存任何數(shù)據(jù)陪每,間接緩沖區(qū)的內(nèi)存池應(yīng)配置為指示減少的內(nèi)存消耗×常可以在幾個示例應(yīng)用程序中找到用于間接緩沖區(qū)的內(nèi)存池(以及間接緩沖區(qū)的用例示例)的初始化示例檩禾,例如IPv4組播示例應(yīng)用程序。
6.8.調(diào)試
在調(diào)試模式(CONFIG_RTE_MBUF_DEBUG使能)下疤祭,mbuf庫的函數(shù)在任何操作之前執(zhí)行完整性檢查(如緩沖區(qū)檢查盼产、類型錯誤等)。
6.9.用例
所有網(wǎng)絡(luò)應(yīng)用程序都應(yīng)該使用mbufs來傳輸網(wǎng)絡(luò)數(shù)據(jù)包勺馆。