1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2015 6WIND S.A. 5 * Copyright 2015 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stddef.h> 35 #include <errno.h> 36 #include <string.h> 37 38 /* Verbs header. */ 39 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 40 #ifdef PEDANTIC 41 #pragma GCC diagnostic ignored "-pedantic" 42 #endif 43 #include <infiniband/verbs.h> 44 #ifdef PEDANTIC 45 #pragma GCC diagnostic error "-pedantic" 46 #endif 47 48 /* DPDK headers don't like -pedantic. */ 49 #ifdef PEDANTIC 50 #pragma GCC diagnostic ignored "-pedantic" 51 #endif 52 #include <rte_ethdev.h> 53 #ifdef PEDANTIC 54 #pragma GCC diagnostic error "-pedantic" 55 #endif 56 57 #include "mlx5.h" 58 #include "mlx5_rxtx.h" 59 #include "mlx5_utils.h" 60 61 static void hash_rxq_promiscuous_disable(struct hash_rxq *); 62 static void hash_rxq_allmulticast_disable(struct hash_rxq *); 63 64 /** 65 * Enable promiscuous mode in a hash RX queue. 66 * 67 * @param hash_rxq 68 * Pointer to hash RX queue structure. 69 * 70 * @return 71 * 0 on success, errno value on failure. 72 */ 73 static int 74 hash_rxq_promiscuous_enable(struct hash_rxq *hash_rxq) 75 { 76 struct ibv_flow *flow; 77 FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0)); 78 struct ibv_flow_attr *attr = &data->attr; 79 80 if (hash_rxq->promisc_flow != NULL) 81 return 0; 82 DEBUG("%p: enabling promiscuous mode", (void *)hash_rxq); 83 /* Promiscuous flows only differ from normal flows by not filtering 84 * on specific MAC addresses. */ 85 hash_rxq_flow_attr(hash_rxq, attr, sizeof(data)); 86 errno = 0; 87 flow = ibv_create_flow(hash_rxq->qp, attr); 88 if (flow == NULL) { 89 /* It's not clear whether errno is always set in this case. */ 90 ERROR("%p: flow configuration failed, errno=%d: %s", 91 (void *)hash_rxq, errno, 92 (errno ? strerror(errno) : "Unknown error")); 93 if (errno) 94 return errno; 95 return EINVAL; 96 } 97 hash_rxq->promisc_flow = flow; 98 DEBUG("%p: promiscuous mode enabled", (void *)hash_rxq); 99 return 0; 100 } 101 102 /** 103 * Enable promiscuous mode in all hash RX queues. 104 * 105 * @param priv 106 * Private structure. 107 * 108 * @return 109 * 0 on success, errno value on failure. 110 */ 111 int 112 priv_promiscuous_enable(struct priv *priv) 113 { 114 unsigned int i; 115 116 for (i = 0; (i != priv->hash_rxqs_n); ++i) { 117 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i]; 118 int ret; 119 120 ret = hash_rxq_promiscuous_enable(hash_rxq); 121 if (!ret) 122 continue; 123 /* Failure, rollback. */ 124 while (i != 0) { 125 hash_rxq = &(*priv->hash_rxqs)[--i]; 126 hash_rxq_promiscuous_disable(hash_rxq); 127 } 128 return ret; 129 } 130 return 0; 131 } 132 133 /** 134 * DPDK callback to enable promiscuous mode. 135 * 136 * @param dev 137 * Pointer to Ethernet device structure. 138 */ 139 void 140 mlx5_promiscuous_enable(struct rte_eth_dev *dev) 141 { 142 struct priv *priv = dev->data->dev_private; 143 int ret; 144 145 priv_lock(priv); 146 priv->promisc_req = 1; 147 ret = priv_promiscuous_enable(priv); 148 if (ret) 149 ERROR("cannot enable promiscuous mode: %s", strerror(ret)); 150 priv_unlock(priv); 151 } 152 153 /** 154 * Disable promiscuous mode in a hash RX queue. 155 * 156 * @param hash_rxq 157 * Pointer to hash RX queue structure. 158 */ 159 static void 160 hash_rxq_promiscuous_disable(struct hash_rxq *hash_rxq) 161 { 162 if (hash_rxq->promisc_flow == NULL) 163 return; 164 DEBUG("%p: disabling promiscuous mode", (void *)hash_rxq); 165 claim_zero(ibv_destroy_flow(hash_rxq->promisc_flow)); 166 hash_rxq->promisc_flow = NULL; 167 DEBUG("%p: promiscuous mode disabled", (void *)hash_rxq); 168 } 169 170 /** 171 * Disable promiscuous mode in all hash RX queues. 172 * 173 * @param priv 174 * Private structure. 175 */ 176 void 177 priv_promiscuous_disable(struct priv *priv) 178 { 179 unsigned int i; 180 181 for (i = 0; (i != priv->hash_rxqs_n); ++i) 182 hash_rxq_promiscuous_disable(&(*priv->hash_rxqs)[i]); 183 } 184 185 /** 186 * DPDK callback to disable promiscuous mode. 187 * 188 * @param dev 189 * Pointer to Ethernet device structure. 190 */ 191 void 192 mlx5_promiscuous_disable(struct rte_eth_dev *dev) 193 { 194 struct priv *priv = dev->data->dev_private; 195 196 priv_lock(priv); 197 priv->promisc_req = 0; 198 priv_promiscuous_disable(priv); 199 priv_unlock(priv); 200 } 201 202 /** 203 * Enable allmulti mode in a hash RX queue. 204 * 205 * @param hash_rxq 206 * Pointer to hash RX queue structure. 207 * 208 * @return 209 * 0 on success, errno value on failure. 210 */ 211 static int 212 hash_rxq_allmulticast_enable(struct hash_rxq *hash_rxq) 213 { 214 struct ibv_flow *flow; 215 FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0)); 216 struct ibv_flow_attr *attr = &data->attr; 217 struct ibv_flow_spec_eth *spec = &data->spec; 218 219 if (hash_rxq->allmulti_flow != NULL) 220 return 0; 221 DEBUG("%p: enabling allmulticast mode", (void *)hash_rxq); 222 /* 223 * No padding must be inserted by the compiler between attr and spec. 224 * This layout is expected by libibverbs. 225 */ 226 assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec); 227 hash_rxq_flow_attr(hash_rxq, attr, sizeof(data)); 228 *spec = (struct ibv_flow_spec_eth){ 229 .type = IBV_FLOW_SPEC_ETH, 230 .size = sizeof(*spec), 231 .val = { 232 .dst_mac = "\x01\x00\x00\x00\x00\x00", 233 }, 234 .mask = { 235 .dst_mac = "\x01\x00\x00\x00\x00\x00", 236 }, 237 }; 238 errno = 0; 239 flow = ibv_create_flow(hash_rxq->qp, attr); 240 if (flow == NULL) { 241 /* It's not clear whether errno is always set in this case. */ 242 ERROR("%p: flow configuration failed, errno=%d: %s", 243 (void *)hash_rxq, errno, 244 (errno ? strerror(errno) : "Unknown error")); 245 if (errno) 246 return errno; 247 return EINVAL; 248 } 249 hash_rxq->allmulti_flow = flow; 250 DEBUG("%p: allmulticast mode enabled", (void *)hash_rxq); 251 return 0; 252 } 253 254 /** 255 * Enable allmulti mode in most hash RX queues. 256 * TCP queues are exempted to save resources. 257 * 258 * @param priv 259 * Private structure. 260 * 261 * @return 262 * 0 on success, errno value on failure. 263 */ 264 int 265 priv_allmulticast_enable(struct priv *priv) 266 { 267 unsigned int i; 268 269 for (i = 0; (i != priv->hash_rxqs_n); ++i) { 270 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i]; 271 int ret; 272 273 /* allmulticast not relevant for TCP. */ 274 if (hash_rxq->type == HASH_RXQ_TCPV4) 275 continue; 276 ret = hash_rxq_allmulticast_enable(hash_rxq); 277 if (!ret) 278 continue; 279 /* Failure, rollback. */ 280 while (i != 0) { 281 hash_rxq = &(*priv->hash_rxqs)[--i]; 282 hash_rxq_allmulticast_disable(hash_rxq); 283 } 284 return ret; 285 } 286 return 0; 287 } 288 289 /** 290 * DPDK callback to enable allmulti mode. 291 * 292 * @param dev 293 * Pointer to Ethernet device structure. 294 */ 295 void 296 mlx5_allmulticast_enable(struct rte_eth_dev *dev) 297 { 298 struct priv *priv = dev->data->dev_private; 299 int ret; 300 301 priv_lock(priv); 302 priv->allmulti_req = 1; 303 ret = priv_allmulticast_enable(priv); 304 if (ret) 305 ERROR("cannot enable allmulticast mode: %s", strerror(ret)); 306 priv_unlock(priv); 307 } 308 309 /** 310 * Disable allmulti mode in a hash RX queue. 311 * 312 * @param hash_rxq 313 * Pointer to hash RX queue structure. 314 */ 315 static void 316 hash_rxq_allmulticast_disable(struct hash_rxq *hash_rxq) 317 { 318 if (hash_rxq->allmulti_flow == NULL) 319 return; 320 DEBUG("%p: disabling allmulticast mode", (void *)hash_rxq); 321 claim_zero(ibv_destroy_flow(hash_rxq->allmulti_flow)); 322 hash_rxq->allmulti_flow = NULL; 323 DEBUG("%p: allmulticast mode disabled", (void *)hash_rxq); 324 } 325 326 /** 327 * Disable allmulti mode in all hash RX queues. 328 * 329 * @param priv 330 * Private structure. 331 */ 332 void 333 priv_allmulticast_disable(struct priv *priv) 334 { 335 unsigned int i; 336 337 for (i = 0; (i != priv->hash_rxqs_n); ++i) 338 hash_rxq_allmulticast_disable(&(*priv->hash_rxqs)[i]); 339 } 340 341 /** 342 * DPDK callback to disable allmulti mode. 343 * 344 * @param dev 345 * Pointer to Ethernet device structure. 346 */ 347 void 348 mlx5_allmulticast_disable(struct rte_eth_dev *dev) 349 { 350 struct priv *priv = dev->data->dev_private; 351 352 priv_lock(priv); 353 priv->allmulti_req = 0; 354 priv_allmulticast_disable(priv); 355 priv_unlock(priv); 356 } 357