]> git.droids-corp.org - dpdk.git/commitdiff
kni: support MAC address change
authorHemant Agrawal <hemant.agrawal@nxp.com>
Thu, 18 Jan 2018 06:12:58 +0000 (11:42 +0530)
committerThomas Monjalon <thomas@monjalon.net>
Thu, 1 Feb 2018 00:02:50 +0000 (01:02 +0100)
This patch adds following:
1. Option to configure the mac address during create. Generate random
   address only if the user has not provided any valid address.
2. Inform usespace, if mac address is being changed in linux.
3. Implement default handling of mac address change in the corresponding
   ethernet device.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Acked-by: Ferruh Yigit <ferruh.yigit@intel.com>
doc/guides/sample_app_ug/kernel_nic_interface.rst
examples/kni/main.c
lib/librte_eal/linuxapp/eal/include/exec-env/rte_kni_common.h
lib/librte_eal/linuxapp/kni/kni_misc.c
lib/librte_eal/linuxapp/kni/kni_net.c
lib/librte_kni/rte_kni.c
lib/librte_kni/rte_kni.h
test/test/test_kni.c

index 67f21406f1fb11bb1315c30eb9176a8eba9800a2..89a4c308a99f354a1a2af4e023e59b5ce908c54d 100644 (file)
@@ -209,6 +209,12 @@ Dumping the network traffic:
 
     #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
@@ -269,11 +275,15 @@ The code for allocating the kernel NIC interfaces for a specific port is as foll
                     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
@@ -502,13 +512,20 @@ Callbacks for Kernel Requests
 
 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 */
@@ -587,3 +604,11 @@ Currently, setting a new MTU and configuring the network interface (up/ down) ar
             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[])
+    {
+        .....
+    }
index dfa2d928f9e8d7b668e8e1305add0cd0785dff55..bd3b329f8e42a1be5b91d466ed2d493c4c9e0722 100644 (file)
@@ -131,6 +131,7 @@ static struct kni_interface_stats kni_stats[RTE_MAX_ETHPORTS];
 
 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);
 
@@ -767,6 +768,37 @@ kni_config_network_interface(uint16_t port_id, uint8_t if_up)
        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)
 {
@@ -810,11 +842,15 @@ 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
index 61ace6f26d5d85e241af66ef83cd2a9697a08ac5..62b4a0592a0c89f6c90baeb3da729adfe7a4107a 100644 (file)
@@ -28,6 +28,7 @@ enum rte_kni_req_id {
        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,
 };
 
@@ -40,6 +41,7 @@ struct rte_kni_request {
        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__));
@@ -116,6 +118,7 @@ struct rte_kni_device_info {
 
        /* mbuf size */
        unsigned mbuf_size;
+       char mac_addr[6];
 };
 
 #define KNI_DEVICE "kni"
index def4f1e480ac8f023d3d2a3c4e06154d428a7409..83649ce49d87b01d5207c61a9b6a799136c05be4 100644 (file)
@@ -439,12 +439,17 @@ kni_ioctl_create(struct net *net, uint32_t ioctl_num,
 
        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) {
index 07d6fdbe3a625bcbc6a4f39813b52cb55fc68d5e..3e35008fa88b289e97eb4b4e3dfc39a231b17637 100644 (file)
@@ -649,12 +649,24 @@ kni_net_rebuild_header(struct sk_buff *skb)
 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
index f4fa9944c0aa82c4eb27dc9c016e62055b624fde..a140dfcadfcc9d5c460b883450b63974d355c73d 100644 (file)
@@ -327,6 +327,8 @@ rte_kni_alloc(struct rte_mempool *pktmbuf_pool,
        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;
@@ -339,6 +341,8 @@ rte_kni_alloc(struct rte_mempool *pktmbuf_pool,
        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);
 
@@ -499,6 +503,28 @@ rte_kni_release(struct rte_kni *kni)
        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)
 {
@@ -530,6 +556,14 @@ 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;
@@ -678,7 +712,9 @@ kni_check_request_register(struct rte_kni_ops *ops)
        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;
@@ -717,8 +753,8 @@ rte_kni_unregister_handlers(struct rte_kni *kni)
                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
index c4dcfffa15c319a9632a10e35591b1aeb973a3b9..370b02a107a9a4600b5a97bd3fdb207fd352c05d 100644 (file)
@@ -20,6 +20,7 @@
 #include <rte_pci.h>
 #include <rte_memory.h>
 #include <rte_mempool.h>
+#include <rte_ether.h>
 
 #include <exec-env/rte_kni_common.h>
 
@@ -41,6 +42,9 @@ struct rte_kni_ops {
 
        /* 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[]);
 };
 
 /**
@@ -61,6 +65,7 @@ struct rte_kni_conf {
 
        __extension__
        uint8_t force_bind : 1; /* Flag to bind kernel thread */
+       char mac_addr[ETHER_ADDR_LEN]; /* MAC address assigned to KNI */
 };
 
 /**
index f6fb1a2fb021f4190ba80a535fcabf5462ad610c..8e08f420a2efc9bbc1a19b66e60ccb5f56126c57 100644 (file)
@@ -74,6 +74,7 @@ static const struct rte_eth_conf port_conf = {
 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;
@@ -231,6 +232,7 @@ test_kni_register_handler_mp(void)
                struct rte_kni_ops ops = {
                        .change_mtu = kni_change_mtu,
                        .config_network_if = NULL,
+                       .config_mac_address = NULL,
                };
 
                if (!kni) {