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
8static bool can_offload(struct mlx5e_priv *priv)
9{
10 return MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_l3_tunnel_to_l2);
11}
12
13static int calc_hlen(struct mlx5e_encap_entry *e)
14{
15 return sizeof(struct udphdr) + MPLS_HLEN;
16}
17
18static 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
28static 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
46static 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
55static 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(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
118struct 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

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_mplsoudp.c