diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 6e09e44ebe7..83a30978880 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2602,6 +2602,9 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) pmd = ovsthread_getspecific(dp->per_pmd_key); if (!pmd) { pmd = dp_netdev_get_pmd(dp, NON_PMD_CORE_ID); + if (!pmd) { + return EBUSY; + } } /* If the current thread is non-pmd thread, acquires @@ -2967,25 +2970,28 @@ dpif_netdev_run(struct dpif *dpif) { struct dp_netdev_port *port; struct dp_netdev *dp = get_dp_netdev(dpif); - struct dp_netdev_pmd_thread *non_pmd = dp_netdev_get_pmd(dp, - NON_PMD_CORE_ID); + struct dp_netdev_pmd_thread *non_pmd; uint64_t new_tnl_seq; ovs_mutex_lock(&dp->port_mutex); - ovs_mutex_lock(&dp->non_pmd_mutex); - HMAP_FOR_EACH (port, node, &dp->ports) { - if (!netdev_is_pmd(port->netdev)) { - int i; + non_pmd = dp_netdev_get_pmd(dp, NON_PMD_CORE_ID); + if (non_pmd) { + ovs_mutex_lock(&dp->non_pmd_mutex); + HMAP_FOR_EACH (port, node, &dp->ports) { + if (!netdev_is_pmd(port->netdev)) { + int i; - for (i = 0; i < port->n_rxq; i++) { - dp_netdev_process_rxq_port(non_pmd, port, port->rxqs[i].rxq); + for (i = 0; i < port->n_rxq; i++) { + dp_netdev_process_rxq_port(non_pmd, port, + port->rxqs[i].rxq); + } } } - } - dpif_netdev_xps_revalidate_pmd(non_pmd, time_msec(), false); - ovs_mutex_unlock(&dp->non_pmd_mutex); + dpif_netdev_xps_revalidate_pmd(non_pmd, time_msec(), false); + ovs_mutex_unlock(&dp->non_pmd_mutex); - dp_netdev_pmd_unref(non_pmd); + dp_netdev_pmd_unref(non_pmd); + } if (dp_netdev_is_reconf_required(dp) || ports_require_restart(dp)) { reconfigure_pmd_threads(dp); @@ -3189,7 +3195,8 @@ dp_netdev_pmd_reload_done(struct dp_netdev_pmd_thread *pmd) } /* Finds and refs the dp_netdev_pmd_thread on core 'core_id'. Returns - * the pointer if succeeds, otherwise, NULL. + * the pointer if succeeds, otherwise, NULL (it can return NULL even if + * 'core_id' is NON_PMD_CORE_ID). * * Caller must unrefs the returned reference. */ static struct dp_netdev_pmd_thread * diff --git a/tests/pmd.at b/tests/pmd.at index 67382113e1e..7b63b671313 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -516,3 +516,41 @@ p1 3 0 2 OVS_VSWITCHD_STOP(["/dpif_netdev|WARN|There is no PMD thread on core/d"]) AT_CLEANUP + +AT_SETUP([PMD - monitor threads]) +OVS_VSWITCHD_START( + [], [], [], [--dummy-numa 0,0]) +AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg]) + +dnl The two devices are connected together externally using net.sock +AT_CHECK([ovs-vsctl add-port br0 p1 -- set Interface p1 type=dummy-pmd ofport_request=1 options:n_rxq=1 options:pstream=punix:$OVS_RUNDIR/net.sock]) +AT_CHECK([ovs-vsctl add-port br0 p2 -- set Interface p2 type=dummy-pmd ofport_request=2 options:n_rxq=1 options:stream=unix:$OVS_RUNDIR/net.sock]) + +AT_CHECK([ovs-appctl dpif-netdev/pmd-rxq-show | parse_pmd_rxq_show], [0], [dnl +p1 0 0 0 +p2 0 0 0 +]) + +dnl Enable bfd with a very aggressive interval. This will make the monitor very +dnl busy, and uncover race conditions with the main thread. +AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true bfd:min_rx=1 bfd:min_tx=1]) +AT_CHECK([ovs-vsctl set Interface p2 bfd:enable=true bfd:min_rx=1 bfd:min_tx=1]) + +AT_CHECK([ovs-vsctl --timeout=10 wait-until Interface p1 bfd_status:forwarding=true \ + -- wait-until Interface p2 bfd_status:forwarding=true]) + +dnl Trigger reconfiguration of the datapath +AT_CHECK([ovs-vsctl set Interface p1 options:n_rxq=2]) +AT_CHECK([ovs-vsctl set Interface p2 options:n_rxq=2]) + +dnl Make sure that reconfiguration succeded +AT_CHECK([ovs-appctl dpif-netdev/pmd-rxq-show | parse_pmd_rxq_show], [0], [dnl +p1 0 0 0 +p1 1 0 0 +p2 0 0 0 +p2 1 0 0 +]) + +dnl During reconfiguration some packets will be dropped. This is expected +OVS_VSWITCHD_STOP(["/dpif(monitor[[0-9]]\+)|WARN|dummy@ovs-dummy: execute [[0-9]]\+ failed/d"]) +AT_CLEANUP