情報畑でつかまえてロゴ
本サイトは NTTテクノクロスが旬の IT をキーワードに
IT 部門が今知っておきたい最新テクノロジーに関する情報をお届けするサイトです

KVMのVM環境でDPDK22.11のl2fwdを動かす 後編 ~DPDK入門 第20回~

今回後編では, DPDKのサンプルプログラムを改造してMACアドレスによるフィルター機能を実装する簡単な例をご紹介いたします。

KVMのVM環境でDPDK22.11のl2fwdを動かす 後編 ~DPDK入門 第20回~

はじめに

こんにちは, NTTテクノクロス株式会社の村木です。

本記事はDPDK入門「KVMのVM環境でDPDK22.11のl2fwdを動かす」の後編です。
前回前編ではDPDK22.11をベースにKVMのVM環境でサンプルアプリケーションを動かす方法までをご紹介いたしました。
今回後編では, DPDKのサンプルプログラムを改造してMACアドレスによるフィルター機能を実装する簡単な例をご紹介いたします。
前編で作成した環境をそのまま利用する前提となっておりますのでご注意いただければと思います。

本記事で紹介しているDPDKやサンプルプログラムの概要については本DPDK入門連載の以下の記事をご確認ください。
DPDKとは? ~DPDK入門 第1回~
DPDKのパケット処理 ~DPDK入門 第2回~

01_network.jpg

動作環境について

今回の動作環境は以下とします。
02_Configuration.jpg

trafgenを用いてl2fwdにMACアドレスフィルタ-を追加したサンプルプログラムを実行

DPDK VMへ導入したdpdkのサンプルプログラムl2fwdの改造を実施します。
今回は流入するパケットのdst macアドレスを見て, 送信ポートの振り分けやパケット破棄の機能を追加してみたいと思います。
あわせてCALL VMで必要なtrafgenコンフィグを準備して動作確認していきます。

送信ポートの振り分けを実施するため, 各VMにブリッジの割り当てを増やすところから実施します。
※今回の例では不要ですが, DPDKのパイプライン処理ではCPU数が処理に影響するため, VMへのCPU割当数増加の手順も実施したいと思います。

05_l2fwd_filter_trafgen.jpg

振り分け用ブリッジの追加

※一例としてCALL VMにbr_CALLtoDPDK2を割り当てる手順を記載するが, DPDK VM側も基本的に同手順
※DPDK VMは以降の「DPDK VMのCPU数を変更(2→3へ変更)」もあわせて実施する
※ホストで実施

◯ブリッジ作成(ホストを再起動するたびに実施する必要がある)

sudo brctl addbr br_DPDKtoCALL2

◯ブリッジ立ち上げ(ホストを再起動するたびに実施する必要がある)

sudo ifconfig br_DPDKtoCALL2 up

◯VMを停止

sudo virsh shutdown CALL
Domain CALL is being shutdown

◯VMにブリッジを割り当て
 →bridge部分にbr_DPDKtoCALL2を追記

sudo virsh edit CALL
<domain type='kvm'>   <name>CALL</name>   <uuid>6439ac13-5e55-4c4f-8e3e-b63c227869e8</uuid>   <memory unit='KiB'>2097152</memory>   <currentMemory unit='KiB'>2097152</currentMemory>   <vcpu placement='static'>2</vcpu>
~中略~
    </interface>     <interface type='bridge'>       <source bridge='br_DPDKtoCALL2'/>       <model type='virtio'/>     </interface>
~中略~
  </devices> </domain>

Domain CALL XML configuration edited.

◯ブリッジ割り当て設定を反映

sudo virsh define /etc/libvirt/qemu/CALL.xml
Domain CALL defined from /etc/libvirt/qemu/CALL.xml

◯VMにブリッジが割り当てられたことを確認

sudo virsh domiflist CALL
Interface Type Source Model MAC ------------------------------------------------------- - network default rtl8139 XX:XX:XX:XX:XX:XX - bridge br_CALLtoDPDK virtio XX:XX:XX:XX:XX:XX - bridge br_DPDKtoCALL virtio XX:XX:XX:XX:XX:XX - bridge br_DPDKtoCALL2 virtio XX:XX:XX:XX:XX:XX

◯VM起動

sudo virsh start CALL
Domain CALL started

DPDK VMのCPU数を変更(2→3へ変更)

※ホストで実施
◯VMを停止

sudo virsh shutdown DPDK
Domain DPDK is being shutdown

◯DPDK VMのCPU数を変更(2→3へ変更)

sudo virsh setvcpus DPDK 3 --config --maximum sudo virsh setvcpus DPDK 3 --config sudo virsh dominfo DPDK
Id: - Name: DPDK UUID: 23532aa9-bde1-4bb7-b833-1202bdb48674 OS Type: hvm State: shut off CPU(s): 3 Max memory: 4194304 KiB Used memory: 4194304 KiB Persistent: yes Autostart: disable Managed save: no Security model: apparmor Security DOI: 0

◯VM起動

sudo virsh start DPDK
Domain DPDK started

各VMに追加したbr_DPDKtoCALL2を割り当てIPアドレス設定

※一例としてCALL VMに割り当てたbr_DPDKtoCALL210.0.3.10を設定する手順を記載するが, DPDK VM側も設定するIPアドレス以外は基本的に同手順
※ホストで実施
◯CALL VMにSSHログイン

ssh user@192.168.122.212

※ここからCALL VMで実施
◯追加されたデバイスにIPを割り当て(ens7が追加されたとする)
※ens2はdefaultネットワークのデバイス
・接続プロファイルを作成

sudo nmcli connection add type ethernet ifname ens7 con-name ens7

・IPアドレスを設定

sudo nmcli connection modify ens7 ipv4.method manual ipv4.addresses 10.0.3.10/24

・デバイスに接続

sudo nmcli device connect ens7

ens7にIPアドレスが設定されていることを確認する

ip a

NW疎通確認

※DPDK VMで実施
◯追加した受信用ブリッジでの疎通確認

ping -I ens7 10.0.3.10

※CALL VMで実施
◯追加した受信用ブリッジでの疎通確認

ping -I ens7 10.0.3.20

VM再起動に伴うDPDKの再ビルドとドライバの追加

※DPDK VMで実施
◯DPDKのビルド/インストール
※以降, DPDK VMの作業はrootで実施する

sudo su -
# cd /opt/dpdk-stable-22.11.4/
# meson build # cd build # ninja # ninja install

◯NICのバインド
・バインド状態の確認
 →Network devices using kernel driverにNICが4つあることを確認する

# $RTE_SDK/usertools/dpdk-devbind.py --status
Network devices using kernel driver =================================== 0000:00:02.0 'Virtio network device 1000' if=ens2 drv=virtio-pci unused= *Active* 0000:00:05.0 'Virtio network device 1000' if=ens5 drv=virtio-pci unused= *Active* 0000:00:06.0 'Virtio network device 1000' if=ens6 drv=virtio-pci unused= *Active* 0000:00:07.0 'Virtio network device 1000' if=ens7 drv=virtio-pci unused= *Active*
No 'Baseband' devices detected ==============================
No 'Crypto' devices detected ============================
No 'DMA' devices detected =========================
No 'Eventdev' devices detected ==============================
No 'Mempool' devices detected =============================
No 'Compress' devices detected ==============================
Misc (rawdev) devices using kernel driver ========================================= 0000:00:05.0 'Virtio block device 1001' drv=virtio-pci unused=
No 'Regex' devices detected ===========================

・igb_uioのロード

# lsmod | grep uio # modprobe uio # insmod /opt/dpdk-stable-22.11.4/drivers/igb_uio.ko # lsmod | grep -e Module -e 'uio' Module Size Used by igb_uio 16384 0 uio 20480 1 igb_uio

・バインド対象のIFのdown

# ifconfig ens5 down # ifconfig ens6 down # ifconfig ens7 down

・バインド状態の確認
 →バインド対象のNICが非Activeであることを確認する

# $RTE_SDK/usertools/dpdk-devbind.py --status
Network devices using kernel driver =================================== 0000:00:02.0 'Virtio network device 1000' if=ens2 drv=virtio-pci unused=igb_uio *Active* 0000:00:05.0 'Virtio network device 1000' if=ens5 drv=virtio-pci unused=igb_uio 0000:00:06.0 'Virtio network device 1000' if=ens6 drv=virtio-pci unused=igb_uio 0000:00:07.0 'Virtio network device 1000' if=ens7 drv=virtio-pci unused=igb_uio
No 'Baseband' devices detected ==============================
No 'Crypto' devices detected ============================
No 'DMA' devices detected =========================
No 'Eventdev' devices detected ==============================
No 'Mempool' devices detected =============================
No 'Compress' devices detected ==============================
Misc (rawdev) devices using kernel driver ========================================= 0000:00:05.0 'Virtio block device 1001' drv=virtio-pci unused=igb_uio
No 'Regex' devices detected ===========================

・NICのバインド(受信用と送信用*2の3つをバインド)
 →バインド時Warning: routing table indicates that interface 0000:00:05.0 is active. Not modifyingのErrorが発生した場合は対象IFがdownしていることを確認する

# $RTE_SDK/usertools/dpdk-devbind.py -b igb_uio 0000:00:05.0 0000:00:06.0 0000:00:07.0

・バインド状態の確認
 →DPDK-compatible driverにバインド対象のIFが表示されていることを確認する

# $RTE_SDK/usertools/dpdk-devbind.py --status
Network devices using DPDK-compatible driver ============================================ 0000:00:05.0 'Virtio network device 1000' drv=igb_uio unused= 0000:00:06.0 'Virtio network device 1000' drv=igb_uio unused= 0000:00:07.0 'Virtio network device 1000' drv=igb_uio unused=
Network devices using kernel driver =================================== 0000:00:02.0 'Virtio network device 1000' if=ens2 drv=virtio-pci unused=igb_uio *Active*
No 'Baseband' devices detected ==============================
No 'Crypto' devices detected ============================
No 'DMA' devices detected =========================
No 'Eventdev' devices detected ==============================
No 'Mempool' devices detected =============================
No 'Compress' devices detected ==============================
Misc (rawdev) devices using kernel driver ========================================= 0000:00:05.0 'Virtio block device 1001' drv=virtio-pci unused=igb_uio
No 'Regex' devices detected ===========================

l2fwdにMACアドレスフィルタ-を追加したサンプルプログラムを作成

※DPDK VMで実施
l2fwd_sortのベースファイルを作成

# cd $RTE_SDK/examples/ # cp -Rp ./l2fwd ./l2fwd_sort # cd ./l2fwd_sort

・l2fwdにMACアドレス振分を追加したl2fwd_sortを作成
 ・l2fwd_mac_check関数を追加
  →mdst_macとハードコーディングの文字列を比較し, 1つ目に一致/2つ目に一致/不一致で1/2/3を返却
 ・l2fwd_simple_forwardl2fwd_mac_checkの戻り値を確認するif文を追加
  →一致(3以下)の場合のみ以降の処理を継続する
 ・l2fwd_main_loopprint_stats();をコメントアウト
  →l2fwd_mac_check関数のprintf関数がわかりやすいように既存の標準出力を非表示に修正

l2fwd_sortの修正

# vi ./main.c

・修正イメージ

/* SPDX-License-Identifier: BSD-3-Clause  * Copyright(c) 2010-2016 Intel Corporation  */
/* ★中略★ */
static int l2fwd_mac_check(struct rte_mbuf *m) {     char str[(6 * 2) + 1] = {0};     char filter1[16] = "52540008250b";     char filter2[16] = "52540008250c";
    uint8_t *eth = rte_pktmbuf_mtod(m, uint8_t * );
    for (int i = 0; i < 6; i++) sprintf(&str[i * 2], "%02x", *(eth + i));
    printf("出力対象1:%s \n", filter1);     printf("出力対象2:%s \n", filter2);     printf("入力対象:%s \n", str);
    if(strcmp(str, filter1)==0) {         printf("転送  :OK, dst:1\n");         return 1;     } else if(strcmp(str, filter2)==0) {         printf("転送  :OK, dst:2\n");         return 2;     } else {         printf("転送  :NG\n");         return 3;     } }
/* Simple forward. 8< */ static void l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) {     unsigned dst_port;     struct rte_eth_dev_tx_buffer *buffer;
    /* dst_port = l2fwd_dst_ports[portid]; */
    dst_port = l2fwd_mac_check(m);
    if (dst_port < 3) {         if (mac_updating)             l2fwd_mac_updating(m, dst_port);
        buffer = tx_buffer[dst_port];         sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
        if (sent)             port_statistics[dst_port].tx += sent;
    } } /* >8 End of simple forward. */
/* ★中略★ */
/* main processing loop */ static void l2fwd_main_loop(void) {     struct rte_mbuf *pkts_burst[MAX_PKT_BURST];     struct rte_mbuf *m;     int sent;     unsigned lcore_id;     uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;     unsigned i, j, portid, nb_rx;     struct lcore_queue_conf *qconf;     const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *             BURST_TX_DRAIN_US;     struct rte_eth_dev_tx_buffer *buffer;
    prev_tsc = 0;     timer_tsc = 0;
    lcore_id = rte_lcore_id();     qconf = &lcore_queue_conf[lcore_id];
    if (qconf->n_rx_port == 0) {         RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);         return;     }
    RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
    for (i = 0; i < qconf->n_rx_port; i++) {
        portid = qconf->rx_port_list[i];         RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,             portid);
    }
    while (!force_quit) {
        /* Drains TX queue in its main loop. 8< */         cur_tsc = rte_rdtsc();
        /*          * TX burst queue drain          */         diff_tsc = cur_tsc - prev_tsc;         if (unlikely(diff_tsc > drain_tsc)) {
            for (i = 0; i < qconf->n_rx_port; i++) {
                portid = l2fwd_dst_ports[qconf->rx_port_list[i]];                 buffer = tx_buffer[portid];
                sent = rte_eth_tx_buffer_flush(portid, 0, buffer);                 if (sent)                     port_statistics[portid].tx += sent;
            }
            /* if timer is enabled */             if (timer_period > 0) {
                /* advance the timer */                 timer_tsc += diff_tsc;
                /* if timer has reached its timeout */                 if (unlikely(timer_tsc >= timer_period)) {
                    /* do this only on main core */                     if (lcore_id == rte_get_main_lcore()) {                         /* print_stats(); */                         /* reset the timer */                         timer_tsc = 0;                     }                 }             }
            prev_tsc = cur_tsc;         }         /* >8 End of draining TX queue. */
        /* Read packet from RX queues. 8< */         for (i = 0; i < qconf->n_rx_port; i++) {
            portid = qconf->rx_port_list[i];             nb_rx = rte_eth_rx_burst(portid, 0,                      pkts_burst, MAX_PKT_BURST);
            if (unlikely(nb_rx == 0))                 continue;
            port_statistics[portid].rx += nb_rx;
            for (j = 0; j < nb_rx; j++) {                 m = pkts_burst[j];                 rte_prefetch0(rte_pktmbuf_mtod(m, void *));                 l2fwd_simple_forward(m, portid);             }         }         /* >8 End of read packet from RX queues. */     } }
/* ★中略★ */
}

l2fwd_sortのコンパイルと実行

※DPDK VMで実施
l2fwd_sortのコンパイルと実行
・l2fwdのコンパイル

# cd $RTE_SDK/examples/l2fwd_sort # make cc -O3 -I/usr/local/include -include rte_config.h -march=native -DALLOW_EXPERIMENTAL_API main.c -o build/l2fwd-shared -Wl,--as-needed -L/usr/local/lib64 -lrte_node -lrte_graph -lrte_pipeline -lrte_table -lrte_pdump -lrte_port -lrte_fib -lrte_ipsec -lrte_vhost -lrte_stack -lrte_security -lrte_sched -lrte_reorder -lrte_rib -lrte_dmadev -lrte_regexdev -lrte_rawdev -lrte_power -lrte_pcapng -lrte_member -lrte_lpm -lrte_latencystats -lrte_jobstats -lrte_ip_frag -lrte_gso -lrte_gro -lrte_gpudev -lrte_eventdev -lrte_efd -lrte_distributor -lrte_cryptodev -lrte_compressdev -lrte_cfgfile -lrte_bpf -lrte_bitratestats -lrte_bbdev -lrte_acl -lrte_timer -lrte_hash -lrte_metrics -lrte_cmdline -lrte_pci -lrte_ethdev -lrte_meter -lrte_net -lrte_mbuf -lrte_mempool -lrte_rcu -lrte_ring -lrte_eal -lrte_telemetry -lrte_kvargs ln -sf l2fwd-shared build/l2fwd

・l2fwd_filterの実行(NIC番号は0-2)

# cd ./build/ # ./l2fwd -l 0-2 -n 3 -- -q 3 -p 0x07

※CALL VMで実施
◯ターミナルを3つ開く(①/②/③とする)
・ターミナル①でtrafgenのコンフィグとしてMACアドレスを変更したものを作成する(適当なIPFIX Data Templateパケットの例)
 →dst_macの末尾をbからcに修正

# cp -p ./sample_temlate.cfg ./sample_temlate_2.cfg vi ./sample_temlate_2.cfg
#include <stddef.h> { /* ----- Etherframe ----- */ 0x52, 0x54, 0x00, 0x08, 0x25, 0x0c, /* Dst MAC address (52:54:00:08:25:0c) */ 0x52, 0x54, 0x00, 0x13, 0x4e, 0x9b, /* Src MAC address (52:54:00:13:4e:9b) */ 0x08, 0x00, /* Type IP */ /* ★中略★ */ }

・ターミナル①でtrafgenのコンフィグとしてMACアドレスを変更したものを作成する(適当なIPFIX Data Templateパケットの例)
 →dst_macの末尾をcからdに修正

# cp -p ./sample_temlate_2.cfg ./sample_temlate_3.cfg vi ./sample_temlate_3.cfg
#include <stddef.h> { /* ----- Etherframe ----- */ 0x52, 0x54, 0x00, 0x08, 0x25, 0x0d, /* Dst MAC address (52:54:00:08:25:0d) */ 0x52, 0x54, 0x00, 0x13, 0x4e, 0x9b, /* Src MAC address (52:54:00:13:4e:9b) */ 0x08, 0x00, /* Type IP */ /* ★中略★ */ }

・ターミナル②でtsharkを実施しておく

sudo tshark -i ens6

・ターミナル③でtsharkを実施しておく

sudo tshark -i ens7

・ターミナル①でtrafgenを実行(10パケット送信する)

sudo trafgen --dev ens5 -P 1 --conf ./sample_temlate.cfg --cpp -n 10 sudo trafgen --dev ens5 -P 1 --conf ./sample_temlate_2.cfg --cpp -n 10 sudo trafgen --dev ens5 -P 1 --conf ./sample_temlate_3.cfg --cpp -n 10

・ターミナル②を確認する

  • sample_temlate.cfg分の10パケットだけ受信している
Running as user "root" and group "root". This could be dangerous. Capturing on 'ens6'     1 0.000000000 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     2 0.000141704 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     3 0.000145356 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     4 0.000155847 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     5 0.000165753 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     6 0.000176537 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     7 0.000199426 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     8 0.000203575 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     9 0.000223063 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]    10 0.000225516 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024] ^C10 packets captured

・ターミナル③を確認する

  • sample_temlate_2.cfg分の10パケットだけ受信している
Running as user "root" and group "root". This could be dangerous. Capturing on 'ens10'     1 0.000000000 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     2 0.000238089 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     3 0.000242236 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     4 0.000248309 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     5 0.000249984 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     6 0.000251082 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     7 0.000255862 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     8 0.000257195 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]     9 0.000258236 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024]    10 0.000262584 10.0.1.10 → 10.0.1.20 CFLOW 86 IPFIX flow ( 44 bytes) Obs-Domain-ID=1 [Data-Template:1024] ^C10 packets captured

※DPDK VMで実施
◯l2fwdの画面を確認
 →確認後Ctrl+Cで停止
 →sample_temlate.cfg分の10パケットが転送  :OK, dst:1となっている
 →sample_temlate_2.cfg分の10パケットが転送  :OK, dst:2となっている
 →sample_temlate_3.cfg分の10パケットが転送  :NGとなっている

EAL: Detected CPU lcores: 3 EAL: Detected NUMA nodes: 1 EAL: Detected shared linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'PA' EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:00:02.0 (socket -1) eth_virtio_pci_init(): Failed to init PCI device EAL: Requested device 0000:00:02.0 cannot be used EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:00:05.0 (socket -1) EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:00:06.0 (socket -1) EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:00:07.0 (socket -1) TELEMETRY: No legacy callbacks, legacy socket not created MAC updating enabled Notice: odd number of ports in portmask. Lcore 0: RX port 0 TX port 1 Lcore 0: RX port 1 TX port 0 Lcore 0: RX port 2 TX port 2 Initializing port 0... done: Port 0, MAC address: 52:54:00:3F:11:69
Initializing port 1... done: Port 1, MAC address: 52:54:00:5D:80:BC
Initializing port 2... done: Port 2, MAC address: 52:54:00:1B:E4:5E

Checking link statusdone Port 0 Link up at Unknown FDX Autoneg Port 1 Link up at Unknown FDX Autoneg Port 2 Link up at Unknown FDX Autoneg L2FWD: lcore 1 has nothing to do L2FWD: lcore 2 has nothing to do L2FWD: entering main loop on lcore 0 L2FWD: -- lcoreid=0 portid=0 L2FWD: -- lcoreid=0 portid=1 L2FWD: -- lcoreid=0 portid=2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250b 転送  :OK, dst:1 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250c 転送  :OK, dst:2 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG 出力対象1:52540008250b 出力対象2:52540008250c 入力対象:52540008250d 転送  :NG ^C
Signal 2 received, preparing to exit... Closing port 0... Done Closing port 1... Done Closing port 2... Done Bye...

トラブルシューティング

arpは通っているがpingが通らない場合

arpも通らない時はホストで対象のブリッジがupになっているかも確認してください。

◯事象
・DPDK VM→CALL VMへのping(通らない)

sudo ping -I ens5 10.0.1.10
PING 10.0.1.10 (10.0.1.10) from 10.0.1.20 ens5: 56(84) bytes of data. ^C --- 10.0.1.10 ping statistics --- 78 packets transmitted, 0 received, 100% packet loss, time 78878ms

・DPDK VM→CALL VMへのarp(通っている)

arp -e
Address HWtype HWaddress Flags Mask Iface 192.168.122.231 ether 52:54:00:23:ec:3c C ens2 10.0.1.10 ether 52:54:00:13:4e:9b C ens5

◯対策の例→Bridge Netfilterを無効化する
※ホストで実施
Bridge Netfilterが有効か確認する(1だと有効)

lsmod | grep br_netfilter br_netfilter 24576 0 bridge 155648 1 br_netfilter
sudo sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-iptables = 1

・無効にする(1→0に変更)

sudo vi /etc/sysctl.conf

・無効設定を反映

sudo sysctl -p
vm.nr_hugepages = 2048 kernel.core_pattern = /home/ntt/core net.bridge.bridge-nf-call-iptables = 0

・無効になっていることを確認

sudo sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-iptables = 0

◯設定変更後の疎通確認
・DPDK VM→CALL VMへのpingが通ることを確認する

sudo ping -I ens8 10.0.1.10 -c 4
PING 10.0.1.10 (10.0.1.10) from 10.0.1.20 ens8: 56(84) bytes of data. 64 bytes from 10.0.1.10: icmp_seq=1 ttl=64 time=1.11 ms 64 bytes from 10.0.1.10: icmp_seq=2 ttl=64 time=0.924 ms 64 bytes from 10.0.1.10: icmp_seq=3 ttl=64 time=0.710 ms 64 bytes from 10.0.1.10: icmp_seq=4 ttl=64 time=0.917 ms
--- 10.0.1.10 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3016ms rtt min/avg/max/mdev = 0.710/0.914/1.108/0.145 ms

・CALL VM側でのtshark(対象IFでの受信を確認)

sudo tshark -i ens8 -Y 'icmp.type==0 or icmp.type==8'
Running as user "root" and group "root". This could be dangerous. Capturing on 'ens8'     1 0.000000000 10.0.1.20 → 10.0.1.10 ICMP 98 Echo (ping) request id=0x001e, seq=1/256, ttl=64     2 0.000056395 10.0.1.10 → 10.0.1.20 ICMP 98 Echo (ping) reply id=0x001e, seq=1/256, ttl=64 (request in 1)     3 1.001523750 10.0.1.20 → 10.0.1.10 ICMP 98 Echo (ping) request id=0x001e, seq=2/512, ttl=64     4 1.001575836 10.0.1.10 → 10.0.1.20 ICMP 98 Echo (ping) reply id=0x001e, seq=2/512, ttl=64 (request in 3)     5 2.002770950 10.0.1.20 → 10.0.1.10 ICMP 98 Echo (ping) request id=0x001e, seq=3/768, ttl=64     6 2.002828184 10.0.1.10 → 10.0.1.20 ICMP 98 Echo (ping) reply id=0x001e, seq=3/768, ttl=64 (request in 5)     7 3.015982890 10.0.1.20 → 10.0.1.10 ICMP 98 Echo (ping) request id=0x001e, seq=4/1024, ttl=64     8 3.016035895 10.0.1.10 → 10.0.1.20 ICMP 98 Echo (ping) reply id=0x001e, seq=4/1024, ttl=64 (request in 7) ^C8 packets captured

おわりに

DPDK入門 第19回に引く続き今回は入門編としてDPDKサンプルプログラム改造の例をご紹介しました。
DPDKを用いた簡易的なNW処理はDPDKのサンプルプログラムが参考になるため, ぜひ手軽に実行できる手元のKVM環境で確認いただけると幸いです。

本件に関するお問い合わせ

NTTテクノクロス
フューチャーネットワーク事業部

村木 遼亮

お問い合わせ

連載シリーズ
著者プロフィール
村木 遼亮
村木 遼亮

[著者プロフィール]
フューチャーネットワーク事業部 第一ビジネスユニット
村木 遼亮(MURAKI RYOUSUKE)