1290650Shselasky/*- 2290650Shselasky * Copyright (c) 2015 Mellanox Technologies. All rights reserved. 3290650Shselasky * 4290650Shselasky * Redistribution and use in source and binary forms, with or without 5290650Shselasky * modification, are permitted provided that the following conditions 6290650Shselasky * are met: 7290650Shselasky * 1. Redistributions of source code must retain the above copyright 8290650Shselasky * notice, this list of conditions and the following disclaimer. 9290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10290650Shselasky * notice, this list of conditions and the following disclaimer in the 11290650Shselasky * documentation and/or other materials provided with the distribution. 12290650Shselasky * 13290650Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16290650Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18290650Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23290650Shselasky * SUCH DAMAGE. 24290650Shselasky * 25290650Shselasky * $FreeBSD: stable/10/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c 310244 2016-12-19 09:38:34Z hselasky $ 26290650Shselasky */ 27290650Shselasky 28290650Shselasky#include "en.h" 29290650Shselasky 30290650Shselasky#include <linux/list.h> 31290650Shselasky#include <dev/mlx5/flow_table.h> 32290650Shselasky 33290650Shselaskyenum { 34290650Shselasky MLX5E_FULLMATCH = 0, 35290650Shselasky MLX5E_ALLMULTI = 1, 36290650Shselasky MLX5E_PROMISC = 2, 37290650Shselasky}; 38290650Shselasky 39290650Shselaskyenum { 40290650Shselasky MLX5E_UC = 0, 41290650Shselasky MLX5E_MC_IPV4 = 1, 42290650Shselasky MLX5E_MC_IPV6 = 2, 43290650Shselasky MLX5E_MC_OTHER = 3, 44290650Shselasky}; 45290650Shselasky 46290650Shselaskyenum { 47290650Shselasky MLX5E_ACTION_NONE = 0, 48290650Shselasky MLX5E_ACTION_ADD = 1, 49290650Shselasky MLX5E_ACTION_DEL = 2, 50290650Shselasky}; 51290650Shselasky 52290650Shselaskystruct mlx5e_eth_addr_hash_node { 53290650Shselasky LIST_ENTRY(mlx5e_eth_addr_hash_node) hlist; 54290650Shselasky u8 action; 55290650Shselasky struct mlx5e_eth_addr_info ai; 56290650Shselasky}; 57290650Shselasky 58290650Shselaskystatic inline int 59290650Shselaskymlx5e_hash_eth_addr(const u8 * addr) 60290650Shselasky{ 61290650Shselasky return (addr[5]); 62290650Shselasky} 63290650Shselasky 64290650Shselaskystatic void 65290650Shselaskymlx5e_add_eth_addr_to_hash(struct mlx5e_eth_addr_hash_head *hash, 66290650Shselasky const u8 * addr) 67290650Shselasky{ 68290650Shselasky struct mlx5e_eth_addr_hash_node *hn; 69290650Shselasky int ix = mlx5e_hash_eth_addr(addr); 70290650Shselasky 71290650Shselasky LIST_FOREACH(hn, &hash[ix], hlist) { 72290650Shselasky if (bcmp(hn->ai.addr, addr, ETHER_ADDR_LEN) == 0) { 73290650Shselasky if (hn->action == MLX5E_ACTION_DEL) 74290650Shselasky hn->action = MLX5E_ACTION_NONE; 75290650Shselasky return; 76290650Shselasky } 77290650Shselasky } 78290650Shselasky 79290650Shselasky hn = malloc(sizeof(*hn), M_MLX5EN, M_NOWAIT | M_ZERO); 80290650Shselasky if (hn == NULL) 81290650Shselasky return; 82290650Shselasky 83290650Shselasky ether_addr_copy(hn->ai.addr, addr); 84290650Shselasky hn->action = MLX5E_ACTION_ADD; 85290650Shselasky 86290650Shselasky LIST_INSERT_HEAD(&hash[ix], hn, hlist); 87290650Shselasky} 88290650Shselasky 89290650Shselaskystatic void 90290650Shselaskymlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn) 91290650Shselasky{ 92290650Shselasky LIST_REMOVE(hn, hlist); 93290650Shselasky free(hn, M_MLX5EN); 94290650Shselasky} 95290650Shselasky 96290650Shselaskystatic void 97290650Shselaskymlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, 98290650Shselasky struct mlx5e_eth_addr_info *ai) 99290650Shselasky{ 100290650Shselasky void *ft = priv->ft.main; 101290650Shselasky 102290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP)) 103290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); 104290650Shselasky 105290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP)) 106290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]); 107290650Shselasky 108290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP)) 109290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]); 110290650Shselasky 111290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP)) 112290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]); 113290650Shselasky 114290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV6)) 115290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]); 116290650Shselasky 117290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_IPV4)) 118290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]); 119290650Shselasky 120290650Shselasky if (ai->tt_vec & (1 << MLX5E_TT_ANY)) 121290650Shselasky mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]); 122290650Shselasky} 123290650Shselasky 124290650Shselaskystatic int 125290650Shselaskymlx5e_get_eth_addr_type(const u8 * addr) 126290650Shselasky{ 127290650Shselasky if (ETHER_IS_MULTICAST(addr) == 0) 128290650Shselasky return (MLX5E_UC); 129290650Shselasky 130290650Shselasky if ((addr[0] == 0x01) && 131290650Shselasky (addr[1] == 0x00) && 132290650Shselasky (addr[2] == 0x5e) && 133290650Shselasky !(addr[3] & 0x80)) 134290650Shselasky return (MLX5E_MC_IPV4); 135290650Shselasky 136290650Shselasky if ((addr[0] == 0x33) && 137290650Shselasky (addr[1] == 0x33)) 138290650Shselasky return (MLX5E_MC_IPV6); 139290650Shselasky 140290650Shselasky return (MLX5E_MC_OTHER); 141290650Shselasky} 142290650Shselasky 143290650Shselaskystatic u32 144290650Shselaskymlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) 145290650Shselasky{ 146290650Shselasky int eth_addr_type; 147290650Shselasky u32 ret; 148290650Shselasky 149290650Shselasky switch (type) { 150290650Shselasky case MLX5E_FULLMATCH: 151290650Shselasky eth_addr_type = mlx5e_get_eth_addr_type(ai->addr); 152290650Shselasky switch (eth_addr_type) { 153290650Shselasky case MLX5E_UC: 154290650Shselasky ret = 155290650Shselasky (1 << MLX5E_TT_IPV4_TCP) | 156290650Shselasky (1 << MLX5E_TT_IPV6_TCP) | 157290650Shselasky (1 << MLX5E_TT_IPV4_UDP) | 158290650Shselasky (1 << MLX5E_TT_IPV6_UDP) | 159290650Shselasky (1 << MLX5E_TT_IPV4) | 160290650Shselasky (1 << MLX5E_TT_IPV6) | 161290650Shselasky (1 << MLX5E_TT_ANY) | 162290650Shselasky 0; 163290650Shselasky break; 164290650Shselasky 165290650Shselasky case MLX5E_MC_IPV4: 166290650Shselasky ret = 167290650Shselasky (1 << MLX5E_TT_IPV4_UDP) | 168290650Shselasky (1 << MLX5E_TT_IPV4) | 169290650Shselasky 0; 170290650Shselasky break; 171290650Shselasky 172290650Shselasky case MLX5E_MC_IPV6: 173290650Shselasky ret = 174290650Shselasky (1 << MLX5E_TT_IPV6_UDP) | 175290650Shselasky (1 << MLX5E_TT_IPV6) | 176290650Shselasky 0; 177290650Shselasky break; 178290650Shselasky 179290650Shselasky default: 180290650Shselasky ret = 181290650Shselasky (1 << MLX5E_TT_ANY) | 182290650Shselasky 0; 183290650Shselasky break; 184290650Shselasky } 185290650Shselasky break; 186290650Shselasky 187290650Shselasky case MLX5E_ALLMULTI: 188290650Shselasky ret = 189290650Shselasky (1 << MLX5E_TT_IPV4_UDP) | 190290650Shselasky (1 << MLX5E_TT_IPV6_UDP) | 191290650Shselasky (1 << MLX5E_TT_IPV4) | 192290650Shselasky (1 << MLX5E_TT_IPV6) | 193290650Shselasky (1 << MLX5E_TT_ANY) | 194290650Shselasky 0; 195290650Shselasky break; 196290650Shselasky 197290650Shselasky default: /* MLX5E_PROMISC */ 198290650Shselasky ret = 199290650Shselasky (1 << MLX5E_TT_IPV4_TCP) | 200290650Shselasky (1 << MLX5E_TT_IPV6_TCP) | 201290650Shselasky (1 << MLX5E_TT_IPV4_UDP) | 202290650Shselasky (1 << MLX5E_TT_IPV6_UDP) | 203290650Shselasky (1 << MLX5E_TT_IPV4) | 204290650Shselasky (1 << MLX5E_TT_IPV6) | 205290650Shselasky (1 << MLX5E_TT_ANY) | 206290650Shselasky 0; 207290650Shselasky break; 208290650Shselasky } 209290650Shselasky 210290650Shselasky return (ret); 211290650Shselasky} 212290650Shselasky 213290650Shselaskystatic int 214290650Shselaskymlx5e_add_eth_addr_rule_sub(struct mlx5e_priv *priv, 215290650Shselasky struct mlx5e_eth_addr_info *ai, int type, 216290650Shselasky void *flow_context, void *match_criteria) 217290650Shselasky{ 218290650Shselasky u8 match_criteria_enable = 0; 219290650Shselasky void *match_value; 220290650Shselasky void *dest; 221290650Shselasky u8 *dmac; 222290650Shselasky u8 *match_criteria_dmac; 223290650Shselasky void *ft = priv->ft.main; 224290650Shselasky u32 *tirn = priv->tirn; 225290650Shselasky u32 tt_vec; 226290650Shselasky int err; 227290650Shselasky 228290650Shselasky match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); 229290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, match_value, 230290650Shselasky outer_headers.dmac_47_16); 231290650Shselasky match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, 232290650Shselasky outer_headers.dmac_47_16); 233290650Shselasky dest = MLX5_ADDR_OF(flow_context, flow_context, destination); 234290650Shselasky 235290650Shselasky MLX5_SET(flow_context, flow_context, action, 236290650Shselasky MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); 237290650Shselasky MLX5_SET(flow_context, flow_context, destination_list_size, 1); 238290650Shselasky MLX5_SET(dest_format_struct, dest, destination_type, 239290650Shselasky MLX5_FLOW_CONTEXT_DEST_TYPE_TIR); 240290650Shselasky 241290650Shselasky switch (type) { 242290650Shselasky case MLX5E_FULLMATCH: 243290650Shselasky match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 244290650Shselasky memset(match_criteria_dmac, 0xff, ETH_ALEN); 245290650Shselasky ether_addr_copy(dmac, ai->addr); 246290650Shselasky break; 247290650Shselasky 248290650Shselasky case MLX5E_ALLMULTI: 249290650Shselasky match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 250290650Shselasky match_criteria_dmac[0] = 0x01; 251290650Shselasky dmac[0] = 0x01; 252290650Shselasky break; 253290650Shselasky 254290650Shselasky case MLX5E_PROMISC: 255290650Shselasky break; 256290650Shselasky default: 257290650Shselasky break; 258290650Shselasky } 259290650Shselasky 260290650Shselasky tt_vec = mlx5e_get_tt_vec(ai, type); 261290650Shselasky 262290650Shselasky if (tt_vec & (1 << MLX5E_TT_ANY)) { 263290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 264290650Shselasky tirn[MLX5E_TT_ANY]); 265290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 266290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_ANY]); 267290650Shselasky if (err) { 268290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 269290650Shselasky return (err); 270290650Shselasky } 271290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_ANY); 272290650Shselasky } 273290650Shselasky match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 274290650Shselasky MLX5_SET_TO_ONES(fte_match_param, match_criteria, 275290650Shselasky outer_headers.ethertype); 276290650Shselasky 277290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV4)) { 278290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 279290650Shselasky ETHERTYPE_IP); 280290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 281290650Shselasky tirn[MLX5E_TT_IPV4]); 282290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 283290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4]); 284290650Shselasky if (err) { 285290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 286290650Shselasky return (err); 287290650Shselasky } 288290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV4); 289290650Shselasky } 290290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV6)) { 291290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 292290650Shselasky ETHERTYPE_IPV6); 293290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 294290650Shselasky tirn[MLX5E_TT_IPV6]); 295290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 296290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6]); 297290650Shselasky if (err) { 298290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 299290650Shselasky return (err); 300290650Shselasky } 301290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV6); 302290650Shselasky } 303290650Shselasky MLX5_SET_TO_ONES(fte_match_param, match_criteria, 304290650Shselasky outer_headers.ip_protocol); 305290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, 306290650Shselasky IPPROTO_UDP); 307290650Shselasky 308290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) { 309290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 310290650Shselasky ETHERTYPE_IP); 311290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 312290650Shselasky tirn[MLX5E_TT_IPV4_UDP]); 313290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 314290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_UDP]); 315290650Shselasky if (err) { 316290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 317290650Shselasky return (err); 318290650Shselasky } 319290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP); 320290650Shselasky } 321290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) { 322290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 323290650Shselasky ETHERTYPE_IPV6); 324290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 325290650Shselasky tirn[MLX5E_TT_IPV6_UDP]); 326290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 327290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_UDP]); 328290650Shselasky if (err) { 329290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 330290650Shselasky return (err); 331290650Shselasky } 332290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP); 333290650Shselasky } 334290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, 335290650Shselasky IPPROTO_TCP); 336290650Shselasky 337290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) { 338290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 339290650Shselasky ETHERTYPE_IP); 340290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 341290650Shselasky tirn[MLX5E_TT_IPV4_TCP]); 342290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 343290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_TCP]); 344290650Shselasky if (err) { 345290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 346290650Shselasky return (err); 347290650Shselasky } 348290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP); 349290650Shselasky } 350290650Shselasky if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) { 351290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, 352290650Shselasky ETHERTYPE_IPV6); 353290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 354290650Shselasky tirn[MLX5E_TT_IPV6_TCP]); 355290650Shselasky err = mlx5_add_flow_table_entry(ft, match_criteria_enable, 356290650Shselasky match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_TCP]); 357290650Shselasky if (err) { 358290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, ai); 359290650Shselasky return (err); 360290650Shselasky } 361290650Shselasky ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP); 362290650Shselasky } 363290650Shselasky return (0); 364290650Shselasky} 365290650Shselasky 366290650Shselaskystatic int 367290650Shselaskymlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, 368290650Shselasky struct mlx5e_eth_addr_info *ai, int type) 369290650Shselasky{ 370290650Shselasky u32 *flow_context; 371290650Shselasky u32 *match_criteria; 372290650Shselasky int err; 373290650Shselasky 374290650Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + 375290650Shselasky MLX5_ST_SZ_BYTES(dest_format_struct)); 376290650Shselasky match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 377290650Shselasky if (!flow_context || !match_criteria) { 378290650Shselasky if_printf(priv->ifp, "%s: alloc failed\n", __func__); 379290650Shselasky err = -ENOMEM; 380290650Shselasky goto add_eth_addr_rule_out; 381290650Shselasky } 382290650Shselasky err = mlx5e_add_eth_addr_rule_sub(priv, ai, type, flow_context, 383290650Shselasky match_criteria); 384290650Shselasky if (err) 385290650Shselasky if_printf(priv->ifp, "%s: failed\n", __func__); 386290650Shselasky 387290650Shselaskyadd_eth_addr_rule_out: 388290650Shselasky kvfree(match_criteria); 389290650Shselasky kvfree(flow_context); 390290650Shselasky return (err); 391290650Shselasky} 392290650Shselasky 393302270Shselaskystatic int mlx5e_vport_context_update_vlans(struct mlx5e_priv *priv) 394302270Shselasky{ 395302270Shselasky struct ifnet *ifp = priv->ifp; 396302270Shselasky int max_list_size; 397302270Shselasky int list_size; 398302270Shselasky u16 *vlans; 399302270Shselasky int vlan; 400302270Shselasky int err; 401302270Shselasky int i; 402302270Shselasky 403302270Shselasky list_size = 0; 404302270Shselasky for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID) 405302270Shselasky list_size++; 406302270Shselasky 407302270Shselasky max_list_size = 1 << MLX5_CAP_GEN(priv->mdev, log_max_vlan_list); 408302270Shselasky 409302270Shselasky if (list_size > max_list_size) { 410302270Shselasky if_printf(ifp, 411302270Shselasky "ifnet vlans list size (%d) > (%d) max vport list size, some vlans will be dropped\n", 412302270Shselasky list_size, max_list_size); 413302270Shselasky list_size = max_list_size; 414302270Shselasky } 415302270Shselasky 416302270Shselasky vlans = kcalloc(list_size, sizeof(*vlans), GFP_KERNEL); 417302270Shselasky if (!vlans) 418302270Shselasky return -ENOMEM; 419302270Shselasky 420302270Shselasky i = 0; 421302270Shselasky for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID) { 422302270Shselasky if (i >= list_size) 423302270Shselasky break; 424302270Shselasky vlans[i++] = vlan; 425302270Shselasky } 426302270Shselasky 427302270Shselasky err = mlx5_modify_nic_vport_vlans(priv->mdev, vlans, list_size); 428302270Shselasky if (err) 429302270Shselasky if_printf(ifp, "Failed to modify vport vlans list err(%d)\n", 430302270Shselasky err); 431302270Shselasky 432302270Shselasky kfree(vlans); 433302270Shselasky return err; 434302270Shselasky} 435302270Shselasky 436290650Shselaskyenum mlx5e_vlan_rule_type { 437290650Shselasky MLX5E_VLAN_RULE_TYPE_UNTAGGED, 438290650Shselasky MLX5E_VLAN_RULE_TYPE_ANY_VID, 439290650Shselasky MLX5E_VLAN_RULE_TYPE_MATCH_VID, 440290650Shselasky}; 441290650Shselasky 442290650Shselaskystatic int 443290650Shselaskymlx5e_add_vlan_rule(struct mlx5e_priv *priv, 444290650Shselasky enum mlx5e_vlan_rule_type rule_type, u16 vid) 445290650Shselasky{ 446290650Shselasky u8 match_criteria_enable = 0; 447290650Shselasky u32 *flow_context; 448290650Shselasky void *match_value; 449290650Shselasky void *dest; 450290650Shselasky u32 *match_criteria; 451290650Shselasky u32 *ft_ix; 452290650Shselasky int err; 453290650Shselasky 454290650Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + 455290650Shselasky MLX5_ST_SZ_BYTES(dest_format_struct)); 456290650Shselasky match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 457290650Shselasky if (!flow_context || !match_criteria) { 458290650Shselasky if_printf(priv->ifp, "%s: alloc failed\n", __func__); 459290650Shselasky err = -ENOMEM; 460290650Shselasky goto add_vlan_rule_out; 461290650Shselasky } 462290650Shselasky match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); 463290650Shselasky dest = MLX5_ADDR_OF(flow_context, flow_context, destination); 464290650Shselasky 465290650Shselasky MLX5_SET(flow_context, flow_context, action, 466291184Shselasky MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); 467290650Shselasky MLX5_SET(flow_context, flow_context, destination_list_size, 1); 468290650Shselasky MLX5_SET(dest_format_struct, dest, destination_type, 469291184Shselasky MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE); 470290650Shselasky MLX5_SET(dest_format_struct, dest, destination_id, 471291184Shselasky mlx5_get_flow_table_id(priv->ft.main)); 472290650Shselasky 473290650Shselasky match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 474290650Shselasky MLX5_SET_TO_ONES(fte_match_param, match_criteria, 475306244Shselasky outer_headers.cvlan_tag); 476290650Shselasky 477290650Shselasky switch (rule_type) { 478290650Shselasky case MLX5E_VLAN_RULE_TYPE_UNTAGGED: 479290650Shselasky ft_ix = &priv->vlan.untagged_rule_ft_ix; 480290650Shselasky break; 481290650Shselasky case MLX5E_VLAN_RULE_TYPE_ANY_VID: 482290650Shselasky ft_ix = &priv->vlan.any_vlan_rule_ft_ix; 483306244Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.cvlan_tag, 484290650Shselasky 1); 485290650Shselasky break; 486290650Shselasky default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ 487290650Shselasky ft_ix = &priv->vlan.active_vlans_ft_ix[vid]; 488306244Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.cvlan_tag, 489290650Shselasky 1); 490290650Shselasky MLX5_SET_TO_ONES(fte_match_param, match_criteria, 491290650Shselasky outer_headers.first_vid); 492290650Shselasky MLX5_SET(fte_match_param, match_value, outer_headers.first_vid, 493290650Shselasky vid); 494302270Shselasky mlx5e_vport_context_update_vlans(priv); 495290650Shselasky break; 496290650Shselasky } 497290650Shselasky 498290650Shselasky err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable, 499290650Shselasky match_criteria, flow_context, ft_ix); 500290650Shselasky if (err) 501290650Shselasky if_printf(priv->ifp, "%s: failed\n", __func__); 502290650Shselasky 503290650Shselaskyadd_vlan_rule_out: 504290650Shselasky kvfree(match_criteria); 505290650Shselasky kvfree(flow_context); 506290650Shselasky return (err); 507290650Shselasky} 508290650Shselasky 509290650Shselaskystatic void 510290650Shselaskymlx5e_del_vlan_rule(struct mlx5e_priv *priv, 511290650Shselasky enum mlx5e_vlan_rule_type rule_type, u16 vid) 512290650Shselasky{ 513290650Shselasky switch (rule_type) { 514290650Shselasky case MLX5E_VLAN_RULE_TYPE_UNTAGGED: 515290650Shselasky mlx5_del_flow_table_entry(priv->ft.vlan, 516290650Shselasky priv->vlan.untagged_rule_ft_ix); 517290650Shselasky break; 518290650Shselasky case MLX5E_VLAN_RULE_TYPE_ANY_VID: 519290650Shselasky mlx5_del_flow_table_entry(priv->ft.vlan, 520290650Shselasky priv->vlan.any_vlan_rule_ft_ix); 521290650Shselasky break; 522290650Shselasky case MLX5E_VLAN_RULE_TYPE_MATCH_VID: 523290650Shselasky mlx5_del_flow_table_entry(priv->ft.vlan, 524290650Shselasky priv->vlan.active_vlans_ft_ix[vid]); 525302270Shselasky mlx5e_vport_context_update_vlans(priv); 526290650Shselasky break; 527290650Shselasky } 528290650Shselasky} 529290650Shselasky 530290650Shselaskyvoid 531290650Shselaskymlx5e_enable_vlan_filter(struct mlx5e_priv *priv) 532290650Shselasky{ 533290650Shselasky if (priv->vlan.filter_disabled) { 534290650Shselasky priv->vlan.filter_disabled = false; 535290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 536290650Shselasky mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 537290650Shselasky 0); 538290650Shselasky } 539290650Shselasky} 540290650Shselasky 541290650Shselaskyvoid 542290650Shselaskymlx5e_disable_vlan_filter(struct mlx5e_priv *priv) 543290650Shselasky{ 544290650Shselasky if (!priv->vlan.filter_disabled) { 545290650Shselasky priv->vlan.filter_disabled = true; 546290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 547290650Shselasky mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 548290650Shselasky 0); 549290650Shselasky } 550290650Shselasky} 551290650Shselasky 552290650Shselaskyvoid 553290650Shselaskymlx5e_vlan_rx_add_vid(void *arg, struct ifnet *ifp, u16 vid) 554290650Shselasky{ 555290650Shselasky struct mlx5e_priv *priv = arg; 556290650Shselasky 557290650Shselasky if (ifp != priv->ifp) 558290650Shselasky return; 559290650Shselasky 560290650Shselasky PRIV_LOCK(priv); 561290650Shselasky set_bit(vid, priv->vlan.active_vlans); 562290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 563290650Shselasky mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); 564290650Shselasky PRIV_UNLOCK(priv); 565290650Shselasky} 566290650Shselasky 567290650Shselaskyvoid 568290650Shselaskymlx5e_vlan_rx_kill_vid(void *arg, struct ifnet *ifp, u16 vid) 569290650Shselasky{ 570290650Shselasky struct mlx5e_priv *priv = arg; 571290650Shselasky 572290650Shselasky if (ifp != priv->ifp) 573290650Shselasky return; 574290650Shselasky 575290650Shselasky PRIV_LOCK(priv); 576290650Shselasky clear_bit(vid, priv->vlan.active_vlans); 577290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 578290650Shselasky mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); 579290650Shselasky PRIV_UNLOCK(priv); 580290650Shselasky} 581290650Shselasky 582290650Shselaskyint 583290650Shselaskymlx5e_add_all_vlan_rules(struct mlx5e_priv *priv) 584290650Shselasky{ 585290650Shselasky u16 vid; 586290650Shselasky int err; 587290650Shselasky 588290650Shselasky for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) { 589290650Shselasky err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, 590290650Shselasky vid); 591290650Shselasky if (err) 592290650Shselasky return (err); 593290650Shselasky } 594290650Shselasky 595290650Shselasky err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); 596290650Shselasky if (err) 597290650Shselasky return (err); 598290650Shselasky 599290650Shselasky if (priv->vlan.filter_disabled) { 600290650Shselasky err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 601290650Shselasky 0); 602290650Shselasky if (err) 603290650Shselasky return (err); 604290650Shselasky } 605290650Shselasky return (0); 606290650Shselasky} 607290650Shselasky 608290650Shselaskyvoid 609290650Shselaskymlx5e_del_all_vlan_rules(struct mlx5e_priv *priv) 610290650Shselasky{ 611290650Shselasky u16 vid; 612290650Shselasky 613290650Shselasky if (priv->vlan.filter_disabled) 614290650Shselasky mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); 615290650Shselasky 616290650Shselasky mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); 617290650Shselasky 618290650Shselasky for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) 619290650Shselasky mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); 620290650Shselasky} 621290650Shselasky 622290650Shselasky#define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ 623290650Shselasky for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \ 624290650Shselasky LIST_FOREACH_SAFE(hn, &(hash)[i], hlist, tmp) 625290650Shselasky 626290650Shselaskystatic void 627290650Shselaskymlx5e_execute_action(struct mlx5e_priv *priv, 628290650Shselasky struct mlx5e_eth_addr_hash_node *hn) 629290650Shselasky{ 630290650Shselasky switch (hn->action) { 631290650Shselasky case MLX5E_ACTION_ADD: 632290650Shselasky mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH); 633290650Shselasky hn->action = MLX5E_ACTION_NONE; 634290650Shselasky break; 635290650Shselasky 636290650Shselasky case MLX5E_ACTION_DEL: 637290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai); 638290650Shselasky mlx5e_del_eth_addr_from_hash(hn); 639290650Shselasky break; 640290650Shselasky 641290650Shselasky default: 642290650Shselasky break; 643290650Shselasky } 644290650Shselasky} 645290650Shselasky 646290650Shselaskystatic void 647290650Shselaskymlx5e_sync_ifp_addr(struct mlx5e_priv *priv) 648290650Shselasky{ 649290650Shselasky struct ifnet *ifp = priv->ifp; 650290650Shselasky struct ifaddr *ifa; 651290650Shselasky struct ifmultiaddr *ifma; 652290650Shselasky 653290650Shselasky /* XXX adding this entry might not be needed */ 654290650Shselasky mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc, 655290650Shselasky LLADDR((struct sockaddr_dl *)(ifp->if_addr->ifa_addr))); 656290650Shselasky 657290650Shselasky if_addr_rlock(ifp); 658290650Shselasky TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 659290650Shselasky if (ifa->ifa_addr->sa_family != AF_LINK) 660290650Shselasky continue; 661290650Shselasky mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc, 662290650Shselasky LLADDR((struct sockaddr_dl *)ifa->ifa_addr)); 663290650Shselasky } 664290650Shselasky if_addr_runlock(ifp); 665290650Shselasky 666290650Shselasky if_maddr_rlock(ifp); 667290650Shselasky TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 668290650Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) 669290650Shselasky continue; 670290650Shselasky mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_mc, 671290650Shselasky LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 672290650Shselasky } 673290650Shselasky if_maddr_runlock(ifp); 674290650Shselasky} 675290650Shselasky 676302270Shselaskystatic void mlx5e_fill_addr_array(struct mlx5e_priv *priv, int list_type, 677302270Shselasky u8 addr_array[][ETH_ALEN], int size) 678302270Shselasky{ 679302270Shselasky bool is_uc = (list_type == MLX5_NIC_VPORT_LIST_TYPE_UC); 680302270Shselasky struct ifnet *ifp = priv->ifp; 681302270Shselasky struct mlx5e_eth_addr_hash_node *hn; 682302270Shselasky struct mlx5e_eth_addr_hash_head *addr_list; 683302270Shselasky struct mlx5e_eth_addr_hash_node *tmp; 684302270Shselasky int i = 0; 685302270Shselasky int hi; 686302270Shselasky 687302270Shselasky addr_list = is_uc ? priv->eth_addr.if_uc : priv->eth_addr.if_mc; 688302270Shselasky 689302270Shselasky if (is_uc) /* Make sure our own address is pushed first */ 690302270Shselasky ether_addr_copy(addr_array[i++], IF_LLADDR(ifp)); 691302270Shselasky else if (priv->eth_addr.broadcast_enabled) 692302270Shselasky ether_addr_copy(addr_array[i++], ifp->if_broadcastaddr); 693302270Shselasky 694302270Shselasky mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) { 695302270Shselasky if (ether_addr_equal(IF_LLADDR(ifp), hn->ai.addr)) 696302270Shselasky continue; 697302270Shselasky if (i >= size) 698302270Shselasky break; 699302270Shselasky ether_addr_copy(addr_array[i++], hn->ai.addr); 700302270Shselasky } 701302270Shselasky} 702302270Shselasky 703302270Shselaskystatic void mlx5e_vport_context_update_addr_list(struct mlx5e_priv *priv, 704302270Shselasky int list_type) 705302270Shselasky{ 706302270Shselasky bool is_uc = (list_type == MLX5_NIC_VPORT_LIST_TYPE_UC); 707302270Shselasky struct mlx5e_eth_addr_hash_node *hn; 708302270Shselasky u8 (*addr_array)[ETH_ALEN] = NULL; 709302270Shselasky struct mlx5e_eth_addr_hash_head *addr_list; 710302270Shselasky struct mlx5e_eth_addr_hash_node *tmp; 711302270Shselasky int max_size; 712302270Shselasky int size; 713302270Shselasky int err; 714302270Shselasky int hi; 715302270Shselasky 716302270Shselasky size = is_uc ? 0 : (priv->eth_addr.broadcast_enabled ? 1 : 0); 717302270Shselasky max_size = is_uc ? 718302270Shselasky 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_uc_list) : 719302270Shselasky 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_mc_list); 720302270Shselasky 721302270Shselasky addr_list = is_uc ? priv->eth_addr.if_uc : priv->eth_addr.if_mc; 722302270Shselasky mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) 723302270Shselasky size++; 724302270Shselasky 725302270Shselasky if (size > max_size) { 726302270Shselasky if_printf(priv->ifp, 727302270Shselasky "ifp %s list size (%d) > (%d) max vport list size, some addresses will be dropped\n", 728302270Shselasky is_uc ? "UC" : "MC", size, max_size); 729302270Shselasky size = max_size; 730302270Shselasky } 731302270Shselasky 732302270Shselasky if (size) { 733302270Shselasky addr_array = kcalloc(size, ETH_ALEN, GFP_KERNEL); 734302270Shselasky if (!addr_array) { 735302270Shselasky err = -ENOMEM; 736302270Shselasky goto out; 737302270Shselasky } 738302270Shselasky mlx5e_fill_addr_array(priv, list_type, addr_array, size); 739302270Shselasky } 740302270Shselasky 741302270Shselasky err = mlx5_modify_nic_vport_mac_list(priv->mdev, list_type, addr_array, size); 742302270Shselaskyout: 743302270Shselasky if (err) 744302270Shselasky if_printf(priv->ifp, 745302270Shselasky "Failed to modify vport %s list err(%d)\n", 746302270Shselasky is_uc ? "UC" : "MC", err); 747302270Shselasky kfree(addr_array); 748302270Shselasky} 749302270Shselasky 750302270Shselaskystatic void mlx5e_vport_context_update(struct mlx5e_priv *priv) 751302270Shselasky{ 752302270Shselasky struct mlx5e_eth_addr_db *ea = &priv->eth_addr; 753302270Shselasky 754302270Shselasky mlx5e_vport_context_update_addr_list(priv, MLX5_NIC_VPORT_LIST_TYPE_UC); 755302270Shselasky mlx5e_vport_context_update_addr_list(priv, MLX5_NIC_VPORT_LIST_TYPE_MC); 756302270Shselasky mlx5_modify_nic_vport_promisc(priv->mdev, 0, 757302270Shselasky ea->allmulti_enabled, 758302270Shselasky ea->promisc_enabled); 759302270Shselasky} 760302270Shselasky 761290650Shselaskystatic void 762290650Shselaskymlx5e_apply_ifp_addr(struct mlx5e_priv *priv) 763290650Shselasky{ 764290650Shselasky struct mlx5e_eth_addr_hash_node *hn; 765290650Shselasky struct mlx5e_eth_addr_hash_node *tmp; 766290650Shselasky int i; 767290650Shselasky 768290650Shselasky mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i) 769290650Shselasky mlx5e_execute_action(priv, hn); 770290650Shselasky 771290650Shselasky mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i) 772290650Shselasky mlx5e_execute_action(priv, hn); 773290650Shselasky} 774290650Shselasky 775290650Shselaskystatic void 776290650Shselaskymlx5e_handle_ifp_addr(struct mlx5e_priv *priv) 777290650Shselasky{ 778290650Shselasky struct mlx5e_eth_addr_hash_node *hn; 779290650Shselasky struct mlx5e_eth_addr_hash_node *tmp; 780290650Shselasky int i; 781290650Shselasky 782290650Shselasky mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i) 783290650Shselasky hn->action = MLX5E_ACTION_DEL; 784290650Shselasky mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i) 785290650Shselasky hn->action = MLX5E_ACTION_DEL; 786290650Shselasky 787290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 788290650Shselasky mlx5e_sync_ifp_addr(priv); 789290650Shselasky 790290650Shselasky mlx5e_apply_ifp_addr(priv); 791290650Shselasky} 792290650Shselasky 793290650Shselaskyvoid 794290650Shselaskymlx5e_set_rx_mode_core(struct mlx5e_priv *priv) 795290650Shselasky{ 796290650Shselasky struct mlx5e_eth_addr_db *ea = &priv->eth_addr; 797290650Shselasky struct ifnet *ndev = priv->ifp; 798290650Shselasky 799290650Shselasky bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state); 800290650Shselasky bool promisc_enabled = rx_mode_enable && (ndev->if_flags & IFF_PROMISC); 801290650Shselasky bool allmulti_enabled = rx_mode_enable && (ndev->if_flags & IFF_ALLMULTI); 802290650Shselasky bool broadcast_enabled = rx_mode_enable; 803290650Shselasky 804290650Shselasky bool enable_promisc = !ea->promisc_enabled && promisc_enabled; 805290650Shselasky bool disable_promisc = ea->promisc_enabled && !promisc_enabled; 806290650Shselasky bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled; 807290650Shselasky bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled; 808290650Shselasky bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled; 809290650Shselasky bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; 810290650Shselasky 811290650Shselasky /* update broadcast address */ 812290650Shselasky ether_addr_copy(priv->eth_addr.broadcast.addr, 813290650Shselasky priv->ifp->if_broadcastaddr); 814290650Shselasky 815290650Shselasky if (enable_promisc) 816290650Shselasky mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC); 817290650Shselasky if (enable_allmulti) 818290650Shselasky mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI); 819290650Shselasky if (enable_broadcast) 820290650Shselasky mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH); 821290650Shselasky 822290650Shselasky mlx5e_handle_ifp_addr(priv); 823290650Shselasky 824290650Shselasky if (disable_broadcast) 825290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast); 826290650Shselasky if (disable_allmulti) 827290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti); 828290650Shselasky if (disable_promisc) 829290650Shselasky mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc); 830290650Shselasky 831290650Shselasky ea->promisc_enabled = promisc_enabled; 832290650Shselasky ea->allmulti_enabled = allmulti_enabled; 833290650Shselasky ea->broadcast_enabled = broadcast_enabled; 834302270Shselasky 835302270Shselasky mlx5e_vport_context_update(priv); 836290650Shselasky} 837290650Shselasky 838290650Shselaskyvoid 839290650Shselaskymlx5e_set_rx_mode_work(struct work_struct *work) 840290650Shselasky{ 841290650Shselasky struct mlx5e_priv *priv = 842290650Shselasky container_of(work, struct mlx5e_priv, set_rx_mode_work); 843290650Shselasky 844290650Shselasky PRIV_LOCK(priv); 845290650Shselasky if (test_bit(MLX5E_STATE_OPENED, &priv->state)) 846290650Shselasky mlx5e_set_rx_mode_core(priv); 847290650Shselasky PRIV_UNLOCK(priv); 848290650Shselasky} 849290650Shselasky 850290650Shselaskystatic int 851290650Shselaskymlx5e_create_main_flow_table(struct mlx5e_priv *priv) 852290650Shselasky{ 853290650Shselasky struct mlx5_flow_table_group *g; 854290650Shselasky u8 *dmac; 855290650Shselasky 856290650Shselasky g = malloc(9 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO); 857290650Shselasky 858290650Shselasky g[0].log_sz = 2; 859290650Shselasky g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 860290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, 861290650Shselasky outer_headers.ethertype); 862290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, 863290650Shselasky outer_headers.ip_protocol); 864290650Shselasky 865290650Shselasky g[1].log_sz = 1; 866290650Shselasky g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 867290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, 868290650Shselasky outer_headers.ethertype); 869290650Shselasky 870290650Shselasky g[2].log_sz = 0; 871290650Shselasky 872290650Shselasky g[3].log_sz = 14; 873290650Shselasky g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 874290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria, 875290650Shselasky outer_headers.dmac_47_16); 876290650Shselasky memset(dmac, 0xff, ETH_ALEN); 877290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, 878290650Shselasky outer_headers.ethertype); 879290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, 880290650Shselasky outer_headers.ip_protocol); 881290650Shselasky 882290650Shselasky g[4].log_sz = 13; 883290650Shselasky g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 884290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria, 885290650Shselasky outer_headers.dmac_47_16); 886290650Shselasky memset(dmac, 0xff, ETH_ALEN); 887290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria, 888290650Shselasky outer_headers.ethertype); 889290650Shselasky 890290650Shselasky g[5].log_sz = 11; 891290650Shselasky g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 892290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria, 893290650Shselasky outer_headers.dmac_47_16); 894290650Shselasky memset(dmac, 0xff, ETH_ALEN); 895290650Shselasky 896290650Shselasky g[6].log_sz = 2; 897290650Shselasky g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 898290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria, 899290650Shselasky outer_headers.dmac_47_16); 900290650Shselasky dmac[0] = 0x01; 901290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, 902290650Shselasky outer_headers.ethertype); 903290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, 904290650Shselasky outer_headers.ip_protocol); 905290650Shselasky 906290650Shselasky g[7].log_sz = 1; 907290650Shselasky g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 908290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria, 909290650Shselasky outer_headers.dmac_47_16); 910290650Shselasky dmac[0] = 0x01; 911290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria, 912290650Shselasky outer_headers.ethertype); 913290650Shselasky 914290650Shselasky g[8].log_sz = 0; 915290650Shselasky g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 916290650Shselasky dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria, 917290650Shselasky outer_headers.dmac_47_16); 918290650Shselasky dmac[0] = 0x01; 919290650Shselasky priv->ft.main = mlx5_create_flow_table(priv->mdev, 1, 920290650Shselasky MLX5_FLOW_TABLE_TYPE_NIC_RCV, 921290650Shselasky 0, 9, g); 922290650Shselasky free(g, M_MLX5EN); 923290650Shselasky 924290650Shselasky return (priv->ft.main ? 0 : -ENOMEM); 925290650Shselasky} 926290650Shselasky 927290650Shselaskystatic void 928290650Shselaskymlx5e_destroy_main_flow_table(struct mlx5e_priv *priv) 929290650Shselasky{ 930290650Shselasky mlx5_destroy_flow_table(priv->ft.main); 931290650Shselasky priv->ft.main = NULL; 932290650Shselasky} 933290650Shselasky 934290650Shselaskystatic int 935290650Shselaskymlx5e_create_vlan_flow_table(struct mlx5e_priv *priv) 936290650Shselasky{ 937290650Shselasky struct mlx5_flow_table_group *g; 938290650Shselasky 939290650Shselasky g = malloc(2 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO); 940290650Shselasky 941290650Shselasky g[0].log_sz = 12; 942290650Shselasky g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 943290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, 944306244Shselasky outer_headers.cvlan_tag); 945290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, 946290650Shselasky outer_headers.first_vid); 947290650Shselasky 948290650Shselasky /* untagged + any vlan id */ 949290650Shselasky g[1].log_sz = 1; 950290650Shselasky g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 951290650Shselasky MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, 952306244Shselasky outer_headers.cvlan_tag); 953290650Shselasky 954290650Shselasky priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0, 955290650Shselasky MLX5_FLOW_TABLE_TYPE_NIC_RCV, 956290650Shselasky 0, 2, g); 957290650Shselasky free(g, M_MLX5EN); 958290650Shselasky 959290650Shselasky return (priv->ft.vlan ? 0 : -ENOMEM); 960290650Shselasky} 961290650Shselasky 962290650Shselaskystatic void 963290650Shselaskymlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv) 964290650Shselasky{ 965290650Shselasky mlx5_destroy_flow_table(priv->ft.vlan); 966290650Shselasky priv->ft.vlan = NULL; 967290650Shselasky} 968290650Shselasky 969290650Shselaskyint 970290650Shselaskymlx5e_open_flow_table(struct mlx5e_priv *priv) 971290650Shselasky{ 972290650Shselasky int err; 973290650Shselasky 974290650Shselasky err = mlx5e_create_main_flow_table(priv); 975290650Shselasky if (err) 976290650Shselasky return (err); 977290650Shselasky 978290650Shselasky err = mlx5e_create_vlan_flow_table(priv); 979290650Shselasky if (err) 980290650Shselasky goto err_destroy_main_flow_table; 981290650Shselasky 982290650Shselasky return (0); 983290650Shselasky 984290650Shselaskyerr_destroy_main_flow_table: 985290650Shselasky mlx5e_destroy_main_flow_table(priv); 986290650Shselasky 987290650Shselasky return (err); 988290650Shselasky} 989290650Shselasky 990290650Shselaskyvoid 991290650Shselaskymlx5e_close_flow_table(struct mlx5e_priv *priv) 992290650Shselasky{ 993290650Shselasky mlx5e_destroy_vlan_flow_table(priv); 994290650Shselasky mlx5e_destroy_main_flow_table(priv); 995290650Shselasky} 996