gdb ovs

 

dpif_netdev_run && pmd_thread_main  (没有启动虚拟机去连接 -chardev socket,id=char1,path=$VHOST_SOCK_DIR/vhost-user1,不会有pmd_thread_main

 执行ovs-vsctl add-port br0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser 会触发pmd_thread_main 

 
[root@localhost ovs]# ovs-vsctl show
c013fe69-c1a7-40dd-833b-bef8cd04d43e
    Bridge br0
        datapath_type: netdev
        Port br0
            Interface br0
                type: internal 
        Port dpdk1
            Interface dpdk1
                type: dpdk
                options: {dpdk-devargs="0000:05:00.0"}
     
[root@localhost ovs]# 

删除端口

 

 

 if (!netdev_is_pmd(port->netdev))

 

Breakpoint 1, dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
5438    {
(gdb) bt
#0  dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
#1  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#2  0x0000000000934c68 in type_run (type=type@entry=0x202dd910 "netdev") at ofproto/ofproto-dpif.c:370
#3  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202dd910 "netdev") at ofproto/ofproto.c:1772
#4  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#5  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#6  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) b dp_netdev_process_rxq_port
Breakpoint 2 at 0x97851c: file lib/dpif-netdev.c, line 4441.
(gdb) b pmd_thread_main
Breakpoint 3 at 0x97880c: file lib/dpif-netdev.c, line 5658.
(gdb) 
(gdb) c
Continuing.
[New Thread 0xffff7c29f910 (LWP 18234)]

Breakpoint 1, dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
5438    {
(gdb) bt
#0  dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
#1  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#2  0x0000000000934c68 in type_run (type=type@entry=0x202dd910 "netdev") at ofproto/ofproto-dpif.c:370
#3  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202dd910 "netdev") at ofproto/ofproto.c:1772
#4  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#5  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#6  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) b dp_netdev_process_rxq_port
Breakpoint 2 at 0x97851c: file lib/dpif-netdev.c, line 4441.
(gdb) b pmd_thread_main
Breakpoint 3 at 0x97880c: file lib/dpif-netdev.c, line 5658.
(gdb) c
Continuing.

Breakpoint 2, dp_netdev_process_rxq_port (pmd=pmd@entry=0xffff75f00010, rxq=0x204f7230, port_no=0) at lib/dpif-netdev.c:4441
4441    {
(gdb) bt
#0  dp_netdev_process_rxq_port (pmd=pmd@entry=0xffff75f00010, rxq=0x204f7230, port_no=0) at lib/dpif-netdev.c:4441
#1  0x000000000097911c in dpif_netdev_run (dpif=<optimized out>) at lib/dpif-netdev.c:5469
#2  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#3  0x0000000000934c68 in type_run (type=type@entry=0x202dd910 "netdev") at ofproto/ofproto-dpif.c:370
#4  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202dd910 "netdev") at ofproto/ofproto.c:1772
#5  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#6  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#7  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) c
Continuing.

Breakpoint 2, dp_netdev_process_rxq_port (pmd=pmd@entry=0xffff75f00010, rxq=0x2052ec80, port_no=2) at lib/dpif-netdev.c:4441
4441    {
(gdb) bt
#0  dp_netdev_process_rxq_port (pmd=pmd@entry=0xffff75f00010, rxq=0x2052ec80, port_no=2) at lib/dpif-netdev.c:4441
#1  0x000000000097911c in dpif_netdev_run (dpif=<optimized out>) at lib/dpif-netdev.c:5469
#2  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#3  0x0000000000934c68 in type_run (type=type@entry=0x202dd910 "netdev") at ofproto/ofproto-dpif.c:370
#4  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202dd910 "netdev") at ofproto/ofproto.c:1772  ----执行了
#5  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#6  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#7  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) 
(gdb) n
4451        cycle_timer_start(&pmd->perf_stats, &timer);
(gdb) n
4441    {
(gdb) n
4447        int rem_qlen = 0, *qlen_p = NULL;
(gdb) n
4451        cycle_timer_start(&pmd->perf_stats, &timer);
(gdb) n
4441    {
(gdb) n
4447        int rem_qlen = 0, *qlen_p = NULL;
(gdb) n
4451        cycle_timer_start(&pmd->perf_stats, &timer);
(gdb) n
4453        pmd->ctx.last_rxq = rxq;
(gdb) n
4457        if (pmd_perf_metrics_enabled(pmd) && rxq->is_vhost) {
(gdb) n
4451        cycle_timer_start(&pmd->perf_stats, &timer);
(gdb) n
4457        if (pmd_perf_metrics_enabled(pmd) && rxq->is_vhost) {
(gdb) n
4451        cycle_timer_start(&pmd->perf_stats, &timer);
(gdb) n
4454        dp_packet_batch_init(&batch);
(gdb) set print pretty on
(gdb) p *batch
Structure has no component named operator*.
(gdb) p batch
$1 = {
  count = 0, 
  trunc = false, 
  do_not_steal = false, 
  packets = {0xffff00000000, 0xa3505c <format_log_message+768>, 0x0, 0x0, 0x20, 0x1, 0xbfe3da, 0x980414 <ds_put_cstr+48>, 0xffffe22505a0, 0xffffe22505a0, 0xffffe2250570, 0xffffff80ffffffd8, 0xffffe22505a0, 0xffffe22505a0, 
    0xffffe22502a0, 0xa28468 <xclock_gettime+12>, 0xffffe22502b0, 0xa28560 <time_timespec__+212>, 0xffffe2250300, 0xa28638 <time_msec+28>, 0x202dd910, 0x204f2150, 0xffffe2250300, 0x9fb848 <ovs_mutex_lock_at+32>, 0xffff7c330f58, 
    0xbd4308, 0xffff00000000, 0xffff7e2a0c64 <malloc+88>, 0xffffe2250320, 0x978f74 <dpif_netdev_run+128>, 0xffffe2250320, 0x979100 <dpif_netdev_run+524>}
}
(gdb) 

dp_netdev_process_rxq_port

(gdb) bt
#0  dp_netdev_process_rxq_port (pmd=pmd@entry=0xfffd546d0010, rxq=0x11c8c5d0, port_no=2) at lib/dpif-netdev.c:4480
#1  0x0000000000978a24 in pmd_thread_main (f_=0xfffd546d0010) at lib/dpif-netdev.c:5731
#2  0x00000000009fc5dc in ovsthread_wrapper (aux_=<optimized out>) at lib/ovs-thread.c:383
#3  0x0000ffff95e37d38 in start_thread (arg=0xfffd4fffd510) at pthread_create.c:309
#4  0x0000ffff95b1f690 in thread_start () from /lib64/libc.so.6
(gdb) c
Continuing.

Breakpoint 1, dp_netdev_process_rxq_port (pmd=pmd@entry=0xfffd546d0010, rxq=0x11c8c5d0, port_no=2) at lib/dpif-netdev.c:4480
4480            dp_netdev_input(pmd, &batch, port_no);
(gdb) 

 

 

dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
                           struct netdev_rxq *rx,
                           odp_port_t port_no)
{
    struct dp_packet_batch batch;
    int error;

    dp_packet_batch_init(&batch);
    cycles_count_start(pmd);
    /*通过调用netdev_class->rxq_recv从rx中收包存入batch中*/
    error = netdev_rxq_recv(rx, &batch);             
    cycles_count_end(pmd, PMD_CYCLES_POLLING);
    if (!error) {
        *recirc_depth_get() = 0;

        cycles_count_start(pmd);
        /*将batch中的包转入datapath中进行处理*/
        dp_netdev_input(pmd, &batch, port_no);
        cycles_count_end(pmd, PMD_CYCLES_PROCESSING);
    } 
    ...
}

 

 

 netdev_class的实例有NETDEV_DPDK_CLASS,NETDEV_DUMMY_CLASS,NETDEV_BSD_CLASS,NETDEV_LINUX_CLASS.

netdev_rxq_recv &netdev_class ----->netdev_dpdk_vhost_rxq_recv

 

netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet_batch *batch,
                int *qfill)
{
    int retval;

    retval = rx->netdev->netdev_class->rxq_recv(rx, batch, qfill);
    if (!retval) {
        COVERAGE_INC(netdev_received);
    } else {
        batch->count = 0;
    }
    return retval;
}

 

ovs-vsctl add-port br0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser

static const struct netdev_class dpdk_vhost_class = {
    .type = "dpdkvhostuser",
    NETDEV_DPDK_CLASS_COMMON,
    .construct = netdev_dpdk_vhost_construct,
    .destruct = netdev_dpdk_vhost_destruct,
    .send = netdev_dpdk_vhost_send,
    .get_carrier = netdev_dpdk_vhost_get_carrier,
    .get_stats = netdev_dpdk_vhost_get_stats,
    .get_custom_stats = netdev_dpdk_get_sw_custom_stats,
    .get_status = netdev_dpdk_vhost_user_get_status,
    .reconfigure = netdev_dpdk_vhost_reconfigure,
    .rxq_recv = netdev_dpdk_vhost_rxq_recv,
    .rxq_enabled = netdev_dpdk_vhost_rxq_enabled,
};

 

 

dp_netdev_input

用户态Datapath处理packet流程:
        pmd_thread_main           dpif_netdev_run
                                       /
                                     /
                dp_netdev_process_rxq_port
                           |
                      dp_netdev_input
                           |
                     fast_path_processing
                           |
                    handle_packet_upcall
                       /             
                 (2) /                 (1)
                   /                     
  dp_netdev_execute_actions       dp_netdev_upcall
                  |                         |
         odp_execute_actions             upcall_cb(调用注册的回调函数)
                  |
            dp_execute_cb
                  |
             netdev_send

 

netdev_dpdk_rxq_recv

   >     >>         #1  0x00000000007d2252 in rte_eth_rx_burst (nb_pkts=32,
    >     >>
    >     >>         rx_pkts=0x7f3e4bffe7b0, queue_id=0, port_id=0 '00')
    >     >>
    >     >>             at /data1/build/dpdk-stable- rte_eth_rx_burst /x86_64-native-linuxapp-gcc/include/rte_ethdev.h:2774
    >     >>
    >     >>         #2  netdev_dpdk_rxq_recv (rxq=<optimized out>, batch=0x7f3e4bffe7a0)
    >     >>
    >     >>         at lib/netdev-dpdk.c:1664
    >     >>
    >     >>         #3  0x000000000072e571 in netdev_rxq_recv (rx=rx at entry=0x7f3e5cc4a680,
    >     >>
    >     >>         batch=batch at entry=0x7f3e4bffe7a0) at lib/netdev.c:701
    >     >>
    >     >>         #4  0x000000000070ab0e in dp_netdev_process_rxq_port
    >     >>
    >     >>         (pmd=pmd at entry=0x29e5e20, rx=0x7f3e5cc4a680, port_no=1) at
    >     >>
    >     >>         lib/dpif-netdev.c:3114
    >     >>
    >     >>         #5  0x000000000070ad76 in pmd_thread_main (f_=<optimized out>) at
    >     >>
    >     >>         lib/dpif-netdev.c:3854
    >     >>
    >     >>         #6  0x000000000077e4b4 in ovsthread_wrapper (aux_=<optimized out>) at
    >     >>
    >     >>         lib/ovs-thread.c:348
    >     >>
    >     >>         #7  0x00007f3e5fe07dc5 in start_thread (arg=0x7f3e4bfff700) at
    >     >>
    >     >>         pthread_create.c:308
    >     >>
    >     >>         #8  0x00007f3e5f3eb73d in clone () at
    >     >>
    >     >>         ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
    >     >>
    >     >>         (gdb) bt

 

dpdk_init

(gdb) bt
#0 0x00007f3d5f5c31d7 in raise () from /lib64/libc.so.6
#1 0x00007f3d5f5c48c8 in abort () from /lib64/libc.so.6
#2 0x00007f3d61184d95 in __rte_panic (
 funcname=funcname@entry=0x7f3d614846b0 <__func__.9925> "rte_eal_init",
 format=format@entry=0x7f3d61483e7c "Cannot init memory
%.0s")
 at /usr/src/debug/openvswitch-2.6.1/dpdk16.11/lib/librte_eal/linuxapp/eal/eal_debug.c:86
#3 0x00007f3d6128973a in rte_eal_init (argc=argc@entry=5, argv=<optimized out>)
 at /usr/src/debug/openvswitch-2.6.1/dpdk16.11/lib/librte_eal/linuxapp/eal/eal.c:814
#4 0x00007f3d61416516 in dpdk_init__
(ovs_other_config=ovs_other_config@entry=0x7f3d62d497f8)
 at lib/netdev-dpdk.c:3486
#5 0x00007f3d61416b1c in dpdk_init (ovs_other_config=0x7f3d62d497f8)
 at lib/netdev-dpdk.c:3541
#6 0x00007f3d613030e2 in bridge_run () at vswitchd/bridge.c:2918
#7 0x00007f3d6118828d in main (argc=10, argv=0x7ffcc105a128) at vswitchd/ovsvswitchd.c:112
(gdb)

 

 

#0 virtio_recv_mergeable_pkts (rx_queue=0x7fbe181bcc00, rx_pkts=0x7fbdd1ffa850,
nb_pkts=32)
 at /usr/src/debug/openvswitch-2.5.0/dpdk2.2.0/drivers/net/virtio/virtio_rxtx.c:684
684 nb_used = VIRTQUEUE_NUSED(rxvq);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-156.el7.x86_64
keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.14.1-20.el7.x86_64 libcom_err-1.42.9-
9.el7.x86_64 libgcc-4.8.5-9.el7.x86_64 libselinux-2.5-4.el7.x86_64 openssl-libs1.0.1e-58.el7.x86_64 pcre-8.32-15.el7_2.1.x86_64 zlib-1.2.7-17.el7.x86_64
(gdb) bt
#0 virtio_recv_mergeable_pkts (rx_queue=0x7fbe181bcc00, rx_pkts=0x7fbdd1ffa850,
nb_pkts=32)
 at /usr/src/debug/openvswitch-2.5.0/dpdk2.2.0/drivers/net/virtio/virtio_rxtx.c:684
#1 0x00007fbe1d61cc6a in rte_eth_rx_burst (nb_pkts=32, rx_pkts=0x7fbdd1ffa850,
queue_id=0,
 port_id=0 '00')
 at /usr/src/debug/openvswitch-2.5.0/dpdk-2.2.0/x86_64-native-linuxappgcc/include/rte_ethdev.h:2510
#2 netdev_dpdk_rxq_recv (rxq_=<optimized out>, packets=0x7fbdd1ffa850,
c=0x7fbdd1ffa84c)
 at lib/netdev-dpdk.c:1092
#3 0x00007fbe1d592351 in netdev_rxq_recv (rx=<optimized out>,
buffers=buffers@entry=0x7fbdd1ffa850,
 cnt=cnt@entry=0x7fbdd1ffa84c) at lib/netdev.c:654
#4 0x00007fbe1d572536 in dp_netdev_process_rxq_port (pmd=pmd@entry=0x7fbe1ea0e730,
 rxq=<optimized out>, port=<optimized out>, port=<optimized out>) at lib/dpifnetdev.c:2594
#5 0x00007fbe1d5728b9 in pmd_thread_main (f_=0x7fbe1ea0e730) at lib/dpifnetdev.c:2725
#6 0x00007fbe1d5d48b6 in ovsthread_wrapper (aux_=<optimized out>) at lib/ovsthread.c:340
#7 0x00007fbe1c733dc5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007fbe1bb2c73d in clone () from /lib64/libc.so.6

 

 

(gdb) bt
#0  0x0000ffff95b14e24 in poll () from /lib64/libc.so.6
#1  0x0000000000a28780 in time_poll (pollfds=pollfds@entry=0x11c8c820, n_pollfds=11, handles=handles@entry=0x0, timeout_when=453308105, elapsed=elapsed@entry=0xffffe8e999dc) at lib/timeval.c:326
#2  0x0000000000a12408 in poll_block () at lib/poll-loop.c:364
#3  0x00000000004246c8 in main (argc=11, argv=0xffffe8e99be8) at vswitchd/ovs-vswitchd.c:138
(gdb) b rte_vhost_enqueue_burst 
Breakpoint 1 at 0x90581c
(gdb) b rte_vhost_dequeue_burst 
Breakpoint 2 at 0x905a3c

 

 

 

(gdb) c
Continuing.
[New Thread 0xffff9333f910 (LWP 14604)]
[New Thread 0xfffd4d62d510 (LWP 14605)]
[Thread 0xffff9333f910 (LWP 14604) exited]
[New Thread 0xffff9333f910 (LWP 14620)]
[Thread 0xffff9333f910 (LWP 14620) exited]
[New Thread 0xffff9333f910 (LWP 14621)]
[Thread 0xffff9333f910 (LWP 14621) exited]
[New Thread 0xffff9333f910 (LWP 14636)]
[Thread 0xffff9333f910 (LWP 14636) exited]
[New Thread 0xffff9333f910 (LWP 14646)]
[Switching to Thread 0xfffd4ef1d510 (LWP 14393)]

Breakpoint 2, 0x0000000000905a3c in rte_vhost_dequeue_burst ()
(gdb) bt
#0  0x0000000000905a3c in rte_vhost_dequeue_burst ()
#1  0x0000000000a62d04 in netdev_dpdk_vhost_rxq_recv (rxq=<optimized out>, batch=0xfffd4ef1ca80, qfill=0x0) at lib/netdev-dpdk.c:2442
#2  0x00000000009a440c in netdev_rxq_recv (rx=<optimized out>, batch=batch@entry=0xfffd4ef1ca80, qfill=<optimized out>) at lib/netdev.c:726
#3  0x00000000009785bc in dp_netdev_process_rxq_port (pmd=pmd@entry=0xfffd4ef20010, rxq=0x11efe540, port_no=3) at lib/dpif-netdev.c:4461
#4  0x0000000000978a24 in pmd_thread_main (f_=0xfffd4ef20010) at lib/dpif-netdev.c:5731
#5  0x00000000009fc5dc in ovsthread_wrapper (aux_=<optimized out>) at lib/ovs-thread.c:383
#6  0x0000ffff95e37d38 in start_thread (arg=0xfffd4ef1d510) at pthread_create.c:309
#7  0x0000ffff95b1f690 in thread_start () from /lib64/libc.so.6
(gdb) c
Continuing.
[Switching to Thread 0xfffd4fffd510 (LWP 14391)]

Breakpoint 1, 0x000000000090581c in rte_vhost_enqueue_burst ()
(gdb) btt
Undefined command: "btt".  Try "help".
(gdb) bt
#0  0x000000000090581c in rte_vhost_enqueue_burst ()
#1  0x0000000000a60b90 in __netdev_dpdk_vhost_send (netdev=0x19fd81a40, qid=<optimized out>, pkts=pkts@entry=0xfffd3019daf0, cnt=32) at lib/netdev-dpdk.c:2662
#2  0x0000000000a6198c in netdev_dpdk_vhost_send (netdev=<optimized out>, qid=<optimized out>, batch=0xfffd3019dae0, concurrent_txq=<optimized out>) at lib/netdev-dpdk.c:2893
#3  0x00000000009a478c in netdev_send (netdev=0x19fd81a40, qid=qid@entry=0, batch=batch@entry=0xfffd3019dae0, concurrent_txq=concurrent_txq@entry=true) at lib/netdev.c:893
#4  0x000000000096fae8 in dp_netdev_pmd_flush_output_on_port (pmd=pmd@entry=0xfffd546d0010, p=p@entry=0xfffd3019dab0) at lib/dpif-netdev.c:4391
#5  0x000000000096fdfc in dp_netdev_pmd_flush_output_packets (pmd=pmd@entry=0xfffd546d0010, force=force@entry=false) at lib/dpif-netdev.c:4431
#6  0x00000000009787d8 in dp_netdev_pmd_flush_output_packets (force=false, pmd=0xfffd546d0010) at lib/dpif-netdev.c:4501
#7  dp_netdev_process_rxq_port (pmd=pmd@entry=0xfffd546d0010, rxq=0x11c8c5d0, port_no=2) at lib/dpif-netdev.c:4486
#8  0x0000000000978a24 in pmd_thread_main (f_=0xfffd546d0010) at lib/dpif-netdev.c:5731
#9  0x00000000009fc5dc in ovsthread_wrapper (aux_=<optimized out>) at lib/ovs-thread.c:383
#10 0x0000ffff95e37d38 in start_thread (arg=0xfffd4fffd510) at pthread_create.c:309
#11 0x0000ffff95b1f690 in thread_start () from /lib64/libc.so.6
(gdb) c
Continuing.

Breakpoint 1, 0x000000000090581c in rte_vhost_enqueue_burst ()
(gdb) bt
#0  0x000000000090581c in rte_vhost_enqueue_burst ()
#1  0x0000000000a60b90 in __netdev_dpdk_vhost_send (netdev=0x19fd81a40, qid=<optimized out>, pkts=pkts@entry=0xfffd3019daf0, cnt=32) at lib/netdev-dpdk.c:2662
#2  0x0000000000a6198c in netdev_dpdk_vhost_send (netdev=<optimized out>, qid=<optimized out>, batch=0xfffd3019dae0, concurrent_txq=<optimized out>) at lib/netdev-dpdk.c:2893
#3  0x00000000009a478c in netdev_send (netdev=0x19fd81a40, qid=qid@entry=0, batch=batch@entry=0xfffd3019dae0, concurrent_txq=concurrent_txq@entry=true) at lib/netdev.c:893
#4  0x000000000096fae8 in dp_netdev_pmd_flush_output_on_port (pmd=pmd@entry=0xfffd546d0010, p=p@entry=0xfffd3019dab0) at lib/dpif-netdev.c:4391
#5  0x000000000096fdfc in dp_netdev_pmd_flush_output_packets (pmd=pmd@entry=0xfffd546d0010, force=force@entry=false) at lib/dpif-netdev.c:4431
#6  0x00000000009787d8 in dp_netdev_pmd_flush_output_packets (force=false, pmd=0xfffd546d0010) at lib/dpif-netdev.c:4501
#7  dp_netdev_process_rxq_port (pmd=pmd@entry=0xfffd546d0010, rxq=0x11c8c5d0, port_no=2) at lib/dpif-netdev.c:4486
#8  0x0000000000978a24 in pmd_thread_main (f_=0xfffd546d0010) at lib/dpif-netdev.c:5731
#9  0x00000000009fc5dc in ovsthread_wrapper (aux_=<optimized out>) at lib/ovs-thread.c:383
#10 0x0000ffff95e37d38 in start_thread (arg=0xfffd4fffd510) at pthread_create.c:309
#11 0x0000ffff95b1f690 in thread_start () from /lib64/libc.so.6

 

 

dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
                           struct dp_netdev_rxq *rxq,
                           odp_port_t port_no)
{
    struct pmd_perf_stats *s = &pmd->perf_stats;
    struct dp_packet_batch batch;
    struct cycle_timer timer;
    int error;
    int batch_cnt = 0;
    int rem_qlen = 0, *qlen_p = NULL;
    uint64_t cycles;

    /* Measure duration for polling and processing rx burst. */
    cycle_timer_start(&pmd->perf_stats, &timer);

    pmd->ctx.last_rxq = rxq;
    dp_packet_batch_init(&batch);

    /* Fetch the rx queue length only for vhostuser ports. */
    if (pmd_perf_metrics_enabled(pmd) && rxq->is_vhost) {
        qlen_p = &rem_qlen;
    }

    error = netdev_rxq_recv(rxq->rx, &batch, qlen_p); //dequeue
    if (!error) {
        /* At least one packet received. */
        *recirc_depth_get() = 0;
        pmd_thread_ctx_time_update(pmd);
        batch_cnt = dp_packet_batch_size(&batch);
        if (pmd_perf_metrics_enabled(pmd)) {
            /* Update batch histogram. */
            s->current.batches++;
            histogram_add_sample(&s->pkts_per_batch, batch_cnt);
            /* Update the maximum vhost rx queue fill level. */
            if (rxq->is_vhost && rem_qlen >= 0) {
                uint32_t qfill = batch_cnt + rem_qlen;
                if (qfill > s->current.max_vhost_qfill) {
                    s->current.max_vhost_qfill = qfill;
                }
            }
        }
        /* Process packet batch. */
        dp_netdev_input(pmd, &batch, port_no); //流处理

        /* Assign processing cycles to rx queue. */
        cycles = cycle_timer_stop(&pmd->perf_stats, &timer);
        dp_netdev_rxq_add_cycles(rxq, RXQ_CYCLES_PROC_CURR, cycles);

        dp_netdev_pmd_flush_output_packets(pmd, false);   // enqueue
    } else {
        /* Discard cycles. */
        cycle_timer_stop(&pmd->perf_stats, &timer);
        if (error != EAGAIN && error != EOPNOTSUPP) {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);

            VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
                    netdev_rxq_get_name(rxq->rx), ovs_strerror(error));
        }
    }

    pmd->ctx.last_rxq = NULL;

    return batch_cnt;
}

 

 

执行 ovs-vsctl add-port br0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser

[New Thread 0xffff9333f910 (LWP 14604)]
[New Thread 0xfffd4d62d510 (LWP 14605)]
[Thread 0xffff9333f910 (LWP 14604) exited]
[New Thread 0xffff9333f910 (LWP 14620)]
[Thread 0xffff9333f910 (LWP 14620) exited]
[New Thread 0xffff9333f910 (LWP 14621)]
[Thread 0xffff9333f910 (LWP 14621) exited]
[New Thread 0xffff9333f910 (LWP 14636)]
[Thread 0xffff9333f910 (LWP 14636) exited]
[New Thread 0xffff9333f910 (LWP 14646)]
[Switching to Thread 0xfffd4ef1d510 (LWP 14393)]

 

 

 

 

 

 

 

netdev_open

could not create netdev dpdk1 of unknown type dpdk

ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
Breakpoint 1, netdev_open (name=0x11f01c40 "br0", type=type@entry=0x0, netdevp=netdevp@entry=0xffffe8e996c8) at lib/netdev.c:372
372     {
(gdb) bt
#0  netdev_open (name=0x11f01c40 "br0", type=type@entry=0x0, netdevp=netdevp@entry=0xffffe8e996c8) at lib/netdev.c:372
#1  0x000000000094f8a0 in xbridge_addr_create (xbridge=0x11c95dc0, xbridge=0x11c95dc0) at ofproto/ofproto-dpif-xlate.c:900
#2  xlate_ofproto_set (ofproto=ofproto@entry=0x11eb6a80, name=0x11c88a50 "br0", dpif=0x11c8cb90, ml=0x11ecc400, stp=0x0, rstp=0x0, ms=0x0, mbridge=0x11ec9e70, sflow=sflow@entry=0x0, ipfix=ipfix@entry=0x0, 
    netflow=netflow@entry=0x0, forward_bpdu=forward_bpdu@entry=false, has_in_band=false, support=0x11c51350) at ofproto/ofproto-dpif-xlate.c:1266
#3  0x000000000093555c in type_run (type=type@entry=0x11c96dc0 "netdev") at ofproto/ofproto-dpif.c:481
#4  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x11c96dc0 "netdev") at ofproto/ofproto.c:1772
#5  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#6  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#7  0x000000000042469c in main (argc=11, argv=0xffffe8e99be8) at vswitchd/ovs-vswitchd.c:127

 ovs的datapath_type有nedev和system,netdev表示用户态数据访问,system表示内核数据访问

 

(gdb) b type_run 
Breakpoint 1 at 0x934c28: file ofproto/ofproto-dpif.c, line 360.
(gdb) c
Continuing.

Breakpoint 1, type_run (type=type@entry=0x20530510 "netdev") at ofproto/ofproto-dpif.c:360
360     {
(gdb) list
355         return NULL;
356     }
357
358     static int
359     type_run(const char *type)
360     {
361         struct dpif_backer *backer;
362
363         backer = shash_find_data(&all_dpif_backers, type);
364         if (!backer) {
(gdb) n
363         backer = shash_find_data(&all_dpif_backers, type);
(gdb) n
360     {
(gdb) n
363         backer = shash_find_data(&all_dpif_backers, type);
(gdb) n
360     {
(gdb) n
363         backer = shash_find_data(&all_dpif_backers, type);
(gdb) n
364         if (!backer) {
(gdb) n
370         if (dpif_run(backer->dpif)) {
(gdb) set print pretty on
(gdb) p *backer
$1 = {
  type = 0x204f2130 "netdev", 
  refcount = 1, 
  dpif = 0x204f78a0, 
  udpif = 0x204f7940, 
  odp_to_ofport_lock = {
    lock = {
      __data = {
        __lock = 0, 
        __nr_readers = 0, 
        __readers_wakeup = 0, 
        __writer_wakeup = 0, 
        __nr_readers_queued = 0, 
        __nr_writers_queued = 0, 
        __writer = 0, 
        __shared = 0, 
        __pad1 = 0, 
        __pad2 = 0, 
        __flags = 1
      }, 
      __size = '00' <repeats 48 times>, "01000000000000", 
      __align = 0
    }, 
    where = 0xbc50c0 "<unlocked>"
  }, 
  odp_to_ofport_map = {
    buckets = 0x202acc60, 
    one = 0x0, 
    mask = 3, 
    n = 2
  }, 
  tnl_backers = {
    map = {
      buckets = 0x204f21d8, 
      one = 0x0, 
      mask = 0, 
      n = 0
    }
  }, 
  need_revalidate = 0, 
  recv_set_enable = true, 
  meter_ids = 0x20504710, 
  tp_ids = 0x20508e40, 
  ct_zones = {
    impl = {
      p = 0x10f2a40 <empty_cmap>
    }
  }, 
  ct_tps = {
    buckets = 0x204f2218, 
    one = 0x0, 
    mask = 0, 
    n = 0
  }, 
  ct_tp_kill_list = {
    prev = 0x204f2230, 
    next = 0x204f2230
  }, 
  dp_version_string = 0x2050c9a0 "<built-in>", 
---Type <return> to continue, or q <return> to quit---
  bt_support = {
    masked_set_action = true, 
    tnl_push_pop = true, 
    ufid = true, 
    trunc = true, 
    clone = true, 
    sample_nesting = 10, 
    ct_eventmask = true, 
    ct_clear = true, 
    max_hash_alg = 1, 
    check_pkt_len = true, 
    ct_timeout = true, 
    explicit_drop_action = true, 
    odp = {
      max_vlan_headers = 1, 
      max_mpls_depth = 3, 
      recirc = true, 
      ct_state = true, 
      ct_zone = true, 
      ct_mark = true, 
      ct_label = true, 
      ct_state_nat = true, 
      ct_orig_tuple = true, 
      ct_orig_tuple6 = true, 
      nd_ext = true
    }
  }, 
  rt_support = {
    masked_set_action = true, 
    tnl_push_pop = true, 
    ufid = true, 
    trunc = true, 
    clone = true, 
    sample_nesting = 10, 
    ct_eventmask = true, 
    ct_clear = true, 
    max_hash_alg = 1, 
    check_pkt_len = true, 
    ct_timeout = true, 
    explicit_drop_action = true, 
    odp = {
      max_vlan_headers = 1, 
      max_mpls_depth = 3, 
      recirc = true, 
      ct_state = true, 
      ct_zone = true, 
      ct_mark = true, 
      ct_label = true, 
      ct_state_nat = true, 
      ct_orig_tuple = true, 
      ct_orig_tuple6 = true, 
      nd_ext = true
    }
  }, 
  tnl_count = {
    count = 0
  }
}
(gdb) 
(gdb) 
(gdb) p backer->dpif
$2 = (struct dpif *) 0x204f78a0
(gdb) p *(backer->dpif)
$3 = {
  dpif_class = 0xbd2650 <dpif_netdev_class>, 
  base_name = 0x204f73e0 "ovs-netdev", 
  full_name = 0x204f78e0 "netdev@ovs-netdev", 
  netflow_engine_type = 47 '/', 
  netflow_engine_id = 209 '321', 
  current_ms = 464123586
}
(gdb)

 

dpif_class

datapath接口实现类,每种datapath都有对应的接口实现实例。dpif有两种实现类:dpif_netlink_class、dpif_netdev_class。即system、netdev。比如,dpdk的netdevdatapath类型的实现实例dpif_netdev_class。

 

(gdb) p *(backer->dpif)
$3 = {
  dpif_class = 0xbd2650 <dpif_netdev_class>, 
  base_name = 0x204f73e0 "ovs-netdev", 
  full_name = 0x204f78e0 "netdev@ovs-netdev", 
  netflow_engine_type = 47 '/', 
  netflow_engine_id = 209 '321', 
  current_ms = 464123586
}
(gdb)

 

 

struct dpif {
    const struct dpif_class *dpif_class;
    char *base_name;
    char *full_name;
    uint8_t netflow_engine_type;
    uint8_t netflow_engine_id;
    long long int current_ms;
};

 

 

struct dpif_class {
    /* Type of dpif in this class, e.g. "system", "netdev", etc.
     *
     * One of the providers should supply a "system" type, since this is
     * the type assumed if no type is specified when opening a dpif. */
    const char *type;

    /* Enumerates the names of all known created datapaths, if possible, into
     * 'all_dps'.  The caller has already initialized 'all_dps' and other dpif
     * classes might already have added names to it.
     *
     * This is used by the vswitch at startup, so that it can delete any
     * datapaths that are not configured.
     *
     * Some kinds of datapaths might not be practically enumerable, in which
     * case this function may be a null pointer. */
    int (*enumerate)(struct sset *all_dps);

    /* Returns the type to pass to netdev_open() when a dpif of class
     * 'dpif_class' has a port of type 'type', for a few special cases
     * when a netdev type differs from a port type.  For example, when
     * using the userspace datapath, a port of type "internal" needs to
     * be opened as "tap".
     *
     * Returns either 'type' itself or a string literal, which must not
     * be freed. */
    const char *(*port_open_type)(const struct dpif_class *dpif_class,
                                  const char *type);

    /* Attempts to open an existing dpif called 'name', if 'create' is false,
     * or to open an existing dpif or create a new one, if 'create' is true.
     *
     * 'dpif_class' is the class of dpif to open.
     *
     * If successful, stores a pointer to the new dpif in '*dpifp', which must
     * have class 'dpif_class'.  On failure there are no requirements on what
     * is stored in '*dpifp'. */
    int (*open)(const struct dpif_class *dpif_class,
                const char *name, bool create, struct dpif **dpifp);

    /* Closes 'dpif' and frees associated memory. */
    void (*close)(struct dpif *dpif);

    /* Attempts to destroy the dpif underlying 'dpif'.
     *
     * If successful, 'dpif' will not be used again except as an argument for
     * the 'close' member function. */
    int (*destroy)(struct dpif *dpif);

    /* Performs periodic work needed by 'dpif', if any is necessary. */
    void (*run)(struct dpif *dpif);

    /* Arranges for poll_block() to wake up if the "run" member function needs
     * to be called for 'dpif'. */
    void (*wait)(struct dpif *dpif);

    /* Retrieves statistics for 'dpif' into 'stats'. */
    int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats);

    /* Adds 'netdev' as a new port in 'dpif'.  If '*port_no' is not
     * UINT32_MAX, attempts to use that as the port's port number.
     *
     * If port is successfully added, sets '*port_no' to the new port's
     * port number.  Returns EBUSY if caller attempted to choose a port
     * number, and it was in use. */
    int (*port_add)(struct dpif *dpif, struct netdev *netdev,
                    uint32_t *port_no);

    /* Removes port numbered 'port_no' from 'dpif'. */
    int (*port_del)(struct dpif *dpif, uint32_t port_no);

    /* Queries 'dpif' for a port with the given 'port_no' or 'devname'.
     * If 'port' is not null, stores information about the port into
     * '*port' if successful.
     *
     * If 'port' is not null, the caller takes ownership of data in
     * 'port' and must free it with dpif_port_destroy() when it is no
     * longer needed. */
    int (*port_query_by_number)(const struct dpif *dpif, uint32_t port_no,
                                struct dpif_port *port);
    int (*port_query_by_name)(const struct dpif *dpif, const char *devname,
                              struct dpif_port *port);

    /* Returns one greater than the largest port number accepted in flow
     * actions. */
    int (*get_max_ports)(const struct dpif *dpif);

    /* Returns the Netlink PID value to supply in OVS_ACTION_ATTR_USERSPACE
     * actions as the OVS_USERSPACE_ATTR_PID attribute's value, for use in
     * flows whose packets arrived on port 'port_no'.
     *
     * A 'port_no' of UINT32_MAX should be treated as a special case.  The
     * implementation should return a reserved PID, not allocated to any port,
     * that the client may use for special purposes.
     *
     * The return value only needs to be meaningful when DPIF_UC_ACTION has
     * been enabled in the 'dpif''s listen mask, and it is allowed to change
     * when DPIF_UC_ACTION is disabled and then re-enabled.
     *
     * A dpif provider that doesn't have meaningful Netlink PIDs can use NULL
     * for this function.  This is equivalent to always returning 0. */
    uint32_t (*port_get_pid)(const struct dpif *dpif, uint32_t port_no);

    /* Attempts to begin dumping the ports in a dpif.  On success, returns 0
     * and initializes '*statep' with any data needed for iteration.  On
     * failure, returns a positive errno value. */
    int (*port_dump_start)(const struct dpif *dpif, void **statep);

    /* Attempts to retrieve another port from 'dpif' for 'state', which was
     * initialized by a successful call to the 'port_dump_start' function for
     * 'dpif'.  On success, stores a new dpif_port into 'port' and returns 0.
     * Returns EOF if the end of the port table has been reached, or a positive
     * errno value on error.  This function will not be called again once it
     * returns nonzero once for a given iteration (but the 'port_dump_done'
     * function will be called afterward).
     *
     * The dpif provider retains ownership of the data stored in 'port'.  It
     * must remain valid until at least the next call to 'port_dump_next' or
     * 'port_dump_done' for 'state'. */
    int (*port_dump_next)(const struct dpif *dpif, void *state,
                          struct dpif_port *port);

    /* Releases resources from 'dpif' for 'state', which was initialized by a
     * successful call to the 'port_dump_start' function for 'dpif'.  */
    int (*port_dump_done)(const struct dpif *dpif, void *state);

    /* Polls for changes in the set of ports in 'dpif'.  If the set of ports in
     * 'dpif' has changed, then this function should do one of the
     * following:
     *
     * - Preferably: store the name of the device that was added to or deleted
     *   from 'dpif' in '*devnamep' and return 0.  The caller is responsible
     *   for freeing '*devnamep' (with free()) when it no longer needs it.
     *
     * - Alternatively: return ENOBUFS, without indicating the device that was
     *   added or deleted.
     *
     * Occasional 'false positives', in which the function returns 0 while
     * indicating a device that was not actually added or deleted or returns
     * ENOBUFS without any change, are acceptable.
     *
     * If the set of ports in 'dpif' has not changed, returns EAGAIN.  May also
     * return other positive errno values to indicate that something has gone
     * wrong. */
    int (*port_poll)(const struct dpif *dpif, char **devnamep);

    /* Arranges for the poll loop to wake up when 'port_poll' will return a
     * value other than EAGAIN. */
    void (*port_poll_wait)(const struct dpif *dpif);

    /* Queries 'dpif' for a flow entry.  The flow is specified by the Netlink
     * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
     * 'key'.
     *
     * Returns 0 if successful.  If no flow matches, returns ENOENT.  On other
     * failure, returns a positive errno value.
     *
     * If 'actionsp' is nonnull, then on success '*actionsp' must be set to an
     * ofpbuf owned by the caller that contains the Netlink attributes for the
     * flow's actions.  The caller must free the ofpbuf (with ofpbuf_delete())
     * when it is no longer needed.
     *
     * If 'stats' is nonnull, then on success it must be updated with the
     * flow's statistics. */
    int (*flow_get)(const struct dpif *dpif,
                    const struct nlattr *key, size_t key_len,
                    struct ofpbuf **actionsp, struct dpif_flow_stats *stats);

    /* Adds or modifies a flow in 'dpif'.  The flow is specified by the Netlink
     * attributes with types OVS_KEY_ATTR_* in the 'put->key_len' bytes
     * starting at 'put->key'.  The associated actions are specified by the
     * Netlink attributes with types OVS_ACTION_ATTR_* in the
     * 'put->actions_len' bytes starting at 'put->actions'.
     *
     * - If the flow's key does not exist in 'dpif', then the flow will be
     *   added if 'put->flags' includes DPIF_FP_CREATE.  Otherwise the
     *   operation will fail with ENOENT.
     *
     *   If the operation succeeds, then 'put->stats', if nonnull, must be
     *   zeroed.
     *
     * - If the flow's key does exist in 'dpif', then the flow's actions will
     *   be updated if 'put->flags' includes DPIF_FP_MODIFY.  Otherwise the
     *   operation will fail with EEXIST.  If the flow's actions are updated,
     *   then its statistics will be zeroed if 'put->flags' includes
     *   DPIF_FP_ZERO_STATS, and left as-is otherwise.
     *
     *   If the operation succeeds, then 'put->stats', if nonnull, must be set
     *   to the flow's statistics before the update.
     */
    int (*flow_put)(struct dpif *dpif, const struct dpif_flow_put *put);

    /* Deletes a flow from 'dpif' and returns 0, or returns ENOENT if 'dpif'
     * does not contain such a flow.  The flow is specified by the Netlink
     * attributes with types OVS_KEY_ATTR_* in the 'del->key_len' bytes
     * starting at 'del->key'.
     *
     * If the operation succeeds, then 'del->stats', if nonnull, must be set to
     * the flow's statistics before its deletion. */
    int (*flow_del)(struct dpif *dpif, const struct dpif_flow_del *del);

    /* Deletes all flows from 'dpif' and clears all of its queues of received
     * packets. */
    int (*flow_flush)(struct dpif *dpif);

    /* Attempts to begin dumping the flows in a dpif.  On success, returns 0
     * and initializes '*statep' with any data needed for iteration.  On
     * failure, returns a positive errno value. */
    int (*flow_dump_start)(const struct dpif *dpif, void **statep);

    /* Attempts to retrieve another flow from 'dpif' for 'state', which was
     * initialized by a successful call to the 'flow_dump_start' function for
     * 'dpif'.  On success, updates the output parameters as described below
     * and returns 0.  Returns EOF if the end of the flow table has been
     * reached, or a positive errno value on error.  This function will not be
     * called again once it returns nonzero within a given iteration (but the
     * 'flow_dump_done' function will be called afterward).
     *
     * On success, if 'key' and 'key_len' are nonnull then '*key' and
     * '*key_len' must be set to Netlink attributes with types OVS_KEY_ATTR_*
     * representing the dumped flow's key.  If 'actions' and 'actions_len' are
     * nonnull then they should be set to Netlink attributes with types
     * OVS_ACTION_ATTR_* representing the dumped flow's actions.  If 'stats'
     * is nonnull then it should be set to the dumped flow's statistics.
     *
     * All of the returned data is owned by 'dpif', not by the caller, and the
     * caller must not modify or free it.  'dpif' must guarantee that it
     * remains accessible and unchanging until at least the next call to
     * 'flow_dump_next' or 'flow_dump_done' for 'state'. */
    int (*flow_dump_next)(const struct dpif *dpif, void *state,
                          const struct nlattr **key, size_t *key_len,
                          const struct nlattr **actions, size_t *actions_len,
                          const struct dpif_flow_stats **stats);

    /* Releases resources from 'dpif' for 'state', which was initialized by a
     * successful call to the 'flow_dump_start' function for 'dpif'.  */
    int (*flow_dump_done)(const struct dpif *dpif, void *state);

    /* Performs the 'execute->actions_len' bytes of actions in
     * 'execute->actions' on the Ethernet frame specified in 'execute->packet'
     * taken from the flow specified in the 'execute->key_len' bytes of
     * 'execute->key'.  ('execute->key' is mostly redundant with
     * 'execute->packet', but it contains some metadata that cannot be
     * recovered from 'execute->packet', such as tunnel and in_port.) */
    int (*execute)(struct dpif *dpif, const struct dpif_execute *execute);

    /* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order
     * in which they are specified, placing each operation's results in the
     * "output" members documented in comments.
     *
     * This function is optional.  It is only worthwhile to implement it if
     * 'dpif' can perform operations in batch faster than individually. */
    void (*operate)(struct dpif *dpif, struct dpif_op **ops, size_t n_ops);

    /* Enables or disables receiving packets with dpif_recv() for 'dpif'.
     * Turning packet receive off and then back on is allowed to change Netlink
     * PID assignments (see ->port_get_pid()).  The client is responsible for
     * updating flows as necessary if it does this. */
    int (*recv_set)(struct dpif *dpif, bool enable);

    /* Translates OpenFlow queue ID 'queue_id' (in host byte order) into a
     * priority value used for setting packet priority. */
    int (*queue_to_priority)(const struct dpif *dpif, uint32_t queue_id,
                             uint32_t *priority);

    /* Polls for an upcall from 'dpif'.  If successful, stores the upcall into
     * '*upcall', using 'buf' for storage.  Should only be called if 'recv_set'
     * has been used to enable receiving packets from 'dpif'.
     *
     * The implementation should point 'upcall->packet' and 'upcall->key' into
     * data in the caller-provided 'buf'.  If necessary to make room, the
     * implementation may expand the data in 'buf'.  (This is hardly a great
     * way to do things but it works out OK for the dpif providers that exist
     * so far.)
     *
     * This function must not block.  If no upcall is pending when it is
     * called, it should return EAGAIN without blocking. */
    int (*recv)(struct dpif *dpif, struct dpif_upcall *upcall,
                struct ofpbuf *buf);

    /* Arranges for the poll loop to wake up when 'dpif' has a message queued
     * to be received with the recv member function. */
    void (*recv_wait)(struct dpif *dpif);

    /* Throws away any queued upcalls that 'dpif' currently has ready to
     * return. */
    void (*recv_purge)(struct dpif *dpif);
};

 

dpif_class注册
dp_initialize(void)
{
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;

    if (ovsthread_once_start(&once)) {
        int i;

        tnl_conf_seq = seq_create();
        dpctl_unixctl_register();
        tnl_port_map_init();
        tnl_neigh_cache_init();
        route_table_init();

        for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) {
            dp_register_provider(base_dpif_classes[i]);
        }

        ovsthread_once_done(&once);
    }
}

 

static const struct dpif_class *base_dpif_classes[] = {
#if defined(__linux__) || defined(_WIN32)
    &dpif_netlink_class,
#endif
    &dpif_netdev_class,
};

 

dpif_netdev_class

const struct dpif_class dpif_netdev_class = {
    "netdev",
    true,                       /* cleanup_required */
    dpif_netdev_init,
    dpif_netdev_enumerate,
    dpif_netdev_port_open_type,
    dpif_netdev_open,
    dpif_netdev_close,
    dpif_netdev_destroy,
    dpif_netdev_run,
    dpif_netdev_wait,
    dpif_netdev_get_stats,
    NULL,                      /* set_features */
    dpif_netdev_port_add,
    dpif_netdev_port_del,
    dpif_netdev_port_set_config,
    dpif_netdev_port_query_by_number,
    dpif_netdev_port_query_by_name,
    NULL,                       /* port_get_pid */
    dpif_netdev_port_dump_start,
    dpif_netdev_port_dump_next,
    dpif_netdev_port_dump_done,
    dpif_netdev_port_poll,
    dpif_netdev_port_poll_wait,
    dpif_netdev_flow_flush,
    dpif_netdev_flow_dump_create,
    dpif_netdev_flow_dump_destroy,
    dpif_netdev_flow_dump_thread_create,
    dpif_netdev_flow_dump_thread_destroy,
    dpif_netdev_flow_dump_next,
    dpif_netdev_operate,
    NULL,                       /* recv_set */
    NULL,                       /* handlers_set */
    dpif_netdev_set_config,
    dpif_netdev_queue_to_priority,
    NULL,                       /* recv */
    NULL,                       /* recv_wait */
    NULL,                       /* recv_purge */
    dpif_netdev_register_dp_purge_cb,
    dpif_netdev_register_upcall_cb,
    dpif_netdev_enable_upcall,
    dpif_netdev_disable_upcall,
    dpif_netdev_get_datapath_version,
    dpif_netdev_ct_dump_start,
    dpif_netdev_ct_dump_next,
    dpif_netdev_ct_dump_done,
    dpif_netdev_ct_flush,
    dpif_netdev_ct_set_maxconns,
    dpif_netdev_ct_get_maxconns,
    dpif_netdev_ct_get_nconns,
    dpif_netdev_ct_set_tcp_seq_chk,
    dpif_netdev_ct_get_tcp_seq_chk,
    dpif_netdev_ct_set_limits,
    dpif_netdev_ct_get_limits,
    dpif_netdev_ct_del_limits,
    NULL,                       /* ct_set_timeout_policy */
    NULL,                       /* ct_get_timeout_policy */

dpif_netdev_run

(gdb) b dpif_netdev_run
Breakpoint 1 at 0x978ef4: file lib/dpif-netdev.c, line 5438.
(gdb) c
Continuing.

Breakpoint 1, dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
5438    {
(gdb) bt
#0  dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
#1  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#2  0x0000000000934c68 in type_run (type=type@entry=0x202db460 "netdev") at ofproto/ofproto-dpif.c:370
#3  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202db460 "netdev") at ofproto/ofproto.c:1772
#4  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#5  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#6  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) 

 

#0 0x000000000053489a in mlx5_tx_mb2mr (mb=0x7fa5d8711180, txq=0x7fa5d812cdc0) at /usr/src/debug/openvswitch-2.9.0-3.el7.tis.1.x86_64/dpdk-17.11/drivers/net/mlx5/mlx5_rxtx.h:551
551 if (likely(txq->mp2mr[i]->start <= addr && txq->mp2mr[i]->end >= addr))
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.15.1-19.el7.x86_64 libcap-ng-0.7.5-4.el7.x86_64 libcom_err-1.42.9-12.el7_5.x86_64 libgcc-4.8.5-28.el7_5.1.x86_64 libibverbs-43mlnx1-1.43302.tis.1.x86_64 libnl3-3.2.28-4.el7.x86_64 libselinux-2.5-12.el7.x86_64 numactl-libs-2.0.9-7.el7.x86_64 openssl-libs-1.0.2k-12.el7.x86_64 pcre-8.32-17.el7.x86_64 zlib-1.2.7-17.el7.x86_64
(gdb) bt
#0 0x000000000053489a in mlx5_tx_mb2mr (mb=0x7fa5d8711180, txq=0x7fa5d812cdc0) at /usr/src/debug/openvswitch-2.9.0-3.el7.tis.1.x86_64/dpdk-17.11/drivers/net/mlx5/mlx5_rxtx.h:551
#1 mlx5_tx_burst_mpw (dpdk_txq=<optimized out>, pkts=0x7ffffae34aa8, pkts_n=<optimized out>) at /usr/src/debug/openvswitch-2.9.0-3.el7.tis.1.x86_64/dpdk-17.11/drivers/net/mlx5/mlx5_rxtx.c:906
#2 0x0000000000410dc5 in rte_eth_tx_burst (nb_pkts=<optimized out>, tx_pkts=0x7ffffae34aa0, queue_id=0, port_id=<optimized out>) at /usr/src/debug/openvswitch-2.9.0-3.el7.tis.1.x86_64/dpdk-17.11/x86_64-native-linuxapp-gcc/include/rte_ethdev.h:3172
#3 netdev_dpdk_eth_tx_burst (cnt=1, pkts=0x7ffffae34aa0, qid=0, dev=0xffffffffffffef40) at lib/netdev-dpdk.c:1690
#4 dpdk_do_tx_copy (netdev=netdev@entry=0x7fa5fffb4700, qid=qid@entry=0, batch=batch@entry=0x160daf0) at lib/netdev-dpdk.c:2089
#5 0x00000000006ae4ab in netdev_dpdk_send__ (concurrent_txq=<optimized out>, batch=0x160daf0, qid=0, dev=<optimized out>) at lib/netdev-dpdk.c:2133
#6 netdev_dpdk_eth_send (netdev=0x7fa5fffb4700, qid=<optimized out>, batch=0x160daf0, concurrent_txq=false) at lib/netdev-dpdk.c:2164
#7 0x00000000005fb521 in netdev_send (netdev=<optimized out>, qid=<optimized out>, batch=batch@entry=0x160daf0, concurrent_txq=concurrent_txq@entry=false) at lib/netdev.c:791
#8 0x00000000005cdf15 in dp_netdev_pmd_flush_output_on_port (pmd=pmd@entry=0x7fa629a74010, p=p@entry=0x160dac0) at lib/dpif-netdev.c:3216
#9 0x00000000005ce247 in dp_netdev_pmd_flush_output_packets (pmd=pmd@entry=0x7fa629a74010, force=force@entry=false) at lib/dpif-netdev.c:3256
#10 0x00000000005d4a68 in dp_netdev_pmd_flush_output_packets (force=false, pmd=0x7fa629a74010) at lib/dpif-netdev.c:3249
#11 dp_netdev_process_rxq_port (pmd=pmd@entry=0x7fa629a74010, rxq=0x1682710, port_no=2) at lib/dpif-netdev.c:3292
#12 0x00000000005d549a in dpif_netdev_run (dpif=<optimized out>) at lib/dpif-netdev.c:3940
#13 0x0000000000592a5a in type_run (type=<optimized out>) at ofproto/ofproto-dpif.c:344
#14 0x000000000057d651 in ofproto_type_run (datapath_type=datapath_type@entry=0x167f5b0 "netdev") at ofproto/ofproto.c:1705
#15 0x000000000056cce5 in bridge_run__ () at vswitchd/bridge.c:2933
#16 0x0000000000572d08 in bridge_run () at vswitchd/bridge.c:2997
#17 0x000000000041246d in main (argc=10, argv=0x7ffffae35328) at vswitchd/ovs-vswitchd.c:119
(gdb)

dpif_netdev_port_add

 

 

Breakpoint 2, dpif_netdev_port_add (dpif=0x204f78a0, netdev=0x19fd81a40, port_nop=0xffffe22502a4) at lib/dpif-netdev.c:1913
1913    {
(gdb) bt
#0  dpif_netdev_port_add (dpif=0x204f78a0, netdev=0x19fd81a40, port_nop=0xffffe22502a4) at lib/dpif-netdev.c:1913
#1  0x000000000097d508 in dpif_port_add (dpif=0x204f78a0, netdev=netdev@entry=0x19fd81a40, port_nop=port_nop@entry=0xffffe225030c) at lib/dpif.c:593
#2  0x000000000092a714 in port_add (ofproto_=0x202de690, netdev=0x19fd81a40) at ofproto/ofproto-dpif.c:3864
#3  0x0000000000920b40 in ofproto_port_add (ofproto=0x202de690, netdev=0x19fd81a40, ofp_portp=ofp_portp@entry=0xffffe2250400) at ofproto/ofproto.c:2070
#4  0x000000000090e530 in iface_do_create (errp=0xffffe2250410, netdevp=0xffffe2250408, ofp_portp=0xffffe2250400, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2060
#5  iface_create (port_cfg=0x2054ec30, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2103
#6  bridge_add_ports__ (br=br@entry=0x202dd9c0, wanted_ports=wanted_ports@entry=0x202ddaa0, with_requested_port=with_requested_port@entry=false) at vswitchd/bridge.c:1167
#7  0x0000000000910278 in bridge_add_ports (wanted_ports=<optimized out>, br=0x202dd9c0) at vswitchd/bridge.c:1183
#8  bridge_reconfigure (ovs_cfg=ovs_cfg@entry=0x202e3c00) at vswitchd/bridge.c:896
#9  0x00000000009134e0 in bridge_run () at vswitchd/bridge.c:3328
#10 0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb)

dpdk_vhost_class && port

static const struct netdev_class dpdk_vhost_class = {
    .type = "dpdkvhostuser",
    NETDEV_DPDK_CLASS_COMMON,
    .construct = netdev_dpdk_vhost_construct,
    .destruct = netdev_dpdk_vhost_destruct,
    .send = netdev_dpdk_vhost_send,// enqeue
    .get_carrier = netdev_dpdk_vhost_get_carrier,
    .get_stats = netdev_dpdk_vhost_get_stats,
    .get_custom_stats = netdev_dpdk_get_sw_custom_stats,
    .get_status = netdev_dpdk_vhost_user_get_status,
    .reconfigure = netdev_dpdk_vhost_reconfigure,
    .rxq_recv = netdev_dpdk_vhost_rxq_recv,  //dequeue
    .rxq_enabled = netdev_dpdk_vhost_rxq_enabled,
};

 

 

static int
dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
                     odp_port_t *port_nop)
{
    struct dp_netdev *dp = get_dp_netdev(dpif);
    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
    const char *dpif_port;
    odp_port_t port_no;
    int error;

    ovs_mutex_lock(&dp->port_mutex);
    dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
    if (*port_nop != ODPP_NONE) {
        port_no = *port_nop;
        error = dp_netdev_lookup_port(dp, *port_nop) ? EBUSY : 0;
    } else {
        port_no = choose_port(dp, dpif_port);
        error = port_no == ODPP_NONE ? EFBIG : 0;
    }
    if (!error) {
        *port_nop = port_no;
        error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
    }
    ovs_mutex_unlock(&dp->port_mutex);

    return error;
}

 

 

(gdb) b dpif_netdev_run
Breakpoint 1 at 0x978ef4: file lib/dpif-netdev.c, line 5438.
(gdb) c
Continuing.

Breakpoint 1, dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
5438    {
(gdb) bt
#0  dpif_netdev_run (dpif=0x204f78a0) at lib/dpif-netdev.c:5438
#1  0x000000000097d290 in dpif_run (dpif=<optimized out>) at lib/dpif.c:463
#2  0x0000000000934c68 in type_run (type=type@entry=0x202db460 "netdev") at ofproto/ofproto-dpif.c:370
#3  0x000000000091eb18 in ofproto_type_run (datapath_type=<optimized out>, datapath_type@entry=0x202db460 "netdev") at ofproto/ofproto.c:1772
#4  0x000000000090d94c in bridge_run__ () at vswitchd/bridge.c:3242
#5  0x0000000000913480 in bridge_run () at vswitchd/bridge.c:3307
#6  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) delete 1
(gdb) b dpif_netdev_port_add
Breakpoint 2 at 0x9747c8: file lib/dpif-netdev.c, line 1913.
(gdb) c
Continuing.
[New Thread 0xffff7c29f910 (LWP 17675)]
[Thread 0xffff7c29f910 (LWP 17675) exited]
[New Thread 0xffff7c29f910 (LWP 17677)]

Breakpoint 2, dpif_netdev_port_add (dpif=0x204f78a0, netdev=0x19fd81a40, port_nop=0xffffe22502a4) at lib/dpif-netdev.c:1913
1913    {
(gdb) bt
#0  dpif_netdev_port_add (dpif=0x204f78a0, netdev=0x19fd81a40, port_nop=0xffffe22502a4) at lib/dpif-netdev.c:1913
#1  0x000000000097d508 in dpif_port_add (dpif=0x204f78a0, netdev=netdev@entry=0x19fd81a40, port_nop=port_nop@entry=0xffffe225030c) at lib/dpif.c:593
#2  0x000000000092a714 in port_add (ofproto_=0x202de690, netdev=0x19fd81a40) at ofproto/ofproto-dpif.c:3864
#3  0x0000000000920b40 in ofproto_port_add (ofproto=0x202de690, netdev=0x19fd81a40, ofp_portp=ofp_portp@entry=0xffffe2250400) at ofproto/ofproto.c:2070
#4  0x000000000090e530 in iface_do_create (errp=0xffffe2250410, netdevp=0xffffe2250408, ofp_portp=0xffffe2250400, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2060
#5  iface_create (port_cfg=0x2054ec30, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2103
#6  bridge_add_ports__ (br=br@entry=0x202dd9c0, wanted_ports=wanted_ports@entry=0x202ddaa0, with_requested_port=with_requested_port@entry=false) at vswitchd/bridge.c:1167
#7  0x0000000000910278 in bridge_add_ports (wanted_ports=<optimized out>, br=0x202dd9c0) at vswitchd/bridge.c:1183
#8  bridge_reconfigure (ovs_cfg=ovs_cfg@entry=0x202e3c00) at vswitchd/bridge.c:896
#9  0x00000000009134e0 in bridge_run () at vswitchd/bridge.c:3328
#10 0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) n
1914        struct dp_netdev *dp = get_dp_netdev(dpif);
(gdb) list
1909
1910    static int
1911    dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
1912                         odp_port_t *port_nop)
1913    {
1914        struct dp_netdev *dp = get_dp_netdev(dpif);
1915        char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
1916        const char *dpif_port;
1917        odp_port_t port_no;
1918        int error;
(gdb) set print pretty on
(gdb) p *dp
value has been optimized out
(gdb) n
1913    {
(gdb) n
1914        struct dp_netdev *dp = get_dp_netdev(dpif);
(gdb) n
1913    {
(gdb) p *dp
value has been optimized out
(gdb) p *dpif
$1 = {
  dpif_class = 0xbd2650 <dpif_netdev_class>, 
  base_name = 0x204f73e0 "ovs-netdev", 
  full_name = 0x204f78e0 "netdev@ovs-netdev", 
  netflow_engine_type = 47 '/', 
  netflow_engine_id = 209 '321', 
  current_ms = 465573501
}
(gdb) n
1914        struct dp_netdev *dp = get_dp_netdev(dpif);
(gdb) n
1920        ovs_mutex_lock(&dp->port_mutex);
(gdb) p *dp
value has been optimized out
(gdb) n
[Thread 0xffff7c29f910 (LWP 17677) exited]
1921        dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
(gdb) p *netdev
$2 = {
  name = 0x20500a30 "vhost-user2", 
  netdev_class = 0xc090e0 <dpdk_vhost_class>, 
  auto_classified = false, 
  ol_flags = 0, 
  mtu_user_config = false, 
  ref_cnt = 1, 
  change_seq = 2, 
  reconfigure_seq = 0x2029d280, 
  last_reconfigure_seq = 16781297, 
  n_txq = 0, 
  n_rxq = 0, 
  node = 0x20533f50, 
  saved_flags_list = {
    prev = 0x19fd81a90, 
    next = 0x19fd81a90
  }, 
  flow_api = {
    p = 0x0
  }, 
  hw_info = {
    oor = false, 
    offload_count = 0, 
    pending_count = 0
  }
}
(gdb) n
1922        if (*port_nop != ODPP_NONE) {
(gdb) n
1921        dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
(gdb) n
1922        if (*port_nop != ODPP_NONE) {
(gdb) n
1926            port_no = choose_port(dp, dpif_port);
(gdb) n
1930            *port_nop = port_no;
(gdb) n
1931            error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
(gdb) p *netdev
$3 = {
  name = 0x20500a30 "vhost-user2", 
  netdev_class = 0xc090e0 <dpdk_vhost_class>, 
  auto_classified = false, 
  ol_flags = 0, 
  mtu_user_config = false, 
  ref_cnt = 1, 
  change_seq = 2, 
  reconfigure_seq = 0x2029d280, 
  last_reconfigure_seq = 16781297, 
  n_txq = 0, 
  n_rxq = 0, 
  node = 0x20533f50, 
  saved_flags_list = {
    prev = 0x19fd81a90, 
    next = 0x19fd81a90
  }, 
  flow_api = {
    p = 0x0
  }, 
  hw_info = {
    oor = false, 
    offload_count = 0, 
    pending_count = 0
  }
}
(gdb) n
[New Thread 0xffff7c29f910 (LWP 17711)]
1933        ovs_mutex_unlock(&dp->port_mutex);
(gdb) n
1936    }
(gdb) n
dpif_port_add (dpif=0x204f78a0, netdev=netdev@entry=0x19fd81a40, port_nop=port_nop@entry=0xffffe225030c) at lib/dpif.c:594
594         if (!error) {
(gdb) n
595             VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu32,
(gdb) n
598             if (!dpif_is_tap_port(netdev_get_type(netdev))) {
(gdb) n
602                 dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev));
(gdb) n
604                 dpif_port.port_no = port_no;
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p *netdev
$4 = {
  name = 0x20500a30 "vhost-user2", 
  netdev_class = 0xc090e0 <dpdk_vhost_class>, 
  auto_classified = false, 
  ol_flags = 0, 
  mtu_user_config = false, 
  ref_cnt = 3, 
  change_seq = 3, 
  reconfigure_seq = 0x2029d280, 
  last_reconfigure_seq = 16781303, 
  n_txq = 1, 
  n_rxq = 1, 
  node = 0x20533f50, 
  saved_flags_list = {
    prev = 0x19fd81a90, 
    next = 0x19fd81a90
  }, 
  flow_api = {
    p = 0x0
  }, 
  hw_info = {
    oor = false, 
    offload_count = 0, 
    pending_count = 0
  }
}
(gdb) p dpif_port
$5 = {
  name = 0x20500a30 "vhost-user2", 
  type = 0xffff <Address 0xffff out of bounds>, 
  port_no = 539616016
}
(gdb) p *(dpif->dpif_class)
$6 = {
  type = 0xbd4548 "netdev", 
  cleanup_required = true, 
  init = 0x96cd7c <dpif_netdev_init>, 
  enumerate = 0x96f3c4 <dpif_netdev_enumerate>, 
  port_open_type = 0x96c2b4 <dpif_netdev_port_open_type>, 
  open = 0x974c00 <dpif_netdev_open>, 
  close = 0x9744b0 <dpif_netdev_close>, 
  destroy = 0x96e734 <dpif_netdev_destroy>, 
  run = 0x978ef4 <dpif_netdev_run>, 
  wait = 0x971798 <dpif_netdev_wait>, 
  get_stats = 0x96e63c <dpif_netdev_get_stats>, 
  set_features = 0x0, 
  port_add = 0x9747c8 <dpif_netdev_port_add>, 
  port_del = 0x9744f4 <dpif_netdev_port_del>, 
  port_set_config = 0x971340 <dpif_netdev_port_set_config>, 
  port_query_by_number = 0x9716b4 <dpif_netdev_port_query_by_number>, 
  port_query_by_name = 0x970af4 <dpif_netdev_port_query_by_name>, 
  port_get_pid = 0x0, 
  port_dump_start = 0x96c1d0 <dpif_netdev_port_dump_start>, 
  port_dump_next = 0x96e580 <dpif_netdev_port_dump_next>, 
  port_dump_done = 0x96c4e8 <dpif_netdev_port_dump_done>, 
  port_poll = 0x96e7f0 <dpif_netdev_port_poll>, 
  port_poll_wait = 0x96e7ac <dpif_netdev_port_poll_wait>, 
  flow_flush = 0x96f7f0 <dpif_netdev_flow_flush>, 
  flow_dump_create = 0x96c204 <dpif_netdev_flow_dump_create>, 
  flow_dump_destroy = 0x96c9d0 <dpif_netdev_flow_dump_destroy>, 
  flow_dump_thread_create = 0x96c808 <dpif_netdev_flow_dump_thread_create>, 
  flow_dump_thread_destroy = 0x96c4e4 <dpif_netdev_flow_dump_thread_destroy>, 
  flow_dump_next = 0x96ebe4 <dpif_netdev_flow_dump_next>, 
  operate = 0x97711c <dpif_netdev_operate>, 
  recv_set = 0x0, 
  handlers_set = 0x0, 
  set_config = 0x96e1a0 <dpif_netdev_set_config>, 
  queue_to_priority = 0x96c130 <dpif_netdev_queue_to_priority>, 
  recv = 0x0, 
  recv_wait = 0x0, 
  recv_purge = 0x0, 
  register_dp_purge_cb = 0x96e164 <dpif_netdev_register_dp_purge_cb>, 
  register_upcall_cb = 0x96e128 <dpif_netdev_register_upcall_cb>, 
  enable_upcall = 0x96e0f0 <dpif_netdev_enable_upcall>, 
  disable_upcall = 0x96e0b8 <dpif_netdev_disable_upcall>, 
  get_datapath_version = 0x96c1f8 <dpif_netdev_get_datapath_version>, 
  ct_dump_start = 0x96e034 <dpif_netdev_ct_dump_start>, 
  ct_dump_next = 0x96cbd8 <dpif_netdev_ct_dump_next>, 
  ct_dump_done = 0x96cba0 <dpif_netdev_ct_dump_done>, 
  ct_flush = 0x96dfdc <dpif_netdev_ct_flush>, 
  ct_set_maxconns = 0x96dfa4 <dpif_netdev_ct_set_maxconns>, 
  ct_get_maxconns = 0x96df6c <dpif_netdev_ct_get_maxconns>, 
  ct_get_nconns = 0x96df34 <dpif_netdev_ct_get_nconns>, 
  ct_set_tcp_seq_chk = 0x96def8 <dpif_netdev_ct_set_tcp_seq_chk>, 
  ct_get_tcp_seq_chk = 0x96deac <dpif_netdev_ct_get_tcp_seq_chk>, 
  ct_set_limits = 0x96ddfc <dpif_netdev_ct_set_limits>, 
  ct_get_limits = 0x96dcf0 <dpif_netdev_ct_get_limits>, 
  ct_del_limits = 0x96dc60 <dpif_netdev_ct_del_limits>, 
  ct_set_timeout_policy = 0x0, 
  ct_get_timeout_policy = 0x0, 
  ct_del_timeout_policy = 0x0, 
  ct_timeout_policy_dump_start = 0x0, 
---Type <return> to continue, or q <return> to quit---
  ct_timeout_policy_dump_next = 0x0, 
  ct_timeout_policy_dump_done = 0x0, 
  ct_get_timeout_policy_name = 0x0, 
  ipf_set_enabled = 0x96dc0c <dpif_netdev_ipf_set_enabled>, 
  ipf_set_min_frag = 0x96dbb8 <dpif_netdev_ipf_set_min_frag>, 
  ipf_set_max_nfrags = 0x96db74 <dpif_netdev_ipf_set_max_nfrags>, 
  ipf_get_status = 0x96db28 <dpif_netdev_ipf_get_status>, 
  ipf_dump_start = 0x96cb98 <dpif_netdev_ipf_dump_start>, 
  ipf_dump_next = 0x96dadc <dpif_netdev_ipf_dump_next>, 
  ipf_dump_done = 0x96cb90 <dpif_netdev_ipf_dump_done>, 
  meter_get_features = 0x96c1a8 <dpif_netdev_meter_get_features>, 
  meter_set = 0x96d900 <dpif_netdev_meter_set>, 
  meter_get = 0x96d718 <dpif_netdev_meter_get>, 
  meter_del = 0x96d854 <dpif_netdev_meter_del>
}
(gdb) 

 

(gdb) n
602                 dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev));
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p dpif_port.type
$7 = 0xc0b588 "dpdkvhostuser"
(gdb) 

 

 

(gdb) n
602                 dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev));
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p dpif_port.type
$7 = 0xc0b588 "dpdkvhostuser"
(gdb) n
603                 dpif_port.name = CONST_CAST(char *, netdev_name);
(gdb) n
604                 dpif_port.port_no = port_no;
(gdb) p dpif_port.name
$8 = 0x20500a30 "vhost-user2"
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p  dpif_port.port_no
$9 = 3
(gdb) n
[Thread 0xffff7c29f910 (LWP 17711) exited]
612         if (port_nop) {
(gdb) n
613             *port_nop = port_no;
(gdb) n
616     }
(gdb) n

 

 

 

 (gdb) n
602                 dpif_port.type = CONST_CAST(char *, netdev_get_type(netdev));
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p dpif_port.type
$7 = 0xc0b588 "dpdkvhostuser"
(gdb) n
603                 dpif_port.name = CONST_CAST(char *, netdev_name);
(gdb) n
604                 dpif_port.port_no = port_no;
(gdb) p dpif_port.name
$8 = 0x20500a30 "vhost-user2"
(gdb) n
605                 netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port);
(gdb) p  dpif_port.port_no
$9 = 3
(gdb) n
[Thread 0xffff7c29f910 (LWP 17711) exited]
612         if (port_nop) {
(gdb) n
613             *port_nop = port_no;
(gdb) n
616     }
(gdb) n
port_add (ofproto_=0x202de690, netdev=0x19fd81a40) at ofproto/ofproto-dpif.c:3865
3865            if (error) {
(gdb) n
3868            if (netdev_get_tunnel_config(netdev)) {
(gdb) n
[New Thread 0xffff7c29f910 (LWP 17739)]
3874        if (netdev_get_tunnel_config(netdev)) {
(gdb) n
3877            sset_add(&ofproto->ports, devname);
(gdb) n
3879        return 0;
(gdb) n
3880    }
(gdb) n
ofproto_port_add (ofproto=0x202de690, netdev=0x19fd81a40, ofp_portp=ofp_portp@entry=0xffffe2250400) at ofproto/ofproto.c:2071
2071        if (!error) {
(gdb) n
2072            const char *netdev_name = netdev_get_name(netdev);
(gdb) n
[Thread 0xffff7c29f910 (LWP 17739) exited]
[New Thread 0xffff7c24f910 (LWP 17740)]
2074            simap_put(&ofproto->ofp_requests, netdev_name,
(gdb) p netdev_name
$10 = 0x20500a30 "vhost-user2"
(gdb) n
2076            error = update_port(ofproto, netdev_name);
(gdb) n
2078        if (ofp_portp) {
(gdb) n
2079            *ofp_portp = OFPP_NONE;
(gdb) n
2080            if (!error) {
(gdb) n
2083                error = ofproto_port_query_by_name(ofproto,
(gdb) n
[Thread 0xffff7c24f910 (LWP 17740) exited]
[New Thread 0xffff7c29f910 (LWP 17741)]
2086                if (!error) {
(gdb) n
2087                    *ofp_portp = ofproto_port.ofp_port;
(gdb) n
2088                    ofproto_port_destroy(&ofproto_port);
(gdb) n
2087                    *ofp_portp = ofproto_port.ofp_port;
(gdb) n
2088                    ofproto_port_destroy(&ofproto_port);
(gdb) n
[Thread 0xffff7c29f910 (LWP 17741) exited]
[New Thread 0xffff7c24f910 (LWP 17742)]
2093    }
(gdb) n
iface_do_create (errp=0xffffe2250410, netdevp=0xffffe2250408, ofp_portp=0xffffe2250400, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2061
2061        if (error) {
(gdb) n
2072        VLOG_INFO("bridge %s: added interface %s on port %d",
(gdb) n
[Thread 0xffff7c24f910 (LWP 17742) exited]
[New Thread 0xffff7c29f910 (LWP 17743)]
2075        *netdevp = netdev;
(gdb) n
iface_create (port_cfg=0x2054ec30, iface_cfg=0x20531860, br=0x202dd9c0) at vswitchd/bridge.c:2111
2111        port = port_lookup(br, port_cfg->name);
(gdb) n
2103        error = iface_do_create(br, iface_cfg, &ofp_port, &netdev, &errp);
(gdb) n
2111        port = port_lookup(br, port_cfg->name);
(gdb) n
2112        if (!port) {
(gdb) n
2113            port = port_create(br, port_cfg);
(gdb) delete 1
No breakpoint number 1.
(gdb) quit
A debugging session is active.

        Inferior 1 [process 17155] will be detached.

Quit anyway? (y or n) y
Detaching from program: /usr/sbin/ovs-vswitchd, process 17155
[Inferior 1 (process 17155) detached]
[root@localhost ovs]# 

 

 

 

 

 

 

iface_do_create(const struct bridge *br,
                const struct ovsrec_interface *iface_cfg,
                ofp_port_t *ofp_portp, struct netdev **netdevp,
                char **errp)
{
    struct netdev *netdev = NULL;
    int error;
    const char *type;

    if (netdev_is_reserved_name(iface_cfg->name)) {
        VLOG_WARN("could not create interface %s, name is reserved",
                  iface_cfg->name);
        error = EINVAL;
        goto error;
    }

    type = ofproto_port_open_type(br->ofproto,
                                  iface_get_type(iface_cfg, br->cfg));
    error = netdev_open(iface_cfg->name, type, &netdev);
    if (error) {
        VLOG_WARN_BUF(errp, "could not open network device %s (%s)",
                      iface_cfg->name, ovs_strerror(error));
        goto error;
    }

    error = iface_set_netdev_config(iface_cfg, netdev, errp);
    if (error) {
        goto error;
    }

 

netdev_dpdk_vhost_construct

Breakpoint 1, netdev_dpdk_vhost_construct (netdev=0x19fd81a40) at lib/netdev-dpdk.c:1369
1369    {
(gdb) bt
#0  netdev_dpdk_vhost_construct (netdev=0x19fd81a40) at lib/netdev-dpdk.c:1369
#1  0x00000000009a3d60 in netdev_open (name=<optimized out>, type=0x20532350 "dpdkvhostuser", netdevp=netdevp@entry=0xffffe2250418) at lib/netdev.c:436
#2  0x000000000090e488 in iface_do_create (errp=0xffffe2250410, netdevp=0xffffe2250408, ofp_portp=0xffffe2250400, iface_cfg=0x2052bcf0, br=0x202dd9c0) at vswitchd/bridge.c:2045
#3  iface_create (port_cfg=0x20550ac0, iface_cfg=0x2052bcf0, br=0x202dd9c0) at vswitchd/bridge.c:2103
#4  bridge_add_ports__ (br=br@entry=0x202dd9c0, wanted_ports=wanted_ports@entry=0x202ddaa0, with_requested_port=with_requested_port@entry=false) at vswitchd/bridge.c:1167
#5  0x0000000000910278 in bridge_add_ports (wanted_ports=<optimized out>, br=0x202dd9c0) at vswitchd/bridge.c:1183
#6  bridge_reconfigure (ovs_cfg=ovs_cfg@entry=0x202e3c00) at vswitchd/bridge.c:896
#7  0x00000000009134e0 in bridge_run () at vswitchd/bridge.c:3328
#8  0x000000000042469c in main (argc=11, argv=0xffffe2250958) at vswitchd/ovs-vswitchd.c:127
(gdb) 
int
netdev_open(const char *name, const char *type, struct netdev **netdevp)
    OVS_EXCLUDED(netdev_mutex)
{
    struct netdev *netdev;
    int error = 0;

    if (!name[0]) {
        /* Reject empty names.  This saves the providers having to do this.  At
         * least one screwed this up: the netdev-linux "tap" implementation
         * passed the name directly to the Linux TUNSETIFF call, which treats
         * an empty string as a request to generate a unique name. */
        return EINVAL;
    }

    netdev_initialize();

    ovs_mutex_lock(&netdev_mutex);
    netdev = shash_find_data(&netdev_shash, name);

    if (netdev &&
        type && type[0] && strcmp(type, netdev->netdev_class->type)) {

        if (netdev->auto_classified) {
            /* If this device was first created without a classification type,
             * for example due to routing or tunneling code, and they keep a
             * reference, a "classified" call to open will fail. In this case
             * we remove the classless device, and re-add it below. We remove
             * the netdev from the shash, and change the sequence, so owners of
             * the old classless device can release/cleanup. */
            if (netdev->node) {
                shash_delete(&netdev_shash, netdev->node);
                netdev->node = NULL;
                netdev_change_seq_changed(netdev);
            }

            netdev = NULL;
        } else {
            error = EEXIST;
        }
    }

    if (!netdev) {
        struct netdev_registered_class *rc;

        rc = netdev_lookup_class(type && type[0] ? type : "system");
        if (rc && ovs_refcount_try_ref_rcu(&rc->refcnt)) {
            netdev = rc->class->alloc();
            if (netdev) {
                memset(netdev, 0, sizeof *netdev);
                netdev->netdev_class = rc->class;
                netdev->auto_classified = type && type[0] ? false : true;
                netdev->name = xstrdup(name);
                netdev->change_seq = 1;
                netdev->reconfigure_seq = seq_create();
                netdev->last_reconfigure_seq =
                    seq_read(netdev->reconfigure_seq);
                ovsrcu_set(&netdev->flow_api, NULL);
                netdev->hw_info.oor = false;
                netdev->node = shash_add(&netdev_shash, name, netdev);

                /* By default enable one tx and rx queue per netdev. */
                netdev->n_txq = netdev->netdev_class->send ? 1 : 0;
                netdev->n_rxq = netdev->netdev_class->rxq_alloc ? 1 : 0;

                ovs_list_init(&netdev->saved_flags_list);

                error = rc->class->construct(netdev);

//调用construct
if (!error) { netdev_change_seq_changed(netdev); } else { ovs_refcount_unref(&rc->refcnt); seq_destroy(netdev->reconfigure_seq); free(netdev->name); ovs_assert(ovs_list_is_empty(&netdev->saved_flags_list)); shash_delete(&netdev_shash, netdev->node); rc->class->dealloc(netdev); } } else { error = ENOMEM; } } else { VLOG_WARN("could not create netdev %s of unknown type %s", name, type); error = EAFNOSUPPORT; } } if (!error) { netdev->ref_cnt++; *netdevp = netdev; } else { *netdevp = NULL; } ovs_mutex_unlock(&netdev_mutex); return error; }

 

 

netdev_class netdev_dpdk_class

static struct netdev_class netdev_dpdk_class = {
    "dpdk",
    dpdk_class_init,            /* init */
    NULL,                       /* netdev_dpdk_run */
    NULL,                       /* netdev_dpdk_wait */

    netdev_dpdk_alloc,
    netdev_dpdk_construct,
    netdev_dpdk_destruct,
    netdev_dpdk_dealloc,
    netdev_dpdk_get_config,
    NULL,                       /* netdev_dpdk_set_config */
    NULL,                       /* get_tunnel_config */

    netdev_dpdk_send,           /* send */
    NULL,                       /* send_wait */

    netdev_dpdk_set_etheraddr,
    netdev_dpdk_get_etheraddr,
    netdev_dpdk_get_mtu,
    netdev_dpdk_set_mtu,
    netdev_dpdk_get_ifindex,
    netdev_dpdk_get_carrier,
    netdev_dpdk_get_carrier_resets,
    netdev_dpdk_set_miimon,
    netdev_dpdk_get_stats,
    netdev_dpdk_set_stats,
    netdev_dpdk_get_features,
    NULL,                       /* set_advertisements */

    NULL,                       /* set_policing */
    NULL,                       /* get_qos_types */
    NULL,                       /* get_qos_capabilities */
    NULL,                       /* get_qos */
    NULL,                       /* set_qos */
    NULL,                       /* get_queue */
    NULL,                       /* set_queue */
    NULL,                       /* delete_queue */
    NULL,                       /* get_queue_stats */
    NULL,                       /* queue_dump_start */
    NULL,                       /* queue_dump_next */
    NULL,                       /* queue_dump_done */
    NULL,                       /* dump_queue_stats */

    NULL,                       /* get_in4 */
    NULL,                       /* set_in4 */
    NULL,                       /* get_in6 */
    NULL,                       /* add_router */
    NULL,                       /* get_next_hop */
    netdev_dpdk_get_status,
    NULL,                       /* arp_lookup */

    netdev_dpdk_update_flags,

    netdev_dpdk_rxq_alloc,
    netdev_dpdk_rxq_construct,
    netdev_dpdk_rxq_destruct,
    netdev_dpdk_rxq_dealloc,
    netdev_dpdk_rxq_recv,
    NULL,                       /* rxq_wait */
    NULL,                       /* rxq_drain */
};

 ovs-vsctl add-port br0 dpdk1 -- set Interface dpdk1 type=dpdk options:dpdk-devargs=0000:05:00.0

(gdb) b netdev_dpdk_construct
Breakpoint 1 at 0xa5aca0: file lib/netdev-dpdk.c, line 1467.
(gdb) b netdev_dpdk_send
Function "netdev_dpdk_send" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b netdev_dpdk_send
Function "netdev_dpdk_send" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (netdev_dpdk_send) pending.
(gdb) b  netdev_dpdk_rxq_recv
Breakpoint 3 at 0xa62fd8: file lib/netdev-dpdk.c, line 2489.
(gdb) c
Continuing.

Breakpoint 1, netdev_dpdk_construct (netdev=0x19fd81ec0) at lib/netdev-dpdk.c:1467
1467    {
(gdb) bt
#0  netdev_dpdk_construct (netdev=0x19fd81ec0) at lib/netdev-dpdk.c:1467
#1  0x00000000009a3d60 in netdev_open (name=<optimized out>, type=0x6ed09a0 "dpdk", netdevp=netdevp@entry=0xfffff6389b38) at lib/netdev.c:436
#2  0x000000000090e488 in iface_do_create (errp=0xfffff6389b30, netdevp=0xfffff6389b28, ofp_portp=0xfffff6389b20, iface_cfg=0x5476680, br=0x51d29b0) at vswitchd/bridge.c:2045
#3  iface_create (port_cfg=0x6ed09c0, iface_cfg=0x5476680, br=0x51d29b0) at vswitchd/bridge.c:2103
#4  bridge_add_ports__ (br=br@entry=0x51d29b0, wanted_ports=wanted_ports@entry=0x51d2a90, with_requested_port=with_requested_port@entry=false) at vswitchd/bridge.c:1167
#5  0x0000000000910278 in bridge_add_ports (wanted_ports=<optimized out>, br=0x51d29b0) at vswitchd/bridge.c:1183
#6  bridge_reconfigure (ovs_cfg=ovs_cfg@entry=0x51d0620) at vswitchd/bridge.c:896
#7  0x00000000009134e0 in bridge_run () at vswitchd/bridge.c:3328
#8  0x000000000042469c in main (argc=11, argv=0xfffff638a078) at vswitchd/ovs-vswitchd.c:127
(gdb) c
Continuing.
[New Thread 0xffffb43df910 (LWP 25825)]
[Switching to Thread 0xfffd53ffd510 (LWP 19066)]

Breakpoint 3, netdev_dpdk_rxq_recv (rxq=0x19fd81400, batch=0xfffd53ffca80, qfill=0x0) at lib/netdev-dpdk.c:2489
2489    {
(gdb) bt
#0  netdev_dpdk_rxq_recv (rxq=0x19fd81400, batch=0xfffd53ffca80, qfill=0x0) at lib/netdev-dpdk.c:2489
#1  0x00000000009a440c in netdev_rxq_recv (rx=<optimized out>, batch=batch@entry=0xfffd53ffca80, qfill=<optimized out>) at lib/netdev.c:726
#2  0x00000000009785bc in dp_netdev_process_rxq_port (pmd=pmd@entry=0x5d3f680, rxq=0x51d14a0, port_no=3) at lib/dpif-netdev.c:4461
#3  0x0000000000978a24 in pmd_thread_main (f_=0x5d3f680) at lib/dpif-netdev.c:5731
#4  0x00000000009fc5dc in ovsthread_wrapper (aux_=<optimized out>) at lib/ovs-thread.c:383
#5  0x0000ffffb7fd7d38 in start_thread (arg=0xfffd53ffd510) at pthread_create.c:309
#6  0x0000ffffb7cbf690 in thread_start () from /lib64/libc.so.6
(gdb) c
Continuing.

 

netdev_dpdk|INFO|vHost Device '/var/run/openvswitch/vhost-user1' has been removed

destroy_device(int vid)
{
    struct netdev_dpdk *dev;
    bool exists = false;
    char ifname[IF_NAME_SZ];

    rte_vhost_get_ifname(vid, ifname, sizeof ifname);

    ovs_mutex_lock(&dpdk_mutex);
    LIST_FOR_EACH (dev, list_node, &dpdk_list) {
        if (netdev_dpdk_get_vid(dev) == vid) {

            ovs_mutex_lock(&dev->mutex);
            dev->vhost_reconfigured = false;
            ovsrcu_index_set(&dev->vid, -1);
            memset(dev->vhost_rxq_enabled, 0,
                   dev->up.n_rxq * sizeof *dev->vhost_rxq_enabled);
            netdev_dpdk_txq_map_clear(dev);

            netdev_change_seq_changed(&dev->up);
            ovs_mutex_unlock(&dev->mutex);
            exists = true;
            break;
        }
    }

    ovs_mutex_unlock(&dpdk_mutex);

    if (exists) {
        /*
         * Wait for other threads to quiesce after setting the 'virtio_dev'
         * to NULL, before returning.
         */
        ovsrcu_synchronize();
        /*
         * As call to ovsrcu_synchronize() will end the quiescent state,
         * put thread back into quiescent state before returning.
         */
        ovsrcu_quiesce_start();
        VLOG_INFO("vHost Device '%s' has been removed", ifname);
    } else {
        VLOG_INFO("vHost Device '%s' not found", ifname);
    }
}

 

原文地址:https://www.cnblogs.com/dream397/p/14173700.html