net/mlx5: add more checks on MAC addresses
[dpdk.git] / drivers / net / mlx5 / mlx5_mac.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2015 6WIND S.A.
3  * Copyright 2015 Mellanox Technologies, Ltd
4  */
5
6 #include <stddef.h>
7 #include <assert.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <errno.h>
12 #include <netinet/in.h>
13 #include <sys/ioctl.h>
14 #include <arpa/inet.h>
15
16 /* Verbs header. */
17 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
18 #ifdef PEDANTIC
19 #pragma GCC diagnostic ignored "-Wpedantic"
20 #endif
21 #include <infiniband/verbs.h>
22 #ifdef PEDANTIC
23 #pragma GCC diagnostic error "-Wpedantic"
24 #endif
25
26 #include <rte_ether.h>
27 #include <rte_ethdev_driver.h>
28 #include <rte_common.h>
29
30 #include "mlx5.h"
31 #include "mlx5_utils.h"
32 #include "mlx5_rxtx.h"
33 #include "mlx5_defs.h"
34
35 /**
36  * Get MAC address by querying netdevice.
37  *
38  * @param[in] dev
39  *   Pointer to Ethernet device.
40  * @param[out] mac
41  *   MAC address output buffer.
42  *
43  * @return
44  *   0 on success, a negative errno value otherwise and rte_errno is set.
45  */
46 int
47 mlx5_get_mac(struct rte_eth_dev *dev, uint8_t (*mac)[ETHER_ADDR_LEN])
48 {
49         struct ifreq request;
50         int ret;
51
52         ret = mlx5_ifreq(dev, SIOCGIFHWADDR, &request);
53         if (ret)
54                 return ret;
55         memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
56         return 0;
57 }
58
59 /**
60  * DPDK callback to remove a MAC address.
61  *
62  * @param dev
63  *   Pointer to Ethernet device structure.
64  * @param index
65  *   MAC address index.
66  */
67 void
68 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
69 {
70         struct priv *priv = dev->data->dev_private;
71         const int vf = priv->config.vf;
72         int ret;
73
74         if (index >= MLX5_MAX_MAC_ADDRESSES)
75                 return;
76         if (is_zero_ether_addr(&dev->data->mac_addrs[index]))
77                 return;
78         if (vf)
79                 mlx5_nl_mac_addr_remove(dev, &dev->data->mac_addrs[index],
80                                         index);
81         memset(&dev->data->mac_addrs[index], 0, sizeof(struct ether_addr));
82         if (!dev->data->promiscuous) {
83                 ret = mlx5_traffic_restart(dev);
84                 if (ret)
85                         DRV_LOG(ERR, "port %u cannot restart traffic: %s",
86                                 dev->data->port_id, strerror(rte_errno));
87         }
88 }
89
90 /**
91  * DPDK callback to add a MAC address.
92  *
93  * @param dev
94  *   Pointer to Ethernet device structure.
95  * @param mac_addr
96  *   MAC address to register.
97  * @param index
98  *   MAC address index.
99  * @param vmdq
100  *   VMDq pool index to associate address with (ignored).
101  *
102  * @return
103  *   0 on success, a negative errno value otherwise and rte_errno is set.
104  */
105 int
106 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac,
107                   uint32_t index, uint32_t vmdq __rte_unused)
108 {
109         struct priv *priv = dev->data->dev_private;
110         const int vf = priv->config.vf;
111         unsigned int i;
112
113         if (index >= MLX5_MAX_MAC_ADDRESSES) {
114                 rte_errno = EINVAL;
115                 return -rte_errno;
116         }
117         if (is_zero_ether_addr(mac)) {
118                 rte_errno = EINVAL;
119                 return -rte_errno;
120         }
121         /* First, make sure this address isn't already configured. */
122         for (i = 0; (i != MLX5_MAX_MAC_ADDRESSES); ++i) {
123                 /* Skip this index, it's going to be reconfigured. */
124                 if (i == index)
125                         continue;
126                 if (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac)))
127                         continue;
128                 /* Address already configured elsewhere, return with error. */
129                 rte_errno = EADDRINUSE;
130                 return -rte_errno;
131         }
132         if (vf) {
133                 int ret = mlx5_nl_mac_addr_add(dev, mac, index);
134
135                 if (ret)
136                         return ret;
137         }
138         dev->data->mac_addrs[index] = *mac;
139         if (!dev->data->promiscuous)
140                 return mlx5_traffic_restart(dev);
141         return 0;
142 }
143
144 /**
145  * DPDK callback to set primary MAC address.
146  *
147  * @param dev
148  *   Pointer to Ethernet device structure.
149  * @param mac_addr
150  *   MAC address to register.
151  *
152  * @return
153  *   0 on success, a negative errno value otherwise and rte_errno is set.
154  */
155 int
156 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
157 {
158         DRV_LOG(DEBUG, "port %u setting primary MAC address",
159                 dev->data->port_id);
160         return mlx5_mac_addr_add(dev, mac_addr, 0, 0);
161 }