#tcpdump -i vEth0_0
+Change the MAC address:
+
+.. code-block:: console
+
+ #ifconfig vEth0_0 hw ether 0C:01:02:03:04:08
+
When the DPDK userspace application is closed, all the KNI devices are deleted from Linux*.
Explanation
conf.addr = dev_info.pci_dev->addr;
conf.id = dev_info.pci_dev->id;
+ /* Get the interface default mac address */
+ rte_eth_macaddr_get(port_id, (struct ether_addr *)&conf.mac_addr);
+
memset(&ops, 0, sizeof(ops));
ops.port_id = port_id;
ops.change_mtu = kni_change_mtu;
ops.config_network_if = kni_config_network_interface;
+ ops.config_mac_address = kni_config_mac_address;
kni = rte_kni_alloc(pktmbuf_pool, &conf, &ops);
} else
To execute specific PMD operations in user space requested by some Linux* commands,
callbacks must be implemented and filled in the struct rte_kni_ops structure.
-Currently, setting a new MTU and configuring the network interface (up/ down) are supported.
+Currently, setting a new MTU, change in MAC address and
+configuring the network interface(up/down) re supported.
+Default implementation for following is available in rte_kni library.
+Application may choose to not implement following callbacks:
+
+- ``config_mac_address``
+
.. code-block:: c
static struct rte_kni_ops kni_ops = {
.change_mtu = kni_change_mtu,
.config_network_if = kni_config_network_interface,
+ .config_mac_address = kni_config_mac_address,
};
/* Callback for request of changing MTU */
RTE_LOG(ERR, APP, "Failed to start port %d\n", port_id);
return ret;
}
+
+ /* Callback for request of configuring device mac address */
+
+ static int
+ kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
+ {
+ .....
+ }
static int kni_change_mtu(uint16_t port_id, unsigned int new_mtu);
static int kni_config_network_interface(uint16_t port_id, uint8_t if_up);
+static int kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[]);
static rte_atomic32_t kni_stop = RTE_ATOMIC32_INIT(0);
return ret;
}
+static void
+print_ethaddr(const char *name, struct ether_addr *mac_addr)
+{
+ char buf[ETHER_ADDR_FMT_SIZE];
+ ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, mac_addr);
+ RTE_LOG(INFO, APP, "\t%s%s\n", name, buf);
+}
+
+/* Callback for request of configuring mac address */
+static int
+kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
+{
+ int ret = 0;
+
+ if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id);
+ return -EINVAL;
+ }
+
+ RTE_LOG(INFO, APP, "Configure mac address of %d\n", port_id);
+ print_ethaddr("Address:", (struct ether_addr *)mac_addr);
+
+ ret = rte_eth_dev_default_mac_addr_set(port_id,
+ (struct ether_addr *)mac_addr);
+ if (ret < 0)
+ RTE_LOG(ERR, APP, "Failed to config mac_addr for port %d\n",
+ port_id);
+
+ return ret;
+}
+
static int
kni_alloc(uint16_t port_id)
{
conf.addr = dev_info.pci_dev->addr;
conf.id = dev_info.pci_dev->id;
}
+ /* Get the interface default mac address */
+ rte_eth_macaddr_get(port_id,
+ (struct ether_addr *)&conf.mac_addr);
memset(&ops, 0, sizeof(ops));
ops.port_id = port_id;
ops.change_mtu = kni_change_mtu;
ops.config_network_if = kni_config_network_interface;
+ ops.config_mac_address = kni_config_mac_address;
kni = rte_kni_alloc(pktmbuf_pool, &conf, &ops);
} else
RTE_KNI_REQ_UNKNOWN = 0,
RTE_KNI_REQ_CHANGE_MTU,
RTE_KNI_REQ_CFG_NETWORK_IF,
+ RTE_KNI_REQ_CHANGE_MAC_ADDR,
RTE_KNI_REQ_MAX,
};
union {
uint32_t new_mtu; /**< New MTU */
uint8_t if_up; /**< 1: interface up, 0: interface down */
+ uint8_t mac_addr[6]; /**< MAC address for interface */
};
int32_t result; /**< Result for processing request */
} __attribute__((__packed__));
/* mbuf size */
unsigned mbuf_size;
+ char mac_addr[6];
};
#define KNI_DEVICE "kni"
if (kni->lad_dev)
ether_addr_copy(net_dev->dev_addr, kni->lad_dev->dev_addr);
- else
- /*
- * Generate random mac address. eth_random_addr() is the newer
- * version of generating mac address in linux kernel.
- */
- random_ether_addr(net_dev->dev_addr);
+ else {
+ /* if user has provided a valid mac address */
+ if (is_valid_ether_addr((unsigned char *)(dev_info.mac_addr)))
+ memcpy(net_dev->dev_addr, dev_info.mac_addr, ETH_ALEN);
+ else
+ /*
+ * Generate random mac address. eth_random_addr() is the
+ * newer version of generating mac address in kernel.
+ */
+ random_ether_addr(net_dev->dev_addr);
+ }
ret = register_netdev(net_dev);
if (ret) {
static int
kni_net_set_mac(struct net_device *netdev, void *p)
{
+ int ret;
+ struct rte_kni_request req;
+ struct kni_dev *kni;
struct sockaddr *addr = p;
+ memset(&req, 0, sizeof(req));
+ req.req_id = RTE_KNI_REQ_CHANGE_MAC_ADDR;
+
if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
return -EADDRNOTAVAIL;
+
+ memcpy(req.mac_addr, addr->sa_data, netdev->addr_len);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- return 0;
+
+ kni = netdev_priv(netdev);
+ ret = kni_net_process_request(kni, &req);
+
+ return (ret == 0 ? req.result : ret);
}
#ifdef HAVE_CHANGE_CARRIER_CB
memset(ctx, 0, sizeof(struct rte_kni));
if (ops)
memcpy(&ctx->ops, ops, sizeof(struct rte_kni_ops));
+ else
+ ctx->ops.port_id = UINT16_MAX;
memset(&dev_info, 0, sizeof(dev_info));
dev_info.bus = conf->addr.bus;
dev_info.group_id = conf->group_id;
dev_info.mbuf_size = conf->mbuf_size;
+ memcpy(dev_info.mac_addr, conf->mac_addr, ETHER_ADDR_LEN);
+
snprintf(ctx->name, RTE_KNI_NAMESIZE, "%s", intf_name);
snprintf(dev_info.name, RTE_KNI_NAMESIZE, "%s", intf_name);
return 0;
}
+/* default callback for request of configuring device mac address */
+static int
+kni_config_mac_address(uint16_t port_id, uint8_t mac_addr[])
+{
+ int ret = 0;
+
+ if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, KNI, "Invalid port id %d\n", port_id);
+ return -EINVAL;
+ }
+
+ RTE_LOG(INFO, KNI, "Configure mac address of %d", port_id);
+
+ ret = rte_eth_dev_default_mac_addr_set(port_id,
+ (struct ether_addr *)mac_addr);
+ if (ret < 0)
+ RTE_LOG(ERR, KNI, "Failed to config mac_addr for port %d\n",
+ port_id);
+
+ return ret;
+}
+
int
rte_kni_handle_request(struct rte_kni *kni)
{
req->result = kni->ops.config_network_if(\
kni->ops.port_id, req->if_up);
break;
+ case RTE_KNI_REQ_CHANGE_MAC_ADDR: /* Change MAC Address */
+ if (kni->ops.config_mac_address)
+ req->result = kni->ops.config_mac_address(
+ kni->ops.port_id, req->mac_addr);
+ else if (kni->ops.port_id != UINT16_MAX)
+ req->result = kni_config_mac_address(
+ kni->ops.port_id, req->mac_addr);
+ break;
default:
RTE_LOG(ERR, KNI, "Unknown request id %u\n", req->req_id);
req->result = -EINVAL;
if( NULL == ops )
return KNI_REQ_NO_REGISTER;
- if((NULL == ops->change_mtu) && (NULL == ops->config_network_if))
+ if ((ops->change_mtu == NULL)
+ && (ops->config_network_if == NULL)
+ && (ops->config_mac_address == NULL))
return KNI_REQ_NO_REGISTER;
return KNI_REQ_REGISTERED;
return -1;
}
- kni->ops.change_mtu = NULL;
- kni->ops.config_network_if = NULL;
+ memset(&kni->ops, 0, sizeof(struct rte_kni_ops));
+
return 0;
}
void
#include <rte_pci.h>
#include <rte_memory.h>
#include <rte_mempool.h>
+#include <rte_ether.h>
#include <exec-env/rte_kni_common.h>
/* Pointer to function of configuring network interface */
int (*config_network_if)(uint16_t port_id, uint8_t if_up);
+
+ /* Pointer to function of configuring mac address */
+ int (*config_mac_address)(uint16_t port_id, uint8_t mac_addr[]);
};
/**
__extension__
uint8_t force_bind : 1; /* Flag to bind kernel thread */
+ char mac_addr[ETHER_ADDR_LEN]; /* MAC address assigned to KNI */
};
/**
static struct rte_kni_ops kni_ops = {
.change_mtu = NULL,
.config_network_if = NULL,
+ .config_mac_address = NULL,
};
static unsigned lcore_master, lcore_ingress, lcore_egress;
struct rte_kni_ops ops = {
.change_mtu = kni_change_mtu,
.config_network_if = NULL,
+ .config_mac_address = NULL,
};
if (!kni) {