Add LSC interrupt support for pass-through (iface=) mode so
applications can receive link state change notifications via
the standard ethdev callback mechanism.

Uses alarm-based polling to periodically check the underlying
interface state via osdep_iface_link_get(). The LSC flag is
advertised only for iface mode devices, and polling is gated
on the application enabling intr_conf.lsc in port configuration.

Signed-off-by: Stephen Hemminger <[email protected]>
---
 doc/guides/nics/features/pcap.ini      |  1 +
 doc/guides/rel_notes/release_26_03.rst |  1 +
 drivers/net/pcap/pcap_ethdev.c         | 44 +++++++++++++++++++++++++-
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/features/pcap.ini 
b/doc/guides/nics/features/pcap.ini
index 814bc2119f..084fefbbbb 100644
--- a/doc/guides/nics/features/pcap.ini
+++ b/doc/guides/nics/features/pcap.ini
@@ -5,6 +5,7 @@
 ;
 [Features]
 Link status          = Y
+Link status event    = Y
 Queue start/stop     = Y
 Scattered Rx         = Y
 Timestamp offload    = Y
diff --git a/doc/guides/rel_notes/release_26_03.rst 
b/doc/guides/rel_notes/release_26_03.rst
index 4d9303ca3a..e614d8a8ac 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -89,6 +89,7 @@ New Features
   * Receive timestamp offload is only done if offload flag set.
   * Receive timestamps support nanosecond precision.
   * Added ``snaplen`` devarg to configure packet capture snapshot length.
+  * Added support for Link State interrupt in ``iface`` mode.
 
 
 Removed Items
diff --git a/drivers/net/pcap/pcap_ethdev.c b/drivers/net/pcap/pcap_ethdev.c
index 6863b78b49..afb68998e7 100644
--- a/drivers/net/pcap/pcap_ethdev.c
+++ b/drivers/net/pcap/pcap_ethdev.c
@@ -17,6 +17,7 @@
 #include <net/if.h>
 #include <pcap.h>
 
+#include <rte_alarm.h>
 #include <rte_cycles.h>
 #include <rte_ring.h>
 #include <rte_ethdev.h>
@@ -48,6 +49,8 @@
 /* This is defined in libpcap but not exposed in headers */
 #define ETH_PCAP_MAXIMUM_SNAPLEN      262144
 
+#define ETH_PCAP_LSC_POLL_INTERVAL_US (1000 * 1000) /* 1 second */
+
 #define ETH_PCAP_ARG_MAXLEN    64
 
 #define RTE_PMD_PCAP_MAX_QUEUES 16
@@ -113,6 +116,7 @@ struct pmd_internals {
        bool infinite_rx;
        bool vlan_strip;
        bool timestamp_offloading;
+       bool lsc_active;
 };
 
 struct pmd_process_private {
@@ -159,9 +163,10 @@ static const char *valid_arguments[] = {
 
 RTE_LOG_REGISTER_DEFAULT(eth_pcap_logtype, NOTICE);
 
-/* Forward declaration */
+/* Forward declarations */
 static inline int set_iface_direction(const char *iface, pcap_t *pcap,
                                      pcap_direction_t direction);
+static int eth_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 
 static struct queue_missed_stat*
 queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
@@ -783,6 +788,28 @@ count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue 
*pcap_q)
        return pcap_pkt_count;
 }
 
+/*
+ * Perodic alarm to poll link state.
+ * Enabled when link state interrupt is enabled in single_iface mode.
+ */
+static void
+eth_pcap_lsc_alarm(void *arg)
+{
+       struct rte_eth_dev *dev = arg;
+       struct pmd_internals *internals = dev->data->dev_private;
+       struct rte_eth_link old_link, new_link;
+
+       rte_eth_linkstatus_get(dev, &old_link);
+       eth_link_update(dev, 0);
+       rte_eth_linkstatus_get(dev, &new_link);
+
+       if (old_link.link_status != new_link.link_status)
+               rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+
+       if (internals->lsc_active)
+               rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US, 
eth_pcap_lsc_alarm, dev);
+}
+
 static int
 eth_dev_start(struct rte_eth_dev *dev)
 {
@@ -850,6 +877,12 @@ eth_dev_start(struct rte_eth_dev *dev)
 
        dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
 
+       /* Start LSC polling for iface mode if application requested it */
+       if (internals->single_iface && dev->data->dev_conf.intr_conf.lsc) {
+               internals->lsc_active = true;
+               
rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US,eth_pcap_lsc_alarm, dev);
+       }
+
        return 0;
 }
 
@@ -867,6 +900,12 @@ eth_dev_stop(struct rte_eth_dev *dev)
 
        /* Special iface case. Single pcap is open and shared between tx/rx. */
        if (internals->single_iface) {
+               /* Cancel LSC polling before closing pcap handles */
+               if (internals->lsc_active) {
+                       internals->lsc_active = false;
+                       rte_eal_alarm_cancel(eth_pcap_lsc_alarm, dev);
+               }
+
                queue_missed_stat_on_stop_update(dev, 0);
                if (pp->tx_pcap[0] != NULL) {
                        pcap_close(pp->tx_pcap[0]);
@@ -1704,6 +1743,9 @@ eth_from_pcaps(struct rte_vdev_device *vdev,
                internals->if_index =
                        osdep_iface_index_get(rx_queues->queue[0].name);
 
+               /* Enable LSC interrupt support for iface mode */
+               eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
+
                /* phy_mac arg is applied only if "iface" devarg is provided */
                if (rx_queues->phy_mac) {
                        if (eth_pcap_update_mac(rx_queues->queue[0].name,
-- 
2.51.0

Reply via email to