summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_mplsoudp.c
blob: 60952b33b5688835ddd5bfdddc2a0e30fa56fd5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2018 Mellanox Technologies. */

#include <net/bareudp.h>
#include <net/mpls.h>
#include "en/tc_tun.h"

static bool can_offload(struct mlx5e_priv *priv)
{
	return MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_l3_tunnel_to_l2);
}

static int calc_hlen(struct mlx5e_encap_entry *e)
{
	return sizeof(struct udphdr) + MPLS_HLEN;
}

static int init_encap_attr(struct net_device *tunnel_dev,
			   struct mlx5e_priv *priv,
			   struct mlx5e_encap_entry *e,
			   struct netlink_ext_ack *extack)
{
	e->tunnel = &mplsoudp_tunnel;
	e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
	return 0;
}

static int generate_ip_tun_hdr(char buf[],
			       __u8 *ip_proto,
			       struct mlx5e_encap_entry *r)
{
	const struct ip_tunnel_key *tun_key = &r->tun_info->key;
	struct udphdr *udp = (struct udphdr *)(buf);
	struct mpls_shim_hdr *mpls;
	u32 tun_id;

	tun_id = be32_to_cpu(tunnel_id_to_key32(tun_key->tun_id));
	mpls = (struct mpls_shim_hdr *)(udp + 1);
	*ip_proto = IPPROTO_UDP;

	udp->dest = tun_key->tp_dst;
	*mpls = mpls_entry_encode(tun_id, tun_key->ttl, tun_key->tos, true);

	return 0;
}

static int parse_udp_ports(struct mlx5e_priv *priv,
			   struct mlx5_flow_spec *spec,
			   struct flow_cls_offload *f,
			   void *headers_c,
			   void *headers_v)
{
	return mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
}

static int parse_tunnel(struct mlx5e_priv *priv,
			struct mlx5_flow_spec *spec,
			struct flow_cls_offload *f,
			void *headers_c,
			void *headers_v)
{
	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
	struct flow_match_enc_keyid enc_keyid;
	struct flow_match_mpls match;
	void *misc2_c;
	void *misc2_v;

	misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
			       misc_parameters_2);
	misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
			       misc_parameters_2);

	if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS))
		return 0;

	if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
		return 0;

	flow_rule_match_enc_keyid(rule, &enc_keyid);

	if (!enc_keyid.mask->keyid)
		return 0;

	if (!MLX5_CAP_ETH(priv->mdev, tunnel_stateless_mpls_over_udp) &&
	    !(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_CW_MPLS_UDP))
		return -EOPNOTSUPP;

	flow_rule_match_mpls(rule, &match);

	/* Only support matching the first LSE */
	if (match.mask->used_lses != 1)
		return -EOPNOTSUPP;

	MLX5_SET(fte_match_set_misc2, misc2_c,
		 outer_first_mpls_over_udp.mpls_label,
		 match.mask->ls[0].mpls_label);
	MLX5_SET(fte_match_set_misc2, misc2_v,
		 outer_first_mpls_over_udp.mpls_label,
		 match.key->ls[0].mpls_label);

	MLX5_SET(fte_match_set_misc2, misc2_c,
		 outer_first_mpls_over_udp.mpls_exp,
		 match.mask->ls[0].mpls_tc);
	MLX5_SET(fte_match_set_misc2, misc2_v,
		 outer_first_mpls_over_udp.mpls_exp, match.key->ls[0].mpls_tc);

	MLX5_SET(fte_match_set_misc2, misc2_c,
		 outer_first_mpls_over_udp.mpls_s_bos,
		 match.mask->ls[0].mpls_bos);
	MLX5_SET(fte_match_set_misc2, misc2_v,
		 outer_first_mpls_over_udp.mpls_s_bos,
		 match.key->ls[0].mpls_bos);

	MLX5_SET(fte_match_set_misc2, misc2_c,
		 outer_first_mpls_over_udp.mpls_ttl,
		 match.mask->ls[0].mpls_ttl);
	MLX5_SET(fte_match_set_misc2, misc2_v,
		 outer_first_mpls_over_udp.mpls_ttl,
		 match.key->ls[0].mpls_ttl);
	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;

	return 0;
}

struct mlx5e_tc_tunnel mplsoudp_tunnel = {
	.tunnel_type          = MLX5E_TC_TUNNEL_TYPE_MPLSOUDP,
	.match_level          = MLX5_MATCH_L4,
	.can_offload          = can_offload,
	.calc_hlen            = calc_hlen,
	.init_encap_attr      = init_encap_attr,
	.generate_ip_tun_hdr  = generate_ip_tun_hdr,
	.parse_udp_ports      = parse_udp_ports,
	.parse_tunnel         = parse_tunnel,
	.encap_info_equal     = mlx5e_tc_tun_encap_info_equal_generic,
};