DPDK RX/TX 回调示例应用程序中没有出现流量

No traffic emerges in DPDK RX/TX Callbacks Sample Application

我是 DPDK 领域的大一新生。我从 DPDK 主页给出的示例应用程序开始。我被困在示例中 --- DPDK RX/TX 回调示例应用程序。条件是长时间没有流量出现(但输出)。我猜原因是我无法将流量发送到 DPDK 端口。

我首先一步一步地展示我的设置。开头的网卡信息

NIC info at startup

然后,我拒绝 eth2eth3

1
2
sudo ifconfig eth2 down
sudo ifconfig eth3 down

接下来,我使用 usertools/dpdk-setup.sh 构建 DPDK 源 (i686-native-linuxapp-gcc),插入 IGB UIO 模块,为非 NUMA 系统设置大页面映射,将设备绑定到 IGB UIO 模块。这是我的设备设置和大页面列表:
device uio bind
hugepage info

所有准备工作都已完成。我开始构建示例应用程序。使用以下命令

1
2
3
4
export RTE_SDK=~/dpdk/dpdk-18.08
export RTE_TARGET=i686-native-linuxapp-gcc
cd examples/rxtx_callbacks/
make

一切正常,输出编译信息:

1
2
3
4
5
mininet@mininet-vm:~/dpdk/dpdk-18.08/examples/rxtx_callbacks$ make
  CC main.o
  LD rxtx_callbacks
  INSTALL-APP rxtx_callbacks
  INSTALL-MAP rxtx_callbacks.map

然后,我开始使用以下命令运行示例应用程序:

1
sudo ./build/rxtx_callbacks -l1 -n4

执行日志为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mininet@mininet-vm:~/dpdk/dpdk-18.08/examples/rxtx_callbacks$ sudo ./build/rxtx_callbacks -l1 -n4
EAL: Detected 2 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Probing VFIO support...
EAL: PCI device 0000:00:08.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:09.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:0a.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:11.0 on NUMA socket 0
EAL:   probe driver: 8086:100f net_e1000_em
Port 0 MAC: 08 00 27 9d f9 5a
Port 1 MAC: 08 00 27 7f e8 8a

随着时间的流逝,什么也没有发生。但是,我发现执行结果应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@ubuntu:/home/chang/dpdk/examples/rxtx_callbacks/build# ./rxtx_callbacks -l 1 -n 4
EAL: Detected 8 lcore(s)
EAL: No free hugepages reported in hugepages-1048576kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: PCI device 0000:02:01.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100f net_e1000_em
EAL: PCI device 0000:02:02.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100f net_e1000_em
EAL: PCI device 0000:02:03.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100f net_e1000_em
EAL: PCI device 0000:02:04.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100f net_e1000_em
Port 0 MAC: 00 0c 29 f7 4d 25
Port 1 MAC: 00 0c 29 f7 4d 2f

Core 1 forwarding packets. [Ctrl+C to quit]
Latency = 629 cycles
Latency = 787 cycles
^C

我试图找到结果,我在 lcore_main() 函数中添加了一个 printf 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for (;;) {
        RTE_ETH_FOREACH_DEV(port) {
                struct rte_mbuf *bufs[BURST_SIZE];
                /* printf("receive a packet\
"); */
                const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
                                bufs, BURST_SIZE);
                if (unlikely(nb_rx == 0))
                        continue;
                printf("send a packet\
");
                const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
                                bufs, nb_rx);
                if (unlikely(nb_tx < nb_rx)) {
                        uint16_t buf;

                        for (buf = nb_tx; buf < nb_rx; buf++)
                                rte_pktmbuf_free(bufs[buf]);
                }
        }
}

我发现没有收到任何数据包,因为它应该通过检查 --- if (unlikely(nb_rx == 0))。因此,我尝试使用Linux提供的pktgen(不是DPDK)自己发送数据包。然而失败。我会展示我的踪迹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/bin/sh

modprobe pktgen

function pgset() {
    local result

    echo $1 > $PGDEV

    result=`cat $PGDEV | fgrep"Result: OK:"`
    if ["$result" ="" ]; then
         cat $PGDEV | fgrep Result:
    fi
}

function pg() {
    echo inject > $PGDEV
    cat $PGDEV
}

# Config Start Here -----------------------------------------------------------


# thread config
# Each CPU has own thread. Two CPU example. We add eth1.

PGDEV=/proc/net/pktgen/kpktgend_0
  echo"Removing all devices"
 pgset"rem_device_all"
  echo"Adding eth1"
 pgset"add_device eth1"
  echo"Setting max_before_softirq 10000"
 pgset"max_before_softirq 10000"


# device config
# delay 0 means maximum speed.

CLONE_SKB="clone_skb 1000000"
# NIC adds 4 bytes CRC
PKT_SIZE="pkt_size 60"

# COUNT 0 means forever
#COUNT="count 0"
COUNT="count 10000000"
DELAY="delay 0"

PGDEV=/proc/net/pktgen/eth1
  echo"Configuring $PGDEV"
 pgset"$COUNT"
 pgset"$CLONE_SKB"
 pgset"$PKT_SIZE"
 pgset"$DELAY"
 pgset"dst 127.0.0.1"
 # here! the mac address given by the sample application
 pgset"dst_mac  08:00:27:9d:f9:5a"

# Time to run
PGDEV=/proc/net/pktgen/pgctrl

 echo"Running... ctrl^C to stop"
 pgset"start"
 echo"Done"

# Result can be vieved in /proc/net/pktgen/eth1

不过,什么也没发生。也许,发送数据包到 dpdk 端口的方式是错误的。由于 dpdk 端口位于第 2 层,因此第 3 层工具(如 ping)是无用的。示例应用程序一直卡住,我很绝望。你能分享一些想法来解决我的问题吗?

最好的祝愿。

EDIT1:

@Amedeo 的回复成功了,但是,我只能向 RX/TX 回调应用程序发送一些数据包(几个数据包不是流量)。我试过使用Linux提供的pktgen,但是接口dtap0无法接收pktgen产生的流量。以下是我的实验课程。

首先,所有准备工作同上。但是,我使用命令

运行示例应用程序

1
 sudo ./build/rxtx_callbacks -l1 -n4 --vdev=net_tap0

而不是

1
 sudo ./build/rxtx_callbacks -l1 -n4

运行示例应用程序后,我可以在 ifconfig 中看到一个新的 nic 项目。
enter image description here

哦,我需要提一下,我已经拒绝了 eth1,因此 eth1eth2eth3 是供 DPDK 使用的。执行输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
EAL: Detected 2 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Probing VFIO support...
EAL: PCI device 0000:00:08.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:09.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:0a.0 on NUMA socket 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:11.0 on NUMA socket 0
EAL:   probe driver: 8086:100f net_e1000_em
rte_pmd_tap_probe(): Initializing pmd_tap for net_tap0 as dtap0
Port 0 MAC: 08 00 27 93 2b 19
Port 1 MAC: 08 00 27 9d f9 5a
Port 2 MAC: 08 00 27 7f e8 8a
Port 3 MAC: fe 02 cf 5a 23 ee

Core 1 forwarding packets. [Ctrl+C to quit]

带有 fe 02 cf 5a 23 ee 的端口 3 正是 ifconfig 中的 dtap0 网卡。现在我尝试向 dtap0 接口注入流量。但是,我尝试使用Linux提供的pktgen,但仍然失败。

我首先给交互dtap0一个IP地址,使用:

1
sudo dhclient dtap0

并得到:

1
2
3
4
5
6
7
dtap0     Link encap:Ethernet  HWaddr fe:02:cf:5a:23:ee
          inet addr:10.0.2.16  Bcast:10.0.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:73 errors:0 dropped:0 overruns:0 frame:0
          TX packets:92 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500
          RX bytes:6651 (6.6 KB)  TX bytes:7808 (7.8 KB)

然后,我编写了一个 shell 脚本来生成从 eth0dtap0 的流量负载(我希望)。这是脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/bin/sh

#modprobe pktgen
modprobe pktgen

function pgset() {
    local result

    echo $1 > $PGDEV

    result=`cat $PGDEV | fgrep"Result: OK:"`
    if ["$result" ="" ]; then
         cat $PGDEV | fgrep Result:
    fi
}

function pg() {
    echo inject > $PGDEV
    cat $PGDEV
}

# Config Start Here -----------------------------------------------------------


# thread config
# Each CPU has own thread. Two CPU exammple. We add eth1, eth2 respectivly.

PGDEV=/proc/net/pktgen/kpktgend_0
  echo"Removing all devices"
 pgset"rem_device_all"
  echo"Adding eth0"
 pgset"add_device eth0"
  echo"Setting max_before_softirq 10000"
 pgset"max_before_softirq 10000"


# device config
# delay 0 means maximum speed.

CLONE_SKB="clone_skb 1000000"
# NIC adds 4 bytes CRC
PKT_SIZE="pkt_size 60"

# COUNT 0 means forever
#COUNT="count 0"
COUNT="count 10000000"
DELAY="delay 0"

PGDEV=/proc/net/pktgen/eth0
  echo"Configuring $PGDEV"
 pgset"$COUNT"
 pgset"$CLONE_SKB"
 pgset"$PKT_SIZE"
 pgset"$DELAY"
 # ip address of interface dtap0
 pgset"dst 10.0.2.16"
 # the mac address of interface dtap0
 pgset"dst_mac  fe:02:cf:5a:23:ee"

# Time to run
PGDEV=/proc/net/pktgen/pgctrl

 echo"Running... ctrl^C to stop"
 pgset"start"
 echo"Done"

运行这个脚本,我真的发现接口 eth0 正在产生输出数据包(使用 nloadifconfig)。但是,接口 dtap0 没有传入流量。我也尝试 iperf 发送流量,但 dtap0 既不能处理 TCP 连接,也不能处理 UDP ACK。 iperfping 都不可用。

感谢您就我的问题分享任何想法。

EDIT2:

感谢@Amedeo 的分享。我已经弄清楚如何使用 Linux 提供的 pktgen 将数据包发送到 RX/TX Callback 示例应用程序。

运行 RX/TX Callback 示例应用程序的所有内容都与 EDIT1 相同。我将 pktgen 的脚本更改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/bin/sh

#modprobe pktgen
modprobe pktgen

function pgset() {
    local result

    echo $1 > $PGDEV

    result=`cat $PGDEV | fgrep"Result: OK:"`
    if ["$result" ="" ]; then
         cat $PGDEV | fgrep Result:
    fi
}

function pg() {
    echo inject > $PGDEV
    cat $PGDEV
}

# Config Start Here -----------------------------------------------------------


# thread config
# Each CPU has own thread. Two CPU exammple. We add dtap0

PGDEV=/proc/net/pktgen/kpktgend_1
  # echo"Removing all devices"
 # pgset"rem_device_all"
  echo"Adding dtap0"
 pgset"add_device dtap0"
  echo"Setting max_before_softirq 10000"
 pgset"max_before_softirq 10000"


# device config
# delay 0 means maximum speed.

CLONE_SKB="clone_skb 1000000"
# NIC adds 4 bytes CRC
PKT_SIZE="pkt_size 60"

# COUNT 0 means forever
#COUNT="count 0"
COUNT="count 10000000"
DELAY="delay 0"

PGDEV=/proc/net/pktgen/dtap0
  echo"Configuring $PGDEV"
 pgset"$COUNT"
 pgset"$CLONE_SKB"
 pgset"$PKT_SIZE"
 pgset"$DELAY"
 # pgset"dst 192.168.211.101"
 # whatever mac address
 pgset"dst_mac ce:2a:23:42:ce:ff"

# Time to run
PGDEV=/proc/net/pktgen/pgctrl

 echo"Running... ctrl^C to stop"
 pgset"start"
 echo"Done"

我需要做的只是从 dtap0 发送数据包!和

1
dtap0 --- dpdk port --- rxtx_callbacks

一切顺利。


预计您看不到流量。 RX/TX 回调示例是 L2FWD 示例的概括。此代码从一个端口接收流量并将其转发到另一个端口。
如果没有传入流量,则应用程序将永远轮询,尝试接收某些内容并且不会转发任何内容。

由于 2 个端口使用的是 DPDK 驱动程序,因此它们对内核不可见。由于这个原因,通常的工具(ifconfig、tcpdump、pktgen 等)看不到这些接口。

您可以只绑定到 dpdk 一个物理接口,并使用一个 tap 接口作为第二个接口。 Tap 接口绑定到内核,因此您可以轻松地在其中注入流量(例如使用 tcpreplay)。

使用点击界面只需要添加参数--vdev=net_tap0:

1
sudo ./build/rxtx_callbacks -l1 -n4 --vdev=net_tap0

这将创建一个从 ifconfig 可见的接口 dtap0。所有进入该接口的流量都会被 rxtx_callbacks 应用程序接收并转发到另一个物理端口。

来源:https://doc.dpdk.org/guides/nics/tap.html

端到端实验

您还可以删除所有 dpdk 物理端口并仅使用 2 个 TAP 端口。
这样你就可以拥有:

1
dtap0 --- dpdk port --- rxtx_callbacks --- dpdk port --- dtap1

两个TAP可以通过rxtx_callbacks应用互相ping通。

重现这个的步骤是:

1) 解除所有物理接口与 DPDK

的绑定

2) 使用 2 个 TAP 运行 rxtx_callbacks:

1
sudo ./rxtx_callbacks -l1 -n4 --vdev=net_tap0 --vdev=net_tap1

3) 现在您有 2 个 TAP 接口:dtap0 和 dtap1。将 dtap1 移动到不同的网络命名空间并将 IP 分配给 dtap0 和 dtap1:

1
2
3
4
sudo ip netns add ns1
sudo ip link set dtap1 netns ns1
sudo ip netns exec ns1 ifconfig dtap1 11.0.0.2/24
sudo ifconfig dtap0 11.0.0.1/24

4) 您可以从 dtap0 ping dtap1(反之亦然):

1
2
sudo ping 11.0.0.2
sudo ip netns exec ns1 ping 11.0.0.1

5) 清理:将 dtap1 移动到默认命名空间并删除命名空间。

1
2
sudo ip netns exec ns1 ip link set dtap1 netns 1
sudo ip netns del ns1


最简单的开始时效果很好的解决方案是使用一台主机作为 DPDK 目标,另一台主机作为数据包生成器。快速数据包生成器占用大量 CPU 资源,因此在 DPDK 目标上运行它肯定会降低 DPDK 性能。

虽然有时另一台主机不可用,所以第二种最简单的解决方案是在同一台主机上连接背靠背的物理以太网设备。在您的情况下,DPDK 端口 eth2eth3 应使用带有 pktgen 端口 eth0eth1 的交叉跳线进行物理连接。

在这种情况下,如果您只配置一个带有 IP 地址的 pktgen 端口,您将能够使用 ping 等,即:

1
2
3
4
5
6
7
# ifconfig eth2 down # for DPDK
# ifconfig eth3 down # for DPDK

# ifconfig eth0 172.16.0.1/24 up # for pktgen with an IP (TX)
# ifconfig eth1 up # for pktgen without IP (RX)

# arp -s 172.16.0.2 00:0c:29:f7:4d:25 # MAC of the connected DPDK port

那么普通的ping 172.16.0.2应该产生带有DST IP 172.16.0.2,dst MAC 00:0c:29:f7:4d:25的ICMP数据包并发送到eth0eth0应该背靠背连接到DPDK端口。

要查看数据包在 eth1 上返回,我们应该将接口置于混杂模式。 tcpdump 默认情况下会这样做。所以,如果一切正常运行:

1
# tcpdump -eni eth1

应该显示从 DPDK 返回的数据包。一旦你测试过了,你可以移动到 pktgen.

@Amedeo 描述的 vdev 解决方案也应该有效。但是,您将无法通过 vdev 推动大量流量。