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