1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2018 Mellanox Technologies. */ 3 4 #include <net/bareudp.h> 5 #include <net/mpls.h> 6 #include "en/tc_tun.h" 7 8 static bool can_offload(struct mlx5e_priv *priv) 9 { 10 return MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_l3_tunnel_to_l2); 11 } 12 13 static int calc_hlen(struct mlx5e_encap_entry *e) 14 { 15 return sizeof(struct udphdr) + MPLS_HLEN; 16 } 17 18 static int init_encap_attr(struct net_device *tunnel_dev, 19 struct mlx5e_priv *priv, 20 struct mlx5e_encap_entry *e, 21 struct netlink_ext_ack *extack) 22 { 23 e->tunnel = &mplsoudp_tunnel; 24 e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 25 return 0; 26 } 27 28 static int generate_ip_tun_hdr(char buf[], 29 __u8 *ip_proto, 30 struct mlx5e_encap_entry *r) 31 { 32 const struct ip_tunnel_key *tun_key = &r->tun_info->key; 33 struct udphdr *udp = (struct udphdr *)(buf); 34 struct mpls_shim_hdr *mpls; 35 u32 tun_id; 36 37 tun_id = be32_to_cpu(tunnel_id_to_key32(tun_key->tun_id)); 38 mpls = (struct mpls_shim_hdr *)(udp + 1); 39 *ip_proto = IPPROTO_UDP; 40 41 udp->dest = tun_key->tp_dst; 42 *mpls = mpls_entry_encode(tun_id, tun_key->ttl, tun_key->tos, true); 43 44 return 0; 45 } 46 47 static int parse_udp_ports(struct mlx5e_priv *priv, 48 struct mlx5_flow_spec *spec, 49 struct flow_cls_offload *f, 50 void *headers_c, 51 void *headers_v) 52 { 53 return mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v); 54 } 55 56 static int parse_tunnel(struct mlx5e_priv *priv, 57 struct mlx5_flow_spec *spec, 58 struct flow_cls_offload *f, 59 void *headers_c, 60 void *headers_v) 61 { 62 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 63 struct flow_match_enc_keyid enc_keyid; 64 struct flow_match_mpls match; 65 void *misc2_c; 66 void *misc2_v; 67 68 misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 69 misc_parameters_2); 70 misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 71 misc_parameters_2); 72 73 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS)) 74 return 0; 75 76 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) 77 return 0; 78 79 flow_rule_match_enc_keyid(rule, &enc_keyid); 80 81 if (!enc_keyid.mask->keyid) 82 return 0; 83 84 if (!MLX5_CAP_ETH(priv->mdev, tunnel_stateless_mpls_over_udp) && 85 !(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_CW_MPLS_UDP)) 86 return -EOPNOTSUPP; 87 88 flow_rule_match_mpls(rule, &match); 89 90 /* Only support matching the first LSE */ 91 if (match.mask->used_lses != 1) 92 return -EOPNOTSUPP; 93 94 MLX5_SET(fte_match_set_misc2, misc2_c, 95 outer_first_mpls_over_udp.mpls_label, 96 match.mask->ls[0].mpls_label); 97 MLX5_SET(fte_match_set_misc2, misc2_v, 98 outer_first_mpls_over_udp.mpls_label, 99 match.key->ls[0].mpls_label); 100 101 MLX5_SET(fte_match_set_misc2, misc2_c, 102 outer_first_mpls_over_udp.mpls_exp, 103 match.mask->ls[0].mpls_tc); 104 MLX5_SET(fte_match_set_misc2, misc2_v, 105 outer_first_mpls_over_udp.mpls_exp, match.key->ls[0].mpls_tc); 106 107 MLX5_SET(fte_match_set_misc2, misc2_c, 108 outer_first_mpls_over_udp.mpls_s_bos, 109 match.mask->ls[0].mpls_bos); 110 MLX5_SET(fte_match_set_misc2, misc2_v, 111 outer_first_mpls_over_udp.mpls_s_bos, 112 match.key->ls[0].mpls_bos); 113 114 MLX5_SET(fte_match_set_misc2, misc2_c, 115 outer_first_mpls_over_udp.mpls_ttl, 116 match.mask->ls[0].mpls_ttl); 117 MLX5_SET(fte_match_set_misc2, misc2_v, 118 outer_first_mpls_over_udp.mpls_ttl, 119 match.key->ls[0].mpls_ttl); 120 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2; 121 122 return 0; 123 } 124 125 struct mlx5e_tc_tunnel mplsoudp_tunnel = { 126 .tunnel_type = MLX5E_TC_TUNNEL_TYPE_MPLSOUDP, 127 .match_level = MLX5_MATCH_L4, 128 .can_offload = can_offload, 129 .calc_hlen = calc_hlen, 130 .init_encap_attr = init_encap_attr, 131 .generate_ip_tun_hdr = generate_ip_tun_hdr, 132 .parse_udp_ports = parse_udp_ports, 133 .parse_tunnel = parse_tunnel, 134 .encap_info_equal = mlx5e_tc_tun_encap_info_equal_generic, 135 }; 136