dpvs學(xué)習(xí)筆記: 16 網(wǎng)卡綁定 mode 4 問題

背景

參考 dpdk 官方 bonding pmd 文檔,mode 0 是輪循,mode 1 是鏡像,我司線上使用的 mode 4 是 802.3AD 協(xié)義,使用特定層面 hash 算法來分配流量。

bond mode 4

使用 mode 4 比較特別,要求

  1. It needs to call rte_eth_tx_burst and rte_eth_rx_burst with intervals period of less than 100ms.
  2. Calls to rte_eth_tx_burst must have a buffer size of at least 2xN, where N is the number of slaves. This is a space required for LACP frames. Additionally LACP packets are included in the statistics, but they are not returned to the application.

dpvs bond 問題

最初搭建 fullnat 時(shí)想用網(wǎng)卡 bonding, 由于線上都是 mode 4, 不給網(wǎng)絡(luò)組同學(xué)添麻煩,最好保持一致。但是 dpvs 程序啟動(dòng)后,初始化報(bào) warning,并且交換機(jī)也看到 bonding 失敗。具體報(bào)錯(cuò)消息如下:

PMD: Slave 1: failed to enqueue LACP packet into RX ring.
Receive and transmit functions must be invoked on bonded
interface at least 10 times per second or LACP will not
work correctly

將 DPDK 編繹成 DEBUG 模式,打開 bond debug 開關(guān)。dpvs 也全部打開 DEBUG, 查看日志輸出:

PMD:    625 [Port 0: rx_machine] LACP -> CURRENT
PMD: LACP: {
  subtype= 01
  ver_num=01
  actor={ tlv=01, len=14
    pri=0080, system=B4:43:26:57:15:01, key=410E, p_pri=0080 p_num=5E00
       state={ ACT AGG DEF }
  }
  partner={ tlv=02, len=14
    pri=0000, system=00:00:00:00:00:00, key=0000, p_pri=0000 p_num=0000
       state={ ACT AGG DEF EXP }
  }
  collector={info=03, length=10, max_delay=0000
, type_term=00, terminator_length = 00}
PMD:    625 [Port 0: tx_machine] Sending LACP frame
PMD: LACP: {
  subtype= 01
  ver_num=01
  actor={ tlv=01, len=14
    pri=FFFF, system=6C:92:BF:47:B2:66, key=2100, p_pri=FF00 p_num=0100
       state={ ACT AGG }
  }
  partner={ tlv=02, len=14
    pri=0080, system=B4:43:26:57:15:01, key=410E, p_pri=0080 p_num=5E00
       state={ ACT AGG DEF }
  }
  collector={info=03, length=10, max_delay=0000
, type_term=00, terminator_length = 00}

結(jié)合 dpdk 源代碼解讀,rx_machine 是收取交換機(jī)發(fā)來的協(xié)義消息,成功接收,看到交換機(jī)的 mac 地址 B4:43:26:57:15:01,dpdk 根據(jù) mode 4 協(xié)義發(fā)送 lacp 回包,內(nèi)容和接收的相反,bond 網(wǎng)卡 mac 是 6C:92:BF:47:B2:66,結(jié)合最后報(bào)錯(cuò) failed to enqueue LACP packet into RX ring, 可以定性是 tx_ring 隊(duì)列一直沒消費(fèi),dpvs 沒有發(fā)送 lacp 回包給交換機(jī)。

dpvs 發(fā)包邏輯

dpvs發(fā)包都在大 loop 里,是個(gè)死循環(huán),發(fā)送函數(shù)是 lcore_job_xmit

static void lcore_job_xmit(void *args)
{
    int i, j;
    lcoreid_t cid;
    portid_t pid;
    struct netif_queue_conf *qconf;

    cid = rte_lcore_id();
    for (i = 0; i < lcore_conf[lcore2index[cid]].nports; i++) {
        pid = lcore_conf[lcore2index[cid]].pqs[i].id;

        for (j = 0; j < lcore_conf[lcore2index[cid]].pqs[i].ntxq; j++) {
            qconf = &lcore_conf[lcore2index[cid]].pqs[i].txqs[j];
            if (qconf->len <= 0)
                continue;
            netif_tx_burst(cid, pid, j);
            qconf->len = 0;
        }
    }
}
static inline void netif_tx_burst(lcoreid_t cid, portid_t pid, queueid_t qindex)
{
    int ntx, ii;
    struct netif_queue_conf *txq;
    unsigned i = 0;
    struct rte_mbuf *mbuf_copied = NULL;
    struct netif_port *dev = NULL;

    assert(LCORE_ID_ANY != cid);
    txq = &lcore_conf[lcore2index[cid]].pqs[port2index[cid][pid]].txqs[qindex];
    if (0 == txq->len)
        return;
    dev = netif_port_get(pid);
   ......
    ntx = rte_eth_tx_burst(pid, txq->id, txq->mbufs, txq->len);
    lcore_stats[cid].opackets += ntx;
    /* do not calculate obytes here in consideration of efficency */
    if (unlikely(ntx < txq->len)) {
        RTE_LOG(DEBUG, NETIF, "Fail to send %d packets on dpdk%d tx%d\n", ntx,pid, txq->id);
        lcore_stats[cid].dropped += txq->len - ntx;
        for (ii = ntx; ii < txq->len; ii++)
            rte_pktmbuf_free(txq->mbufs[ii]);
    }
}

基本邏輯,就是判斷 qconf->len 發(fā)包隊(duì)列長(zhǎng)度,如果大于 0,表示有數(shù)據(jù)需要發(fā)送。最終調(diào)用 dpdk 庫函數(shù) rte_eth_tx_burst 完成最終發(fā)送邏輯。

但是這個(gè) qconf 隊(duì)列和 lacp tx_ring 有什么關(guān)系呢?完全沒有關(guān)系...

dpdk lacp 發(fā)包邏輯

首先,每個(gè)物理網(wǎng)卡都是一個(gè) rte_eth_dev, 而 bonding 的網(wǎng)卡是 rte_vdev_device, 需要調(diào)用 bond_alloc 初始化,最重要有兩個(gè)函數(shù) bond_mode_8023ad_setupbond_ethdev_mode_set

bond_mode_8023ad_setup 會(huì)設(shè)置一個(gè)定時(shí)器,每 100ms 調(diào)用一次 bond_mode_8023ad_periodic_cb 函數(shù),這個(gè)就是用來協(xié)商 lacp 的。rx_machine_update 接收 rx_ring 數(shù)據(jù),tx_machine 封裝好本機(jī) lacp 后發(fā)送到 tx_ring. bond_ethdev_mode_set 最重要的是調(diào)置 rx_burst 和 tx_burst 回調(diào)函數(shù)

eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_8023ad;
eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_8023ad;

非 bonding 的普通網(wǎng)卡,tx_pkt_burst,rx_pkt_burst 都是 ixgbe 的。

bond_ethdev_tx_burst_8023ad 代碼比較長(zhǎng)不貼了,原理就是在業(yè)務(wù)正常調(diào)用 rte_eth_tx_burst 時(shí),順便把 lacp tx_ring 的數(shù)據(jù)發(fā)送到網(wǎng)卡。

問題所在

結(jié)合兩個(gè)發(fā)包邏輯可以明確,dpvs 屬于業(yè)務(wù)層,qconf 的緩存里有數(shù)據(jù)才發(fā)送,而 lcap 的數(shù)據(jù)是存儲(chǔ)在 dpdk 底層的 tx_ring 中,當(dāng) bond 網(wǎng)卡剛被 dpvs up 起來時(shí),業(yè)務(wù)層是沒有數(shù)據(jù)的,也就不會(huì)調(diào)用 rte_eth_tx_burst 順便把 lacp 發(fā)送給交換機(jī)。

解決方案?

最簡(jiǎn)單的就是修改 lcore_job_xmit 代碼,去掉所有隊(duì)列長(zhǎng)度判斷的邏輯,這樣就會(huì)一直調(diào)用底層 rte_eth_tx_burst. 測(cè)試一下,bond 成功。但是性能肯定會(huì)受影響,希望 dpvs 開發(fā)團(tuán)隊(duì)能 fix 一下。

想到的另外一個(gè)方案,就是注冊(cè)一個(gè) slow 類型的 job,專職用于刷新 lacp, 我去掉個(gè) pr 吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 10.鏈路綁定PMD 除了用于物理和虛擬硬件的輪詢模式驅(qū)動(dòng)程序(PMD)之外,DPDK還包括一個(gè)純軟件庫,可將多個(gè)...
    半天妖閱讀 8,586評(píng)論 0 5
  • 7.輪詢模式驅(qū)動(dòng) DPDK包括1Gigabit、10Gigabit 及 40Gigabit 和半虛擬化IO的輪詢模...
    半天妖閱讀 5,882評(píng)論 0 4
  • 1. 簡(jiǎn)介 本文檔包含DPDK軟件安裝和配置的相關(guān)說明。旨在幫助用戶快速啟動(dòng)和運(yùn)行軟件。文檔主要描述了在Linux...
    半天妖閱讀 18,118評(píng)論 0 22
  • 這篇博客先介紹在dpdk中使用到的一些優(yōu)化點(diǎn)[后期如果遇到其他的會(huì)完善],然后是NUMA架構(gòu),看了官方說明,對(duì)于1...
    fooboo閱讀 8,547評(píng)論 0 5
  • 前兩天學(xué)習(xí)了五大數(shù)字力的第五個(gè)模塊:償債能力,里面包括兩個(gè)指標(biāo):流動(dòng)比率和速動(dòng)比率。今天對(duì)這兩個(gè)指標(biāo)進(jìn)行小結(jié)。 1...
    verolai閱讀 291評(píng)論 0 0

友情鏈接更多精彩內(nèi)容