@@ -345,6 +345,12 @@ dpdk_init__(const struct smap *ovs_other_config)
vhost_sock_dir = sock_dir_subcomponent;
}
+ if (smap_get_bool(ovs_other_config, "dpdk-lsc-interrupt", false)) {
+ netdev_dpdk_set_default_lsc_detect_mode(NETDEV_DPDK_LSC_DETECT_INTERRUPT_MODE);
+ } else {
+ netdev_dpdk_set_default_lsc_detect_mode(NETDEV_DPDK_LSC_DETECT_POLL_MODE);
+ }
+
argv = grow_argv(&argv, 0, 1);
argc = 1;
argv[0] = xstrdup(ovs_get_program_name());
@@ -146,7 +146,7 @@ typedef uint8_t dpdk_port_t;
#define VHOST_ENQ_RETRY_NUM 8
#define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
-static const struct rte_eth_conf port_conf = {
+static struct rte_eth_conf port_conf = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
.split_hdr_size = 0,
@@ -165,6 +165,9 @@ static const struct rte_eth_conf port_conf = {
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
+ .intr_conf = {
+ .lsc = (uint16_t)NETDEV_DPDK_LSC_DETECT_POLL_MODE, /* LSC interrupt mode disabled, polling mode used. */
+ },
};
/*
@@ -397,6 +400,9 @@ struct netdev_dpdk {
int requested_n_rxq;
int requested_rxq_size;
int requested_txq_size;
+ enum netdev_dpdk_lsc_detect_mode requested_lsc_detect_mode;
+
+ enum netdev_dpdk_lsc_detect_mode lsc_detect_mode;
/* Number of rx/tx descriptors for physical devices */
int rxq_size;
@@ -430,6 +436,18 @@ int netdev_dpdk_get_vid(const struct netdev_dpdk *dev);
struct ingress_policer *
netdev_dpdk_get_ingress_policer(const struct netdev_dpdk *dev);
+void
+netdev_dpdk_set_default_lsc_detect_mode(enum netdev_dpdk_lsc_detect_mode default_lsc)
+{
+ port_conf.intr_conf.lsc = (uint16_t)default_lsc;
+}
+
+enum netdev_dpdk_lsc_detect_mode
+netdev_dpdk_get_default_lsc_detect_mode(void)
+{
+ return port_conf.intr_conf.lsc;
+}
+
static bool
is_dpdk_class(const struct netdev_class *class)
{
@@ -663,6 +681,8 @@ dpdk_eth_dev_queue_setup(struct netdev_dpdk *dev, int n_rxq, int n_txq)
int i;
struct rte_eth_conf conf = port_conf;
+ conf.intr_conf.lsc = dev->lsc_detect_mode;
+
/* For some NICs (e.g. Niantic), scatter_rx mode needs to be explicitly
* enabled. */
if (dev->mtu > ETHER_MTU) {
@@ -868,6 +888,7 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no,
dev->flags = 0;
dev->requested_mtu = ETHER_MTU;
dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu);
+ dev->requested_lsc_detect_mode = netdev_dpdk_get_default_lsc_detect_mode();
ovsrcu_index_init(&dev->vid, -1);
dev->vhost_reconfigured = false;
dev->attached = false;
@@ -2005,6 +2026,38 @@ netdev_dpdk_set_mtu(struct netdev *netdev, int mtu)
}
static int
+netdev_dpdk_get_lsc_detect_mode(const struct netdev *netdev, uint16_t *lscp)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+
+ ovs_mutex_lock(&dev->mutex);
+ *lscp = (uint16_t)dev->lsc_detect_mode;
+ ovs_mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static int
+netdev_dpdk_set_lsc_detect_mode(struct netdev *netdev, uint16_t lsc_detect_mode)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+
+ if (lsc_detect_mode > NETDEV_DPDK_LSC_DETECT_MAX) {
+ VLOG_WARN("%s: invalid LSC value %d\n", dev->up.name, lsc_detect_mode);
+ return EINVAL;
+ }
+
+ ovs_mutex_lock(&dev->mutex);
+ if (dev->requested_lsc_detect_mode != (enum netdev_dpdk_lsc_detect_mode)lsc_detect_mode) {
+ dev->requested_lsc_detect_mode = (enum netdev_dpdk_lsc_detect_mode)lsc_detect_mode;
+ netdev_request_reconfigure(netdev);
+ }
+ ovs_mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static int
netdev_dpdk_get_carrier(const struct netdev *netdev, bool *carrier);
static int
@@ -3166,6 +3219,7 @@ netdev_dpdk_reconfigure(struct netdev *netdev)
if (netdev->n_txq == dev->requested_n_txq
&& netdev->n_rxq == dev->requested_n_rxq
&& dev->mtu == dev->requested_mtu
+ && dev->lsc_detect_mode == dev->requested_lsc_detect_mode
&& dev->rxq_size == dev->requested_rxq_size
&& dev->txq_size == dev->requested_txq_size
&& dev->socket_id == dev->requested_socket_id) {
@@ -3181,6 +3235,8 @@ netdev_dpdk_reconfigure(struct netdev *netdev)
goto out;
}
+ dev->lsc_detect_mode = dev->requested_lsc_detect_mode;
+
netdev->n_txq = dev->requested_n_txq;
netdev->n_rxq = dev->requested_n_rxq;
@@ -3343,6 +3399,8 @@ unlock:
netdev_dpdk_get_etheraddr, \
netdev_dpdk_get_mtu, \
netdev_dpdk_set_mtu, \
+ netdev_dpdk_get_lsc_detect_mode, \
+ netdev_dpdk_set_lsc_detect_mode, \
netdev_dpdk_get_ifindex, \
GET_CARRIER, \
netdev_dpdk_get_carrier_resets, \
@@ -25,8 +25,16 @@ struct dp_packet;
#ifdef DPDK_NETDEV
+enum netdev_dpdk_lsc_detect_mode {
+ NETDEV_DPDK_LSC_DETECT_POLL_MODE,
+ NETDEV_DPDK_LSC_DETECT_INTERRUPT_MODE,
+ NETDEV_DPDK_LSC_DETECT_MAX = NETDEV_DPDK_LSC_DETECT_INTERRUPT_MODE,
+};
+
void netdev_dpdk_register(void);
void free_dpdk_buf(struct dp_packet *);
+void netdev_dpdk_set_default_lsc_detect_mode(enum netdev_dpdk_lsc_detect_mode default_lsc);
+enum netdev_dpdk_lsc_detect_mode netdev_dpdk_get_default_lsc_detect_mode(void);
#else
@@ -1378,6 +1378,8 @@ netdev_dummy_update_flags(struct netdev *netdev_,
netdev_dummy_get_etheraddr, \
netdev_dummy_get_mtu, \
netdev_dummy_set_mtu, \
+ NULL, /* get_lsc_detect_mode */ \
+ NULL, /* set_lsc_detect_mode */ \
netdev_dummy_get_ifindex, \
NULL, /* get_carrier */ \
NULL, /* get_carrier_resets */ \
@@ -2848,6 +2848,8 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
netdev_linux_get_etheraddr, \
netdev_linux_get_mtu, \
netdev_linux_set_mtu, \
+ NULL, /* get_lsc_detect_mode */ \
+ NULL, /* set_lsc_detect_mode */ \
netdev_linux_get_ifindex, \
netdev_linux_get_carrier, \
netdev_linux_get_carrier_resets, \
@@ -413,6 +413,9 @@ struct netdev_class {
* null if it would always return EOPNOTSUPP. */
int (*set_mtu)(struct netdev *netdev, int mtu);
+ int (*get_lsc_detect_mode)(const struct netdev *netdev, uint16_t *lscp);
+ int (*set_lsc_detect_mode)(struct netdev *netdev, uint16_t lsc);
+
/* Returns the ifindex of 'netdev', if successful, as a positive number.
* On failure, returns a negative errno value.
*
@@ -901,6 +901,8 @@ netdev_vport_get_ifindex(const struct netdev *netdev_)
netdev_vport_get_etheraddr, \
NULL, /* get_mtu */ \
NULL, /* set_mtu */ \
+ NULL, /* get_lsc_detect_mode */ \
+ NULL, /* set_lsc_detect_mode */ \
GET_IFINDEX, \
NULL, /* get_carrier */ \
NULL, /* get_carrier_resets */ \
@@ -960,6 +960,38 @@ netdev_set_mtu(struct netdev *netdev, int mtu)
return error;
}
+int
+netdev_get_lsc_detect_mode(const struct netdev *netdev, uint16_t *lscp)
+{
+ const struct netdev_class *class = netdev->netdev_class;
+ int error;
+
+ error = class->get_lsc_detect_mode ? class->get_lsc_detect_mode(netdev, lscp) : EOPNOTSUPP;
+ if (error) {
+ *lscp = 0;
+ if (error != EOPNOTSUPP) {
+ VLOG_DBG_RL(&rl, "failed to retrieve LSC for network device %s: "
+ "%s", netdev_get_name(netdev), ovs_strerror(error));
+ }
+ }
+ return error;
+}
+
+int
+netdev_set_lsc_detect_mode(struct netdev *netdev, uint16_t lsc)
+{
+ const struct netdev_class *class = netdev->netdev_class;
+ int error;
+
+ error = class->set_lsc_detect_mode ? class->set_lsc_detect_mode(netdev, lsc) : EOPNOTSUPP;
+ if (error && error != EOPNOTSUPP) {
+ VLOG_DBG_RL(&rl, "failed to set LSC for network device %s: %s",
+ netdev_get_name(netdev), ovs_strerror(error));
+ }
+
+ return error;
+}
+
/* If 'user_config' is true, the user wants to control 'netdev''s MTU and we
* should not override it. If 'user_config' is false, we may adjust
* 'netdev''s MTU (e.g., if 'netdev' is internal). */
@@ -162,6 +162,8 @@ const char *netdev_get_type(const struct netdev *);
const char *netdev_get_type_from_name(const char *);
int netdev_get_mtu(const struct netdev *, int *mtup);
int netdev_set_mtu(struct netdev *, int mtu);
+int netdev_get_lsc_detect_mode(const struct netdev *, uint16_t *lscp);
+int netdev_set_lsc_detect_mode(struct netdev *, uint16_t lsc);
void netdev_mtu_user_config(struct netdev *, bool);
bool netdev_mtu_is_user_config(struct netdev *);
int netdev_get_ifindex(const struct netdev *);
@@ -68,6 +68,9 @@
#include "lib/vswitch-idl.h"
#include "xenserver.h"
#include "vlan-bitmap.h"
+#ifdef DPDK_NETDEV
+#include "./lib/netdev-provider.h"
+#endif
VLOG_DEFINE_THIS_MODULE(bridge);
@@ -776,6 +779,30 @@ iface_set_netdev_mtu(const struct ovsrec_interface *iface_cfg,
return 0;
}
+#ifdef DPDK_NETDEV
+static void
+iface_set_netdev_lsc_detect_mode(struct netdev *netdev,
+ const struct ovsrec_interface *cfg)
+{
+ if(netdev && netdev_get_class(netdev) && netdev_get_class(netdev)->set_lsc_detect_mode)
+ {
+ struct smap_node *node = smap_get_node(&cfg->other_config, "dpdk-lsc-interrupt");
+ uint16_t lsc;
+
+ if(node) {
+ /* Set local LSC interrupt config for interface. */
+ lsc = smap_get_bool(&cfg->other_config, "dpdk-lsc-interrupt", false);
+ } else {
+ /* Set global LSC interrupt config if port specific is not defined. */
+ lsc = netdev_dpdk_get_default_lsc_detect_mode();
+ }
+ /* Update port specific configuration, and reconfigure device.
+ Can be applied only for physical interfaces. */
+ netdev_set_lsc_detect_mode(netdev, lsc);
+ }
+}
+#endif
+
static void
bridge_delete_or_reconfigure_ports(struct bridge *br)
{
@@ -832,6 +859,10 @@ bridge_delete_or_reconfigure_ports(struct bridge *br)
iface_set_netdev_mtu(iface->cfg, iface->netdev);
+#ifdef DPDK_NETDEV
+ iface_set_netdev_lsc_detect_mode(iface->netdev, iface->cfg);
+#endif
+
/* If the requested OpenFlow port for 'iface' changed, and it's not
* already the correct port, then we might want to temporarily delete
* this interface, so we can add it back again with the new OpenFlow
@@ -1794,6 +1825,9 @@ iface_do_create(const struct bridge *br,
}
iface_set_netdev_mtu(iface_cfg, netdev);
+#ifdef DPDK_NETDEV
+ iface_set_netdev_lsc_detect_mode(netdev, iface_cfg);
+#endif
*ofp_portp = iface_pick_ofport(iface_cfg);
error = ofproto_port_add(br->ofproto, netdev, ofp_portp);
@@ -320,6 +320,29 @@
</p>
</column>
+ <column name="other_config" key="dpdk-lsc-interrupt"
+ type='{"type": "boolean"}'>
+ <p>
+ Set this value to <code>true</code> to set interrupt mode for Link
+ State Change (LSC) detection instead of poll mode for DPDK interfaces.
+ </p>
+ <p>
+ The default value is <code>false</code>. Changing this value requires
+ restarting the daemon
+ </p>
+ <p>
+ If this value is <code>false</code> at startup, poll mode is used for
+ all netdev dpdk interfaces.
+ </p>
+ <p>
+ This value can be overridden for a single interface in the other_config
+ section of that interface.
+ </p>
+ <p>
+ This parameter has any effect only on netdev dpdk interfaces.
+ </p>
+ </column>
+
<column name="other_config" key="dpdk-extra"
type='{"type": "string"}'>
<p>
@@ -3512,6 +3535,25 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
</column>
</group>
+ <group title="Link State Change detection mode">
+ <column name="other_config" key="dpdk-lsc-interrupt"
+ type='{"type": "boolean"}'>
+ <p>
+ Set this value to <code>true</code> to set interrupt mode for Link
+ State Change (LSC) detection instead of poll mode for the DPDK interface.
+ </p>
+ <p>
+ If this value is not set, the value is taken from the global settings.
+ </p>
+ <p>
+ If this value is set, the global LSC interrupt settings are overridden.
+ </p>
+ <p>
+ This parameter has any effect only on netdev dpdk interfaces.
+ </p>
+ </column>
+ </group>
+
<group title="Common Columns">
The overall purpose of these columns is described under <code>Common
Columns</code> at the beginning of this document.
It is possible to set LSC detection mode to polling or interrupt mode for DPDK interfaces. The default is polling mode. To set interrupt mode, option dpdk-lsc-interrupt has to be set to true. Global settings Service restart is necessary for the global settings to take effect. Command to set interrupt mode for all interfaces: ovs-vsctl set Open_vSwitch . other_config:dpdk-lsc-interrupt=true Command to set polling mode for all interfaces: ovs-vsctl set Open_vSwitch . other_config:dpdk-lsc-interrupt=false or: ovs-vsctl remove Open_vSwitch . other_config dpdk-lsc-interrupt Interface specific settings (override global settings) Service restart is not necessary to take effect. Command to set interrupt mode for a specific interface: ovs-vsctl set interface <interface_name> other_config:dpdk-lsc-interrupt=true Command to set polling mode for a specific interface: ovs-vsctl set interface <interface_name> other_config:dpdk-lsc-interrupt=false Command to reset to globally defined mode for a specific interface: ovs-vsctl remove interface <interface_name> other_config dpdk-lsc-interrupt Signed-off-by: Robert Mulik <robert.mulik@ericsson.com> --- lib/dpdk.c | 6 ++++++ lib/netdev-dpdk.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++- lib/netdev-dpdk.h | 8 +++++++ lib/netdev-dummy.c | 2 ++ lib/netdev-linux.c | 2 ++ lib/netdev-provider.h | 3 +++ lib/netdev-vport.c | 2 ++ lib/netdev.c | 32 +++++++++++++++++++++++++++ lib/netdev.h | 2 ++ vswitchd/bridge.c | 34 +++++++++++++++++++++++++++++ vswitchd/vswitch.xml | 42 ++++++++++++++++++++++++++++++++++++ 11 files changed, 192 insertions(+), 1 deletion(-) -- 1.9.1