1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2018 Mellanox Technologies. */ 3 4 #include <net/vxlan.h> 5 #include "lib/vxlan.h" 6 #include "en/tc_tun.h" 7 8 static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv) 9 { 10 return !!MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap); 11 } 12 13 static int mlx5e_tc_tun_calc_hlen_vxlan(struct mlx5e_encap_entry *e) 14 { 15 return VXLAN_HLEN; 16 } 17 18 static int mlx5e_tc_tun_check_udp_dport_vxlan(struct mlx5e_priv *priv, 19 struct flow_cls_offload *f) 20 { 21 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 22 struct netlink_ext_ack *extack = f->common.extack; 23 struct flow_match_ports enc_ports; 24 25 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) 26 return -EOPNOTSUPP; 27 28 flow_rule_match_enc_ports(rule, &enc_ports); 29 30 /* check the UDP destination port validity */ 31 32 if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, 33 be16_to_cpu(enc_ports.key->dst))) { 34 NL_SET_ERR_MSG_MOD(extack, 35 "Matched UDP dst port is not registered as a VXLAN port"); 36 netdev_warn(priv->netdev, 37 "UDP port %d is not registered as a VXLAN port\n", 38 be16_to_cpu(enc_ports.key->dst)); 39 return -EOPNOTSUPP; 40 } 41 42 return 0; 43 } 44 45 static int mlx5e_tc_tun_parse_udp_ports_vxlan(struct mlx5e_priv *priv, 46 struct mlx5_flow_spec *spec, 47 struct flow_cls_offload *f, 48 void *headers_c, 49 void *headers_v) 50 { 51 int err = 0; 52 53 err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v); 54 if (err) 55 return err; 56 57 return mlx5e_tc_tun_check_udp_dport_vxlan(priv, f); 58 } 59 60 static int mlx5e_tc_tun_init_encap_attr_vxlan(struct net_device *tunnel_dev, 61 struct mlx5e_priv *priv, 62 struct mlx5e_encap_entry *e, 63 struct netlink_ext_ack *extack) 64 { 65 int dst_port = be16_to_cpu(e->tun_info->key.tp_dst); 66 67 e->tunnel = &vxlan_tunnel; 68 69 if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) { 70 NL_SET_ERR_MSG_MOD(extack, 71 "vxlan udp dport was not registered with the HW"); 72 netdev_warn(priv->netdev, 73 "%d isn't an offloaded vxlan udp dport\n", 74 dst_port); 75 return -EOPNOTSUPP; 76 } 77 78 e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN; 79 return 0; 80 } 81 82 static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[], 83 __u8 *ip_proto, 84 struct mlx5e_encap_entry *e) 85 { 86 const struct ip_tunnel_key *tun_key = &e->tun_info->key; 87 __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id); 88 struct udphdr *udp = (struct udphdr *)(buf); 89 struct vxlanhdr *vxh; 90 91 vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 92 *ip_proto = IPPROTO_UDP; 93 94 udp->dest = tun_key->tp_dst; 95 vxh->vx_flags = VXLAN_HF_VNI; 96 vxh->vx_vni = vxlan_vni_field(tun_id); 97 98 return 0; 99 } 100 101 static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv, 102 struct mlx5_flow_spec *spec, 103 struct flow_cls_offload *f, 104 void *headers_c, 105 void *headers_v) 106 { 107 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 108 struct netlink_ext_ack *extack = f->common.extack; 109 struct flow_match_enc_keyid enc_keyid; 110 void *misc_c, *misc_v; 111 112 misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); 113 misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); 114 115 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) 116 return 0; 117 118 flow_rule_match_enc_keyid(rule, &enc_keyid); 119 120 if (!enc_keyid.mask->keyid) 121 return 0; 122 123 /* match on VNI is required */ 124 125 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, 126 ft_field_support.outer_vxlan_vni)) { 127 NL_SET_ERR_MSG_MOD(extack, 128 "Matching on VXLAN VNI is not supported"); 129 netdev_warn(priv->netdev, 130 "Matching on VXLAN VNI is not supported\n"); 131 return -EOPNOTSUPP; 132 } 133 134 MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 135 be32_to_cpu(enc_keyid.mask->keyid)); 136 MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 137 be32_to_cpu(enc_keyid.key->keyid)); 138 139 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS; 140 141 return 0; 142 } 143 144 static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev) 145 { 146 const struct vxlan_dev *vxlan = netdev_priv(mirred_dev); 147 const struct vxlan_rdst *dst = &vxlan->default_dst; 148 149 return dst->remote_ifindex; 150 } 151 152 struct mlx5e_tc_tunnel vxlan_tunnel = { 153 .tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN, 154 .match_level = MLX5_MATCH_L4, 155 .can_offload = mlx5e_tc_tun_can_offload_vxlan, 156 .calc_hlen = mlx5e_tc_tun_calc_hlen_vxlan, 157 .init_encap_attr = mlx5e_tc_tun_init_encap_attr_vxlan, 158 .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_vxlan, 159 .parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_vxlan, 160 .parse_tunnel = mlx5e_tc_tun_parse_vxlan, 161 .encap_info_equal = mlx5e_tc_tun_encap_info_equal_generic, 162 .get_remote_ifindex = mlx5e_tc_tun_get_remote_ifindex, 163 }; 164