1291939Shselasky/*- 2291939Shselasky * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. 3291939Shselasky * 4291939Shselasky * Redistribution and use in source and binary forms, with or without 5291939Shselasky * modification, are permitted provided that the following conditions 6291939Shselasky * are met: 7291939Shselasky * 1. Redistributions of source code must retain the above copyright 8291939Shselasky * notice, this list of conditions and the following disclaimer. 9291939Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10291939Shselasky * notice, this list of conditions and the following disclaimer in the 11291939Shselasky * documentation and/or other materials provided with the distribution. 12291939Shselasky * 13291939Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14291939Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15291939Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16291939Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17291939Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18291939Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19291939Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20291939Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21291939Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22291939Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23291939Shselasky * SUCH DAMAGE. 24291939Shselasky * 25291939Shselasky * $FreeBSD: releng/10.3/sys/dev/mlx5/mlx5_core/mlx5_eswitch_vacl.c 292196 2015-12-14 10:31:03Z hselasky $ 26291939Shselasky */ 27291939Shselasky 28292196Shselasky#include <linux/if_ether.h> 29291939Shselasky#include <linux/etherdevice.h> 30291939Shselasky#include <dev/mlx5/driver.h> 31291939Shselasky#include <dev/mlx5/flow_table.h> 32291939Shselasky#include <dev/mlx5/eswitch_vacl.h> 33291939Shselasky#include "mlx5_core.h" 34291939Shselasky 35291939Shselaskyenum { 36291939Shselasky MLX5_ACL_LOOPBACK_GROUP_IDX = 0, 37291939Shselasky MLX5_ACL_UNTAGGED_GROUP_IDX = 1, 38291939Shselasky MLX5_ACL_VLAN_GROUP_IDX = 2, 39291939Shselasky MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX = 3, 40291939Shselasky MLX5_ACL_DEFAULT_GROUP_IDX = 4, 41291939Shselasky MLX5_ACL_GROUPS_NUM, 42291939Shselasky}; 43291939Shselasky 44291939Shselaskystruct mlx_vacl_fr { 45291939Shselasky bool applied; 46291939Shselasky u32 fi; 47291939Shselasky u16 action; 48291939Shselasky}; 49291939Shselasky 50291939Shselaskystruct mlx5_vacl_table { 51291939Shselasky struct mlx5_core_dev *dev; 52291939Shselasky u16 vport; 53291939Shselasky void *ft; 54291939Shselasky int max_ft_size; 55291939Shselasky int acl_type; 56291939Shselasky 57291939Shselasky struct mlx_vacl_fr loopback_fr; 58291939Shselasky struct mlx_vacl_fr untagged_fr; 59291939Shselasky struct mlx_vacl_fr unknown_vlan_fr; 60291939Shselasky struct mlx_vacl_fr default_fr; 61291939Shselasky 62291939Shselasky bool vlan_filter_enabled; 63291939Shselasky bool vlan_filter_applied; 64291939Shselasky unsigned long *vlan_allowed_bitmap; 65291939Shselasky u32 vlan_fi_table[4096]; 66291939Shselasky 67291939Shselasky bool spoofchk_enabled; 68291939Shselasky u8 smac[ETH_ALEN]; 69291939Shselasky}; 70291939Shselasky 71291939Shselaskystatic int mlx5_vacl_table_allow_vlan(void *acl_t, u16 vlan) 72291939Shselasky{ 73291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 74291939Shselasky u32 *flow_context = NULL; 75291939Shselasky void *in_match_criteria = NULL; 76291939Shselasky void *in_match_value = NULL; 77291939Shselasky u8 *smac; 78291939Shselasky int vlan_mc_enable = MLX5_MATCH_OUTER_HEADERS; 79291939Shselasky int err = 0; 80291939Shselasky 81291939Shselasky if (!test_bit(vlan, acl_table->vlan_allowed_bitmap)) 82291939Shselasky return -EINVAL; 83291939Shselasky 84291939Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context)); 85291939Shselasky if (!flow_context) { 86291939Shselasky err = -ENOMEM; 87291939Shselasky goto out; 88291939Shselasky } 89291939Shselasky 90291939Shselasky in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 91291939Shselasky if (!in_match_criteria) { 92291939Shselasky err = -ENOMEM; 93291939Shselasky goto out; 94291939Shselasky } 95291939Shselasky 96291939Shselasky /* Apply vlan rule */ 97291939Shselasky MLX5_SET(flow_context, flow_context, action, 98291939Shselasky MLX5_FLOW_CONTEXT_ACTION_ALLOW); 99291939Shselasky in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); 100291939Shselasky MLX5_SET(fte_match_param, in_match_value, outer_headers.vlan_tag, 1); 101291939Shselasky MLX5_SET(fte_match_param, in_match_value, outer_headers.first_vid, 102291939Shselasky vlan); 103291939Shselasky MLX5_SET(fte_match_param, in_match_criteria, outer_headers.vlan_tag, 1); 104291939Shselasky MLX5_SET(fte_match_param, in_match_criteria, outer_headers.first_vid, 105291939Shselasky 0xfff); 106291939Shselasky if (acl_table->spoofchk_enabled) { 107291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 108291939Shselasky in_match_value, 109291939Shselasky outer_headers.smac_47_16); 110291939Shselasky ether_addr_copy(smac, acl_table->smac); 111291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 112291939Shselasky in_match_criteria, 113291939Shselasky outer_headers.smac_47_16); 114291939Shselasky memset(smac, 0xff, ETH_ALEN); 115291939Shselasky } 116291939Shselasky err = mlx5_add_flow_table_entry(acl_table->ft, vlan_mc_enable, 117291939Shselasky in_match_criteria, flow_context, 118291939Shselasky &acl_table->vlan_fi_table[vlan]); 119291939Shselaskyout: 120291939Shselasky if (flow_context) 121291939Shselasky vfree(flow_context); 122291939Shselasky if (in_match_criteria) 123291939Shselasky vfree(in_match_criteria); 124291939Shselasky return err; 125291939Shselasky} 126291939Shselasky 127291939Shselaskystatic int mlx5_vacl_table_apply_loopback_filter(void *acl_t, u16 new_action) 128291939Shselasky{ 129291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 130291939Shselasky u8 loopback_mc_enable = MLX5_MATCH_MISC_PARAMETERS; 131291939Shselasky u32 *flow_context = NULL; 132291939Shselasky void *in_match_criteria = NULL; 133291939Shselasky void *in_match_value = NULL; 134291939Shselasky void *mv_misc = NULL; 135291939Shselasky void *mc_misc = NULL; 136291939Shselasky int err = 0; 137291939Shselasky 138291939Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context)); 139291939Shselasky if (!flow_context) { 140291939Shselasky err = -ENOMEM; 141291939Shselasky goto out; 142291939Shselasky } 143291939Shselasky 144291939Shselasky in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 145291939Shselasky if (!in_match_criteria) { 146291939Shselasky err = -ENOMEM; 147291939Shselasky goto out; 148291939Shselasky } 149291939Shselasky 150291939Shselasky if (acl_table->loopback_fr.applied) 151291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 152291939Shselasky acl_table->loopback_fr.fi); 153291939Shselasky 154291939Shselasky /* Apply new loopback rule */ 155291939Shselasky MLX5_SET(flow_context, flow_context, action, new_action); 156291939Shselasky in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); 157291939Shselasky mv_misc = MLX5_ADDR_OF(fte_match_param, in_match_value, 158291939Shselasky misc_parameters); 159291939Shselasky mc_misc = MLX5_ADDR_OF(fte_match_param, in_match_criteria, 160291939Shselasky misc_parameters); 161291939Shselasky MLX5_SET(fte_match_set_misc, mv_misc, source_port, acl_table->vport); 162291939Shselasky 163291939Shselasky MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port); 164291939Shselasky 165291939Shselasky err = mlx5_add_flow_table_entry(acl_table->ft, loopback_mc_enable, 166291939Shselasky in_match_criteria, flow_context, 167291939Shselasky &acl_table->loopback_fr.fi); 168291939Shselasky if (err) { 169291939Shselasky acl_table->loopback_fr.applied = false; 170291939Shselasky } else { 171291939Shselasky acl_table->loopback_fr.applied = true; 172291939Shselasky acl_table->loopback_fr.action = new_action; 173291939Shselasky } 174291939Shselasky 175291939Shselaskyout: 176291939Shselasky if (flow_context) 177291939Shselasky vfree(flow_context); 178291939Shselasky if (in_match_criteria) 179291939Shselasky vfree(in_match_criteria); 180291939Shselasky return err; 181291939Shselasky} 182291939Shselasky 183291939Shselaskystatic int mlx5_vacl_table_apply_default(void *acl_t, u16 new_action) 184291939Shselasky{ 185291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 186291939Shselasky u8 default_mc_enable = 0; 187291939Shselasky u32 *flow_context = NULL; 188291939Shselasky void *in_match_criteria = NULL; 189291939Shselasky int err = 0; 190291939Shselasky 191291939Shselasky if (!acl_table->spoofchk_enabled) 192291939Shselasky return -EINVAL; 193291939Shselasky 194291939Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context)); 195291939Shselasky if (!flow_context) { 196291939Shselasky err = -ENOMEM; 197291939Shselasky goto out; 198291939Shselasky } 199291939Shselasky 200291939Shselasky in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 201291939Shselasky if (!in_match_criteria) { 202291939Shselasky err = -ENOMEM; 203291939Shselasky goto out; 204291939Shselasky } 205291939Shselasky 206291939Shselasky if (acl_table->default_fr.applied) 207291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 208291939Shselasky acl_table->default_fr.fi); 209291939Shselasky 210291939Shselasky /* Apply new default rule */ 211291939Shselasky MLX5_SET(flow_context, flow_context, action, new_action); 212291939Shselasky err = mlx5_add_flow_table_entry(acl_table->ft, default_mc_enable, 213291939Shselasky in_match_criteria, flow_context, 214291939Shselasky &acl_table->default_fr.fi); 215291939Shselasky if (err) { 216291939Shselasky acl_table->default_fr.applied = false; 217291939Shselasky } else { 218291939Shselasky acl_table->default_fr.applied = true; 219291939Shselasky acl_table->default_fr.action = new_action; 220291939Shselasky } 221291939Shselasky 222291939Shselaskyout: 223291939Shselasky if (flow_context) 224291939Shselasky vfree(flow_context); 225291939Shselasky if (in_match_criteria) 226291939Shselasky vfree(in_match_criteria); 227291939Shselasky return err; 228291939Shselasky} 229291939Shselasky 230291939Shselaskystatic int mlx5_vacl_table_apply_untagged(void *acl_t, u16 new_action) 231291939Shselasky{ 232291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 233291939Shselasky u8 untagged_mc_enable = MLX5_MATCH_OUTER_HEADERS; 234291939Shselasky u8 *smac; 235291939Shselasky u32 *flow_context = NULL; 236291939Shselasky void *in_match_criteria = NULL; 237291939Shselasky void *in_match_value = NULL; 238291939Shselasky int err = 0; 239291939Shselasky 240291939Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context)); 241291939Shselasky if (!flow_context) { 242291939Shselasky err = -ENOMEM; 243291939Shselasky goto out; 244291939Shselasky } 245291939Shselasky 246291939Shselasky in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 247291939Shselasky if (!in_match_criteria) { 248291939Shselasky err = -ENOMEM; 249291939Shselasky goto out; 250291939Shselasky } 251291939Shselasky 252291939Shselasky if (acl_table->untagged_fr.applied) 253291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 254291939Shselasky acl_table->untagged_fr.fi); 255291939Shselasky 256291939Shselasky /* Apply new untagged rule */ 257291939Shselasky MLX5_SET(flow_context, flow_context, action, new_action); 258291939Shselasky in_match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); 259291939Shselasky MLX5_SET(fte_match_param, in_match_value, outer_headers.vlan_tag, 0); 260291939Shselasky MLX5_SET(fte_match_param, in_match_criteria, outer_headers.vlan_tag, 1); 261291939Shselasky if (acl_table->spoofchk_enabled) { 262291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 263291939Shselasky in_match_value, 264291939Shselasky outer_headers.smac_47_16); 265291939Shselasky ether_addr_copy(smac, acl_table->smac); 266291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 267291939Shselasky in_match_criteria, 268291939Shselasky outer_headers.smac_47_16); 269291939Shselasky memset(smac, 0xff, ETH_ALEN); 270291939Shselasky } 271291939Shselasky err = mlx5_add_flow_table_entry(acl_table->ft, untagged_mc_enable, 272291939Shselasky in_match_criteria, flow_context, 273291939Shselasky &acl_table->untagged_fr.fi); 274291939Shselasky if (err) { 275291939Shselasky acl_table->untagged_fr.applied = false; 276291939Shselasky } else { 277291939Shselasky acl_table->untagged_fr.applied = true; 278291939Shselasky acl_table->untagged_fr.action = new_action; 279291939Shselasky } 280291939Shselasky 281291939Shselaskyout: 282291939Shselasky if (flow_context) 283291939Shselasky vfree(flow_context); 284291939Shselasky if (in_match_criteria) 285291939Shselasky vfree(in_match_criteria); 286291939Shselasky return err; 287291939Shselasky} 288291939Shselasky 289291939Shselaskystatic int mlx5_vacl_table_apply_unknown_vlan(void *acl_t, u16 new_action) 290291939Shselasky{ 291291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 292291939Shselasky u8 default_mc_enable = (!acl_table->spoofchk_enabled) ? 0 : 293291939Shselasky MLX5_MATCH_OUTER_HEADERS; 294291939Shselasky u32 *flow_context = NULL; 295291939Shselasky void *in_match_criteria = NULL; 296291939Shselasky void *in_match_value = NULL; 297291939Shselasky u8 *smac; 298291939Shselasky int err = 0; 299291939Shselasky 300291939Shselasky flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context)); 301291939Shselasky if (!flow_context) { 302291939Shselasky err = -ENOMEM; 303291939Shselasky goto out; 304291939Shselasky } 305291939Shselasky 306291939Shselasky in_match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); 307291939Shselasky if (!in_match_criteria) { 308291939Shselasky err = -ENOMEM; 309291939Shselasky goto out; 310291939Shselasky } 311291939Shselasky 312291939Shselasky if (acl_table->unknown_vlan_fr.applied) 313291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 314291939Shselasky acl_table->unknown_vlan_fr.fi); 315291939Shselasky 316291939Shselasky /* Apply new unknown vlan rule */ 317291939Shselasky MLX5_SET(flow_context, flow_context, action, new_action); 318291939Shselasky if (acl_table->spoofchk_enabled) { 319291939Shselasky in_match_value = MLX5_ADDR_OF(flow_context, flow_context, 320291939Shselasky match_value); 321291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 322291939Shselasky in_match_value, 323291939Shselasky outer_headers.smac_47_16); 324291939Shselasky ether_addr_copy(smac, acl_table->smac); 325291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 326291939Shselasky in_match_criteria, 327291939Shselasky outer_headers.smac_47_16); 328291939Shselasky memset(smac, 0xff, ETH_ALEN); 329291939Shselasky } 330291939Shselasky err = mlx5_add_flow_table_entry(acl_table->ft, default_mc_enable, 331291939Shselasky in_match_criteria, flow_context, 332291939Shselasky &acl_table->unknown_vlan_fr.fi); 333291939Shselasky if (err) { 334291939Shselasky acl_table->unknown_vlan_fr.applied = false; 335291939Shselasky } else { 336291939Shselasky acl_table->unknown_vlan_fr.applied = true; 337291939Shselasky acl_table->unknown_vlan_fr.action = new_action; 338291939Shselasky } 339291939Shselasky 340291939Shselaskyout: 341291939Shselasky if (flow_context) 342291939Shselasky vfree(flow_context); 343291939Shselasky if (in_match_criteria) 344291939Shselasky vfree(in_match_criteria); 345291939Shselasky return err; 346291939Shselasky} 347291939Shselasky 348291939Shselaskystatic int mlx5_vacl_table_apply_vlan_filter(void *acl_t) 349291939Shselasky{ 350291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 351291939Shselasky int index = 0; 352291939Shselasky int err_index = 0; 353291939Shselasky int err = 0; 354291939Shselasky 355291939Shselasky if (acl_table->vlan_filter_applied) 356291939Shselasky return 0; 357291939Shselasky 358291939Shselasky for (index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096); 359291939Shselasky index < 4096; 360291939Shselasky index = find_next_bit(acl_table->vlan_allowed_bitmap, 361291939Shselasky 4096, ++index)) { 362291939Shselasky err = mlx5_vacl_table_allow_vlan(acl_t, index); 363291939Shselasky if (err) 364291939Shselasky goto err_disable_vlans; 365291939Shselasky } 366291939Shselasky 367291939Shselasky acl_table->vlan_filter_applied = true; 368291939Shselasky return 0; 369291939Shselasky 370291939Shselaskyerr_disable_vlans: 371291939Shselasky for (err_index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096); 372291939Shselasky err_index < index; 373291939Shselasky err_index = find_next_bit(acl_table->vlan_allowed_bitmap, 4096, 374291939Shselasky ++err_index)) { 375291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 376291939Shselasky acl_table->vlan_fi_table[err_index]); 377291939Shselasky } 378291939Shselasky return err; 379291939Shselasky} 380291939Shselasky 381291939Shselaskystatic void mlx5_vacl_table_disapply_vlan_filter(void *acl_t) 382291939Shselasky{ 383291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 384291939Shselasky int index = 0; 385291939Shselasky 386291939Shselasky if (!acl_table->vlan_filter_applied) 387291939Shselasky return; 388291939Shselasky 389291939Shselasky for (index = find_first_bit(acl_table->vlan_allowed_bitmap, 4096); 390291939Shselasky index < 4096; 391291939Shselasky index = find_next_bit(acl_table->vlan_allowed_bitmap, 4096, 392291939Shselasky ++index)) { 393291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 394291939Shselasky acl_table->vlan_fi_table[index]); 395291939Shselasky } 396291939Shselasky 397291939Shselasky acl_table->vlan_filter_applied = false; 398291939Shselasky} 399291939Shselasky 400291939Shselaskystatic void mlx5_vacl_table_disapply_all_filters(void *acl_t) 401291939Shselasky{ 402291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 403291939Shselasky 404291939Shselasky if (acl_table->default_fr.applied) { 405291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 406291939Shselasky acl_table->default_fr.fi); 407291939Shselasky acl_table->default_fr.applied = false; 408291939Shselasky } 409291939Shselasky if (acl_table->unknown_vlan_fr.applied) { 410291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 411291939Shselasky acl_table->unknown_vlan_fr.fi); 412291939Shselasky acl_table->unknown_vlan_fr.applied = false; 413291939Shselasky } 414291939Shselasky if (acl_table->loopback_fr.applied) { 415291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 416291939Shselasky acl_table->loopback_fr.fi); 417291939Shselasky acl_table->loopback_fr.applied = false; 418291939Shselasky } 419291939Shselasky if (acl_table->untagged_fr.applied) { 420291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 421291939Shselasky acl_table->untagged_fr.fi); 422291939Shselasky acl_table->untagged_fr.applied = false; 423291939Shselasky } 424291939Shselasky if (acl_table->vlan_filter_applied) { 425291939Shselasky mlx5_vacl_table_disapply_vlan_filter(acl_t); 426291939Shselasky acl_table->vlan_filter_applied = false; 427291939Shselasky } 428291939Shselasky} 429291939Shselasky 430291939Shselaskystatic int mlx5_vacl_table_apply_all_filters(void *acl_t) 431291939Shselasky{ 432291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 433291939Shselasky int err = 0; 434291939Shselasky 435291939Shselasky if (!acl_table->default_fr.applied && acl_table->spoofchk_enabled) { 436291939Shselasky err = mlx5_vacl_table_apply_default(acl_table, 437291939Shselasky acl_table->default_fr.action); 438291939Shselasky if (err) 439291939Shselasky goto err_disapply_all; 440291939Shselasky } 441291939Shselasky 442291939Shselasky if (!acl_table->unknown_vlan_fr.applied) { 443291939Shselasky err = mlx5_vacl_table_apply_unknown_vlan(acl_table, 444291939Shselasky acl_table->unknown_vlan_fr.action); 445291939Shselasky if (err) 446291939Shselasky goto err_disapply_all; 447291939Shselasky } 448291939Shselasky 449291939Shselasky if (!acl_table->loopback_fr.applied && 450291939Shselasky acl_table->acl_type == MLX5_FLOW_TABLE_TYPE_EGRESS_ACL) { 451291939Shselasky err = mlx5_vacl_table_apply_loopback_filter( 452291939Shselasky acl_table, 453291939Shselasky acl_table->loopback_fr.action); 454291939Shselasky if (err) 455291939Shselasky goto err_disapply_all; 456291939Shselasky } 457291939Shselasky 458291939Shselasky if (!acl_table->untagged_fr.applied) { 459291939Shselasky err = mlx5_vacl_table_apply_untagged(acl_table, 460291939Shselasky acl_table->untagged_fr.action); 461291939Shselasky if (err) 462291939Shselasky goto err_disapply_all; 463291939Shselasky } 464291939Shselasky 465291939Shselasky if (!acl_table->vlan_filter_applied && acl_table->vlan_filter_enabled) { 466291939Shselasky err = mlx5_vacl_table_apply_vlan_filter(acl_t); 467291939Shselasky if (err) 468291939Shselasky goto err_disapply_all; 469291939Shselasky } 470291939Shselasky 471291939Shselasky goto out; 472291939Shselasky 473291939Shselaskyerr_disapply_all: 474291939Shselasky mlx5_vacl_table_disapply_all_filters(acl_t); 475291939Shselasky 476291939Shselaskyout: 477291939Shselasky return err; 478291939Shselasky} 479291939Shselasky 480291939Shselaskystatic void mlx5_vacl_table_destroy_ft(void *acl_t) 481291939Shselasky{ 482291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 483291939Shselasky 484291939Shselasky mlx5_vacl_table_disapply_all_filters(acl_t); 485291939Shselasky if (acl_table->ft) 486291939Shselasky mlx5_destroy_flow_table(acl_table->ft); 487291939Shselasky acl_table->ft = NULL; 488291939Shselasky} 489291939Shselasky 490291939Shselaskystatic int mlx5_vacl_table_create_ft(void *acl_t, bool spoofchk) 491291939Shselasky{ 492291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 493291939Shselasky int log_acl_ft_size; 494291939Shselasky int err = 0; 495291939Shselasky int groups_num = MLX5_ACL_GROUPS_NUM - 1; 496291939Shselasky int shift_idx = MLX5_ACL_UNTAGGED_GROUP_IDX; 497291939Shselasky u8 *smac; 498291939Shselasky struct mlx5_flow_table_group *g; 499291939Shselasky 500291939Shselasky if (acl_table->ft) 501291939Shselasky return -EINVAL; 502291939Shselasky 503291939Shselasky g = kcalloc(MLX5_ACL_GROUPS_NUM, sizeof(*g), GFP_KERNEL); 504291939Shselasky if (!g) 505291939Shselasky goto out; 506291939Shselasky 507291939Shselasky acl_table->spoofchk_enabled = spoofchk; 508291939Shselasky 509291939Shselasky /* 510291939Shselasky * for vlan group 511291939Shselasky */ 512291939Shselasky log_acl_ft_size = 4096; 513291939Shselasky /* 514291939Shselasky * for loopback filter rule 515291939Shselasky */ 516291939Shselasky log_acl_ft_size += 1; 517291939Shselasky /* 518291939Shselasky * for untagged rule 519291939Shselasky */ 520291939Shselasky log_acl_ft_size += 1; 521291939Shselasky /* 522291939Shselasky * for unknown vlan rule 523291939Shselasky */ 524291939Shselasky log_acl_ft_size += 1; 525291939Shselasky /* 526291939Shselasky * for default rule 527291939Shselasky */ 528291939Shselasky log_acl_ft_size += 1; 529291939Shselasky 530291939Shselasky log_acl_ft_size = order_base_2(log_acl_ft_size); 531291939Shselasky log_acl_ft_size = min_t(int, log_acl_ft_size, acl_table->max_ft_size); 532291939Shselasky 533291939Shselasky if (log_acl_ft_size < 2) 534291939Shselasky goto out; 535291939Shselasky 536291939Shselasky if (acl_table->acl_type == MLX5_FLOW_TABLE_TYPE_EGRESS_ACL) { 537291939Shselasky /* Loopback filter group */ 538291939Shselasky g[MLX5_ACL_LOOPBACK_GROUP_IDX].log_sz = 0; 539291939Shselasky g[MLX5_ACL_LOOPBACK_GROUP_IDX].match_criteria_enable = 540291939Shselasky MLX5_MATCH_MISC_PARAMETERS; 541291939Shselasky MLX5_SET_TO_ONES(fte_match_param, 542291939Shselasky g[MLX5_ACL_LOOPBACK_GROUP_IDX].match_criteria, 543291939Shselasky misc_parameters.source_port); 544291939Shselasky groups_num++; 545291939Shselasky shift_idx = MLX5_ACL_LOOPBACK_GROUP_IDX; 546291939Shselasky } 547291939Shselasky /* Untagged traffic group */ 548291939Shselasky g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].log_sz = 0; 549291939Shselasky g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].match_criteria_enable = 550291939Shselasky MLX5_MATCH_OUTER_HEADERS; 551291939Shselasky MLX5_SET(fte_match_param, 552291939Shselasky g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx].match_criteria, 553291939Shselasky outer_headers.vlan_tag, 1); 554291939Shselasky if (spoofchk) { 555291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 556291939Shselasky g[MLX5_ACL_UNTAGGED_GROUP_IDX - shift_idx] 557291939Shselasky .match_criteria, 558291939Shselasky outer_headers.smac_47_16); 559291939Shselasky memset(smac, 0xff, ETH_ALEN); 560291939Shselasky } 561291939Shselasky 562291939Shselasky /* Allowed vlans group */ 563291939Shselasky g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].log_sz = log_acl_ft_size - 1; 564291939Shselasky g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria_enable = 565291939Shselasky MLX5_MATCH_OUTER_HEADERS; 566291939Shselasky MLX5_SET(fte_match_param, 567291939Shselasky g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria, 568291939Shselasky outer_headers.vlan_tag, 1); 569291939Shselasky MLX5_SET(fte_match_param, 570291939Shselasky g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx].match_criteria, 571291939Shselasky outer_headers.first_vid, 0xfff); 572291939Shselasky if (spoofchk) { 573291939Shselasky smac = MLX5_ADDR_OF(fte_match_param, 574291939Shselasky g[MLX5_ACL_VLAN_GROUP_IDX - shift_idx] 575291939Shselasky .match_criteria, 576291939Shselasky outer_headers.smac_47_16); 577291939Shselasky memset(smac, 0xff, ETH_ALEN); 578291939Shselasky } 579291939Shselasky 580291939Shselasky /* Unknown vlan traffic group */ 581291939Shselasky g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx].log_sz = 0; 582291939Shselasky g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx].match_criteria_enable = 583291939Shselasky (spoofchk ? MLX5_MATCH_OUTER_HEADERS : 0); 584291939Shselasky if (spoofchk) { 585291939Shselasky smac = MLX5_ADDR_OF( 586291939Shselasky fte_match_param, 587291939Shselasky g[MLX5_ACL_UNKNOWN_VLAN_GROUP_IDX - shift_idx] 588291939Shselasky .match_criteria, 589291939Shselasky outer_headers.smac_47_16); 590291939Shselasky memset(smac, 0xff, ETH_ALEN); 591291939Shselasky } 592291939Shselasky 593291939Shselasky /* 594291939Shselasky * Default group - for spoofchk only. 595291939Shselasky */ 596291939Shselasky g[MLX5_ACL_DEFAULT_GROUP_IDX - shift_idx].log_sz = 0; 597291939Shselasky g[MLX5_ACL_DEFAULT_GROUP_IDX - shift_idx].match_criteria_enable = 0; 598291939Shselasky 599291939Shselasky acl_table->ft = mlx5_create_flow_table(acl_table->dev, 600291939Shselasky 0, 601291939Shselasky acl_table->acl_type, 602291939Shselasky acl_table->vport, 603291939Shselasky groups_num, 604291939Shselasky g); 605291939Shselasky if (!acl_table->ft) { 606291939Shselasky err = -ENOMEM; 607291939Shselasky goto out; 608291939Shselasky } 609291939Shselasky 610291939Shselasky err = mlx5_vacl_table_apply_all_filters(acl_t); 611291939Shselasky if (err) 612291939Shselasky goto err_destroy_ft; 613291939Shselasky 614291939Shselasky goto out; 615291939Shselasky 616291939Shselaskyerr_destroy_ft: 617291939Shselasky mlx5_vacl_table_destroy_ft(acl_table->ft); 618291939Shselasky acl_table->ft = NULL; 619291939Shselasky 620291939Shselaskyout: 621291939Shselasky kfree(g); 622291939Shselasky return err; 623291939Shselasky} 624291939Shselasky 625291939Shselaskyvoid *mlx5_vacl_table_create(struct mlx5_core_dev *dev, 626291939Shselasky u16 vport, bool is_egress) 627291939Shselasky{ 628291939Shselasky struct mlx5_vacl_table *acl_table; 629291939Shselasky int err = 0; 630291939Shselasky 631291939Shselasky if (is_egress && !MLX5_CAP_ESW_FLOWTABLE_EGRESS_ACL(dev, ft_support)) 632291939Shselasky return NULL; 633291939Shselasky 634291939Shselasky if (!is_egress && !MLX5_CAP_ESW_FLOWTABLE_INGRESS_ACL(dev, ft_support)) 635291939Shselasky return NULL; 636291939Shselasky 637291939Shselasky acl_table = kzalloc(sizeof(*acl_table), GFP_KERNEL); 638291939Shselasky if (!acl_table) 639291939Shselasky return NULL; 640291939Shselasky 641291939Shselasky acl_table->acl_type = is_egress ? MLX5_FLOW_TABLE_TYPE_EGRESS_ACL : 642291939Shselasky MLX5_FLOW_TABLE_TYPE_INGRESS_ACL; 643291939Shselasky acl_table->max_ft_size = (is_egress ? 644291939Shselasky MLX5_CAP_ESW_FLOWTABLE_EGRESS_ACL(dev, 645291939Shselasky log_max_ft_size) : 646291939Shselasky MLX5_CAP_ESW_FLOWTABLE_INGRESS_ACL(dev, 647291939Shselasky log_max_ft_size)); 648291939Shselasky acl_table->dev = dev; 649291939Shselasky acl_table->vport = vport; 650291939Shselasky 651291939Shselasky /* 652291939Shselasky * default behavior : Allow and if spoofchk drop the default 653291939Shselasky */ 654291939Shselasky acl_table->default_fr.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 655291939Shselasky acl_table->loopback_fr.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 656291939Shselasky acl_table->unknown_vlan_fr.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; 657291939Shselasky acl_table->untagged_fr.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; 658291939Shselasky err = mlx5_vacl_table_create_ft(acl_table, false); 659291939Shselasky if (err) 660291939Shselasky goto err_free_acl_table; 661291939Shselasky 662291939Shselasky acl_table->vlan_allowed_bitmap = kcalloc(BITS_TO_LONGS(4096), 663291939Shselasky sizeof(uintptr_t), 664291939Shselasky GFP_KERNEL); 665291939Shselasky if (!acl_table->vlan_allowed_bitmap) 666291939Shselasky goto err_destroy_ft; 667291939Shselasky 668291939Shselasky goto out; 669291939Shselasky 670291939Shselaskyerr_destroy_ft: 671291939Shselasky mlx5_vacl_table_destroy_ft(acl_table->ft); 672291939Shselasky acl_table->ft = NULL; 673291939Shselasky 674291939Shselaskyerr_free_acl_table: 675291939Shselasky kfree(acl_table); 676291939Shselasky acl_table = NULL; 677291939Shselasky 678291939Shselaskyout: 679291939Shselasky return (void *)acl_table; 680291939Shselasky} 681291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_create); 682291939Shselasky 683291939Shselaskyvoid mlx5_vacl_table_cleanup(void *acl_t) 684291939Shselasky{ 685291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 686291939Shselasky 687291939Shselasky mlx5_vacl_table_destroy_ft(acl_t); 688291939Shselasky kfree(acl_table->vlan_allowed_bitmap); 689291939Shselasky kfree(acl_table); 690291939Shselasky} 691291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_cleanup); 692291939Shselasky 693291939Shselaskyint mlx5_vacl_table_add_vlan(void *acl_t, u16 vlan) 694291939Shselasky{ 695291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 696291939Shselasky int err = 0; 697291939Shselasky 698291939Shselasky if (test_bit(vlan, acl_table->vlan_allowed_bitmap)) 699291939Shselasky return 0; 700291939Shselasky __set_bit(vlan, acl_table->vlan_allowed_bitmap); 701291939Shselasky if (!acl_table->vlan_filter_applied) 702291939Shselasky return 0; 703291939Shselasky 704291939Shselasky err = mlx5_vacl_table_allow_vlan(acl_t, vlan); 705291939Shselasky if (err) 706291939Shselasky goto err_clear_vbit; 707291939Shselasky 708291939Shselasky goto out; 709291939Shselasky 710291939Shselaskyerr_clear_vbit: 711291939Shselasky __clear_bit(vlan, acl_table->vlan_allowed_bitmap); 712291939Shselasky 713291939Shselaskyout: 714291939Shselasky return err; 715291939Shselasky} 716291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_add_vlan); 717291939Shselasky 718291939Shselaskyvoid mlx5_vacl_table_del_vlan(void *acl_t, u16 vlan) 719291939Shselasky{ 720291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 721291939Shselasky 722291939Shselasky if (!test_bit(vlan, acl_table->vlan_allowed_bitmap)) 723291939Shselasky return; 724291939Shselasky 725291939Shselasky __clear_bit(vlan, acl_table->vlan_allowed_bitmap); 726291939Shselasky 727291939Shselasky if (!acl_table->vlan_filter_applied) 728291939Shselasky return; 729291939Shselasky 730291939Shselasky mlx5_del_flow_table_entry(acl_table->ft, 731291939Shselasky acl_table->vlan_fi_table[vlan]); 732291939Shselasky} 733291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_del_vlan); 734291939Shselasky 735291939Shselaskyint mlx5_vacl_table_enable_vlan_filter(void *acl_t) 736291939Shselasky{ 737291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 738291939Shselasky 739291939Shselasky acl_table->vlan_filter_enabled = true; 740291939Shselasky return mlx5_vacl_table_apply_vlan_filter(acl_t); 741291939Shselasky} 742291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_enable_vlan_filter); 743291939Shselasky 744291939Shselaskyvoid mlx5_vacl_table_disable_vlan_filter(void *acl_t) 745291939Shselasky{ 746291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 747291939Shselasky 748291939Shselasky acl_table->vlan_filter_enabled = false; 749291939Shselasky mlx5_vacl_table_disapply_vlan_filter(acl_t); 750291939Shselasky} 751291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_disable_vlan_filter); 752291939Shselasky 753291939Shselaskyint mlx5_vacl_table_drop_untagged(void *acl_t) 754291939Shselasky{ 755291939Shselasky return mlx5_vacl_table_apply_untagged(acl_t, 756291939Shselasky MLX5_FLOW_CONTEXT_ACTION_DROP); 757291939Shselasky} 758291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_drop_untagged); 759291939Shselasky 760291939Shselaskyint mlx5_vacl_table_allow_untagged(void *acl_t) 761291939Shselasky{ 762291939Shselasky return mlx5_vacl_table_apply_untagged(acl_t, 763291939Shselasky MLX5_FLOW_CONTEXT_ACTION_ALLOW); 764291939Shselasky} 765291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_allow_untagged); 766291939Shselasky 767291939Shselaskyint mlx5_vacl_table_drop_unknown_vlan(void *acl_t) 768291939Shselasky{ 769291939Shselasky return mlx5_vacl_table_apply_unknown_vlan(acl_t, 770291939Shselasky MLX5_FLOW_CONTEXT_ACTION_DROP); 771291939Shselasky} 772291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_drop_unknown_vlan); 773291939Shselasky 774291939Shselaskyint mlx5_vacl_table_allow_unknown_vlan(void *acl_t) 775291939Shselasky{ 776291939Shselasky return mlx5_vacl_table_apply_unknown_vlan(acl_t, 777291939Shselasky MLX5_FLOW_CONTEXT_ACTION_ALLOW); 778291939Shselasky} 779291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_allow_unknown_vlan); 780291939Shselasky 781291939Shselaskyint mlx5_vacl_table_set_spoofchk(void *acl_t, bool spoofchk, u8 *vport_mac) 782291939Shselasky{ 783291939Shselasky struct mlx5_vacl_table *acl_table = (struct mlx5_vacl_table *)acl_t; 784291939Shselasky int err = 0; 785291939Shselasky 786291939Shselasky if (spoofchk == acl_table->spoofchk_enabled) { 787291939Shselasky if (!spoofchk || 788291939Shselasky (spoofchk && !memcmp(acl_table->smac, vport_mac, ETH_ALEN))) 789291939Shselasky return 0; 790291939Shselasky } 791291939Shselasky 792291939Shselasky ether_addr_copy(acl_table->smac, vport_mac); 793291939Shselasky if (spoofchk != acl_table->spoofchk_enabled) { 794291939Shselasky mlx5_vacl_table_destroy_ft(acl_t); 795291939Shselasky err = mlx5_vacl_table_create_ft(acl_t, spoofchk); 796291939Shselasky } else { 797291939Shselasky mlx5_vacl_table_disapply_all_filters(acl_t); 798291939Shselasky err = mlx5_vacl_table_apply_all_filters(acl_t); 799291939Shselasky } 800291939Shselasky 801291939Shselasky return err; 802291939Shselasky} 803291939ShselaskyEXPORT_SYMBOL(mlx5_vacl_table_set_spoofchk); 804291939Shselasky 805