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