xref: /aosp_15_r20/external/ethtool/rxclass.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
3  */
4 #include <stdio.h>
5 #include <stdint.h>
6 #include <stddef.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10 
11 #include <linux/sockios.h>
12 #include <arpa/inet.h>
13 #include "internal.h"
14 
invert_flow_mask(struct ethtool_rx_flow_spec * fsp)15 static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
16 {
17 	size_t i;
18 
19 	for (i = 0; i < sizeof(fsp->m_u); i++)
20 		fsp->m_u.hdata[i] ^= 0xFF;
21 }
22 
rxclass_print_ipv4_rule(__be32 sip,__be32 sipm,__be32 dip,__be32 dipm,u8 tos,u8 tosm)23 static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
24 				    __be32 dipm, u8 tos, u8 tosm)
25 {
26 	char sip_str[INET_ADDRSTRLEN];
27 	char sipm_str[INET_ADDRSTRLEN];
28 	char dip_str[INET_ADDRSTRLEN];
29 	char dipm_str[INET_ADDRSTRLEN];
30 
31 	fprintf(stdout,
32 		"\tSrc IP addr: %s mask: %s\n"
33 		"\tDest IP addr: %s mask: %s\n"
34 		"\tTOS: 0x%x mask: 0x%x\n",
35 		inet_ntop(AF_INET, &sip, sip_str, INET_ADDRSTRLEN),
36 		inet_ntop(AF_INET, &sipm, sipm_str, INET_ADDRSTRLEN),
37 		inet_ntop(AF_INET, &dip, dip_str, INET_ADDRSTRLEN),
38 		inet_ntop(AF_INET, &dipm, dipm_str, INET_ADDRSTRLEN),
39 		tos, tosm);
40 }
41 
rxclass_print_ipv6_rule(__be32 * sip,__be32 * sipm,__be32 * dip,__be32 * dipm,u8 tclass,u8 tclassm)42 static void rxclass_print_ipv6_rule(__be32 *sip, __be32 *sipm, __be32 *dip,
43 				    __be32 *dipm, u8 tclass, u8 tclassm)
44 {
45 	char sip_str[INET6_ADDRSTRLEN];
46 	char sipm_str[INET6_ADDRSTRLEN];
47 	char dip_str[INET6_ADDRSTRLEN];
48 	char dipm_str[INET6_ADDRSTRLEN];
49 
50 	fprintf(stdout,
51 		"\tSrc IP addr: %s mask: %s\n"
52 		"\tDest IP addr: %s mask: %s\n"
53 		"\tTraffic Class: 0x%x mask: 0x%x\n",
54 		inet_ntop(AF_INET6, sip, sip_str, INET6_ADDRSTRLEN),
55 		inet_ntop(AF_INET6, sipm, sipm_str, INET6_ADDRSTRLEN),
56 		inet_ntop(AF_INET6, dip, dip_str, INET6_ADDRSTRLEN),
57 		inet_ntop(AF_INET6, dipm, dipm_str, INET6_ADDRSTRLEN),
58 		tclass, tclassm);
59 }
60 
rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec * fsp)61 static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
62 {
63 	if (fsp->flow_type & FLOW_EXT) {
64 		u64 data, datam;
65 		__u16 etype, etypem, tci, tcim;
66 		etype = ntohs(fsp->h_ext.vlan_etype);
67 		etypem = ntohs(~fsp->m_ext.vlan_etype);
68 		tci = ntohs(fsp->h_ext.vlan_tci);
69 		tcim = ntohs(~fsp->m_ext.vlan_tci);
70 		data = (u64)ntohl(fsp->h_ext.data[0]) << 32;
71 		data |= (u64)ntohl(fsp->h_ext.data[1]);
72 		datam = (u64)ntohl(~fsp->m_ext.data[0]) << 32;
73 		datam |= (u64)ntohl(~fsp->m_ext.data[1]);
74 
75 		fprintf(stdout,
76 			"\tVLAN EtherType: 0x%x mask: 0x%x\n"
77 			"\tVLAN: 0x%x mask: 0x%x\n"
78 			"\tUser-defined: 0x%llx mask: 0x%llx\n",
79 			etype, etypem, tci, tcim, data, datam);
80 	}
81 
82 	if (fsp->flow_type & FLOW_MAC_EXT) {
83 		unsigned char *dmac, *dmacm;
84 
85 		dmac = fsp->h_ext.h_dest;
86 		dmacm = fsp->m_ext.h_dest;
87 
88 		fprintf(stdout,
89 			"\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
90 			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n",
91 			dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
92 			dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
93 			dmacm[4], dmacm[5]);
94 	}
95 }
96 
rxclass_print_nfc_rule(struct ethtool_rx_flow_spec * fsp,__u32 rss_context)97 static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp,
98 				   __u32 rss_context)
99 {
100 	unsigned char	*smac, *smacm, *dmac, *dmacm;
101 	__u32		flow_type;
102 
103 	fprintf(stdout,	"Filter: %d\n", fsp->location);
104 
105 	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
106 
107 	invert_flow_mask(fsp);
108 
109 	switch (flow_type) {
110 	case TCP_V4_FLOW:
111 	case UDP_V4_FLOW:
112 	case SCTP_V4_FLOW:
113 		if (flow_type == TCP_V4_FLOW)
114 			fprintf(stdout, "\tRule Type: TCP over IPv4\n");
115 		else if (flow_type == UDP_V4_FLOW)
116 			fprintf(stdout, "\tRule Type: UDP over IPv4\n");
117 		else
118 			fprintf(stdout, "\tRule Type: SCTP over IPv4\n");
119 		rxclass_print_ipv4_rule(fsp->h_u.tcp_ip4_spec.ip4src,
120 				     fsp->m_u.tcp_ip4_spec.ip4src,
121 				     fsp->h_u.tcp_ip4_spec.ip4dst,
122 				     fsp->m_u.tcp_ip4_spec.ip4dst,
123 				     fsp->h_u.tcp_ip4_spec.tos,
124 				     fsp->m_u.tcp_ip4_spec.tos);
125 		fprintf(stdout,
126 			"\tSrc port: %d mask: 0x%x\n"
127 			"\tDest port: %d mask: 0x%x\n",
128 			ntohs(fsp->h_u.tcp_ip4_spec.psrc),
129 			ntohs(fsp->m_u.tcp_ip4_spec.psrc),
130 			ntohs(fsp->h_u.tcp_ip4_spec.pdst),
131 			ntohs(fsp->m_u.tcp_ip4_spec.pdst));
132 		break;
133 	case AH_V4_FLOW:
134 	case ESP_V4_FLOW:
135 		if (flow_type == AH_V4_FLOW)
136 			fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
137 		else
138 			fprintf(stdout, "\tRule Type: IPSEC ESP over IPv4\n");
139 		rxclass_print_ipv4_rule(fsp->h_u.ah_ip4_spec.ip4src,
140 				     fsp->m_u.ah_ip4_spec.ip4src,
141 				     fsp->h_u.ah_ip4_spec.ip4dst,
142 				     fsp->m_u.ah_ip4_spec.ip4dst,
143 				     fsp->h_u.ah_ip4_spec.tos,
144 				     fsp->m_u.ah_ip4_spec.tos);
145 		fprintf(stdout,
146 			"\tSPI: %d mask: 0x%x\n",
147 			ntohl(fsp->h_u.esp_ip4_spec.spi),
148 			ntohl(fsp->m_u.esp_ip4_spec.spi));
149 		break;
150 	case IPV4_USER_FLOW:
151 		fprintf(stdout, "\tRule Type: Raw IPv4\n");
152 		rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
153 				     fsp->m_u.usr_ip4_spec.ip4src,
154 				     fsp->h_u.usr_ip4_spec.ip4dst,
155 				     fsp->m_u.usr_ip4_spec.ip4dst,
156 				     fsp->h_u.usr_ip4_spec.tos,
157 				     fsp->m_u.usr_ip4_spec.tos);
158 		fprintf(stdout,
159 			"\tProtocol: %d mask: 0x%x\n"
160 			"\tL4 bytes: 0x%x mask: 0x%x\n",
161 			fsp->h_u.usr_ip4_spec.proto,
162 			fsp->m_u.usr_ip4_spec.proto,
163 			ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
164 			ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
165 		break;
166 	case TCP_V6_FLOW:
167 	case UDP_V6_FLOW:
168 	case SCTP_V6_FLOW:
169 		if (flow_type == TCP_V6_FLOW)
170 			fprintf(stdout, "\tRule Type: TCP over IPv6\n");
171 		else if (flow_type == UDP_V6_FLOW)
172 			fprintf(stdout, "\tRule Type: UDP over IPv6\n");
173 		else
174 			fprintf(stdout, "\tRule Type: SCTP over IPv6\n");
175 		rxclass_print_ipv6_rule(fsp->h_u.tcp_ip6_spec.ip6src,
176 				     fsp->m_u.tcp_ip6_spec.ip6src,
177 				     fsp->h_u.tcp_ip6_spec.ip6dst,
178 				     fsp->m_u.tcp_ip6_spec.ip6dst,
179 				     fsp->h_u.tcp_ip6_spec.tclass,
180 				     fsp->m_u.tcp_ip6_spec.tclass);
181 		fprintf(stdout,
182 			"\tSrc port: %d mask: 0x%x\n"
183 			"\tDest port: %d mask: 0x%x\n",
184 			ntohs(fsp->h_u.tcp_ip6_spec.psrc),
185 			ntohs(fsp->m_u.tcp_ip6_spec.psrc),
186 			ntohs(fsp->h_u.tcp_ip6_spec.pdst),
187 			ntohs(fsp->m_u.tcp_ip6_spec.pdst));
188 		break;
189 	case AH_V6_FLOW:
190 	case ESP_V6_FLOW:
191 		if (flow_type == AH_V6_FLOW)
192 			fprintf(stdout, "\tRule Type: IPSEC AH over IPv6\n");
193 		else
194 			fprintf(stdout, "\tRule Type: IPSEC ESP over IPv6\n");
195 		rxclass_print_ipv6_rule(fsp->h_u.ah_ip6_spec.ip6src,
196 				     fsp->m_u.ah_ip6_spec.ip6src,
197 				     fsp->h_u.ah_ip6_spec.ip6dst,
198 				     fsp->m_u.ah_ip6_spec.ip6dst,
199 				     fsp->h_u.ah_ip6_spec.tclass,
200 				     fsp->m_u.ah_ip6_spec.tclass);
201 		fprintf(stdout,
202 			"\tSPI: %d mask: 0x%x\n",
203 			ntohl(fsp->h_u.esp_ip6_spec.spi),
204 			ntohl(fsp->m_u.esp_ip6_spec.spi));
205 		break;
206 	case IPV6_USER_FLOW:
207 		fprintf(stdout, "\tRule Type: Raw IPv6\n");
208 		rxclass_print_ipv6_rule(fsp->h_u.usr_ip6_spec.ip6src,
209 				     fsp->m_u.usr_ip6_spec.ip6src,
210 				     fsp->h_u.usr_ip6_spec.ip6dst,
211 				     fsp->m_u.usr_ip6_spec.ip6dst,
212 				     fsp->h_u.usr_ip6_spec.tclass,
213 				     fsp->m_u.usr_ip6_spec.tclass);
214 		fprintf(stdout,
215 			"\tProtocol: %d mask: 0x%x\n"
216 			"\tL4 bytes: 0x%x mask: 0x%x\n",
217 			fsp->h_u.usr_ip6_spec.l4_proto,
218 			fsp->m_u.usr_ip6_spec.l4_proto,
219 			ntohl(fsp->h_u.usr_ip6_spec.l4_4_bytes),
220 			ntohl(fsp->m_u.usr_ip6_spec.l4_4_bytes));
221 		break;
222 	case ETHER_FLOW:
223 		dmac = fsp->h_u.ether_spec.h_dest;
224 		dmacm = fsp->m_u.ether_spec.h_dest;
225 		smac = fsp->h_u.ether_spec.h_source;
226 		smacm = fsp->m_u.ether_spec.h_source;
227 
228 		fprintf(stdout,
229 			"\tFlow Type: Raw Ethernet\n"
230 			"\tSrc MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
231 			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
232 			"\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
233 			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
234 			"\tEthertype: 0x%X mask: 0x%X\n",
235 			smac[0], smac[1], smac[2], smac[3], smac[4], smac[5],
236 			smacm[0], smacm[1], smacm[2], smacm[3], smacm[4],
237 			smacm[5], dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
238 			dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
239 			dmacm[4], dmacm[5],
240 			ntohs(fsp->h_u.ether_spec.h_proto),
241 			ntohs(fsp->m_u.ether_spec.h_proto));
242 		break;
243 	default:
244 		fprintf(stdout,
245 			"\tUnknown Flow type: %d\n", flow_type);
246 		break;
247 	}
248 
249 	rxclass_print_nfc_spec_ext(fsp);
250 
251 	if (fsp->flow_type & FLOW_RSS)
252 		fprintf(stdout, "\tRSS Context ID: %u\n", rss_context);
253 
254 	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
255 		fprintf(stdout, "\tAction: Drop\n");
256 	} else if (fsp->ring_cookie == RX_CLS_FLOW_WAKE) {
257 		fprintf(stdout, "\tAction: Wake-on-LAN\n");
258 	} else {
259 		u64 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
260 		u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
261 
262 		/* A value of zero indicates that this rule targeted the main
263 		 * function. A positive value indicates which virtual function
264 		 * was targeted, so we'll subtract 1 in order to show the
265 		 * correct VF index
266 		 */
267 		if (vf)
268 			fprintf(stdout, "\tAction: Direct to VF %llu queue %llu\n",
269 				vf - 1, queue);
270 		else
271 			fprintf(stdout, "\tAction: Direct to queue %llu\n",
272 				queue);
273 	}
274 
275 	fprintf(stdout, "\n");
276 }
277 
rxclass_print_rule(struct ethtool_rx_flow_spec * fsp,__u32 rss_context)278 static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp,
279 			       __u32 rss_context)
280 {
281 	/* print the rule in this location */
282 	switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
283 	case TCP_V4_FLOW:
284 	case UDP_V4_FLOW:
285 	case SCTP_V4_FLOW:
286 	case AH_V4_FLOW:
287 	case ESP_V4_FLOW:
288 	case TCP_V6_FLOW:
289 	case UDP_V6_FLOW:
290 	case SCTP_V6_FLOW:
291 	case AH_V6_FLOW:
292 	case ESP_V6_FLOW:
293 	case IPV6_USER_FLOW:
294 	case ETHER_FLOW:
295 		rxclass_print_nfc_rule(fsp, rss_context);
296 		break;
297 	case IPV4_USER_FLOW:
298 		if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
299 			rxclass_print_nfc_rule(fsp, rss_context);
300 		else /* IPv6 uses IPV6_USER_FLOW */
301 			fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
302 		break;
303 	default:
304 		fprintf(stderr, "rxclass: Unknown flow type\n");
305 		break;
306 	}
307 }
308 
rxclass_get_dev_info(struct cmd_context * ctx,__u32 * count,int * driver_select)309 static int rxclass_get_dev_info(struct cmd_context *ctx, __u32 *count,
310 				int *driver_select)
311 {
312 	struct ethtool_rxnfc nfccmd;
313 	int err;
314 
315 	nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
316 	nfccmd.data = 0;
317 	err = send_ioctl(ctx, &nfccmd);
318 	*count = nfccmd.rule_cnt;
319 	if (driver_select)
320 		*driver_select = !!(nfccmd.data & RX_CLS_LOC_SPECIAL);
321 	if (err < 0)
322 		perror("rxclass: Cannot get RX class rule count");
323 
324 	return err;
325 }
326 
rxclass_rule_get(struct cmd_context * ctx,__u32 loc)327 int rxclass_rule_get(struct cmd_context *ctx, __u32 loc)
328 {
329 	struct ethtool_rxnfc nfccmd;
330 	int err;
331 
332 	/* fetch rule from netdev */
333 	nfccmd.cmd = ETHTOOL_GRXCLSRULE;
334 	memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
335 	nfccmd.fs.location = loc;
336 	err = send_ioctl(ctx, &nfccmd);
337 	if (err < 0) {
338 		perror("rxclass: Cannot get RX class rule");
339 		return err;
340 	}
341 
342 	/* display rule */
343 	rxclass_print_rule(&nfccmd.fs, (__u32)nfccmd.rss_context);
344 	return err;
345 }
346 
rxclass_rule_getall(struct cmd_context * ctx)347 int rxclass_rule_getall(struct cmd_context *ctx)
348 {
349 	struct ethtool_rxnfc *nfccmd;
350 	__u32 *rule_locs;
351 	unsigned int i;
352 	__u32 count;
353 	int err;
354 
355 	/* determine rule count */
356 	err = rxclass_get_dev_info(ctx, &count, NULL);
357 	if (err < 0)
358 		return err;
359 
360 	fprintf(stdout, "Total %d rules\n\n", count);
361 
362 	/* alloc memory for request of location list */
363 	nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
364 	if (!nfccmd) {
365 		perror("rxclass: Cannot allocate memory for"
366 		       " RX class rule locations");
367 		return -ENOMEM;
368 	}
369 
370 	/* request location list */
371 	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
372 	nfccmd->rule_cnt = count;
373 	err = send_ioctl(ctx, nfccmd);
374 	if (err < 0) {
375 		perror("rxclass: Cannot get RX class rules");
376 		free(nfccmd);
377 		return err;
378 	}
379 
380 	/* write locations to bitmap */
381 	rule_locs = nfccmd->rule_locs;
382 	for (i = 0; i < count; i++) {
383 		err = rxclass_rule_get(ctx, rule_locs[i]);
384 		if (err < 0)
385 			break;
386 	}
387 
388 	/* free memory and set flag to avoid reinit */
389 	free(nfccmd);
390 
391 	return err;
392 }
393 
394 /*
395  * This is a simple rule manager implementation for ordering rx flow
396  * classification rules based on newest rules being first in the list.
397  * The assumption is that this rule manager is the only one adding rules to
398  * the device's hardware classifier.
399  */
400 
401 struct rmgr_ctrl {
402 	/* flag for device/driver that can select locations itself */
403 	int			driver_select;
404 	/* slot contains a bitmap indicating which filters are valid */
405 	unsigned long		*slot;
406 	__u32			n_rules;
407 	__u32			size;
408 };
409 
rmgr_ins(struct rmgr_ctrl * rmgr,__u32 loc)410 static int rmgr_ins(struct rmgr_ctrl *rmgr, __u32 loc)
411 {
412 	/* verify location is in rule manager range */
413 	if (loc >= rmgr->size) {
414 		fprintf(stderr, "rmgr: Location out of range\n");
415 		return -1;
416 	}
417 
418 	/* set bit for the rule */
419 	set_bit(loc, rmgr->slot);
420 
421 	return 0;
422 }
423 
rmgr_find_empty_slot(struct rmgr_ctrl * rmgr,struct ethtool_rx_flow_spec * fsp)424 static int rmgr_find_empty_slot(struct rmgr_ctrl *rmgr,
425 				struct ethtool_rx_flow_spec *fsp)
426 {
427 	__u32 loc;
428 	__u32 slot_num;
429 
430 	/* leave this to the driver if possible */
431 	if (rmgr->driver_select)
432 		return 0;
433 
434 	/* start at the end of the list since it is lowest priority */
435 	loc = rmgr->size - 1;
436 
437 	/* locate the first slot a rule can be placed in */
438 	slot_num = loc / BITS_PER_LONG;
439 
440 	/*
441 	 * Avoid testing individual bits by inverting the word and checking
442 	 * to see if any bits are left set, if so there are empty spots.  By
443 	 * moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
444 	 * in the previous word.
445 	 *
446 	 * If loc rolls over it should be greater than or equal to rmgr->size
447 	 * and as such we know we have reached the end of the list.
448 	 */
449 	if (!~(rmgr->slot[slot_num] | (~1UL << loc % BITS_PER_LONG))) {
450 		loc -= 1 + (loc % BITS_PER_LONG);
451 		slot_num--;
452 	}
453 
454 	/*
455 	 * Now that we are aligned with the last bit in each long we can just
456 	 * go though and eliminate all the longs with no free bits
457 	 */
458 	while (loc < rmgr->size && !~(rmgr->slot[slot_num])) {
459 		loc -= BITS_PER_LONG;
460 		slot_num--;
461 	}
462 
463 	/*
464 	 * If we still are inside the range, test individual bits as one is
465 	 * likely available for our use.
466 	 */
467 	while (loc < rmgr->size && test_bit(loc, rmgr->slot))
468 		loc--;
469 
470 	/* location found, insert rule */
471 	if (loc < rmgr->size) {
472 		fsp->location = loc;
473 		return rmgr_ins(rmgr, loc);
474 	}
475 
476 	/* No space to add this rule */
477 	fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
478 
479 	return -1;
480 }
481 
rmgr_init(struct cmd_context * ctx,struct rmgr_ctrl * rmgr)482 static int rmgr_init(struct cmd_context *ctx, struct rmgr_ctrl *rmgr)
483 {
484 	struct ethtool_rxnfc *nfccmd;
485 	__u32 *rule_locs;
486 	unsigned int i;
487 	int err;
488 
489 	/* clear rule manager settings */
490 	memset(rmgr, 0, sizeof(*rmgr));
491 
492 	/* request device/driver information */
493 	err = rxclass_get_dev_info(ctx, &rmgr->n_rules, &rmgr->driver_select);
494 	if (err < 0)
495 		return err;
496 
497 	/* do not get the table if the device/driver can select locations */
498 	if (rmgr->driver_select)
499 		return 0;
500 
501 	/* alloc memory for request of location list */
502 	nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr->n_rules * sizeof(__u32)));
503 	if (!nfccmd) {
504 		perror("rmgr: Cannot allocate memory for"
505 		       " RX class rule locations");
506 		return -1;
507 	}
508 
509 	/* request location list */
510 	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
511 	nfccmd->rule_cnt = rmgr->n_rules;
512 	err = send_ioctl(ctx, nfccmd);
513 	if (err < 0) {
514 		perror("rmgr: Cannot get RX class rules");
515 		free(nfccmd);
516 		return err;
517 	}
518 
519 	/* make certain the table size is valid */
520 	rmgr->size = nfccmd->data;
521 	if (rmgr->size == 0 || rmgr->size < rmgr->n_rules) {
522 		perror("rmgr: Invalid RX class rules table size");
523 		return -1;
524 	}
525 
526 	/* initialize bitmap for storage of valid locations */
527 	rmgr->slot = calloc(1, BITS_TO_LONGS(rmgr->size) * sizeof(long));
528 	if (!rmgr->slot) {
529 		perror("rmgr: Cannot allocate memory for RX class rules");
530 		return -1;
531 	}
532 
533 	/* write locations to bitmap */
534 	rule_locs = nfccmd->rule_locs;
535 	for (i = 0; i < rmgr->n_rules; i++) {
536 		err = rmgr_ins(rmgr, rule_locs[i]);
537 		if (err < 0)
538 			break;
539 	}
540 
541 	free(nfccmd);
542 
543 	return err;
544 }
545 
rmgr_cleanup(struct rmgr_ctrl * rmgr)546 static void rmgr_cleanup(struct rmgr_ctrl *rmgr)
547 {
548 	free(rmgr->slot);
549 	rmgr->slot = NULL;
550 	rmgr->size = 0;
551 }
552 
rmgr_set_location(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp)553 static int rmgr_set_location(struct cmd_context *ctx,
554 			     struct ethtool_rx_flow_spec *fsp)
555 {
556 	struct rmgr_ctrl rmgr;
557 	int err;
558 
559 	/* init table of available rules */
560 	err = rmgr_init(ctx, &rmgr);
561 	if (err < 0)
562 		goto out;
563 
564 	/* verify rule location */
565 	err = rmgr_find_empty_slot(&rmgr, fsp);
566 
567 out:
568 	/* cleanup table and free resources */
569 	rmgr_cleanup(&rmgr);
570 
571 	return err;
572 }
573 
rxclass_rule_ins(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp,__u32 rss_context)574 int rxclass_rule_ins(struct cmd_context *ctx,
575 		     struct ethtool_rx_flow_spec *fsp, __u32 rss_context)
576 {
577 	struct ethtool_rxnfc nfccmd;
578 	__u32 loc = fsp->location;
579 	int err;
580 
581 	/*
582 	 * if location is unspecified and driver cannot select locations, pull
583 	 * rules from device and allocate a free rule for our use
584 	 */
585 	if (loc & RX_CLS_LOC_SPECIAL) {
586 		err = rmgr_set_location(ctx, fsp);
587 		if (err < 0)
588 			return err;
589 	}
590 
591 	/* notify netdev of new rule */
592 	nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
593 	nfccmd.rss_context = rss_context;
594 	nfccmd.fs = *fsp;
595 	err = send_ioctl(ctx, &nfccmd);
596 	if (err < 0)
597 		perror("rmgr: Cannot insert RX class rule");
598 	else if (loc & RX_CLS_LOC_SPECIAL)
599 		printf("Added rule with ID %d\n", nfccmd.fs.location);
600 
601 	return err;
602 }
603 
rxclass_rule_del(struct cmd_context * ctx,__u32 loc)604 int rxclass_rule_del(struct cmd_context *ctx, __u32 loc)
605 {
606 	struct ethtool_rxnfc nfccmd;
607 	int err;
608 
609 	/* notify netdev of rule removal */
610 	nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
611 	nfccmd.fs.location = loc;
612 	err = send_ioctl(ctx, &nfccmd);
613 	if (err < 0)
614 		perror("rmgr: Cannot delete RX class rule");
615 
616 	return err;
617 }
618 
619 typedef enum {
620 	OPT_NONE = 0,
621 	OPT_S32,
622 	OPT_U8,
623 	OPT_U16,
624 	OPT_U32,
625 	OPT_U64,
626 	OPT_RING_VF,
627 	OPT_RING_QUEUE,
628 	OPT_BE16,
629 	OPT_BE32,
630 	OPT_BE64,
631 	OPT_IP4,
632 	OPT_IP6,
633 	OPT_MAC,
634 } rule_opt_type_t;
635 
636 #define NFC_FLAG_RING		0x0001
637 #define NFC_FLAG_LOC		0x0002
638 #define NFC_FLAG_SADDR		0x0004
639 #define NFC_FLAG_DADDR		0x0008
640 #define NFC_FLAG_SPORT		0x0010
641 #define NFC_FLAG_DPORT		0x0020
642 #define NFC_FLAG_SPI		0x0030
643 #define NFC_FLAG_TOS		0x0040
644 #define NFC_FLAG_PROTO		0x0080
645 #define NTUPLE_FLAG_VLAN	0x0100
646 #define NTUPLE_FLAG_UDEF	0x0200
647 #define NTUPLE_FLAG_VETH	0x0400
648 #define NFC_FLAG_MAC_ADDR	0x0800
649 #define NFC_FLAG_RING_VF	0x1000
650 #define NFC_FLAG_RING_QUEUE	0x2000
651 
652 struct rule_opts {
653 	const char	*name;
654 	rule_opt_type_t	type;
655 	u32		flag;
656 	int		offset;
657 	int		moffset;
658 };
659 
660 static const struct rule_opts rule_nfc_tcp_ip4[] = {
661 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
662 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
663 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
664 	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
665 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4dst),
666 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4dst) },
667 	{ "tos", OPT_U8, NFC_FLAG_TOS,
668 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.tos),
669 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.tos) },
670 	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
671 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.psrc),
672 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.psrc) },
673 	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
674 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.pdst),
675 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.pdst) },
676 	{ "action", OPT_U64, NFC_FLAG_RING,
677 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
678 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
679 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
680 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
681 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
682 	{ "loc", OPT_U32, NFC_FLAG_LOC,
683 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
684 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
685 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
686 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
687 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
688 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
689 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
690 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
691 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
692 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
693 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
694 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
695 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
696 };
697 
698 static const struct rule_opts rule_nfc_esp_ip4[] = {
699 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
700 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
701 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
702 	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
703 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4dst),
704 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4dst) },
705 	{ "tos", OPT_U8, NFC_FLAG_TOS,
706 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.tos),
707 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.tos) },
708 	{ "spi", OPT_BE32, NFC_FLAG_SPI,
709 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.spi),
710 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.spi) },
711 	{ "action", OPT_U64, NFC_FLAG_RING,
712 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
713 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
714 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
715 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
716 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
717 	{ "loc", OPT_U32, NFC_FLAG_LOC,
718 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
719 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
720 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
721 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
722 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
723 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
724 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
725 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
726 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
727 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
728 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
729 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
730 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
731 };
732 
733 static const struct rule_opts rule_nfc_usr_ip4[] = {
734 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
735 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
736 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
737 	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
738 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4dst),
739 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4dst) },
740 	{ "tos", OPT_U8, NFC_FLAG_TOS,
741 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.tos),
742 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.tos) },
743 	{ "l4proto", OPT_U8, NFC_FLAG_PROTO,
744 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.proto),
745 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.proto) },
746 	{ "l4data", OPT_BE32, NFC_FLAG_SPI,
747 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
748 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
749 	{ "spi", OPT_BE32, NFC_FLAG_SPI,
750 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
751 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
752 	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
753 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
754 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
755 	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
756 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes) + 2,
757 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) + 2 },
758 	{ "action", OPT_U64, NFC_FLAG_RING,
759 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
760 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
761 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
762 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
763 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
764 	{ "loc", OPT_U32, NFC_FLAG_LOC,
765 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
766 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
767 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
768 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
769 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
770 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
771 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
772 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
773 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
774 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
775 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
776 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
777 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
778 };
779 
780 static const struct rule_opts rule_nfc_tcp_ip6[] = {
781 	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
782 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6src),
783 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6src) },
784 	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
785 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6dst),
786 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6dst) },
787 	{ "tclass", OPT_U8, NFC_FLAG_TOS,
788 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.tclass),
789 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.tclass) },
790 	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
791 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.psrc),
792 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.psrc) },
793 	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
794 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.pdst),
795 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.pdst) },
796 	{ "action", OPT_U64, NFC_FLAG_RING,
797 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
798 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
799 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
800 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
801 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
802 	{ "loc", OPT_U32, NFC_FLAG_LOC,
803 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
804 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
805 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
806 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
807 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
808 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
809 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
810 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
811 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
812 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
813 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
814 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
815 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
816 };
817 
818 static const struct rule_opts rule_nfc_esp_ip6[] = {
819 	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
820 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6src),
821 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6src) },
822 	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
823 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6dst),
824 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6dst) },
825 	{ "tclass", OPT_U8, NFC_FLAG_TOS,
826 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.tclass),
827 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.tclass) },
828 	{ "spi", OPT_BE32, NFC_FLAG_SPI,
829 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.spi),
830 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.spi) },
831 	{ "action", OPT_U64, NFC_FLAG_RING,
832 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
833 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
834 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
835 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
836 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
837 	{ "loc", OPT_U32, NFC_FLAG_LOC,
838 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
839 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
840 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
841 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
842 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
843 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
844 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
845 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
846 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
847 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
848 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
849 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
850 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
851 };
852 
853 static const struct rule_opts rule_nfc_usr_ip6[] = {
854 	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
855 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6src),
856 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6src) },
857 	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
858 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6dst),
859 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6dst) },
860 	{ "tclass", OPT_U8, NFC_FLAG_TOS,
861 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.tclass),
862 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.tclass) },
863 	{ "l4proto", OPT_U8, NFC_FLAG_PROTO,
864 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_proto),
865 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_proto) },
866 	{ "l4data", OPT_BE32, NFC_FLAG_SPI,
867 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
868 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
869 	{ "spi", OPT_BE32, NFC_FLAG_SPI,
870 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
871 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
872 	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
873 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
874 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
875 	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
876 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes) + 2,
877 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) + 2 },
878 	{ "action", OPT_U64, NFC_FLAG_RING,
879 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
880 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
881 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
882 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
883 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
884 	{ "loc", OPT_U32, NFC_FLAG_LOC,
885 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
886 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
887 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
888 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
889 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
890 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
891 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
892 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
893 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
894 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
895 	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
896 	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
897 	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
898 };
899 
900 static const struct rule_opts rule_nfc_ether[] = {
901 	{ "src", OPT_MAC, NFC_FLAG_SADDR,
902 	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
903 	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
904 	{ "dst", OPT_MAC, NFC_FLAG_DADDR,
905 	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
906 	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
907 	{ "proto", OPT_BE16, NFC_FLAG_PROTO,
908 	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_proto),
909 	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_proto) },
910 	{ "action", OPT_U64, NFC_FLAG_RING,
911 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
912 	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
913 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
914 	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
915 	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
916 	{ "loc", OPT_U32, NFC_FLAG_LOC,
917 	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
918 	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
919 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
920 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
921 	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
922 	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
923 	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
924 	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
925 	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
926 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
927 };
928 
rxclass_get_long(char * str,long long * val,int size)929 static int rxclass_get_long(char *str, long long *val, int size)
930 {
931 	long long max = ~0ULL >> (65 - size);
932 	char *endp;
933 
934 	errno = 0;
935 
936 	*val = strtoll(str, &endp, 0);
937 
938 	if (*endp || errno || (*val > max) || (*val < ~max))
939 		return -1;
940 
941 	return 0;
942 }
943 
rxclass_get_ulong(char * str,unsigned long long * val,int size)944 static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
945 {
946 	unsigned long long max = ~0ULL >> (64 - size);
947 	char *endp;
948 
949 	errno = 0;
950 
951 	*val = strtoull(str, &endp, 0);
952 
953 	if (*endp || errno || (*val > max))
954 		return -1;
955 
956 	return 0;
957 }
958 
rxclass_get_ipv4(char * str,__be32 * val)959 static int rxclass_get_ipv4(char *str, __be32 *val)
960 {
961 	if (!inet_pton(AF_INET, str, val))
962 		return -1;
963 
964 	return 0;
965 }
966 
rxclass_get_ipv6(char * str,__be32 * val)967 static int rxclass_get_ipv6(char *str, __be32 *val)
968 {
969 	if (!inet_pton(AF_INET6, str, val))
970 		return -1;
971 
972 	return 0;
973 }
974 
rxclass_get_ether(char * str,unsigned char * val)975 static int rxclass_get_ether(char *str, unsigned char *val)
976 {
977 	unsigned int buf[ETH_ALEN];
978 	int count;
979 
980 	if (!strchr(str, ':'))
981 		return -1;
982 
983 	count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
984 		       &buf[0], &buf[1], &buf[2],
985 		       &buf[3], &buf[4], &buf[5]);
986 
987 	if (count != ETH_ALEN)
988 		return -1;
989 
990 	do {
991 		count--;
992 		val[count] = buf[count];
993 	} while (count);
994 
995 	return 0;
996 }
997 
rxclass_get_val(char * str,unsigned char * p,u32 * flags,const struct rule_opts * opt)998 static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
999 			   const struct rule_opts *opt)
1000 {
1001 	unsigned long long mask = ~0ULL;
1002 	int err = 0;
1003 
1004 	if (*flags & opt->flag)
1005 		return -1;
1006 
1007 	*flags |= opt->flag;
1008 
1009 	switch (opt->type) {
1010 	case OPT_S32: {
1011 		long long val;
1012 		err = rxclass_get_long(str, &val, 32);
1013 		if (err)
1014 			return -1;
1015 		*(int *)&p[opt->offset] = (int)val;
1016 		if (opt->moffset >= 0)
1017 			*(int *)&p[opt->moffset] = (int)mask;
1018 		break;
1019 	}
1020 	case OPT_U8: {
1021 		unsigned long long val;
1022 		err = rxclass_get_ulong(str, &val, 8);
1023 		if (err)
1024 			return -1;
1025 		*(u8 *)&p[opt->offset] = (u8)val;
1026 		if (opt->moffset >= 0)
1027 			*(u8 *)&p[opt->moffset] = (u8)mask;
1028 		break;
1029 	}
1030 	case OPT_U16: {
1031 		unsigned long long val;
1032 		err = rxclass_get_ulong(str, &val, 16);
1033 		if (err)
1034 			return -1;
1035 		*(u16 *)&p[opt->offset] = (u16)val;
1036 		if (opt->moffset >= 0)
1037 			*(u16 *)&p[opt->moffset] = (u16)mask;
1038 		break;
1039 	}
1040 	case OPT_U32: {
1041 		unsigned long long val;
1042 		err = rxclass_get_ulong(str, &val, 32);
1043 		if (err)
1044 			return -1;
1045 		*(u32 *)&p[opt->offset] = (u32)val;
1046 		if (opt->moffset >= 0)
1047 			*(u32 *)&p[opt->moffset] = (u32)mask;
1048 		break;
1049 	}
1050 	case OPT_U64: {
1051 		unsigned long long val;
1052 		err = rxclass_get_ulong(str, &val, 64);
1053 		if (err)
1054 			return -1;
1055 		*(u64 *)&p[opt->offset] = (u64)val;
1056 		if (opt->moffset >= 0)
1057 			*(u64 *)&p[opt->moffset] = (u64)mask;
1058 		break;
1059 	}
1060 	case OPT_RING_VF: {
1061 		unsigned long long val;
1062 		err = rxclass_get_ulong(str, &val, 8);
1063 		if (err)
1064 			return -1;
1065 
1066 		/* The ring_cookie uses 0 to indicate the rule targets the
1067 		 * main function, so add 1 to the value in order to target the
1068 		 * correct virtual function.
1069 		 */
1070 		val++;
1071 
1072 		*(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING_VF;
1073 		*(u64 *)&p[opt->offset] |= (u64)val << ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
1074 		break;
1075 	}
1076 	case OPT_RING_QUEUE: {
1077 		unsigned long long val;
1078 		err = rxclass_get_ulong(str, &val, 32);
1079 		if (err)
1080 			return -1;
1081 		*(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING;
1082 		*(u64 *)&p[opt->offset] |= (u64)val;
1083 		break;
1084 	}
1085 	case OPT_BE16: {
1086 		unsigned long long val;
1087 		err = rxclass_get_ulong(str, &val, 16);
1088 		if (err)
1089 			return -1;
1090 		*(__be16 *)&p[opt->offset] = htons((u16)val);
1091 		if (opt->moffset >= 0)
1092 			*(__be16 *)&p[opt->moffset] = (__be16)mask;
1093 		break;
1094 	}
1095 	case OPT_BE32: {
1096 		unsigned long long val;
1097 		err = rxclass_get_ulong(str, &val, 32);
1098 		if (err)
1099 			return -1;
1100 		*(__be32 *)&p[opt->offset] = htonl((u32)val);
1101 		if (opt->moffset >= 0)
1102 			*(__be32 *)&p[opt->moffset] = (__be32)mask;
1103 		break;
1104 	}
1105 	case OPT_BE64: {
1106 		unsigned long long val;
1107 		err = rxclass_get_ulong(str, &val, 64);
1108 		if (err)
1109 			return -1;
1110 		*(__be64 *)&p[opt->offset] = htonll((u64)val);
1111 		if (opt->moffset >= 0)
1112 			*(__be64 *)&p[opt->moffset] = (__be64)mask;
1113 		break;
1114 	}
1115 	case OPT_IP4: {
1116 		__be32 val;
1117 		err = rxclass_get_ipv4(str, &val);
1118 		if (err)
1119 			return -1;
1120 		*(__be32 *)&p[opt->offset] = val;
1121 		if (opt->moffset >= 0)
1122 			*(__be32 *)&p[opt->moffset] = (__be32)mask;
1123 		break;
1124 	}
1125 	case OPT_IP6: {
1126 		__be32 val[4];
1127 		err = rxclass_get_ipv6(str, val);
1128 		if (err)
1129 			return -1;
1130 		memcpy(&p[opt->offset], val, sizeof(val));
1131 		if (opt->moffset >= 0)
1132 			memset(&p[opt->moffset], mask, sizeof(val));
1133 		break;
1134 	}
1135 	case OPT_MAC: {
1136 		unsigned char val[ETH_ALEN];
1137 		err = rxclass_get_ether(str, val);
1138 		if (err)
1139 			return -1;
1140 		memcpy(&p[opt->offset], val, ETH_ALEN);
1141 		if (opt->moffset >= 0)
1142 			memcpy(&p[opt->moffset], &mask, ETH_ALEN);
1143 		break;
1144 	}
1145 	case OPT_NONE:
1146 	default:
1147 		return -1;
1148 	}
1149 
1150 	return 0;
1151 }
1152 
rxclass_get_mask(char * str,unsigned char * p,const struct rule_opts * opt)1153 static int rxclass_get_mask(char *str, unsigned char *p,
1154 			    const struct rule_opts *opt)
1155 {
1156 	int err = 0;
1157 
1158 	if (opt->moffset < 0)
1159 		return -1;
1160 
1161 	switch (opt->type) {
1162 	case OPT_S32: {
1163 		long long val;
1164 		err = rxclass_get_long(str, &val, 32);
1165 		if (err)
1166 			return -1;
1167 		*(int *)&p[opt->moffset] = ~(int)val;
1168 		break;
1169 	}
1170 	case OPT_U8: {
1171 		unsigned long long val;
1172 		err = rxclass_get_ulong(str, &val, 8);
1173 		if (err)
1174 			return -1;
1175 		*(u8 *)&p[opt->moffset] = ~(u8)val;
1176 		break;
1177 	}
1178 	case OPT_U16: {
1179 		unsigned long long val;
1180 		err = rxclass_get_ulong(str, &val, 16);
1181 		if (err)
1182 			return -1;
1183 		*(u16 *)&p[opt->moffset] = ~(u16)val;
1184 		break;
1185 	}
1186 	case OPT_U32: {
1187 		unsigned long long val;
1188 		err = rxclass_get_ulong(str, &val, 32);
1189 		if (err)
1190 			return -1;
1191 		*(u32 *)&p[opt->moffset] = ~(u32)val;
1192 		break;
1193 	}
1194 	case OPT_U64: {
1195 		unsigned long long val;
1196 		err = rxclass_get_ulong(str, &val, 64);
1197 		if (err)
1198 			return -1;
1199 		*(u64 *)&p[opt->moffset] = ~(u64)val;
1200 		break;
1201 	}
1202 	case OPT_BE16: {
1203 		unsigned long long val;
1204 		err = rxclass_get_ulong(str, &val, 16);
1205 		if (err)
1206 			return -1;
1207 		*(__be16 *)&p[opt->moffset] = ~htons((u16)val);
1208 		break;
1209 	}
1210 	case OPT_BE32: {
1211 		unsigned long long val;
1212 		err = rxclass_get_ulong(str, &val, 32);
1213 		if (err)
1214 			return -1;
1215 		*(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
1216 		break;
1217 	}
1218 	case OPT_BE64: {
1219 		unsigned long long val;
1220 		err = rxclass_get_ulong(str, &val, 64);
1221 		if (err)
1222 			return -1;
1223 		*(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
1224 		break;
1225 	}
1226 	case OPT_IP4: {
1227 		__be32 val;
1228 		err = rxclass_get_ipv4(str, &val);
1229 		if (err)
1230 			return -1;
1231 		*(__be32 *)&p[opt->moffset] = ~val;
1232 		break;
1233 	}
1234 	case OPT_IP6: {
1235 		__be32 val[4], *field;
1236 		int i;
1237 		err = rxclass_get_ipv6(str, val);
1238 		if (err)
1239 			return -1;
1240 		field = (__be32 *)&p[opt->moffset];
1241 		for (i = 0; i < 4; i++)
1242 			field[i] = ~val[i];
1243 		break;
1244 	}
1245 	case OPT_MAC: {
1246 		unsigned char val[ETH_ALEN];
1247 		int i;
1248 		err = rxclass_get_ether(str, val);
1249 		if (err)
1250 			return -1;
1251 
1252 		for (i = 0; i < ETH_ALEN; i++)
1253 			val[i] = ~val[i];
1254 
1255 		memcpy(&p[opt->moffset], val, ETH_ALEN);
1256 		break;
1257 	}
1258 	case OPT_NONE:
1259 	default:
1260 		return -1;
1261 	}
1262 
1263 	return 0;
1264 }
1265 
rxclass_parse_ruleopts(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp,__u32 * rss_context)1266 int rxclass_parse_ruleopts(struct cmd_context *ctx,
1267 			   struct ethtool_rx_flow_spec *fsp, __u32 *rss_context)
1268 {
1269 	const struct rule_opts *options;
1270 	unsigned char *p = (unsigned char *)fsp;
1271 	int i = 0, n_opts, err;
1272 	u32 flags = 0;
1273 	int flow_type;
1274 	int argc = ctx->argc;
1275 	char **argp = ctx->argp;
1276 
1277 	if (argc < 1)
1278 		goto syntax_err;
1279 
1280 	if (!strcmp(argp[0], "tcp4"))
1281 		flow_type = TCP_V4_FLOW;
1282 	else if (!strcmp(argp[0], "udp4"))
1283 		flow_type = UDP_V4_FLOW;
1284 	else if (!strcmp(argp[0], "sctp4"))
1285 		flow_type = SCTP_V4_FLOW;
1286 	else if (!strcmp(argp[0], "ah4"))
1287 		flow_type = AH_V4_FLOW;
1288 	else if (!strcmp(argp[0], "esp4"))
1289 		flow_type = ESP_V4_FLOW;
1290 	else if (!strcmp(argp[0], "ip4"))
1291 		flow_type = IPV4_USER_FLOW;
1292 	else if (!strcmp(argp[0], "tcp6"))
1293 		flow_type = TCP_V6_FLOW;
1294 	else if (!strcmp(argp[0], "udp6"))
1295 		flow_type = UDP_V6_FLOW;
1296 	else if (!strcmp(argp[0], "sctp6"))
1297 		flow_type = SCTP_V6_FLOW;
1298 	else if (!strcmp(argp[0], "ah6"))
1299 		flow_type = AH_V6_FLOW;
1300 	else if (!strcmp(argp[0], "esp6"))
1301 		flow_type = ESP_V6_FLOW;
1302 	else if (!strcmp(argp[0], "ip6"))
1303 		flow_type = IPV6_USER_FLOW;
1304 	else if (!strcmp(argp[0], "ether"))
1305 		flow_type = ETHER_FLOW;
1306 	else
1307 		goto syntax_err;
1308 
1309 	switch (flow_type) {
1310 	case TCP_V4_FLOW:
1311 	case UDP_V4_FLOW:
1312 	case SCTP_V4_FLOW:
1313 		options = rule_nfc_tcp_ip4;
1314 		n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
1315 		break;
1316 	case AH_V4_FLOW:
1317 	case ESP_V4_FLOW:
1318 		options = rule_nfc_esp_ip4;
1319 		n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
1320 		break;
1321 	case IPV4_USER_FLOW:
1322 		options = rule_nfc_usr_ip4;
1323 		n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
1324 		break;
1325 	case TCP_V6_FLOW:
1326 	case UDP_V6_FLOW:
1327 	case SCTP_V6_FLOW:
1328 		options = rule_nfc_tcp_ip6;
1329 		n_opts = ARRAY_SIZE(rule_nfc_tcp_ip6);
1330 		break;
1331 	case AH_V6_FLOW:
1332 	case ESP_V6_FLOW:
1333 		options = rule_nfc_esp_ip6;
1334 		n_opts = ARRAY_SIZE(rule_nfc_esp_ip6);
1335 		break;
1336 	case IPV6_USER_FLOW:
1337 		options = rule_nfc_usr_ip6;
1338 		n_opts = ARRAY_SIZE(rule_nfc_usr_ip6);
1339 		break;
1340 	case ETHER_FLOW:
1341 		options = rule_nfc_ether;
1342 		n_opts = ARRAY_SIZE(rule_nfc_ether);
1343 		break;
1344 	default:
1345 		fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
1346 		return -1;
1347 	}
1348 
1349 	memset(p, 0, sizeof(*fsp));
1350 	fsp->flow_type = flow_type;
1351 	fsp->location = RX_CLS_LOC_ANY;
1352 
1353 	for (i = 1; i < argc;) {
1354 		const struct rule_opts *opt;
1355 		int idx;
1356 
1357 		/* special handling for 'context %d' as it doesn't go in
1358 		 * the struct ethtool_rx_flow_spec
1359 		 */
1360 		if (!strcmp(argp[i], "context")) {
1361 			unsigned long long val;
1362 
1363 			i++;
1364 			if (i >= argc) {
1365 				fprintf(stderr, "'context' missing value\n");
1366 				return -1;
1367 			}
1368 
1369 			if (rxclass_get_ulong(argp[i], &val, 32)) {
1370 				fprintf(stderr, "Invalid context value[%s]\n",
1371 					argp[i]);
1372 				return -1;
1373 			}
1374 
1375 			/* Can't use the ALLOC special value as the context ID
1376 			 * of a filter to insert
1377 			 */
1378 			if ((__u32)val == ETH_RXFH_CONTEXT_ALLOC) {
1379 				fprintf(stderr, "Bad context value %x\n",
1380 					(__u32)val);
1381 				return -1;
1382 			}
1383 
1384 			*rss_context = (__u32)val;
1385 			fsp->flow_type |= FLOW_RSS;
1386 			i++;
1387 			continue;
1388 		}
1389 
1390 		for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
1391 			char mask_name[16];
1392 
1393 			if (strcmp(argp[i], opt->name))
1394 				continue;
1395 
1396 			i++;
1397 			if (i >= argc)
1398 				break;
1399 
1400 			err = rxclass_get_val(argp[i], p, &flags, opt);
1401 			if (err) {
1402 				fprintf(stderr, "Invalid %s value[%s]\n",
1403 					opt->name, argp[i]);
1404 				return -1;
1405 			}
1406 
1407 			i++;
1408 			if (i >= argc)
1409 				break;
1410 
1411 			sprintf(mask_name, "%s-mask", opt->name);
1412 			if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
1413 				break;
1414 
1415 			i++;
1416 			if (i >= argc)
1417 				goto syntax_err;
1418 
1419 			err = rxclass_get_mask(argp[i], p, opt);
1420 			if (err) {
1421 				fprintf(stderr, "Invalid %s mask[%s]\n",
1422 					opt->name, argp[i]);
1423 				return -1;
1424 			}
1425 
1426 			i++;
1427 
1428 			break;
1429 		}
1430 		if (idx == n_opts) {
1431 			fprintf(stdout, "Add rule, unrecognized option[%s]\n",
1432 				argp[i]);
1433 			return -1;
1434 		}
1435 	}
1436 
1437 	if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_QUEUE)) {
1438 		fprintf(stderr, "action and queue are not compatible\n");
1439 			return -1;
1440 	}
1441 
1442 	if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_VF)) {
1443 		fprintf(stderr, "action and vf are not compatible\n");
1444 			return -1;
1445 	}
1446 
1447 	if (flow_type == IPV4_USER_FLOW)
1448 		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
1449 	if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
1450 		fsp->flow_type |= FLOW_EXT;
1451 	if (flags & NFC_FLAG_MAC_ADDR)
1452 		fsp->flow_type |= FLOW_MAC_EXT;
1453 
1454 	return 0;
1455 
1456 syntax_err:
1457 	fprintf(stderr, "Add rule, invalid syntax\n");
1458 	return -1;
1459 }
1460