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 ((tun_key->tun_flags & TUNNEL_VXLAN_OPT) && 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 (tun_key->tun_flags & TUNNEL_VXLAN_OPT) { 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 != TUNNEL_VXLAN_OPT) { 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)\n", *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 misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); 169 misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); 170 171 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) 172 return 0; 173 174 flow_rule_match_enc_keyid(rule, &enc_keyid); 175 176 if (!enc_keyid.mask->keyid) 177 return 0; 178 179 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS)) { 180 int err; 181 182 err = mlx5e_tc_tun_parse_vxlan_gbp_option(priv, spec, f); 183 if (err) 184 return err; 185 } 186 187 /* match on VNI is required */ 188 189 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, 190 ft_field_support.outer_vxlan_vni)) { 191 NL_SET_ERR_MSG_MOD(extack, 192 "Matching on VXLAN VNI is not supported"); 193 netdev_warn(priv->netdev, 194 "Matching on VXLAN VNI is not supported\n"); 195 return -EOPNOTSUPP; 196 } 197 198 MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 199 be32_to_cpu(enc_keyid.mask->keyid)); 200 MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 201 be32_to_cpu(enc_keyid.key->keyid)); 202 203 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS; 204 205 return 0; 206} 207 208static bool mlx5e_tc_tun_encap_info_equal_vxlan(struct mlx5e_encap_key *a, 209 struct mlx5e_encap_key *b) 210{ 211 return mlx5e_tc_tun_encap_info_equal_options(a, b, TUNNEL_VXLAN_OPT); 212} 213 214static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev) 215{ 216 const struct vxlan_dev *vxlan = netdev_priv(mirred_dev); 217 const struct vxlan_rdst *dst = &vxlan->default_dst; 218 219 return dst->remote_ifindex; 220} 221 222struct mlx5e_tc_tunnel vxlan_tunnel = { 223 .tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN, 224 .match_level = MLX5_MATCH_L4, 225 .can_offload = mlx5e_tc_tun_can_offload_vxlan, 226 .calc_hlen = mlx5e_tc_tun_calc_hlen_vxlan, 227 .init_encap_attr = mlx5e_tc_tun_init_encap_attr_vxlan, 228 .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_vxlan, 229 .parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_vxlan, 230 .parse_tunnel = mlx5e_tc_tun_parse_vxlan, 231 .encap_info_equal = mlx5e_tc_tun_encap_info_equal_vxlan, 232 .get_remote_ifindex = mlx5e_tc_tun_get_remote_ifindex, 233}; 234