aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/pktio
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/pktio')
-rw-r--r--platform/linux-generic/pktio/dpdk.c60
-rw-r--r--platform/linux-generic/pktio/ipc.c31
-rw-r--r--platform/linux-generic/pktio/loop.c20
-rw-r--r--platform/linux-generic/pktio/netmap.c26
-rw-r--r--platform/linux-generic/pktio/null.c22
-rw-r--r--platform/linux-generic/pktio/pcap.c22
-rw-r--r--platform/linux-generic/pktio/socket.c6
-rw-r--r--platform/linux-generic/pktio/socket_common.c139
-rw-r--r--platform/linux-generic/pktio/socket_mmap.c6
-rw-r--r--platform/linux-generic/pktio/tap.c6
10 files changed, 330 insertions, 8 deletions
diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c
index 18f583a65..7aee73dc1 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2016-2018, Linaro Limited
- * Copyright (c) 2019, Nokia
+ * Copyright (c) 2019-2020, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -2056,8 +2056,63 @@ static int dpdk_link_status(pktio_entry_t *pktio_entry)
memset(&link, 0, sizeof(struct rte_eth_link));
rte_eth_link_get_nowait(pkt_priv(pktio_entry)->port_id, &link);
+ if (link.link_status)
+ return ODP_PKTIO_LINK_STATUS_UP;
+ return ODP_PKTIO_LINK_STATUS_DOWN;
+}
+
+static int dpdk_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ struct rte_eth_link link;
+ struct rte_eth_fc_conf fc_conf;
+ uint16_t port_id = pkt_priv(pktio_entry)->port_id;
+ int ret;
- return link.link_status;
+ memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf));
+ memset(&link, 0, sizeof(struct rte_eth_link));
+
+ ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+ if (ret && ret != -ENOTSUP) {
+ ODP_ERR("rte_eth_dev_flow_ctrl_get() failed\n");
+ return -1;
+ }
+
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ if (fc_conf.mode == RTE_FC_RX_PAUSE) {
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON;
+ } else if (fc_conf.mode == RTE_FC_TX_PAUSE) {
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON;
+ } else if (fc_conf.mode == RTE_FC_FULL) {
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON;
+ }
+
+ rte_eth_link_get_nowait(port_id, &link);
+ if (link.link_autoneg == ETH_LINK_AUTONEG)
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON;
+ else
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+
+ if (link.link_duplex == ETH_LINK_FULL_DUPLEX)
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ else
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF;
+
+ if (link.link_speed == ETH_SPEED_NUM_NONE)
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ else
+ info->speed = link.link_speed;
+
+ if (link.link_status == ETH_LINK_UP)
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+ else
+ info->status = ODP_PKTIO_LINK_STATUS_DOWN;
+
+ info->media = "unknown";
+
+ return 0;
}
static void stats_convert(const struct rte_eth_stats *rte_stats,
@@ -2106,6 +2161,7 @@ const pktio_if_ops_t dpdk_pktio_ops = {
.recv = dpdk_recv,
.send = dpdk_send,
.link_status = dpdk_link_status,
+ .link_info = dpdk_link_info,
.mtu_get = dpdk_frame_maxlen,
.promisc_mode_set = dpdk_promisc_mode_set,
.promisc_mode_get = dpdk_promisc_mode_get,
diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c
index d63a77b74..34b32ae2c 100644
--- a/platform/linux-generic/pktio/ipc.c
+++ b/platform/linux-generic/pktio/ipc.c
@@ -900,6 +900,35 @@ static int ipc_stop(pktio_entry_t *pktio_entry)
return 0;
}
+static int ipc_link_status(pktio_entry_t *pktio_entry)
+{
+ pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry);
+
+ if (odp_atomic_load_u32(&pktio_ipc->ready))
+ return ODP_PKTIO_LINK_STATUS_UP;
+ return ODP_PKTIO_LINK_STATUS_DOWN;
+}
+
+static int ipc_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry);
+
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ info->media = "virtual";
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ if (odp_atomic_load_u32(&pktio_ipc->ready))
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+ else
+ info->status = ODP_PKTIO_LINK_STATUS_DOWN;
+
+ return 0;
+}
+
static int ipc_close(pktio_entry_t *pktio_entry)
{
pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry);
@@ -947,6 +976,8 @@ const pktio_if_ops_t ipc_pktio_ops = {
.send = ipc_pktio_send,
.start = ipc_start,
.stop = ipc_stop,
+ .link_status = ipc_link_status,
+ .link_info = ipc_link_info,
.mtu_get = ipc_mtu_get,
.promisc_mode_set = NULL,
.promisc_mode_get = NULL,
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index e6d004d43..3de096139 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2013-2018, Linaro Limited
- * Copyright (c) 2013, Nokia Solutions and Networks
+ * Copyright (c) 2013-2020, Nokia Solutions and Networks
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -367,7 +367,22 @@ static int loopback_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED,
static int loopback_link_status(pktio_entry_t *pktio_entry ODP_UNUSED)
{
/* loopback interfaces are always up */
- return 1;
+ return ODP_PKTIO_LINK_STATUS_UP;
+}
+
+static int loopback_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info)
+{
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ info->media = "virtual";
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+
+ return 0;
}
static int loopback_init_capability(pktio_entry_t *pktio_entry)
@@ -467,6 +482,7 @@ const pktio_if_ops_t loopback_pktio_ops = {
.mac_get = loopback_mac_addr_get,
.mac_set = NULL,
.link_status = loopback_link_status,
+ .link_info = loopback_link_info,
.capability = loopback_capability,
.pktin_ts_res = NULL,
.pktin_ts_from_ns = NULL,
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c
index e1a5da773..0f608c6f6 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2015-2018, Linaro Limited
- * Copyright (c) 2019, Nokia
+ * Copyright (c) 2019-2020, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -355,12 +355,33 @@ static int netmap_close(pktio_entry_t *pktio_entry)
static int netmap_link_status(pktio_entry_t *pktio_entry)
{
if (pkt_priv(pktio_entry)->is_virtual)
- return 1;
+ return ODP_PKTIO_LINK_STATUS_UP;
return link_status_fd(pkt_priv(pktio_entry)->sockfd,
pkt_priv(pktio_entry)->if_name);
}
+static int netmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry);
+
+ if (pkt_nm->is_virtual) {
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ info->media = "virtual";
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+
+ return 0;
+ }
+
+ return link_info_fd(pkt_nm->sockfd, pkt_nm->if_name, info);
+}
+
/**
* Wait for netmap link to come up
*
@@ -1225,6 +1246,7 @@ const pktio_if_ops_t netmap_pktio_ops = {
.start = netmap_start,
.stop = netmap_stop,
.link_status = netmap_link_status,
+ .link_info = netmap_link_info,
.stats = netmap_stats,
.stats_reset = netmap_stats_reset,
.mtu_get = netmap_mtu_get,
diff --git a/platform/linux-generic/pktio/null.c b/platform/linux-generic/pktio/null.c
index bb7f85c9b..d739ccafe 100644
--- a/platform/linux-generic/pktio/null.c
+++ b/platform/linux-generic/pktio/null.c
@@ -154,6 +154,26 @@ static int null_init_global(void)
return 0;
}
+static int null_link_status(pktio_entry_t *pktio_entry ODP_UNUSED)
+{
+ return ODP_PKTIO_LINK_STATUS_UP;
+}
+
+static int null_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info)
+{
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ info->media = "virtual";
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+
+ return 0;
+}
+
const pktio_if_ops_t null_pktio_ops = {
.name = "null",
.print = NULL,
@@ -179,4 +199,6 @@ const pktio_if_ops_t null_pktio_ops = {
.config = NULL,
.input_queues_config = null_inqueues_config,
.output_queues_config = null_outqueues_config,
+ .link_status = null_link_status,
+ .link_info = null_link_info
};
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
index 6ef998717..262528abc 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -444,6 +444,26 @@ static int pcapif_init_global(void)
return 0;
}
+static int pcapif_link_status(pktio_entry_t *pktio_entry ODP_UNUSED)
+{
+ return ODP_PKTIO_LINK_STATUS_UP;
+}
+
+static int pcapif_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info)
+{
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ info->media = "virtual";
+ info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF;
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ info->status = ODP_PKTIO_LINK_STATUS_UP;
+
+ return 0;
+}
+
const pktio_if_ops_t pcap_pktio_ops = {
.name = "pcap",
.print = NULL,
@@ -466,4 +486,6 @@ const pktio_if_ops_t pcap_pktio_ops = {
.config = NULL,
.input_queues_config = NULL,
.output_queues_config = NULL,
+ .link_status = pcapif_link_status,
+ .link_info = pcapif_link_info
};
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index d148edf03..4776b83f9 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -493,6 +493,11 @@ static int sock_link_status(pktio_entry_t *pktio_entry)
pktio_entry->s.name);
}
+static int sock_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info);
+}
+
static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED,
odp_pktio_capability_t *capa)
{
@@ -566,6 +571,7 @@ const pktio_if_ops_t sock_mmsg_pktio_ops = {
.mac_get = sock_mac_addr_get,
.mac_set = NULL,
.link_status = sock_link_status,
+ .link_info = sock_link_info,
.capability = sock_capability,
.pktin_ts_res = NULL,
.pktin_ts_from_ns = NULL,
diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c
index 4fbf2f041..2eb3b4001 100644
--- a/platform/linux-generic/pktio/socket_common.c
+++ b/platform/linux-generic/pktio/socket_common.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2018, Linaro Limited
- * Copyright (c) 2019, Nokia
+ * Copyright (c) 2019-2020, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -14,7 +14,9 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
+#include <linux/ethtool.h>
#include <linux/if_packet.h>
+#include <linux/sockios.h>
#include <errno.h>
#include <odp_debug_internal.h>
#include <odp_errno_define.h>
@@ -155,8 +157,141 @@ int link_status_fd(int fd, const char *name)
__odp_errno = errno;
ODP_DBG("ioctl(SIOCGIFFLAGS): %s: \"%s\".\n", strerror(errno),
ifr.ifr_name);
+ return ODP_PKTIO_LINK_STATUS_UNKNOWN;
+ }
+
+ if (ifr.ifr_flags & IFF_RUNNING)
+ return ODP_PKTIO_LINK_STATUS_UP;
+ return ODP_PKTIO_LINK_STATUS_DOWN;
+}
+
+int link_info_fd(int fd, const char *name, odp_pktio_link_info_t *info)
+{
+ struct ethtool_link_settings hcmd = {.cmd = ETHTOOL_GLINKSETTINGS};
+ struct ethtool_link_settings *ecmd;
+ struct ethtool_pauseparam pcmd = {.cmd = ETHTOOL_GPAUSEPARAM};
+ struct ifreq ifr;
+ int status;
+
+ status = link_status_fd(fd, name);
+ if (status < 0)
+ return -1;
+
+ snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name);
+
+ /* Link pause status */
+ ifr.ifr_data = (void *)&pcmd;
+ if (ioctl(fd, SIOCETHTOOL, &ifr) && errno != EOPNOTSUPP) {
+ __odp_errno = errno;
+ ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno),
+ ifr.ifr_name);
+ return -1;
+ }
+
+ /* Try to perform handshake and fall back to old API if failed */
+ ifr.ifr_data = (void *)&hcmd;
+ if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
+ struct ethtool_cmd ecmd_old = {.cmd = ETHTOOL_GSET};
+
+ ifr.ifr_data = (void *)&ecmd_old;
+ if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
+ __odp_errno = errno;
+ ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), ifr.ifr_name);
+ return -1;
+ }
+
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+ info->speed = ethtool_cmd_speed(&ecmd_old);
+ if (info->speed == (uint32_t)SPEED_UNKNOWN)
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+
+ if (ecmd_old.autoneg == AUTONEG_ENABLE)
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON;
+ else if (ecmd_old.autoneg == AUTONEG_DISABLE)
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ else
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN;
+
+ if (ecmd_old.duplex == DUPLEX_HALF)
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF;
+ else if (ecmd_old.duplex == DUPLEX_FULL)
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ else
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN;
+
+ info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF;
+
+ if (ecmd_old.port == PORT_TP)
+ info->media = "copper";
+ else if (ecmd_old.port == PORT_FIBRE)
+ info->media = "fiber";
+ else if (ecmd_old.port == PORT_OTHER)
+ info->media = "other";
+ else
+ info->media = "unknown";
+
+ info->status = status;
+
+ return 0;
+ }
+
+ if (hcmd.link_mode_masks_nwords >= 0 || hcmd.cmd != ETHTOOL_GLINKSETTINGS) {
+ ODP_ERR("ETHTOOL_GLINKSETTINGS handshake failed\n");
+ return -1;
+ }
+ /* Absolute value indicates kernel recommended 'link_mode_masks_nwords' value. */
+ hcmd.link_mode_masks_nwords = -hcmd.link_mode_masks_nwords;
+
+ /* Reserve space for the three bitmasks (map_supported, map_advertising, map_lp_advertising)
+ * at the end of struct ethtool_link_settings. 'link_mode_masks_nwords' defines the bitmask
+ * length in 32-bit words. */
+ uint8_t ODP_ALIGNED_CACHE data[offsetof(struct ethtool_link_settings, link_mode_masks) +
+ (3 * sizeof(uint32_t) * hcmd.link_mode_masks_nwords)];
+
+ ecmd = (void *)data;
+ *ecmd = hcmd;
+ ifr.ifr_data = (void *)ecmd;
+ if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
+ __odp_errno = errno;
+ ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno),
+ ifr.ifr_name);
return -1;
}
- return !!(ifr.ifr_flags & IFF_RUNNING);
+ memset(info, 0, sizeof(odp_pktio_link_info_t));
+ if (ecmd->speed == (uint32_t)SPEED_UNKNOWN)
+ info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN;
+ else
+ info->speed = ecmd->speed;
+
+ if (ecmd->autoneg == AUTONEG_ENABLE)
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON;
+ else if (ecmd->autoneg == AUTONEG_DISABLE)
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF;
+ else
+ info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN;
+
+ if (ecmd->duplex == DUPLEX_HALF)
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF;
+ else if (ecmd->duplex == DUPLEX_FULL)
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL;
+ else
+ info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN;
+
+ info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF;
+ info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF;
+
+ if (ecmd->port == PORT_TP)
+ info->media = "copper";
+ else if (ecmd->port == PORT_FIBRE)
+ info->media = "fiber";
+ else if (ecmd->port == PORT_OTHER)
+ info->media = "other";
+ else
+ info->media = "unknown";
+
+ info->status = status;
+
+ return 0;
}
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index bf1cbad81..d0d37636d 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -784,6 +784,11 @@ static int sock_mmap_link_status(pktio_entry_t *pktio_entry)
pktio_entry->s.name);
}
+static int sock_mmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info);
+}
+
static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED,
odp_pktio_capability_t *capa)
{
@@ -860,6 +865,7 @@ const pktio_if_ops_t sock_mmap_pktio_ops = {
.mac_get = sock_mmap_mac_addr_get,
.mac_set = NULL,
.link_status = sock_mmap_link_status,
+ .link_info = sock_mmap_link_info,
.capability = sock_mmap_capability,
.pktin_ts_res = NULL,
.pktin_ts_from_ns = NULL,
diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c
index db5c701b2..13a9feaf8 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -467,6 +467,11 @@ static int tap_link_status(pktio_entry_t *pktio_entry)
pktio_entry->s.name + 4);
}
+static int tap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info)
+{
+ return link_info_fd(pkt_priv(pktio_entry)->skfd, pktio_entry->s.name + 4, info);
+}
+
static int tap_capability(pktio_entry_t *pktio_entry ODP_UNUSED,
odp_pktio_capability_t *capa)
{
@@ -501,6 +506,7 @@ const pktio_if_ops_t tap_pktio_ops = {
.mac_get = tap_mac_addr_get,
.mac_set = tap_mac_addr_set,
.link_status = tap_link_status,
+ .link_info = tap_link_info,
.capability = tap_capability,
.pktin_ts_res = NULL,
.pktin_ts_from_ns = NULL,