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 | 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(label: mpls_info->label, ttl: mpls_info->ttl, tc: mpls_info->tc, bos: mpls_info->bos); |
42 | |
43 | return 0; |
44 | } |
45 | |
46 | static int parse_udp_ports(struct mlx5e_priv *priv, |
47 | struct mlx5_flow_spec *spec, |
48 | struct flow_cls_offload *f, |
49 | void *, |
50 | void *) |
51 | { |
52 | return mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v); |
53 | } |
54 | |
55 | static int parse_tunnel(struct mlx5e_priv *priv, |
56 | struct mlx5_flow_spec *spec, |
57 | struct flow_cls_offload *f, |
58 | void *, |
59 | void *) |
60 | { |
61 | struct flow_rule *rule = flow_cls_offload_flow_rule(flow_cmd: 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, key: FLOW_DISSECTOR_KEY_ENC_KEYID)) |
71 | return -EOPNOTSUPP; |
72 | |
73 | if (!flow_rule_match_key(rule, key: FLOW_DISSECTOR_KEY_MPLS)) |
74 | return 0; |
75 | |
76 | flow_rule_match_mpls(rule, out: &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 | |