summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/sfc/tc.h
blob: 2aba9ca0061858e67b2cf2e6a607b05b19629287 (plain) (blame)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
 * Driver for Solarflare network controllers and boards
 * Copyright 2019 Solarflare Communications Inc.
 * Copyright 2020-2022 Xilinx Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation, incorporated herein by reference.
 */

#ifndef EFX_TC_H
#define EFX_TC_H
#include <net/flow_offload.h>
#include <linux/rhashtable.h>
#include "net_driver.h"
#include "tc_counters.h"

#define IS_ALL_ONES(v)	(!(typeof (v))~(v))

static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr)
{
	return !memchr_inv(addr, 0xff, sizeof(*addr));
}

struct efx_tc_encap_action; /* see tc_encap_actions.h */

struct efx_tc_action_set {
	u16 vlan_push:2;
	u16 vlan_pop:2;
	u16 decap:1;
	u16 deliver:1;
	__be16 vlan_tci[2]; /* TCIs for vlan_push */
	__be16 vlan_proto[2]; /* Ethertypes for vlan_push */
	struct efx_tc_counter_index *count;
	struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */
	struct list_head encap_user; /* entry on encap_md->users list */
	struct efx_tc_action_set_list *user; /* Only populated if encap_md */
	struct list_head count_user; /* entry on counter->users list, if encap */
	u32 dest_mport;
	u32 fw_id; /* index of this entry in firmware actions table */
	struct list_head list;
};

struct efx_tc_match_fields {
	/* L1 */
	u32 ingress_port;
	u8 recirc_id;
	/* L2 (inner when encap) */
	__be16 eth_proto;
	__be16 vlan_tci[2], vlan_proto[2];
	u8 eth_saddr[ETH_ALEN], eth_daddr[ETH_ALEN];
	/* L3 (when IP) */
	u8 ip_proto, ip_tos, ip_ttl;
	__be32 src_ip, dst_ip;
#ifdef CONFIG_IPV6
	struct in6_addr src_ip6, dst_ip6;
#endif
	bool ip_frag, ip_firstfrag;
	/* L4 */
	__be16 l4_sport, l4_dport; /* Ports (UDP, TCP) */
	__be16 tcp_flags;
	/* Encap.  The following are *outer* fields.  Note that there are no
	 * outer eth (L2) fields; this is because TC doesn't have them.
	 */
	__be32 enc_src_ip, enc_dst_ip;
	struct in6_addr enc_src_ip6, enc_dst_ip6;
	u8 enc_ip_tos, enc_ip_ttl;
	__be16 enc_sport, enc_dport;
	__be32 enc_keyid; /* e.g. VNI, VSID */
};

static inline bool efx_tc_match_is_encap(const struct efx_tc_match_fields *mask)
{
	return mask->enc_src_ip || mask->enc_dst_ip ||
	       !ipv6_addr_any(&mask->enc_src_ip6) ||
	       !ipv6_addr_any(&mask->enc_dst_ip6) || mask->enc_ip_tos ||
	       mask->enc_ip_ttl || mask->enc_sport || mask->enc_dport;
}

/**
 * enum efx_tc_em_pseudo_type - &struct efx_tc_encap_match pseudo type
 *
 * These are used to classify "pseudo" encap matches, which don't refer
 * to an entry in hardware but rather indicate that a section of the
 * match space is in use by another Outer Rule.
 *
 * @EFX_TC_EM_DIRECT: real HW entry in Outer Rule table; not a pseudo.
 *	Hardware index in &struct efx_tc_encap_match.fw_id is valid.
 * @EFX_TC_EM_PSEUDO_MASK: registered by an encap match which includes a
 *	match on an optional field (currently ip_tos and/or udp_sport),
 *	to prevent an overlapping encap match _without_ optional fields.
 *	The pseudo encap match may be referenced again by an encap match
 *	with different values for these fields, but all masks must match the
 *	first (stored in our child_* fields).
 */
enum efx_tc_em_pseudo_type {
	EFX_TC_EM_DIRECT,
	EFX_TC_EM_PSEUDO_MASK,
};

struct efx_tc_encap_match {
	__be32 src_ip, dst_ip;
	struct in6_addr src_ip6, dst_ip6;
	__be16 udp_dport;
	__be16 udp_sport, udp_sport_mask;
	u8 ip_tos, ip_tos_mask;
	struct rhash_head linkage;
	enum efx_encap_type tun_type;
	u8 child_ip_tos_mask;
	__be16 child_udp_sport_mask;
	refcount_t ref;
	enum efx_tc_em_pseudo_type type;
	u32 fw_id; /* index of this entry in firmware encap match table */
	struct efx_tc_encap_match *pseudo; /* Referenced pseudo EM if needed */
};

struct efx_tc_match {
	struct efx_tc_match_fields value;
	struct efx_tc_match_fields mask;
	struct efx_tc_encap_match *encap;
};

struct efx_tc_action_set_list {
	struct list_head list;
	u32 fw_id;
};

struct efx_tc_flow_rule {
	unsigned long cookie;
	struct rhash_head linkage;
	struct efx_tc_match match;
	struct efx_tc_action_set_list acts;
	struct efx_tc_action_set_list *fallback; /* what to use when unready? */
	u32 fw_id;
};

enum efx_tc_rule_prios {
	EFX_TC_PRIO_TC, /* Rule inserted by TC */
	EFX_TC_PRIO_DFLT, /* Default switch rule; one of efx_tc_default_rules */
	EFX_TC_PRIO__NUM
};

struct efx_tc_table_field_fmt {
	u16 field_id;
	u16 lbn;
	u16 width;
	u8 masking;
	u8 scheme;
};

struct efx_tc_table_desc {
	u16 type;
	u16 key_width;
	u16 resp_width;
	u16 n_keys;
	u16 n_resps;
	u16 n_prios;
	u8 flags;
	u8 scheme;
	struct efx_tc_table_field_fmt *keys;
	struct efx_tc_table_field_fmt *resps;
};

struct efx_tc_table_ct { /* TABLE_ID_CONNTRACK_TABLE */
	struct efx_tc_table_desc desc;
	bool hooked;
	struct { /* indices of named fields within @desc.keys */
		u8 eth_proto_idx;
		u8 ip_proto_idx;
		u8 src_ip_idx; /* either v4 or v6 */
		u8 dst_ip_idx;
		u8 l4_sport_idx;
		u8 l4_dport_idx;
		u8 zone_idx; /* for TABLE_FIELD_ID_DOMAIN */
	} keys;
	struct { /* indices of named fields within @desc.resps */
		u8 dnat_idx;
		u8 nat_ip_idx;
		u8 l4_natport_idx;
		u8 mark_idx;
		u8 counter_id_idx;
	} resps;
};

/**
 * struct efx_tc_state - control plane data for TC offload
 *
 * @caps: MAE capabilities reported by MCDI
 * @block_list: List of &struct efx_tc_block_binding
 * @mutex: Used to serialise operations on TC hashtables
 * @counter_ht: Hashtable of TC counters (FW IDs and counter values)
 * @counter_id_ht: Hashtable mapping TC counter cookies to counters
 * @encap_ht: Hashtable of TC encap actions
 * @encap_match_ht: Hashtable of TC encap matches
 * @match_action_ht: Hashtable of TC match-action rules
 * @ct_zone_ht: Hashtable of TC conntrack flowtable bindings
 * @ct_ht: Hashtable of TC conntrack flow entries
 * @neigh_ht: Hashtable of neighbour watches (&struct efx_neigh_binder)
 * @meta_ct: MAE table layout for conntrack table
 * @reps_mport_id: MAE port allocated for representor RX
 * @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
 * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
 * @reps_mport_vport_id: vport_id for representor RX filters
 * @flush_counters: counters have been stopped, waiting for drain
 * @flush_gen: final generation count per type array as reported by
 *             MC_CMD_MAE_COUNTERS_STREAM_STOP
 * @seen_gen: most recent generation count per type as seen by efx_tc_rx()
 * @flush_wq: wait queue used by efx_mae_stop_counters() to wait for
 *	MAE counters RXQ to finish draining
 * @dflt: Match-action rules for default switching; at priority
 *	%EFX_TC_PRIO_DFLT.  Named by *ingress* port
 * @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
 * @dflt.wire: rule for traffic ingressing from wire (egresses to PF)
 * @facts: Fallback action-set-lists for unready rules.  Named by *egress* port
 * @facts.pf: action-set-list for unready rules on PF netdev, hence applying to
 *	traffic from wire, and egressing to PF
 * @facts.reps: action-set-list for unready rules on representors, hence
 *	applying to traffic from representees, and egressing to the reps mport
 * @up: have TC datastructures been set up?
 */
struct efx_tc_state {
	struct mae_caps *caps;
	struct list_head block_list;
	struct mutex mutex;
	struct rhashtable counter_ht;
	struct rhashtable counter_id_ht;
	struct rhashtable encap_ht;
	struct rhashtable encap_match_ht;
	struct rhashtable match_action_ht;
	struct rhashtable ct_zone_ht;
	struct rhashtable ct_ht;
	struct rhashtable neigh_ht;
	struct efx_tc_table_ct meta_ct;
	u32 reps_mport_id, reps_mport_vport_id;
	s32 reps_filter_uc, reps_filter_mc;
	bool flush_counters;
	u32 flush_gen[EFX_TC_COUNTER_TYPE_MAX];
	u32 seen_gen[EFX_TC_COUNTER_TYPE_MAX];
	wait_queue_head_t flush_wq;
	struct {
		struct efx_tc_flow_rule pf;
		struct efx_tc_flow_rule wire;
	} dflt;
	struct {
		struct efx_tc_action_set_list pf;
		struct efx_tc_action_set_list reps;
	} facts;
	bool up;
};

struct efx_rep;

enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev);
struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx,
					 struct net_device *dev);
s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv);
int efx_tc_configure_default_rule_rep(struct efx_rep *efv);
void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
				     struct efx_tc_flow_rule *rule);
int efx_tc_flower(struct efx_nic *efx, struct net_device *net_dev,
		  struct flow_cls_offload *tc, struct efx_rep *efv);

int efx_tc_insert_rep_filters(struct efx_nic *efx);
void efx_tc_remove_rep_filters(struct efx_nic *efx);

int efx_init_tc(struct efx_nic *efx);
void efx_fini_tc(struct efx_nic *efx);

int efx_init_struct_tc(struct efx_nic *efx);
void efx_fini_struct_tc(struct efx_nic *efx);

#endif /* EFX_TC_H */