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 
can_offload(struct mlx5e_priv * priv)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 
calc_hlen(struct mlx5e_encap_entry * e)13 static int calc_hlen(struct mlx5e_encap_entry *e)
14 {
15 	return sizeof(struct udphdr) + MPLS_HLEN;
16 }
17 
init_encap_attr(struct net_device * tunnel_dev,struct mlx5e_priv * priv,struct mlx5e_encap_entry * e,struct netlink_ext_ack * extack)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 
generate_ip_tun_hdr(char buf[],__u8 * ip_proto,struct mlx5e_encap_entry * r)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 	const struct mlx5e_mpls_info *mpls_info = &r->mpls_info;
34 	struct udphdr *udp = (struct udphdr *)(buf);
35 	struct mpls_shim_hdr *mpls;
36 
37 	mpls = (struct mpls_shim_hdr *)(udp + 1);
38 	*ip_proto = IPPROTO_UDP;
39 
40 	udp->dest = tun_key->tp_dst;
41 	*mpls = mpls_entry_encode(mpls_info->label, mpls_info->ttl, mpls_info->tc, mpls_info->bos);
42 
43 	return 0;
44 }
45 
parse_udp_ports(struct mlx5e_priv * priv,struct mlx5_flow_spec * spec,struct flow_cls_offload * f,void * headers_c,void * headers_v)46 static int parse_udp_ports(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 	return mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
53 }
54 
parse_tunnel(struct mlx5e_priv * priv,struct mlx5_flow_spec * spec,struct flow_cls_offload * f,void * headers_c,void * headers_v)55 static int parse_tunnel(struct mlx5e_priv *priv,
56 			struct mlx5_flow_spec *spec,
57 			struct flow_cls_offload *f,
58 			void *headers_c,
59 			void *headers_v)
60 {
61 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
62 	struct flow_match_mpls match;
63 	void *misc2_c;
64 	void *misc2_v;
65 
66 	if (!MLX5_CAP_ETH(priv->mdev, tunnel_stateless_mpls_over_udp) &&
67 	    !(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_CW_MPLS_UDP))
68 		return -EOPNOTSUPP;
69 
70 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
71 		return -EOPNOTSUPP;
72 
73 	if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS))
74 		return 0;
75 
76 	flow_rule_match_mpls(rule, &match);
77 
78 	/* Only support matching the first LSE */
79 	if (match.mask->used_lses != 1)
80 		return -EOPNOTSUPP;
81 
82 	misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
83 			       misc_parameters_2);
84 	misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
85 			       misc_parameters_2);
86 
87 	MLX5_SET(fte_match_set_misc2, misc2_c,
88 		 outer_first_mpls_over_udp.mpls_label,
89 		 match.mask->ls[0].mpls_label);
90 	MLX5_SET(fte_match_set_misc2, misc2_v,
91 		 outer_first_mpls_over_udp.mpls_label,
92 		 match.key->ls[0].mpls_label);
93 
94 	MLX5_SET(fte_match_set_misc2, misc2_c,
95 		 outer_first_mpls_over_udp.mpls_exp,
96 		 match.mask->ls[0].mpls_tc);
97 	MLX5_SET(fte_match_set_misc2, misc2_v,
98 		 outer_first_mpls_over_udp.mpls_exp, match.key->ls[0].mpls_tc);
99 
100 	MLX5_SET(fte_match_set_misc2, misc2_c,
101 		 outer_first_mpls_over_udp.mpls_s_bos,
102 		 match.mask->ls[0].mpls_bos);
103 	MLX5_SET(fte_match_set_misc2, misc2_v,
104 		 outer_first_mpls_over_udp.mpls_s_bos,
105 		 match.key->ls[0].mpls_bos);
106 
107 	MLX5_SET(fte_match_set_misc2, misc2_c,
108 		 outer_first_mpls_over_udp.mpls_ttl,
109 		 match.mask->ls[0].mpls_ttl);
110 	MLX5_SET(fte_match_set_misc2, misc2_v,
111 		 outer_first_mpls_over_udp.mpls_ttl,
112 		 match.key->ls[0].mpls_ttl);
113 	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
114 
115 	return 0;
116 }
117 
118 struct mlx5e_tc_tunnel mplsoudp_tunnel = {
119 	.tunnel_type          = MLX5E_TC_TUNNEL_TYPE_MPLSOUDP,
120 	.match_level          = MLX5_MATCH_L4,
121 	.can_offload          = can_offload,
122 	.calc_hlen            = calc_hlen,
123 	.init_encap_attr      = init_encap_attr,
124 	.generate_ip_tun_hdr  = generate_ip_tun_hdr,
125 	.parse_udp_ports      = parse_udp_ports,
126 	.parse_tunnel         = parse_tunnel,
127 	.encap_info_equal     = mlx5e_tc_tun_encap_info_equal_generic,
128 };
129