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