bridge.c (50407B)
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2021 Mellanox Technologies. */ 3 4#include <linux/list.h> 5#include <linux/notifier.h> 6#include <net/netevent.h> 7#include <net/switchdev.h> 8#include "lib/devcom.h" 9#include "bridge.h" 10#include "eswitch.h" 11#include "bridge_priv.h" 12#define CREATE_TRACE_POINTS 13#include "diag/bridge_tracepoint.h" 14 15#define MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE 64000 16#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM 0 17#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 4 - 1) 18#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM \ 19 (MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO + 1) 20#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO \ 21 (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 2 - 1) 22#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM \ 23 (MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO + 1) 24#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE - 1) 25 26#define MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE 64000 27#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM 0 28#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE / 2 - 1) 29#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM \ 30 (MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO + 1) 31#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 2) 32#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_FROM \ 33 (MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO + 1) 34#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 1) 35 36#define MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE 0 37 38enum { 39 MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE, 40 MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE, 41 MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE, 42}; 43 44static const struct rhashtable_params fdb_ht_params = { 45 .key_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, key), 46 .key_len = sizeof(struct mlx5_esw_bridge_fdb_key), 47 .head_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, ht_node), 48 .automatic_shrinking = true, 49}; 50 51enum { 52 MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG = BIT(0), 53}; 54 55struct mlx5_esw_bridge { 56 int ifindex; 57 int refcnt; 58 struct list_head list; 59 struct mlx5_esw_bridge_offloads *br_offloads; 60 61 struct list_head fdb_list; 62 struct rhashtable fdb_ht; 63 64 struct mlx5_flow_table *egress_ft; 65 struct mlx5_flow_group *egress_vlan_fg; 66 struct mlx5_flow_group *egress_mac_fg; 67 struct mlx5_flow_group *egress_miss_fg; 68 struct mlx5_pkt_reformat *egress_miss_pkt_reformat; 69 struct mlx5_flow_handle *egress_miss_handle; 70 unsigned long ageing_time; 71 u32 flags; 72}; 73 74static void 75mlx5_esw_bridge_fdb_offload_notify(struct net_device *dev, const unsigned char *addr, u16 vid, 76 unsigned long val) 77{ 78 struct switchdev_notifier_fdb_info send_info = {}; 79 80 send_info.addr = addr; 81 send_info.vid = vid; 82 send_info.offloaded = true; 83 call_switchdev_notifiers(val, dev, &send_info.info, NULL); 84} 85 86static void 87mlx5_esw_bridge_fdb_del_notify(struct mlx5_esw_bridge_fdb_entry *entry) 88{ 89 if (!(entry->flags & (MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER | MLX5_ESW_BRIDGE_FLAG_PEER))) 90 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr, 91 entry->key.vid, 92 SWITCHDEV_FDB_DEL_TO_BRIDGE); 93} 94 95static bool mlx5_esw_bridge_pkt_reformat_vlan_pop_supported(struct mlx5_eswitch *esw) 96{ 97 return BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_remove)) && 98 MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_size) >= sizeof(struct vlan_hdr) && 99 MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_offset) >= 100 offsetof(struct vlan_ethhdr, h_vlan_proto); 101} 102 103static struct mlx5_pkt_reformat * 104mlx5_esw_bridge_pkt_reformat_vlan_pop_create(struct mlx5_eswitch *esw) 105{ 106 struct mlx5_pkt_reformat_params reformat_params = {}; 107 108 reformat_params.type = MLX5_REFORMAT_TYPE_REMOVE_HDR; 109 reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START; 110 reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto); 111 reformat_params.size = sizeof(struct vlan_hdr); 112 return mlx5_packet_reformat_alloc(esw->dev, &reformat_params, MLX5_FLOW_NAMESPACE_FDB); 113} 114 115static struct mlx5_flow_table * 116mlx5_esw_bridge_table_create(int max_fte, u32 level, struct mlx5_eswitch *esw) 117{ 118 struct mlx5_flow_table_attr ft_attr = {}; 119 struct mlx5_core_dev *dev = esw->dev; 120 struct mlx5_flow_namespace *ns; 121 struct mlx5_flow_table *fdb; 122 123 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); 124 if (!ns) { 125 esw_warn(dev, "Failed to get FDB namespace\n"); 126 return ERR_PTR(-ENOENT); 127 } 128 129 ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; 130 ft_attr.max_fte = max_fte; 131 ft_attr.level = level; 132 ft_attr.prio = FDB_BR_OFFLOAD; 133 fdb = mlx5_create_flow_table(ns, &ft_attr); 134 if (IS_ERR(fdb)) 135 esw_warn(dev, "Failed to create bridge FDB Table (err=%ld)\n", PTR_ERR(fdb)); 136 137 return fdb; 138} 139 140static struct mlx5_flow_group * 141mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft) 142{ 143 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 144 struct mlx5_flow_group *fg; 145 u32 *in, *match; 146 147 in = kvzalloc(inlen, GFP_KERNEL); 148 if (!in) 149 return ERR_PTR(-ENOMEM); 150 151 MLX5_SET(create_flow_group_in, in, match_criteria_enable, 152 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2); 153 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 154 155 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16); 156 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0); 157 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag); 158 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid); 159 160 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0, 161 mlx5_eswitch_get_vport_metadata_mask()); 162 163 MLX5_SET(create_flow_group_in, in, start_flow_index, 164 MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM); 165 MLX5_SET(create_flow_group_in, in, end_flow_index, 166 MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO); 167 168 fg = mlx5_create_flow_group(ingress_ft, in); 169 kvfree(in); 170 if (IS_ERR(fg)) 171 esw_warn(esw->dev, 172 "Failed to create VLAN flow group for bridge ingress table (err=%ld)\n", 173 PTR_ERR(fg)); 174 175 return fg; 176} 177 178static struct mlx5_flow_group * 179mlx5_esw_bridge_ingress_filter_fg_create(struct mlx5_eswitch *esw, 180 struct mlx5_flow_table *ingress_ft) 181{ 182 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 183 struct mlx5_flow_group *fg; 184 u32 *in, *match; 185 186 in = kvzalloc(inlen, GFP_KERNEL); 187 if (!in) 188 return ERR_PTR(-ENOMEM); 189 190 MLX5_SET(create_flow_group_in, in, match_criteria_enable, 191 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2); 192 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 193 194 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16); 195 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0); 196 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag); 197 198 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0, 199 mlx5_eswitch_get_vport_metadata_mask()); 200 201 MLX5_SET(create_flow_group_in, in, start_flow_index, 202 MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM); 203 MLX5_SET(create_flow_group_in, in, end_flow_index, 204 MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO); 205 206 fg = mlx5_create_flow_group(ingress_ft, in); 207 if (IS_ERR(fg)) 208 esw_warn(esw->dev, 209 "Failed to create bridge ingress table VLAN filter flow group (err=%ld)\n", 210 PTR_ERR(fg)); 211 212 kvfree(in); 213 return fg; 214} 215 216static struct mlx5_flow_group * 217mlx5_esw_bridge_ingress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft) 218{ 219 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 220 struct mlx5_flow_group *fg; 221 u32 *in, *match; 222 223 in = kvzalloc(inlen, GFP_KERNEL); 224 if (!in) 225 return ERR_PTR(-ENOMEM); 226 227 MLX5_SET(create_flow_group_in, in, match_criteria_enable, 228 MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2); 229 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 230 231 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16); 232 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0); 233 234 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0, 235 mlx5_eswitch_get_vport_metadata_mask()); 236 237 MLX5_SET(create_flow_group_in, in, start_flow_index, 238 MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM); 239 MLX5_SET(create_flow_group_in, in, end_flow_index, 240 MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO); 241 242 fg = mlx5_create_flow_group(ingress_ft, in); 243 if (IS_ERR(fg)) 244 esw_warn(esw->dev, 245 "Failed to create MAC flow group for bridge ingress table (err=%ld)\n", 246 PTR_ERR(fg)); 247 248 kvfree(in); 249 return fg; 250} 251 252static struct mlx5_flow_group * 253mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft) 254{ 255 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 256 struct mlx5_flow_group *fg; 257 u32 *in, *match; 258 259 in = kvzalloc(inlen, GFP_KERNEL); 260 if (!in) 261 return ERR_PTR(-ENOMEM); 262 263 MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 264 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 265 266 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16); 267 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0); 268 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag); 269 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid); 270 271 MLX5_SET(create_flow_group_in, in, start_flow_index, 272 MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM); 273 MLX5_SET(create_flow_group_in, in, end_flow_index, 274 MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO); 275 276 fg = mlx5_create_flow_group(egress_ft, in); 277 if (IS_ERR(fg)) 278 esw_warn(esw->dev, 279 "Failed to create VLAN flow group for bridge egress table (err=%ld)\n", 280 PTR_ERR(fg)); 281 kvfree(in); 282 return fg; 283} 284 285static struct mlx5_flow_group * 286mlx5_esw_bridge_egress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft) 287{ 288 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 289 struct mlx5_flow_group *fg; 290 u32 *in, *match; 291 292 in = kvzalloc(inlen, GFP_KERNEL); 293 if (!in) 294 return ERR_PTR(-ENOMEM); 295 296 MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 297 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 298 299 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16); 300 MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0); 301 302 MLX5_SET(create_flow_group_in, in, start_flow_index, 303 MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM); 304 MLX5_SET(create_flow_group_in, in, end_flow_index, 305 MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO); 306 307 fg = mlx5_create_flow_group(egress_ft, in); 308 if (IS_ERR(fg)) 309 esw_warn(esw->dev, 310 "Failed to create bridge egress table MAC flow group (err=%ld)\n", 311 PTR_ERR(fg)); 312 kvfree(in); 313 return fg; 314} 315 316static struct mlx5_flow_group * 317mlx5_esw_bridge_egress_miss_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft) 318{ 319 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 320 struct mlx5_flow_group *fg; 321 u32 *in, *match; 322 323 in = kvzalloc(inlen, GFP_KERNEL); 324 if (!in) 325 return ERR_PTR(-ENOMEM); 326 327 MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS_2); 328 match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); 329 330 MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK); 331 332 MLX5_SET(create_flow_group_in, in, start_flow_index, 333 MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_FROM); 334 MLX5_SET(create_flow_group_in, in, end_flow_index, 335 MLX5_ESW_BRIDGE_EGRESS_TABLE_MISS_GRP_IDX_TO); 336 337 fg = mlx5_create_flow_group(egress_ft, in); 338 if (IS_ERR(fg)) 339 esw_warn(esw->dev, 340 "Failed to create bridge egress table miss flow group (err=%ld)\n", 341 PTR_ERR(fg)); 342 kvfree(in); 343 return fg; 344} 345 346static int 347mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads) 348{ 349 struct mlx5_flow_group *mac_fg, *filter_fg, *vlan_fg; 350 struct mlx5_flow_table *ingress_ft, *skip_ft; 351 struct mlx5_eswitch *esw = br_offloads->esw; 352 int err; 353 354 if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) 355 return -EOPNOTSUPP; 356 357 ingress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE, 358 MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE, 359 esw); 360 if (IS_ERR(ingress_ft)) 361 return PTR_ERR(ingress_ft); 362 363 skip_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE, 364 MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE, 365 esw); 366 if (IS_ERR(skip_ft)) { 367 err = PTR_ERR(skip_ft); 368 goto err_skip_tbl; 369 } 370 371 vlan_fg = mlx5_esw_bridge_ingress_vlan_fg_create(esw, ingress_ft); 372 if (IS_ERR(vlan_fg)) { 373 err = PTR_ERR(vlan_fg); 374 goto err_vlan_fg; 375 } 376 377 filter_fg = mlx5_esw_bridge_ingress_filter_fg_create(esw, ingress_ft); 378 if (IS_ERR(filter_fg)) { 379 err = PTR_ERR(filter_fg); 380 goto err_filter_fg; 381 } 382 383 mac_fg = mlx5_esw_bridge_ingress_mac_fg_create(esw, ingress_ft); 384 if (IS_ERR(mac_fg)) { 385 err = PTR_ERR(mac_fg); 386 goto err_mac_fg; 387 } 388 389 br_offloads->ingress_ft = ingress_ft; 390 br_offloads->skip_ft = skip_ft; 391 br_offloads->ingress_vlan_fg = vlan_fg; 392 br_offloads->ingress_filter_fg = filter_fg; 393 br_offloads->ingress_mac_fg = mac_fg; 394 return 0; 395 396err_mac_fg: 397 mlx5_destroy_flow_group(filter_fg); 398err_filter_fg: 399 mlx5_destroy_flow_group(vlan_fg); 400err_vlan_fg: 401 mlx5_destroy_flow_table(skip_ft); 402err_skip_tbl: 403 mlx5_destroy_flow_table(ingress_ft); 404 return err; 405} 406 407static void 408mlx5_esw_bridge_ingress_table_cleanup(struct mlx5_esw_bridge_offloads *br_offloads) 409{ 410 mlx5_destroy_flow_group(br_offloads->ingress_mac_fg); 411 br_offloads->ingress_mac_fg = NULL; 412 mlx5_destroy_flow_group(br_offloads->ingress_filter_fg); 413 br_offloads->ingress_filter_fg = NULL; 414 mlx5_destroy_flow_group(br_offloads->ingress_vlan_fg); 415 br_offloads->ingress_vlan_fg = NULL; 416 mlx5_destroy_flow_table(br_offloads->skip_ft); 417 br_offloads->skip_ft = NULL; 418 mlx5_destroy_flow_table(br_offloads->ingress_ft); 419 br_offloads->ingress_ft = NULL; 420} 421 422static struct mlx5_flow_handle * 423mlx5_esw_bridge_egress_miss_flow_create(struct mlx5_flow_table *egress_ft, 424 struct mlx5_flow_table *skip_ft, 425 struct mlx5_pkt_reformat *pkt_reformat); 426 427static int 428mlx5_esw_bridge_egress_table_init(struct mlx5_esw_bridge_offloads *br_offloads, 429 struct mlx5_esw_bridge *bridge) 430{ 431 struct mlx5_flow_group *miss_fg = NULL, *mac_fg, *vlan_fg; 432 struct mlx5_pkt_reformat *miss_pkt_reformat = NULL; 433 struct mlx5_flow_handle *miss_handle = NULL; 434 struct mlx5_eswitch *esw = br_offloads->esw; 435 struct mlx5_flow_table *egress_ft; 436 int err; 437 438 egress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE, 439 MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE, 440 esw); 441 if (IS_ERR(egress_ft)) 442 return PTR_ERR(egress_ft); 443 444 vlan_fg = mlx5_esw_bridge_egress_vlan_fg_create(esw, egress_ft); 445 if (IS_ERR(vlan_fg)) { 446 err = PTR_ERR(vlan_fg); 447 goto err_vlan_fg; 448 } 449 450 mac_fg = mlx5_esw_bridge_egress_mac_fg_create(esw, egress_ft); 451 if (IS_ERR(mac_fg)) { 452 err = PTR_ERR(mac_fg); 453 goto err_mac_fg; 454 } 455 456 if (mlx5_esw_bridge_pkt_reformat_vlan_pop_supported(esw)) { 457 miss_fg = mlx5_esw_bridge_egress_miss_fg_create(esw, egress_ft); 458 if (IS_ERR(miss_fg)) { 459 esw_warn(esw->dev, "Failed to create miss flow group (err=%ld)\n", 460 PTR_ERR(miss_fg)); 461 miss_fg = NULL; 462 goto skip_miss_flow; 463 } 464 465 miss_pkt_reformat = mlx5_esw_bridge_pkt_reformat_vlan_pop_create(esw); 466 if (IS_ERR(miss_pkt_reformat)) { 467 esw_warn(esw->dev, 468 "Failed to alloc packet reformat REMOVE_HEADER (err=%ld)\n", 469 PTR_ERR(miss_pkt_reformat)); 470 miss_pkt_reformat = NULL; 471 mlx5_destroy_flow_group(miss_fg); 472 miss_fg = NULL; 473 goto skip_miss_flow; 474 } 475 476 miss_handle = mlx5_esw_bridge_egress_miss_flow_create(egress_ft, 477 br_offloads->skip_ft, 478 miss_pkt_reformat); 479 if (IS_ERR(miss_handle)) { 480 esw_warn(esw->dev, "Failed to create miss flow (err=%ld)\n", 481 PTR_ERR(miss_handle)); 482 miss_handle = NULL; 483 mlx5_packet_reformat_dealloc(esw->dev, miss_pkt_reformat); 484 miss_pkt_reformat = NULL; 485 mlx5_destroy_flow_group(miss_fg); 486 miss_fg = NULL; 487 goto skip_miss_flow; 488 } 489 } 490skip_miss_flow: 491 492 bridge->egress_ft = egress_ft; 493 bridge->egress_vlan_fg = vlan_fg; 494 bridge->egress_mac_fg = mac_fg; 495 bridge->egress_miss_fg = miss_fg; 496 bridge->egress_miss_pkt_reformat = miss_pkt_reformat; 497 bridge->egress_miss_handle = miss_handle; 498 return 0; 499 500err_mac_fg: 501 mlx5_destroy_flow_group(vlan_fg); 502err_vlan_fg: 503 mlx5_destroy_flow_table(egress_ft); 504 return err; 505} 506 507static void 508mlx5_esw_bridge_egress_table_cleanup(struct mlx5_esw_bridge *bridge) 509{ 510 if (bridge->egress_miss_handle) 511 mlx5_del_flow_rules(bridge->egress_miss_handle); 512 if (bridge->egress_miss_pkt_reformat) 513 mlx5_packet_reformat_dealloc(bridge->br_offloads->esw->dev, 514 bridge->egress_miss_pkt_reformat); 515 if (bridge->egress_miss_fg) 516 mlx5_destroy_flow_group(bridge->egress_miss_fg); 517 mlx5_destroy_flow_group(bridge->egress_mac_fg); 518 mlx5_destroy_flow_group(bridge->egress_vlan_fg); 519 mlx5_destroy_flow_table(bridge->egress_ft); 520} 521 522static struct mlx5_flow_handle * 523mlx5_esw_bridge_ingress_flow_with_esw_create(u16 vport_num, const unsigned char *addr, 524 struct mlx5_esw_bridge_vlan *vlan, u32 counter_id, 525 struct mlx5_esw_bridge *bridge, 526 struct mlx5_eswitch *esw) 527{ 528 struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads; 529 struct mlx5_flow_act flow_act = { 530 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT, 531 .flags = FLOW_ACT_NO_APPEND, 532 }; 533 struct mlx5_flow_destination dests[2] = {}; 534 struct mlx5_flow_spec *rule_spec; 535 struct mlx5_flow_handle *handle; 536 u8 *smac_v, *smac_c; 537 538 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL); 539 if (!rule_spec) 540 return ERR_PTR(-ENOMEM); 541 542 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2; 543 544 smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value, 545 outer_headers.smac_47_16); 546 ether_addr_copy(smac_v, addr); 547 smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria, 548 outer_headers.smac_47_16); 549 eth_broadcast_addr(smac_c); 550 551 MLX5_SET(fte_match_param, rule_spec->match_criteria, 552 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask()); 553 MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0, 554 mlx5_eswitch_get_vport_metadata_for_match(esw, vport_num)); 555 556 if (vlan && vlan->pkt_reformat_push) { 557 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT | 558 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; 559 flow_act.pkt_reformat = vlan->pkt_reformat_push; 560 flow_act.modify_hdr = vlan->pkt_mod_hdr_push_mark; 561 } else if (vlan) { 562 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria, 563 outer_headers.cvlan_tag); 564 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value, 565 outer_headers.cvlan_tag); 566 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria, 567 outer_headers.first_vid); 568 MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid, 569 vlan->vid); 570 } 571 572 dests[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 573 dests[0].ft = bridge->egress_ft; 574 dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 575 dests[1].counter_id = counter_id; 576 577 handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, dests, 578 ARRAY_SIZE(dests)); 579 580 kvfree(rule_spec); 581 return handle; 582} 583 584static struct mlx5_flow_handle * 585mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr, 586 struct mlx5_esw_bridge_vlan *vlan, u32 counter_id, 587 struct mlx5_esw_bridge *bridge) 588{ 589 return mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id, 590 bridge, bridge->br_offloads->esw); 591} 592 593static struct mlx5_flow_handle * 594mlx5_esw_bridge_ingress_flow_peer_create(u16 vport_num, const unsigned char *addr, 595 struct mlx5_esw_bridge_vlan *vlan, u32 counter_id, 596 struct mlx5_esw_bridge *bridge) 597{ 598 struct mlx5_devcom *devcom = bridge->br_offloads->esw->dev->priv.devcom; 599 static struct mlx5_flow_handle *handle; 600 struct mlx5_eswitch *peer_esw; 601 602 peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); 603 if (!peer_esw) 604 return ERR_PTR(-ENODEV); 605 606 handle = mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id, 607 bridge, peer_esw); 608 609 mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); 610 return handle; 611} 612 613static struct mlx5_flow_handle * 614mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *addr, 615 struct mlx5_esw_bridge *bridge) 616{ 617 struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads; 618 struct mlx5_flow_destination dest = { 619 .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE, 620 .ft = br_offloads->skip_ft, 621 }; 622 struct mlx5_flow_act flow_act = { 623 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 624 .flags = FLOW_ACT_NO_APPEND, 625 }; 626 struct mlx5_flow_spec *rule_spec; 627 struct mlx5_flow_handle *handle; 628 u8 *smac_v, *smac_c; 629 630 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL); 631 if (!rule_spec) 632 return ERR_PTR(-ENOMEM); 633 634 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2; 635 636 smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value, 637 outer_headers.smac_47_16); 638 ether_addr_copy(smac_v, addr); 639 smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria, 640 outer_headers.smac_47_16); 641 eth_broadcast_addr(smac_c); 642 643 MLX5_SET(fte_match_param, rule_spec->match_criteria, 644 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask()); 645 MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0, 646 mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num)); 647 648 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria, 649 outer_headers.cvlan_tag); 650 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value, 651 outer_headers.cvlan_tag); 652 653 handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, &dest, 1); 654 655 kvfree(rule_spec); 656 return handle; 657} 658 659static struct mlx5_flow_handle * 660mlx5_esw_bridge_egress_flow_create(u16 vport_num, u16 esw_owner_vhca_id, const unsigned char *addr, 661 struct mlx5_esw_bridge_vlan *vlan, 662 struct mlx5_esw_bridge *bridge) 663{ 664 struct mlx5_flow_destination dest = { 665 .type = MLX5_FLOW_DESTINATION_TYPE_VPORT, 666 .vport.num = vport_num, 667 }; 668 struct mlx5_flow_act flow_act = { 669 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 670 .flags = FLOW_ACT_NO_APPEND, 671 }; 672 struct mlx5_flow_spec *rule_spec; 673 struct mlx5_flow_handle *handle; 674 u8 *dmac_v, *dmac_c; 675 676 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL); 677 if (!rule_spec) 678 return ERR_PTR(-ENOMEM); 679 680 if (MLX5_CAP_ESW_FLOWTABLE(bridge->br_offloads->esw->dev, flow_source) && 681 vport_num == MLX5_VPORT_UPLINK) 682 rule_spec->flow_context.flow_source = 683 MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT; 684 rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 685 686 dmac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value, 687 outer_headers.dmac_47_16); 688 ether_addr_copy(dmac_v, addr); 689 dmac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria, 690 outer_headers.dmac_47_16); 691 eth_broadcast_addr(dmac_c); 692 693 if (vlan) { 694 if (vlan->pkt_reformat_pop) { 695 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; 696 flow_act.pkt_reformat = vlan->pkt_reformat_pop; 697 } 698 699 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria, 700 outer_headers.cvlan_tag); 701 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value, 702 outer_headers.cvlan_tag); 703 MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria, 704 outer_headers.first_vid); 705 MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid, 706 vlan->vid); 707 } 708 709 if (MLX5_CAP_ESW(bridge->br_offloads->esw->dev, merged_eswitch)) { 710 dest.vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID; 711 dest.vport.vhca_id = esw_owner_vhca_id; 712 } 713 handle = mlx5_add_flow_rules(bridge->egress_ft, rule_spec, &flow_act, &dest, 1); 714 715 kvfree(rule_spec); 716 return handle; 717} 718 719static struct mlx5_flow_handle * 720mlx5_esw_bridge_egress_miss_flow_create(struct mlx5_flow_table *egress_ft, 721 struct mlx5_flow_table *skip_ft, 722 struct mlx5_pkt_reformat *pkt_reformat) 723{ 724 struct mlx5_flow_destination dest = { 725 .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE, 726 .ft = skip_ft, 727 }; 728 struct mlx5_flow_act flow_act = { 729 .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 730 MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT, 731 .flags = FLOW_ACT_NO_APPEND, 732 .pkt_reformat = pkt_reformat, 733 }; 734 struct mlx5_flow_spec *rule_spec; 735 struct mlx5_flow_handle *handle; 736 737 rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL); 738 if (!rule_spec) 739 return ERR_PTR(-ENOMEM); 740 741 rule_spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2; 742 743 MLX5_SET(fte_match_param, rule_spec->match_criteria, 744 misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK); 745 MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_1, 746 ESW_TUN_BRIDGE_INGRESS_PUSH_VLAN_MARK); 747 748 handle = mlx5_add_flow_rules(egress_ft, rule_spec, &flow_act, &dest, 1); 749 750 kvfree(rule_spec); 751 return handle; 752} 753 754static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex, 755 struct mlx5_esw_bridge_offloads *br_offloads) 756{ 757 struct mlx5_esw_bridge *bridge; 758 int err; 759 760 bridge = kvzalloc(sizeof(*bridge), GFP_KERNEL); 761 if (!bridge) 762 return ERR_PTR(-ENOMEM); 763 764 bridge->br_offloads = br_offloads; 765 err = mlx5_esw_bridge_egress_table_init(br_offloads, bridge); 766 if (err) 767 goto err_egress_tbl; 768 769 err = rhashtable_init(&bridge->fdb_ht, &fdb_ht_params); 770 if (err) 771 goto err_fdb_ht; 772 773 INIT_LIST_HEAD(&bridge->fdb_list); 774 bridge->ifindex = ifindex; 775 bridge->refcnt = 1; 776 bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME); 777 list_add(&bridge->list, &br_offloads->bridges); 778 779 return bridge; 780 781err_fdb_ht: 782 mlx5_esw_bridge_egress_table_cleanup(bridge); 783err_egress_tbl: 784 kvfree(bridge); 785 return ERR_PTR(err); 786} 787 788static void mlx5_esw_bridge_get(struct mlx5_esw_bridge *bridge) 789{ 790 bridge->refcnt++; 791} 792 793static void mlx5_esw_bridge_put(struct mlx5_esw_bridge_offloads *br_offloads, 794 struct mlx5_esw_bridge *bridge) 795{ 796 if (--bridge->refcnt) 797 return; 798 799 mlx5_esw_bridge_egress_table_cleanup(bridge); 800 list_del(&bridge->list); 801 rhashtable_destroy(&bridge->fdb_ht); 802 kvfree(bridge); 803 804 if (list_empty(&br_offloads->bridges)) 805 mlx5_esw_bridge_ingress_table_cleanup(br_offloads); 806} 807 808static struct mlx5_esw_bridge * 809mlx5_esw_bridge_lookup(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads) 810{ 811 struct mlx5_esw_bridge *bridge; 812 813 ASSERT_RTNL(); 814 815 list_for_each_entry(bridge, &br_offloads->bridges, list) { 816 if (bridge->ifindex == ifindex) { 817 mlx5_esw_bridge_get(bridge); 818 return bridge; 819 } 820 } 821 822 if (!br_offloads->ingress_ft) { 823 int err = mlx5_esw_bridge_ingress_table_init(br_offloads); 824 825 if (err) 826 return ERR_PTR(err); 827 } 828 829 bridge = mlx5_esw_bridge_create(ifindex, br_offloads); 830 if (IS_ERR(bridge) && list_empty(&br_offloads->bridges)) 831 mlx5_esw_bridge_ingress_table_cleanup(br_offloads); 832 return bridge; 833} 834 835static unsigned long mlx5_esw_bridge_port_key_from_data(u16 vport_num, u16 esw_owner_vhca_id) 836{ 837 return vport_num | (unsigned long)esw_owner_vhca_id << sizeof(vport_num) * BITS_PER_BYTE; 838} 839 840static unsigned long mlx5_esw_bridge_port_key(struct mlx5_esw_bridge_port *port) 841{ 842 return mlx5_esw_bridge_port_key_from_data(port->vport_num, port->esw_owner_vhca_id); 843} 844 845static int mlx5_esw_bridge_port_insert(struct mlx5_esw_bridge_port *port, 846 struct mlx5_esw_bridge_offloads *br_offloads) 847{ 848 return xa_insert(&br_offloads->ports, mlx5_esw_bridge_port_key(port), port, GFP_KERNEL); 849} 850 851static struct mlx5_esw_bridge_port * 852mlx5_esw_bridge_port_lookup(u16 vport_num, u16 esw_owner_vhca_id, 853 struct mlx5_esw_bridge_offloads *br_offloads) 854{ 855 return xa_load(&br_offloads->ports, mlx5_esw_bridge_port_key_from_data(vport_num, 856 esw_owner_vhca_id)); 857} 858 859static void mlx5_esw_bridge_port_erase(struct mlx5_esw_bridge_port *port, 860 struct mlx5_esw_bridge_offloads *br_offloads) 861{ 862 xa_erase(&br_offloads->ports, mlx5_esw_bridge_port_key(port)); 863} 864 865static void mlx5_esw_bridge_fdb_entry_refresh(struct mlx5_esw_bridge_fdb_entry *entry) 866{ 867 trace_mlx5_esw_bridge_fdb_entry_refresh(entry); 868 869 mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr, 870 entry->key.vid, 871 SWITCHDEV_FDB_ADD_TO_BRIDGE); 872} 873 874static void 875mlx5_esw_bridge_fdb_entry_cleanup(struct mlx5_esw_bridge_fdb_entry *entry, 876 struct mlx5_esw_bridge *bridge) 877{ 878 trace_mlx5_esw_bridge_fdb_entry_cleanup(entry); 879 880 rhashtable_remove_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params); 881 mlx5_del_flow_rules(entry->egress_handle); 882 if (entry->filter_handle) 883 mlx5_del_flow_rules(entry->filter_handle); 884 mlx5_del_flow_rules(entry->ingress_handle); 885 mlx5_fc_destroy(bridge->br_offloads->esw->dev, entry->ingress_counter); 886 list_del(&entry->vlan_list); 887 list_del(&entry->list); 888 kvfree(entry); 889} 890 891static void 892mlx5_esw_bridge_fdb_entry_notify_and_cleanup(struct mlx5_esw_bridge_fdb_entry *entry, 893 struct mlx5_esw_bridge *bridge) 894{ 895 mlx5_esw_bridge_fdb_del_notify(entry); 896 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge); 897} 898 899static void mlx5_esw_bridge_fdb_flush(struct mlx5_esw_bridge *bridge) 900{ 901 struct mlx5_esw_bridge_fdb_entry *entry, *tmp; 902 903 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) 904 mlx5_esw_bridge_fdb_entry_notify_and_cleanup(entry, bridge); 905} 906 907static struct mlx5_esw_bridge_vlan * 908mlx5_esw_bridge_vlan_lookup(u16 vid, struct mlx5_esw_bridge_port *port) 909{ 910 return xa_load(&port->vlans, vid); 911} 912 913static int 914mlx5_esw_bridge_vlan_push_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 915{ 916 struct { 917 __be16 h_vlan_proto; 918 __be16 h_vlan_TCI; 919 } vlan_hdr = { htons(ETH_P_8021Q), htons(vlan->vid) }; 920 struct mlx5_pkt_reformat_params reformat_params = {}; 921 struct mlx5_pkt_reformat *pkt_reformat; 922 923 if (!BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_insert)) || 924 MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_size) < sizeof(vlan_hdr) || 925 MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_offset) < 926 offsetof(struct vlan_ethhdr, h_vlan_proto)) { 927 esw_warn(esw->dev, "Packet reformat INSERT_HEADER is not supported\n"); 928 return -EOPNOTSUPP; 929 } 930 931 reformat_params.type = MLX5_REFORMAT_TYPE_INSERT_HDR; 932 reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START; 933 reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto); 934 reformat_params.size = sizeof(vlan_hdr); 935 reformat_params.data = &vlan_hdr; 936 pkt_reformat = mlx5_packet_reformat_alloc(esw->dev, 937 &reformat_params, 938 MLX5_FLOW_NAMESPACE_FDB); 939 if (IS_ERR(pkt_reformat)) { 940 esw_warn(esw->dev, "Failed to alloc packet reformat INSERT_HEADER (err=%ld)\n", 941 PTR_ERR(pkt_reformat)); 942 return PTR_ERR(pkt_reformat); 943 } 944 945 vlan->pkt_reformat_push = pkt_reformat; 946 return 0; 947} 948 949static void 950mlx5_esw_bridge_vlan_push_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 951{ 952 mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_push); 953 vlan->pkt_reformat_push = NULL; 954} 955 956static int 957mlx5_esw_bridge_vlan_pop_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 958{ 959 struct mlx5_pkt_reformat *pkt_reformat; 960 961 if (!mlx5_esw_bridge_pkt_reformat_vlan_pop_supported(esw)) { 962 esw_warn(esw->dev, "Packet reformat REMOVE_HEADER is not supported\n"); 963 return -EOPNOTSUPP; 964 } 965 966 pkt_reformat = mlx5_esw_bridge_pkt_reformat_vlan_pop_create(esw); 967 if (IS_ERR(pkt_reformat)) { 968 esw_warn(esw->dev, "Failed to alloc packet reformat REMOVE_HEADER (err=%ld)\n", 969 PTR_ERR(pkt_reformat)); 970 return PTR_ERR(pkt_reformat); 971 } 972 973 vlan->pkt_reformat_pop = pkt_reformat; 974 return 0; 975} 976 977static void 978mlx5_esw_bridge_vlan_pop_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 979{ 980 mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_pop); 981 vlan->pkt_reformat_pop = NULL; 982} 983 984static int 985mlx5_esw_bridge_vlan_push_mark_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 986{ 987 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {}; 988 struct mlx5_modify_hdr *pkt_mod_hdr; 989 990 MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET); 991 MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_1); 992 MLX5_SET(set_action_in, action, offset, 8); 993 MLX5_SET(set_action_in, action, length, ESW_TUN_OPTS_BITS + ESW_TUN_ID_BITS); 994 MLX5_SET(set_action_in, action, data, ESW_TUN_BRIDGE_INGRESS_PUSH_VLAN); 995 996 pkt_mod_hdr = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_FDB, 1, action); 997 if (IS_ERR(pkt_mod_hdr)) 998 return PTR_ERR(pkt_mod_hdr); 999 1000 vlan->pkt_mod_hdr_push_mark = pkt_mod_hdr; 1001 return 0; 1002} 1003 1004static void 1005mlx5_esw_bridge_vlan_push_mark_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw) 1006{ 1007 mlx5_modify_header_dealloc(esw->dev, vlan->pkt_mod_hdr_push_mark); 1008 vlan->pkt_mod_hdr_push_mark = NULL; 1009} 1010 1011static struct mlx5_esw_bridge_vlan * 1012mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *port, 1013 struct mlx5_eswitch *esw) 1014{ 1015 struct mlx5_esw_bridge_vlan *vlan; 1016 int err; 1017 1018 vlan = kvzalloc(sizeof(*vlan), GFP_KERNEL); 1019 if (!vlan) 1020 return ERR_PTR(-ENOMEM); 1021 1022 vlan->vid = vid; 1023 vlan->flags = flags; 1024 INIT_LIST_HEAD(&vlan->fdb_list); 1025 1026 if (flags & BRIDGE_VLAN_INFO_PVID) { 1027 err = mlx5_esw_bridge_vlan_push_create(vlan, esw); 1028 if (err) 1029 goto err_vlan_push; 1030 1031 err = mlx5_esw_bridge_vlan_push_mark_create(vlan, esw); 1032 if (err) 1033 goto err_vlan_push_mark; 1034 } 1035 if (flags & BRIDGE_VLAN_INFO_UNTAGGED) { 1036 err = mlx5_esw_bridge_vlan_pop_create(vlan, esw); 1037 if (err) 1038 goto err_vlan_pop; 1039 } 1040 1041 err = xa_insert(&port->vlans, vid, vlan, GFP_KERNEL); 1042 if (err) 1043 goto err_xa_insert; 1044 1045 trace_mlx5_esw_bridge_vlan_create(vlan); 1046 return vlan; 1047 1048err_xa_insert: 1049 if (vlan->pkt_reformat_pop) 1050 mlx5_esw_bridge_vlan_pop_cleanup(vlan, esw); 1051err_vlan_pop: 1052 if (vlan->pkt_mod_hdr_push_mark) 1053 mlx5_esw_bridge_vlan_push_mark_cleanup(vlan, esw); 1054err_vlan_push_mark: 1055 if (vlan->pkt_reformat_push) 1056 mlx5_esw_bridge_vlan_push_cleanup(vlan, esw); 1057err_vlan_push: 1058 kvfree(vlan); 1059 return ERR_PTR(err); 1060} 1061 1062static void mlx5_esw_bridge_vlan_erase(struct mlx5_esw_bridge_port *port, 1063 struct mlx5_esw_bridge_vlan *vlan) 1064{ 1065 xa_erase(&port->vlans, vlan->vid); 1066} 1067 1068static void mlx5_esw_bridge_vlan_flush(struct mlx5_esw_bridge_vlan *vlan, 1069 struct mlx5_esw_bridge *bridge) 1070{ 1071 struct mlx5_eswitch *esw = bridge->br_offloads->esw; 1072 struct mlx5_esw_bridge_fdb_entry *entry, *tmp; 1073 1074 list_for_each_entry_safe(entry, tmp, &vlan->fdb_list, vlan_list) 1075 mlx5_esw_bridge_fdb_entry_notify_and_cleanup(entry, bridge); 1076 1077 if (vlan->pkt_reformat_pop) 1078 mlx5_esw_bridge_vlan_pop_cleanup(vlan, esw); 1079 if (vlan->pkt_mod_hdr_push_mark) 1080 mlx5_esw_bridge_vlan_push_mark_cleanup(vlan, esw); 1081 if (vlan->pkt_reformat_push) 1082 mlx5_esw_bridge_vlan_push_cleanup(vlan, esw); 1083} 1084 1085static void mlx5_esw_bridge_vlan_cleanup(struct mlx5_esw_bridge_port *port, 1086 struct mlx5_esw_bridge_vlan *vlan, 1087 struct mlx5_esw_bridge *bridge) 1088{ 1089 trace_mlx5_esw_bridge_vlan_cleanup(vlan); 1090 mlx5_esw_bridge_vlan_flush(vlan, bridge); 1091 mlx5_esw_bridge_vlan_erase(port, vlan); 1092 kvfree(vlan); 1093} 1094 1095static void mlx5_esw_bridge_port_vlans_flush(struct mlx5_esw_bridge_port *port, 1096 struct mlx5_esw_bridge *bridge) 1097{ 1098 struct mlx5_esw_bridge_vlan *vlan; 1099 unsigned long index; 1100 1101 xa_for_each(&port->vlans, index, vlan) 1102 mlx5_esw_bridge_vlan_cleanup(port, vlan, bridge); 1103} 1104 1105static struct mlx5_esw_bridge_vlan * 1106mlx5_esw_bridge_port_vlan_lookup(u16 vid, u16 vport_num, u16 esw_owner_vhca_id, 1107 struct mlx5_esw_bridge *bridge, struct mlx5_eswitch *esw) 1108{ 1109 struct mlx5_esw_bridge_port *port; 1110 struct mlx5_esw_bridge_vlan *vlan; 1111 1112 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, bridge->br_offloads); 1113 if (!port) { 1114 /* FDB is added asynchronously on wq while port might have been deleted 1115 * concurrently. Report on 'info' logging level and skip the FDB offload. 1116 */ 1117 esw_info(esw->dev, "Failed to lookup bridge port (vport=%u)\n", vport_num); 1118 return ERR_PTR(-EINVAL); 1119 } 1120 1121 vlan = mlx5_esw_bridge_vlan_lookup(vid, port); 1122 if (!vlan) { 1123 /* FDB is added asynchronously on wq while vlan might have been deleted 1124 * concurrently. Report on 'info' logging level and skip the FDB offload. 1125 */ 1126 esw_info(esw->dev, "Failed to lookup bridge port vlan metadata (vport=%u)\n", 1127 vport_num); 1128 return ERR_PTR(-EINVAL); 1129 } 1130 1131 return vlan; 1132} 1133 1134static struct mlx5_esw_bridge_fdb_entry * 1135mlx5_esw_bridge_fdb_lookup(struct mlx5_esw_bridge *bridge, 1136 const unsigned char *addr, u16 vid) 1137{ 1138 struct mlx5_esw_bridge_fdb_key key = {}; 1139 1140 ether_addr_copy(key.addr, addr); 1141 key.vid = vid; 1142 return rhashtable_lookup_fast(&bridge->fdb_ht, &key, fdb_ht_params); 1143} 1144 1145static struct mlx5_esw_bridge_fdb_entry * 1146mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id, 1147 const unsigned char *addr, u16 vid, bool added_by_user, bool peer, 1148 struct mlx5_eswitch *esw, struct mlx5_esw_bridge *bridge) 1149{ 1150 struct mlx5_esw_bridge_vlan *vlan = NULL; 1151 struct mlx5_esw_bridge_fdb_entry *entry; 1152 struct mlx5_flow_handle *handle; 1153 struct mlx5_fc *counter; 1154 int err; 1155 1156 if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG && vid) { 1157 vlan = mlx5_esw_bridge_port_vlan_lookup(vid, vport_num, esw_owner_vhca_id, bridge, 1158 esw); 1159 if (IS_ERR(vlan)) 1160 return ERR_CAST(vlan); 1161 } 1162 1163 entry = mlx5_esw_bridge_fdb_lookup(bridge, addr, vid); 1164 if (entry) 1165 mlx5_esw_bridge_fdb_entry_notify_and_cleanup(entry, bridge); 1166 1167 entry = kvzalloc(sizeof(*entry), GFP_KERNEL); 1168 if (!entry) 1169 return ERR_PTR(-ENOMEM); 1170 1171 ether_addr_copy(entry->key.addr, addr); 1172 entry->key.vid = vid; 1173 entry->dev = dev; 1174 entry->vport_num = vport_num; 1175 entry->esw_owner_vhca_id = esw_owner_vhca_id; 1176 entry->lastuse = jiffies; 1177 if (added_by_user) 1178 entry->flags |= MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER; 1179 if (peer) 1180 entry->flags |= MLX5_ESW_BRIDGE_FLAG_PEER; 1181 1182 counter = mlx5_fc_create(esw->dev, true); 1183 if (IS_ERR(counter)) { 1184 err = PTR_ERR(counter); 1185 goto err_ingress_fc_create; 1186 } 1187 entry->ingress_counter = counter; 1188 1189 handle = peer ? 1190 mlx5_esw_bridge_ingress_flow_peer_create(vport_num, addr, vlan, 1191 mlx5_fc_id(counter), bridge) : 1192 mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan, 1193 mlx5_fc_id(counter), bridge); 1194 if (IS_ERR(handle)) { 1195 err = PTR_ERR(handle); 1196 esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d)\n", 1197 vport_num, err); 1198 goto err_ingress_flow_create; 1199 } 1200 entry->ingress_handle = handle; 1201 1202 if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG) { 1203 handle = mlx5_esw_bridge_ingress_filter_flow_create(vport_num, addr, bridge); 1204 if (IS_ERR(handle)) { 1205 err = PTR_ERR(handle); 1206 esw_warn(esw->dev, "Failed to create ingress filter(vport=%u,err=%d)\n", 1207 vport_num, err); 1208 goto err_ingress_filter_flow_create; 1209 } 1210 entry->filter_handle = handle; 1211 } 1212 1213 handle = mlx5_esw_bridge_egress_flow_create(vport_num, esw_owner_vhca_id, addr, vlan, 1214 bridge); 1215 if (IS_ERR(handle)) { 1216 err = PTR_ERR(handle); 1217 esw_warn(esw->dev, "Failed to create egress flow(vport=%u,err=%d)\n", 1218 vport_num, err); 1219 goto err_egress_flow_create; 1220 } 1221 entry->egress_handle = handle; 1222 1223 err = rhashtable_insert_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params); 1224 if (err) { 1225 esw_warn(esw->dev, "Failed to insert FDB flow(vport=%u,err=%d)\n", vport_num, err); 1226 goto err_ht_init; 1227 } 1228 1229 if (vlan) 1230 list_add(&entry->vlan_list, &vlan->fdb_list); 1231 else 1232 INIT_LIST_HEAD(&entry->vlan_list); 1233 list_add(&entry->list, &bridge->fdb_list); 1234 1235 trace_mlx5_esw_bridge_fdb_entry_init(entry); 1236 return entry; 1237 1238err_ht_init: 1239 mlx5_del_flow_rules(entry->egress_handle); 1240err_egress_flow_create: 1241 if (entry->filter_handle) 1242 mlx5_del_flow_rules(entry->filter_handle); 1243err_ingress_filter_flow_create: 1244 mlx5_del_flow_rules(entry->ingress_handle); 1245err_ingress_flow_create: 1246 mlx5_fc_destroy(esw->dev, entry->ingress_counter); 1247err_ingress_fc_create: 1248 kvfree(entry); 1249 return ERR_PTR(err); 1250} 1251 1252int mlx5_esw_bridge_ageing_time_set(u16 vport_num, u16 esw_owner_vhca_id, unsigned long ageing_time, 1253 struct mlx5_esw_bridge_offloads *br_offloads) 1254{ 1255 struct mlx5_esw_bridge_port *port; 1256 1257 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1258 if (!port) 1259 return -EINVAL; 1260 1261 port->bridge->ageing_time = clock_t_to_jiffies(ageing_time); 1262 return 0; 1263} 1264 1265int mlx5_esw_bridge_vlan_filtering_set(u16 vport_num, u16 esw_owner_vhca_id, bool enable, 1266 struct mlx5_esw_bridge_offloads *br_offloads) 1267{ 1268 struct mlx5_esw_bridge_port *port; 1269 struct mlx5_esw_bridge *bridge; 1270 bool filtering; 1271 1272 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1273 if (!port) 1274 return -EINVAL; 1275 1276 bridge = port->bridge; 1277 filtering = bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG; 1278 if (filtering == enable) 1279 return 0; 1280 1281 mlx5_esw_bridge_fdb_flush(bridge); 1282 if (enable) 1283 bridge->flags |= MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG; 1284 else 1285 bridge->flags &= ~MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG; 1286 1287 return 0; 1288} 1289 1290static int mlx5_esw_bridge_vport_init(u16 vport_num, u16 esw_owner_vhca_id, u16 flags, 1291 struct mlx5_esw_bridge_offloads *br_offloads, 1292 struct mlx5_esw_bridge *bridge) 1293{ 1294 struct mlx5_eswitch *esw = br_offloads->esw; 1295 struct mlx5_esw_bridge_port *port; 1296 int err; 1297 1298 port = kvzalloc(sizeof(*port), GFP_KERNEL); 1299 if (!port) 1300 return -ENOMEM; 1301 1302 port->vport_num = vport_num; 1303 port->esw_owner_vhca_id = esw_owner_vhca_id; 1304 port->bridge = bridge; 1305 port->flags |= flags; 1306 xa_init(&port->vlans); 1307 err = mlx5_esw_bridge_port_insert(port, br_offloads); 1308 if (err) { 1309 esw_warn(esw->dev, 1310 "Failed to insert port metadata (vport=%u,esw_owner_vhca_id=%u,err=%d)\n", 1311 port->vport_num, port->esw_owner_vhca_id, err); 1312 goto err_port_insert; 1313 } 1314 trace_mlx5_esw_bridge_vport_init(port); 1315 1316 return 0; 1317 1318err_port_insert: 1319 kvfree(port); 1320 return err; 1321} 1322 1323static int mlx5_esw_bridge_vport_cleanup(struct mlx5_esw_bridge_offloads *br_offloads, 1324 struct mlx5_esw_bridge_port *port) 1325{ 1326 u16 vport_num = port->vport_num, esw_owner_vhca_id = port->esw_owner_vhca_id; 1327 struct mlx5_esw_bridge *bridge = port->bridge; 1328 struct mlx5_esw_bridge_fdb_entry *entry, *tmp; 1329 1330 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) 1331 if (entry->vport_num == vport_num && entry->esw_owner_vhca_id == esw_owner_vhca_id) 1332 mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge); 1333 1334 trace_mlx5_esw_bridge_vport_cleanup(port); 1335 mlx5_esw_bridge_port_vlans_flush(port, bridge); 1336 mlx5_esw_bridge_port_erase(port, br_offloads); 1337 kvfree(port); 1338 mlx5_esw_bridge_put(br_offloads, bridge); 1339 return 0; 1340} 1341 1342static int mlx5_esw_bridge_vport_link_with_flags(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, 1343 u16 flags, 1344 struct mlx5_esw_bridge_offloads *br_offloads, 1345 struct netlink_ext_ack *extack) 1346{ 1347 struct mlx5_esw_bridge *bridge; 1348 int err; 1349 1350 bridge = mlx5_esw_bridge_lookup(ifindex, br_offloads); 1351 if (IS_ERR(bridge)) { 1352 NL_SET_ERR_MSG_MOD(extack, "Error checking for existing bridge with same ifindex"); 1353 return PTR_ERR(bridge); 1354 } 1355 1356 err = mlx5_esw_bridge_vport_init(vport_num, esw_owner_vhca_id, flags, br_offloads, bridge); 1357 if (err) { 1358 NL_SET_ERR_MSG_MOD(extack, "Error initializing port"); 1359 goto err_vport; 1360 } 1361 return 0; 1362 1363err_vport: 1364 mlx5_esw_bridge_put(br_offloads, bridge); 1365 return err; 1366} 1367 1368int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, 1369 struct mlx5_esw_bridge_offloads *br_offloads, 1370 struct netlink_ext_ack *extack) 1371{ 1372 return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id, 0, 1373 br_offloads, extack); 1374} 1375 1376int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, 1377 struct mlx5_esw_bridge_offloads *br_offloads, 1378 struct netlink_ext_ack *extack) 1379{ 1380 struct mlx5_esw_bridge_port *port; 1381 int err; 1382 1383 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1384 if (!port) { 1385 NL_SET_ERR_MSG_MOD(extack, "Port is not attached to any bridge"); 1386 return -EINVAL; 1387 } 1388 if (port->bridge->ifindex != ifindex) { 1389 NL_SET_ERR_MSG_MOD(extack, "Port is attached to another bridge"); 1390 return -EINVAL; 1391 } 1392 1393 err = mlx5_esw_bridge_vport_cleanup(br_offloads, port); 1394 if (err) 1395 NL_SET_ERR_MSG_MOD(extack, "Port cleanup failed"); 1396 return err; 1397} 1398 1399int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, 1400 struct mlx5_esw_bridge_offloads *br_offloads, 1401 struct netlink_ext_ack *extack) 1402{ 1403 if (!MLX5_CAP_ESW(br_offloads->esw->dev, merged_eswitch)) 1404 return 0; 1405 1406 return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id, 1407 MLX5_ESW_BRIDGE_PORT_FLAG_PEER, 1408 br_offloads, extack); 1409} 1410 1411int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, 1412 struct mlx5_esw_bridge_offloads *br_offloads, 1413 struct netlink_ext_ack *extack) 1414{ 1415 return mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, br_offloads, 1416 extack); 1417} 1418 1419int mlx5_esw_bridge_port_vlan_add(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, u16 flags, 1420 struct mlx5_esw_bridge_offloads *br_offloads, 1421 struct netlink_ext_ack *extack) 1422{ 1423 struct mlx5_esw_bridge_port *port; 1424 struct mlx5_esw_bridge_vlan *vlan; 1425 1426 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1427 if (!port) 1428 return -EINVAL; 1429 1430 vlan = mlx5_esw_bridge_vlan_lookup(vid, port); 1431 if (vlan) { 1432 if (vlan->flags == flags) 1433 return 0; 1434 mlx5_esw_bridge_vlan_cleanup(port, vlan, port->bridge); 1435 } 1436 1437 vlan = mlx5_esw_bridge_vlan_create(vid, flags, port, br_offloads->esw); 1438 if (IS_ERR(vlan)) { 1439 NL_SET_ERR_MSG_MOD(extack, "Failed to create VLAN entry"); 1440 return PTR_ERR(vlan); 1441 } 1442 return 0; 1443} 1444 1445void mlx5_esw_bridge_port_vlan_del(u16 vport_num, u16 esw_owner_vhca_id, u16 vid, 1446 struct mlx5_esw_bridge_offloads *br_offloads) 1447{ 1448 struct mlx5_esw_bridge_port *port; 1449 struct mlx5_esw_bridge_vlan *vlan; 1450 1451 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1452 if (!port) 1453 return; 1454 1455 vlan = mlx5_esw_bridge_vlan_lookup(vid, port); 1456 if (!vlan) 1457 return; 1458 mlx5_esw_bridge_vlan_cleanup(port, vlan, port->bridge); 1459} 1460 1461void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id, 1462 struct mlx5_esw_bridge_offloads *br_offloads, 1463 struct switchdev_notifier_fdb_info *fdb_info) 1464{ 1465 struct mlx5_esw_bridge_fdb_entry *entry; 1466 struct mlx5_esw_bridge_port *port; 1467 struct mlx5_esw_bridge *bridge; 1468 1469 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1470 if (!port || port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER) 1471 return; 1472 1473 bridge = port->bridge; 1474 entry = mlx5_esw_bridge_fdb_lookup(bridge, fdb_info->addr, fdb_info->vid); 1475 if (!entry) { 1476 esw_debug(br_offloads->esw->dev, 1477 "FDB entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n", 1478 fdb_info->addr, fdb_info->vid, vport_num); 1479 return; 1480 } 1481 1482 entry->lastuse = jiffies; 1483} 1484 1485void mlx5_esw_bridge_fdb_create(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id, 1486 struct mlx5_esw_bridge_offloads *br_offloads, 1487 struct switchdev_notifier_fdb_info *fdb_info) 1488{ 1489 struct mlx5_esw_bridge_fdb_entry *entry; 1490 struct mlx5_esw_bridge_port *port; 1491 struct mlx5_esw_bridge *bridge; 1492 1493 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1494 if (!port) 1495 return; 1496 1497 bridge = port->bridge; 1498 entry = mlx5_esw_bridge_fdb_entry_init(dev, vport_num, esw_owner_vhca_id, fdb_info->addr, 1499 fdb_info->vid, fdb_info->added_by_user, 1500 port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER, 1501 br_offloads->esw, bridge); 1502 if (IS_ERR(entry)) 1503 return; 1504 1505 if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER) 1506 mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid, 1507 SWITCHDEV_FDB_OFFLOADED); 1508 else if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_PEER)) 1509 /* Take over dynamic entries to prevent kernel bridge from aging them out. */ 1510 mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid, 1511 SWITCHDEV_FDB_ADD_TO_BRIDGE); 1512} 1513 1514void mlx5_esw_bridge_fdb_remove(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id, 1515 struct mlx5_esw_bridge_offloads *br_offloads, 1516 struct switchdev_notifier_fdb_info *fdb_info) 1517{ 1518 struct mlx5_eswitch *esw = br_offloads->esw; 1519 struct mlx5_esw_bridge_fdb_entry *entry; 1520 struct mlx5_esw_bridge_port *port; 1521 struct mlx5_esw_bridge *bridge; 1522 1523 port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); 1524 if (!port) 1525 return; 1526 1527 bridge = port->bridge; 1528 entry = mlx5_esw_bridge_fdb_lookup(bridge, fdb_info->addr, fdb_info->vid); 1529 if (!entry) { 1530 esw_warn(esw->dev, 1531 "FDB entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n", 1532 fdb_info->addr, fdb_info->vid, vport_num); 1533 return; 1534 } 1535 1536 mlx5_esw_bridge_fdb_entry_notify_and_cleanup(entry, bridge); 1537} 1538 1539void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads) 1540{ 1541 struct mlx5_esw_bridge_fdb_entry *entry, *tmp; 1542 struct mlx5_esw_bridge *bridge; 1543 1544 list_for_each_entry(bridge, &br_offloads->bridges, list) { 1545 list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) { 1546 unsigned long lastuse = 1547 (unsigned long)mlx5_fc_query_lastuse(entry->ingress_counter); 1548 1549 if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER) 1550 continue; 1551 1552 if (time_after(lastuse, entry->lastuse)) 1553 mlx5_esw_bridge_fdb_entry_refresh(entry); 1554 else if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_PEER) && 1555 time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) 1556 mlx5_esw_bridge_fdb_entry_notify_and_cleanup(entry, bridge); 1557 } 1558 } 1559} 1560 1561static void mlx5_esw_bridge_flush(struct mlx5_esw_bridge_offloads *br_offloads) 1562{ 1563 struct mlx5_esw_bridge_port *port; 1564 unsigned long i; 1565 1566 xa_for_each(&br_offloads->ports, i, port) 1567 mlx5_esw_bridge_vport_cleanup(br_offloads, port); 1568 1569 WARN_ONCE(!list_empty(&br_offloads->bridges), 1570 "Cleaning up bridge offloads while still having bridges attached\n"); 1571} 1572 1573struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw) 1574{ 1575 struct mlx5_esw_bridge_offloads *br_offloads; 1576 1577 ASSERT_RTNL(); 1578 1579 br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL); 1580 if (!br_offloads) 1581 return ERR_PTR(-ENOMEM); 1582 1583 INIT_LIST_HEAD(&br_offloads->bridges); 1584 xa_init(&br_offloads->ports); 1585 br_offloads->esw = esw; 1586 esw->br_offloads = br_offloads; 1587 1588 return br_offloads; 1589} 1590 1591void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw) 1592{ 1593 struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads; 1594 1595 ASSERT_RTNL(); 1596 1597 if (!br_offloads) 1598 return; 1599 1600 mlx5_esw_bridge_flush(br_offloads); 1601 WARN_ON(!xa_empty(&br_offloads->ports)); 1602 1603 esw->br_offloads = NULL; 1604 kvfree(br_offloads); 1605}