Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / tc_tun_mplsoudp.c
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 };