[ovs-dev] Configurable Link State Change (LSC) detection mode

Message ID HE1PR07MB31153AC1F22B458D2C4BDE00ED320@HE1PR07MB3115.eurprd07.prod.outlook.com
State New
Headers show
Series
  • [ovs-dev] Configurable Link State Change (LSC) detection mode
Related show

Commit Message

Róbert Mulik Dec. 6, 2017, 10:29 a.m.
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

Comments

Ilya Maximets Dec. 6, 2017, 11:39 a.m. | #1
Hi Robert.

Few general comments:

If you'll move per-interface config from 'other_config' to 'options' column,
you'll be able to localize code changes to only dpdk.c and netdev-dpdk.c.
The changes in all other code files are redundant especially because
the option could only affect dpdk ports.
The second vote for 'options' is that all other interface configuration
options like number of RX/TX queues, descriptor ring sizes are located
in 'options' not in 'other_config'.
The third is that you'll be able to add proper 'area' prefix to you patch.
It's really hard to recognize that this patch is about DPDK while looking
at its name.

Also, please, check you patch with ./utilities/checkpatch.py script.
I see at least few too long lines. Check out coding-style.rst for details.

Best regards, Ilya Maximets.

> 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 at 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(-)
Róbert Mulik Dec. 6, 2017, 11:46 a.m. | #2
Hi Ilya,

Thank you for the comments, I try to refactor the code according to them.

Regards,
Robert

-----Original Message-----
From: Ilya Maximets [mailto:i.maximets@samsung.com] 

Sent: Wednesday, December 06, 2017 12:40 PM
To: ovs-dev@openvswitch.org; Róbert Mulik <robert.mulik@ericsson.com>
Subject: Re: [ovs-dev] [PATCH] Configurable Link State Change (LSC) detection mode

Hi Robert.

Few general comments:

If you'll move per-interface config from 'other_config' to 'options' column, you'll be able to localize code changes to only dpdk.c and netdev-dpdk.c.
The changes in all other code files are redundant especially because the option could only affect dpdk ports.
The second vote for 'options' is that all other interface configuration options like number of RX/TX queues, descriptor ring sizes are located in 'options' not in 'other_config'.
The third is that you'll be able to add proper 'area' prefix to you patch.
It's really hard to recognize that this patch is about DPDK while looking at its name.

Also, please, check you patch with ./utilities/checkpatch.py script.
I see at least few too long lines. Check out coding-style.rst for details.

Best regards, Ilya Maximets.

> 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 at 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(-)

Patch

diff --git a/lib/dpdk.c b/lib/dpdk.c
index 8da6c32..09c4f9b 100644
--- a/lib/dpdk.c
+++ b/lib/dpdk.c
@@ -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());
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index faff842..ac722cc 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -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,                           \
diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h
index b7d02a7..28a6c98 100644
--- a/lib/netdev-dpdk.h
+++ b/lib/netdev-dpdk.h
@@ -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

diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 246cdf1..31052c7 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -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 */        \
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index e809b88..252a8f9 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -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,                            \
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 1720deb..865c0c4 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -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.
      *
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 518058a..7788ce8 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -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 */    \
diff --git a/lib/netdev.c b/lib/netdev.c
index 2d69fe5..3ea2394 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -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). */
diff --git a/lib/netdev.h b/lib/netdev.h
index 3a545fe..465285a 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -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 *);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 630c6fa..2249e75 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -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);
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index c145e1a..87c0b52 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -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.