FILE
tc_tun_vxlan.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2018 Mellanox Technologies. */ 3 4#include <net/ip_tunnels.h> 5#include <net/vxlan.h> 6#include "lib/vxlan.h" 7#include "en/tc_tun.h" 8 9static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv) 10{ 11 return !!MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap); 12} 13 14static int mlx5e_tc_tun_calc_hlen_vxlan(struct mlx5e_encap_entry *e) 15{ 16 return VXLAN_HLEN; 17} 18 19static int mlx5e_tc_tun_check_udp_dport_vxlan(struct mlx5e_priv *priv, 20 struct flow_cls_offload *f) 21{ 22 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 23 struct netlink_ext_ack *extack = f->common.extack; 24 struct flow_match_ports enc_ports; 25 26 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) 27 return -EOPNOTSUPP; 28 29 flow_rule_match_enc_ports(rule, &enc_ports); 30 31 /* check the UDP destination port validity */ 32 33 if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, 34 be16_to_cpu(enc_ports.key->dst))) { 35 NL_SET_ERR_MSG_MOD(extack, 36 "Matched UDP dst port is not registered as a VXLAN port"); 37 netdev_warn(priv->netdev, 38 "UDP port %d is not registered as a VXLAN port\n", 39 be16_to_cpu(enc_ports.key->dst)); 40 return -EOPNOTSUPP; 41 } 42 43 return 0; 44} 45 46static int mlx5e_tc_tun_parse_udp_ports_vxlan(struct mlx5e_priv *priv, 47 struct mlx5_flow_spec *spec, 48 struct flow_cls_offload *f, 49 void *headers_c, 50 void *headers_v) 51{ 52 int err = 0; 53 54 err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v); 55 if (err) 56 return err; 57 58 return mlx5e_tc_tun_check_udp_dport_vxlan(priv, f); 59} 60 61static int mlx5e_tc_tun_init_encap_attr_vxlan(struct net_device *tunnel_dev, 62 struct mlx5e_priv *priv, 63 struct mlx5e_encap_entry *e, 64 struct netlink_ext_ack *extack) 65{ 66 int dst_port = be16_to_cpu(e->tun_info->key.tp_dst); 67 68 e->tunnel = &vxlan_tunnel; 69 70 if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) { 71 NL_SET_ERR_MSG_MOD(extack, 72 "vxlan udp dport was not registered with the HW"); 73 netdev_warn(priv->netdev, 74 "%d isn't an offloaded vxlan udp dport\n", 75 dst_port); 76 return -EOPNOTSUPP; 77 } 78 79 e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN; 80 return 0; 81} 82 83static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[], 84 __u8 *ip_proto, 85 struct mlx5e_encap_entry *e) 86{ 87 const struct ip_tunnel_key *tun_key = &e->tun_info->key; 88 __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id); 89 struct udphdr *udp = (struct udphdr *)(buf); 90 const struct vxlan_metadata *md; 91 struct vxlanhdr *vxh; 92 93 if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT, tun_key->tun_flags) && 94 e->tun_info->options_len != sizeof(*md)) 95 return -EOPNOTSUPP; 96 vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 97 *ip_proto = IPPROTO_UDP; 98 99 udp->dest = tun_key->tp_dst; 100 vxh->vx_flags = VXLAN_HF_VNI; 101 vxh->vx_vni = vxlan_vni_field(tun_id); 102 if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT, tun_key->tun_flags)) { 103 md = ip_tunnel_info_opts(e->tun_info); 104 vxlan_build_gbp_hdr(vxh, md); 105 } 106 107 return 0; 108} 109 110static int mlx5e_tc_tun_parse_vxlan_gbp_option(struct mlx5e_priv *priv, 111 struct mlx5_flow_spec *spec, 112 struct flow_cls_offload *f) 113{ 114 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 115 struct netlink_ext_ack *extack = f->common.extack; 116 struct flow_match_enc_opts enc_opts; 117 void *misc5_c, *misc5_v; 118 u32 *gbp, *gbp_mask; 119 120 flow_rule_match_enc_opts(rule, &enc_opts); 121 122 if (memchr_inv(&enc_opts.mask->data, 0, sizeof(enc_opts.mask->data)) && 123 !MLX5_CAP_ESW_FT_FIELD_SUPPORT_2(priv->mdev, tunnel_header_0_1)) { 124 NL_SET_ERR_MSG_MOD(extack, "Matching on VxLAN GBP is not supported"); 125 return -EOPNOTSUPP; 126 } 127 128 if (enc_opts.key->dst_opt_type != IP_TUNNEL_VXLAN_OPT_BIT) { 129 NL_SET_ERR_MSG_MOD(extack, "Wrong VxLAN option type: not GBP"); 130 return -EOPNOTSUPP; 131 } 132 133 if (enc_opts.key->len != sizeof(*gbp) || 134 enc_opts.mask->len != sizeof(*gbp_mask)) { 135 NL_SET_ERR_MSG_MOD(extack, "VxLAN GBP option/mask len is not 32 bits"); 136 return -EINVAL; 137 } 138 139 gbp = (u32 *)&enc_opts.key->data[0]; 140 gbp_mask = (u32 *)&enc_opts.mask->data[0]; 141 142 if (*gbp_mask & ~VXLAN_GBP_MASK) { 143 NL_SET_ERR_MSG_FMT_MOD(extack, "Wrong VxLAN GBP mask(0x%08X)", *gbp_mask); 144 return -EINVAL; 145 } 146 147 misc5_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_5); 148 misc5_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_5); 149 MLX5_SET(fte_match_set_misc5, misc5_c, tunnel_header_0, *gbp_mask); 150 MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_0, *gbp); 151 152 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5; 153 154 return 0; 155} 156 157static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv, 158 struct mlx5_flow_spec *spec, 159 struct flow_cls_offload *f, 160 void *headers_c, 161 void *headers_v) 162{ 163 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 164 struct netlink_ext_ack *extack = f->common.extack; 165 struct flow_match_enc_keyid enc_keyid; 166 void *misc_c, *misc_v; 167 168 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) 169 return 0; 170 171 flow_rule_match_enc_keyid(rule, &enc_keyid); 172 173 if (!enc_keyid.mask->keyid) 174 return 0; 175 176 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS)) { 177 int err; 178 179 err = mlx5e_tc_tun_parse_vxlan_gbp_option(priv, spec, f); 180 if (err) 181 return err; 182 183 /* We can't mix custom tunnel headers with symbolic ones and we 184 * don't have a symbolic field name for GBP, so we use custom 185 * tunnel headers in this case. We need hardware support to 186 * match on custom tunnel headers, but we already know it's 187 * supported because the previous call successfully checked for 188 * that. 189 */ 190 misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 191 misc_parameters_5); 192 misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 193 misc_parameters_5); 194 195 /* Shift by 8 to account for the reserved bits in the vxlan 196 * header after the VNI. 197 */ 198 MLX5_SET(fte_match_set_misc5, misc_c, tunnel_header_1, 199 be32_to_cpu(enc_keyid.mask->keyid) << 8); 200 MLX5_SET(fte_match_set_misc5, misc_v, tunnel_header_1, 201 be32_to_cpu(enc_keyid.key->keyid) << 8); 202 203 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5; 204 205 return 0; 206 } 207 208 /* match on VNI is required */ 209 210 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, 211 ft_field_support.outer_vxlan_vni)) { 212 NL_SET_ERR_MSG_MOD(extack, 213 "Matching on VXLAN VNI is not supported"); 214 netdev_warn(priv->netdev, 215 "Matching on VXLAN VNI is not supported\n"); 216 return -EOPNOTSUPP; 217 } 218 219 misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 220 misc_parameters); 221 misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 222 misc_parameters); 223 224 MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 225 be32_to_cpu(enc_keyid.mask->keyid)); 226 MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 227 be32_to_cpu(enc_keyid.key->keyid)); 228 229 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS; 230 231 return 0; 232} 233 234static bool mlx5e_tc_tun_encap_info_equal_vxlan(struct mlx5e_encap_key *a, 235 struct mlx5e_encap_key *b) 236{ 237 return mlx5e_tc_tun_encap_info_equal_options(a, b, 238 IP_TUNNEL_VXLAN_OPT_BIT); 239} 240 241static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev) 242{ 243 const struct vxlan_dev *vxlan = netdev_priv(mirred_dev); 244 const struct vxlan_rdst *dst = &vxlan->default_dst; 245 246 return dst->remote_ifindex; 247} 248 249struct mlx5e_tc_tunnel vxlan_tunnel = { 250 .tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN, 251 .match_level = MLX5_MATCH_L4, 252 .can_offload = mlx5e_tc_tun_can_offload_vxlan, 253 .calc_hlen = mlx5e_tc_tun_calc_hlen_vxlan, 254 .init_encap_attr = mlx5e_tc_tun_init_encap_attr_vxlan, 255 .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_vxlan, 256 .parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_vxlan, 257 .parse_tunnel = mlx5e_tc_tun_parse_vxlan, 258 .encap_info_equal = mlx5e_tc_tun_encap_info_equal_vxlan, 259 .get_remote_ifindex = mlx5e_tc_tun_get_remote_ifindex, 260};
~/
Read-only file preview.