1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* Copyright (c) 2018 Mellanox Technologies. */ |
3 | |
4 | #include <net/gre.h> |
5 | #include "en/tc_tun.h" |
6 | |
7 | static bool mlx5e_tc_tun_can_offload_gretap(struct mlx5e_priv *priv) |
8 | { |
9 | return !!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap); |
10 | } |
11 | |
12 | static int mlx5e_tc_tun_calc_hlen_gretap(struct mlx5e_encap_entry *e) |
13 | { |
14 | return gre_calc_hlen(o_flags: e->tun_info->key.tun_flags); |
15 | } |
16 | |
17 | static int mlx5e_tc_tun_init_encap_attr_gretap(struct net_device *tunnel_dev, |
18 | struct mlx5e_priv *priv, |
19 | struct mlx5e_encap_entry *e, |
20 | struct netlink_ext_ack *extack) |
21 | { |
22 | e->tunnel = &gre_tunnel; |
23 | e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE; |
24 | return 0; |
25 | } |
26 | |
27 | static int (char buf[], |
28 | __u8 *ip_proto, |
29 | struct mlx5e_encap_entry *e) |
30 | { |
31 | const struct ip_tunnel_key *tun_key = &e->tun_info->key; |
32 | struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf); |
33 | __be32 tun_id = tunnel_id_to_key32(tun_id: tun_key->tun_id); |
34 | int hdr_len; |
35 | |
36 | *ip_proto = IPPROTO_GRE; |
37 | |
38 | /* the HW does not calculate GRE csum or sequences */ |
39 | if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ)) |
40 | return -EOPNOTSUPP; |
41 | |
42 | greh->protocol = htons(ETH_P_TEB); |
43 | |
44 | /* GRE key */ |
45 | hdr_len = mlx5e_tc_tun_calc_hlen_gretap(e); |
46 | greh->flags = gre_tnl_flags_to_gre_flags(tflags: tun_key->tun_flags); |
47 | if (tun_key->tun_flags & TUNNEL_KEY) { |
48 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); |
49 | *ptr = tun_id; |
50 | } |
51 | |
52 | return 0; |
53 | } |
54 | |
55 | static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv, |
56 | struct mlx5_flow_spec *spec, |
57 | struct flow_cls_offload *f, |
58 | void *, |
59 | void *) |
60 | { |
61 | void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); |
62 | void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); |
63 | struct flow_rule *rule = flow_cls_offload_flow_rule(flow_cmd: f); |
64 | |
65 | MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol); |
66 | MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE); |
67 | |
68 | /* gre protocol */ |
69 | MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol); |
70 | MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB); |
71 | |
72 | /* gre key */ |
73 | if (flow_rule_match_key(rule, key: FLOW_DISSECTOR_KEY_ENC_KEYID)) { |
74 | struct flow_match_enc_keyid enc_keyid; |
75 | |
76 | flow_rule_match_enc_keyid(rule, out: &enc_keyid); |
77 | MLX5_SET(fte_match_set_misc, misc_c, |
78 | gre_key.key, be32_to_cpu(enc_keyid.mask->keyid)); |
79 | MLX5_SET(fte_match_set_misc, misc_v, |
80 | gre_key.key, be32_to_cpu(enc_keyid.key->keyid)); |
81 | } |
82 | |
83 | spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS; |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | struct mlx5e_tc_tunnel gre_tunnel = { |
89 | .tunnel_type = MLX5E_TC_TUNNEL_TYPE_GRETAP, |
90 | .match_level = MLX5_MATCH_L3, |
91 | .can_offload = mlx5e_tc_tun_can_offload_gretap, |
92 | .calc_hlen = mlx5e_tc_tun_calc_hlen_gretap, |
93 | .init_encap_attr = mlx5e_tc_tun_init_encap_attr_gretap, |
94 | .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_gretap, |
95 | .parse_udp_ports = NULL, |
96 | .parse_tunnel = mlx5e_tc_tun_parse_gretap, |
97 | .encap_info_equal = mlx5e_tc_tun_encap_info_equal_generic, |
98 | }; |
99 | |