blob: 79972651e706e98e8b73bf2a8c8041f8adbef56e [file] [log] [blame]
Alexander Duyck8d63f722011-05-04 11:41:51 -07001/*
2 * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
3 */
4#include <stdio.h>
5#include <stdint.h>
6#include <stddef.h>
7#include <stdlib.h>
8#include <string.h>
9#include <errno.h>
10
11#include <linux/sockios.h>
12#include <arpa/inet.h>
Ben Hutchings5ba70c02011-11-01 16:48:31 +000013#include "internal.h"
Alexander Duyck8d63f722011-05-04 11:41:51 -070014
15static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
16{
17 size_t i;
18
19 for (i = 0; i < sizeof(fsp->m_u); i++)
20 fsp->m_u.hdata[i] ^= 0xFF;
21}
22
23static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
24 __be32 dipm, u8 tos, u8 tosm)
25{
26 char sip_str[INET_ADDRSTRLEN];
27 char sipm_str[INET_ADDRSTRLEN];
28 char dip_str[INET_ADDRSTRLEN];
29 char dipm_str[INET_ADDRSTRLEN];
30
31 fprintf(stdout,
32 "\tSrc IP addr: %s mask: %s\n"
33 "\tDest IP addr: %s mask: %s\n"
34 "\tTOS: 0x%x mask: 0x%x\n",
35 inet_ntop(AF_INET, &sip, sip_str, INET_ADDRSTRLEN),
36 inet_ntop(AF_INET, &sipm, sipm_str, INET_ADDRSTRLEN),
37 inet_ntop(AF_INET, &dip, dip_str, INET_ADDRSTRLEN),
38 inet_ntop(AF_INET, &dipm, dipm_str, INET_ADDRSTRLEN),
39 tos, tosm);
40}
41
Edward Creeb56b9512016-03-17 19:17:16 +000042static void rxclass_print_ipv6_rule(__be32 *sip, __be32 *sipm, __be32 *dip,
43 __be32 *dipm, u8 tclass, u8 tclassm)
44{
45 char sip_str[INET6_ADDRSTRLEN];
46 char sipm_str[INET6_ADDRSTRLEN];
47 char dip_str[INET6_ADDRSTRLEN];
48 char dipm_str[INET6_ADDRSTRLEN];
49
50 fprintf(stdout,
51 "\tSrc IP addr: %s mask: %s\n"
52 "\tDest IP addr: %s mask: %s\n"
53 "\tTraffic Class: 0x%x mask: 0x%x\n",
54 inet_ntop(AF_INET6, sip, sip_str, INET6_ADDRSTRLEN),
55 inet_ntop(AF_INET6, sipm, sipm_str, INET6_ADDRSTRLEN),
56 inet_ntop(AF_INET6, dip, dip_str, INET6_ADDRSTRLEN),
57 inet_ntop(AF_INET6, dipm, dipm_str, INET6_ADDRSTRLEN),
58 tclass, tclassm);
59}
60
Alexander Duyck8d63f722011-05-04 11:41:51 -070061static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
62{
Yan Burmanb29aa902012-12-11 14:03:56 +020063 if (fsp->flow_type & FLOW_EXT) {
64 u64 data, datam;
65 __u16 etype, etypem, tci, tcim;
66 etype = ntohs(fsp->h_ext.vlan_etype);
67 etypem = ntohs(~fsp->m_ext.vlan_etype);
68 tci = ntohs(fsp->h_ext.vlan_tci);
69 tcim = ntohs(~fsp->m_ext.vlan_tci);
70 data = (u64)ntohl(fsp->h_ext.data[0]) << 32;
Ben Hutchingsfa1bed32013-01-22 20:28:02 +000071 data |= (u64)ntohl(fsp->h_ext.data[1]);
Yan Burmanb29aa902012-12-11 14:03:56 +020072 datam = (u64)ntohl(~fsp->m_ext.data[0]) << 32;
73 datam |= (u64)ntohl(~fsp->m_ext.data[1]);
Alexander Duyck8d63f722011-05-04 11:41:51 -070074
Yan Burmanb29aa902012-12-11 14:03:56 +020075 fprintf(stdout,
76 "\tVLAN EtherType: 0x%x mask: 0x%x\n"
77 "\tVLAN: 0x%x mask: 0x%x\n"
78 "\tUser-defined: 0x%llx mask: 0x%llx\n",
79 etype, etypem, tci, tcim, data, datam);
80 }
Alexander Duyck8d63f722011-05-04 11:41:51 -070081
Yan Burmanb29aa902012-12-11 14:03:56 +020082 if (fsp->flow_type & FLOW_MAC_EXT) {
83 unsigned char *dmac, *dmacm;
Alexander Duyck8d63f722011-05-04 11:41:51 -070084
Yan Burmanb29aa902012-12-11 14:03:56 +020085 dmac = fsp->h_ext.h_dest;
86 dmacm = fsp->m_ext.h_dest;
87
88 fprintf(stdout,
89 "\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
90 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n",
91 dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
92 dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
93 dmacm[4], dmacm[5]);
94 }
Alexander Duyck8d63f722011-05-04 11:41:51 -070095}
96
Edward Creef5d55b92018-03-09 15:04:12 +000097static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp,
98 __u32 rss_context)
Alexander Duyck8d63f722011-05-04 11:41:51 -070099{
100 unsigned char *smac, *smacm, *dmac, *dmacm;
101 __u32 flow_type;
102
Ben Hutchings578e6a52012-01-03 20:21:45 +0000103 fprintf(stdout, "Filter: %d\n", fsp->location);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700104
Edward Creef5d55b92018-03-09 15:04:12 +0000105 flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700106
107 invert_flow_mask(fsp);
108
109 switch (flow_type) {
110 case TCP_V4_FLOW:
111 case UDP_V4_FLOW:
112 case SCTP_V4_FLOW:
113 if (flow_type == TCP_V4_FLOW)
114 fprintf(stdout, "\tRule Type: TCP over IPv4\n");
115 else if (flow_type == UDP_V4_FLOW)
116 fprintf(stdout, "\tRule Type: UDP over IPv4\n");
117 else
118 fprintf(stdout, "\tRule Type: SCTP over IPv4\n");
119 rxclass_print_ipv4_rule(fsp->h_u.tcp_ip4_spec.ip4src,
120 fsp->m_u.tcp_ip4_spec.ip4src,
121 fsp->h_u.tcp_ip4_spec.ip4dst,
122 fsp->m_u.tcp_ip4_spec.ip4dst,
123 fsp->h_u.tcp_ip4_spec.tos,
124 fsp->m_u.tcp_ip4_spec.tos);
125 fprintf(stdout,
126 "\tSrc port: %d mask: 0x%x\n"
127 "\tDest port: %d mask: 0x%x\n",
128 ntohs(fsp->h_u.tcp_ip4_spec.psrc),
129 ntohs(fsp->m_u.tcp_ip4_spec.psrc),
130 ntohs(fsp->h_u.tcp_ip4_spec.pdst),
131 ntohs(fsp->m_u.tcp_ip4_spec.pdst));
132 break;
133 case AH_V4_FLOW:
134 case ESP_V4_FLOW:
135 if (flow_type == AH_V4_FLOW)
136 fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
137 else
138 fprintf(stdout, "\tRule Type: IPSEC ESP over IPv4\n");
139 rxclass_print_ipv4_rule(fsp->h_u.ah_ip4_spec.ip4src,
140 fsp->m_u.ah_ip4_spec.ip4src,
141 fsp->h_u.ah_ip4_spec.ip4dst,
142 fsp->m_u.ah_ip4_spec.ip4dst,
143 fsp->h_u.ah_ip4_spec.tos,
144 fsp->m_u.ah_ip4_spec.tos);
145 fprintf(stdout,
146 "\tSPI: %d mask: 0x%x\n",
147 ntohl(fsp->h_u.esp_ip4_spec.spi),
148 ntohl(fsp->m_u.esp_ip4_spec.spi));
149 break;
Edward Creeb56b9512016-03-17 19:17:16 +0000150 case IPV4_USER_FLOW:
Alexander Duyck8d63f722011-05-04 11:41:51 -0700151 fprintf(stdout, "\tRule Type: Raw IPv4\n");
152 rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
153 fsp->m_u.usr_ip4_spec.ip4src,
154 fsp->h_u.usr_ip4_spec.ip4dst,
155 fsp->m_u.usr_ip4_spec.ip4dst,
156 fsp->h_u.usr_ip4_spec.tos,
157 fsp->m_u.usr_ip4_spec.tos);
158 fprintf(stdout,
159 "\tProtocol: %d mask: 0x%x\n"
160 "\tL4 bytes: 0x%x mask: 0x%x\n",
161 fsp->h_u.usr_ip4_spec.proto,
162 fsp->m_u.usr_ip4_spec.proto,
163 ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
164 ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
165 break;
Edward Creeb56b9512016-03-17 19:17:16 +0000166 case TCP_V6_FLOW:
167 case UDP_V6_FLOW:
168 case SCTP_V6_FLOW:
169 if (flow_type == TCP_V6_FLOW)
170 fprintf(stdout, "\tRule Type: TCP over IPv6\n");
171 else if (flow_type == UDP_V6_FLOW)
172 fprintf(stdout, "\tRule Type: UDP over IPv6\n");
173 else
174 fprintf(stdout, "\tRule Type: SCTP over IPv6\n");
175 rxclass_print_ipv6_rule(fsp->h_u.tcp_ip6_spec.ip6src,
176 fsp->m_u.tcp_ip6_spec.ip6src,
177 fsp->h_u.tcp_ip6_spec.ip6dst,
178 fsp->m_u.tcp_ip6_spec.ip6dst,
179 fsp->h_u.tcp_ip6_spec.tclass,
180 fsp->m_u.tcp_ip6_spec.tclass);
181 fprintf(stdout,
182 "\tSrc port: %d mask: 0x%x\n"
183 "\tDest port: %d mask: 0x%x\n",
184 ntohs(fsp->h_u.tcp_ip6_spec.psrc),
185 ntohs(fsp->m_u.tcp_ip6_spec.psrc),
186 ntohs(fsp->h_u.tcp_ip6_spec.pdst),
187 ntohs(fsp->m_u.tcp_ip6_spec.pdst));
188 break;
189 case AH_V6_FLOW:
190 case ESP_V6_FLOW:
191 if (flow_type == AH_V6_FLOW)
192 fprintf(stdout, "\tRule Type: IPSEC AH over IPv6\n");
193 else
194 fprintf(stdout, "\tRule Type: IPSEC ESP over IPv6\n");
195 rxclass_print_ipv6_rule(fsp->h_u.ah_ip6_spec.ip6src,
196 fsp->m_u.ah_ip6_spec.ip6src,
197 fsp->h_u.ah_ip6_spec.ip6dst,
198 fsp->m_u.ah_ip6_spec.ip6dst,
199 fsp->h_u.ah_ip6_spec.tclass,
200 fsp->m_u.ah_ip6_spec.tclass);
201 fprintf(stdout,
202 "\tSPI: %d mask: 0x%x\n",
203 ntohl(fsp->h_u.esp_ip6_spec.spi),
204 ntohl(fsp->m_u.esp_ip6_spec.spi));
205 break;
206 case IPV6_USER_FLOW:
207 fprintf(stdout, "\tRule Type: Raw IPv6\n");
208 rxclass_print_ipv6_rule(fsp->h_u.usr_ip6_spec.ip6src,
209 fsp->m_u.usr_ip6_spec.ip6src,
210 fsp->h_u.usr_ip6_spec.ip6dst,
211 fsp->m_u.usr_ip6_spec.ip6dst,
212 fsp->h_u.usr_ip6_spec.tclass,
213 fsp->m_u.usr_ip6_spec.tclass);
214 fprintf(stdout,
215 "\tProtocol: %d mask: 0x%x\n"
216 "\tL4 bytes: 0x%x mask: 0x%x\n",
217 fsp->h_u.usr_ip6_spec.l4_proto,
218 fsp->m_u.usr_ip6_spec.l4_proto,
219 ntohl(fsp->h_u.usr_ip6_spec.l4_4_bytes),
220 ntohl(fsp->m_u.usr_ip6_spec.l4_4_bytes));
221 break;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700222 case ETHER_FLOW:
223 dmac = fsp->h_u.ether_spec.h_dest;
224 dmacm = fsp->m_u.ether_spec.h_dest;
225 smac = fsp->h_u.ether_spec.h_source;
226 smacm = fsp->m_u.ether_spec.h_source;
227
228 fprintf(stdout,
229 "\tFlow Type: Raw Ethernet\n"
230 "\tSrc MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
231 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
232 "\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
233 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
234 "\tEthertype: 0x%X mask: 0x%X\n",
235 smac[0], smac[1], smac[2], smac[3], smac[4], smac[5],
236 smacm[0], smacm[1], smacm[2], smacm[3], smacm[4],
237 smacm[5], dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
238 dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
239 dmacm[4], dmacm[5],
240 ntohs(fsp->h_u.ether_spec.h_proto),
241 ntohs(fsp->m_u.ether_spec.h_proto));
242 break;
243 default:
244 fprintf(stdout,
245 "\tUnknown Flow type: %d\n", flow_type);
246 break;
247 }
248
249 rxclass_print_nfc_spec_ext(fsp);
250
Edward Creef5d55b92018-03-09 15:04:12 +0000251 if (fsp->flow_type & FLOW_RSS)
252 fprintf(stdout, "\tRSS Context ID: %u\n", rss_context);
253
Florian Fainelli36a69c72018-08-09 11:04:02 -0700254 if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
255 fprintf(stdout, "\tAction: Drop\n");
256 } else if (fsp->ring_cookie == RX_CLS_FLOW_WAKE) {
257 fprintf(stdout, "\tAction: Wake-on-LAN\n");
258 } else {
Jacob Keller36ee7122017-03-23 23:07:13 -0700259 u64 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
260 u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
261
Jacob Kellerd7b70e52018-02-26 10:49:56 -0800262 /* A value of zero indicates that this rule targeted the main
263 * function. A positive value indicates which virtual function
264 * was targeted, so we'll subtract 1 in order to show the
265 * correct VF index
266 */
Jacob Keller36ee7122017-03-23 23:07:13 -0700267 if (vf)
Jacob Keller36ee7122017-03-23 23:07:13 -0700268 fprintf(stdout, "\tAction: Direct to VF %llu queue %llu\n",
Jacob Kellerd7b70e52018-02-26 10:49:56 -0800269 vf - 1, queue);
Jacob Keller3d534802018-02-26 10:49:54 -0800270 else
271 fprintf(stdout, "\tAction: Direct to queue %llu\n",
272 queue);
Jacob Keller36ee7122017-03-23 23:07:13 -0700273 }
Alexander Duyck8d63f722011-05-04 11:41:51 -0700274
275 fprintf(stdout, "\n");
276}
277
Edward Creef5d55b92018-03-09 15:04:12 +0000278static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp,
279 __u32 rss_context)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700280{
281 /* print the rule in this location */
Edward Creef5d55b92018-03-09 15:04:12 +0000282 switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700283 case TCP_V4_FLOW:
284 case UDP_V4_FLOW:
285 case SCTP_V4_FLOW:
286 case AH_V4_FLOW:
287 case ESP_V4_FLOW:
Alexander Duyck8d63f722011-05-04 11:41:51 -0700288 case TCP_V6_FLOW:
289 case UDP_V6_FLOW:
290 case SCTP_V6_FLOW:
291 case AH_V6_FLOW:
292 case ESP_V6_FLOW:
Edward Creeb56b9512016-03-17 19:17:16 +0000293 case IPV6_USER_FLOW:
294 case ETHER_FLOW:
Edward Creef5d55b92018-03-09 15:04:12 +0000295 rxclass_print_nfc_rule(fsp, rss_context);
Edward Creeb56b9512016-03-17 19:17:16 +0000296 break;
297 case IPV4_USER_FLOW:
298 if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
Edward Creef5d55b92018-03-09 15:04:12 +0000299 rxclass_print_nfc_rule(fsp, rss_context);
Edward Creeb56b9512016-03-17 19:17:16 +0000300 else /* IPv6 uses IPV6_USER_FLOW */
301 fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
Alexander Duyck8d63f722011-05-04 11:41:51 -0700302 break;
303 default:
304 fprintf(stderr, "rxclass: Unknown flow type\n");
305 break;
306 }
307}
308
Ben Hutchings29766372011-12-17 01:18:51 +0000309static int rxclass_get_dev_info(struct cmd_context *ctx, __u32 *count,
310 int *driver_select)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700311{
312 struct ethtool_rxnfc nfccmd;
313 int err;
314
Alexander Duyck8d63f722011-05-04 11:41:51 -0700315 nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
Alexander Duyckb17dcb92012-07-13 09:55:29 -0700316 nfccmd.data = 0;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100317 err = send_ioctl(ctx, &nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700318 *count = nfccmd.rule_cnt;
Ben Hutchings29766372011-12-17 01:18:51 +0000319 if (driver_select)
320 *driver_select = !!(nfccmd.data & RX_CLS_LOC_SPECIAL);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700321 if (err < 0)
322 perror("rxclass: Cannot get RX class rule count");
323
324 return err;
325}
326
Ben Hutchings37897ca2011-10-29 02:33:30 +0100327int rxclass_rule_get(struct cmd_context *ctx, __u32 loc)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700328{
329 struct ethtool_rxnfc nfccmd;
330 int err;
331
332 /* fetch rule from netdev */
333 nfccmd.cmd = ETHTOOL_GRXCLSRULE;
334 memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
335 nfccmd.fs.location = loc;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100336 err = send_ioctl(ctx, &nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700337 if (err < 0) {
338 perror("rxclass: Cannot get RX class rule");
339 return err;
340 }
341
342 /* display rule */
Edward Creef5d55b92018-03-09 15:04:12 +0000343 rxclass_print_rule(&nfccmd.fs, (__u32)nfccmd.rss_context);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700344 return err;
345}
346
Ben Hutchings37897ca2011-10-29 02:33:30 +0100347int rxclass_rule_getall(struct cmd_context *ctx)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700348{
349 struct ethtool_rxnfc *nfccmd;
350 __u32 *rule_locs;
351 int err, i;
352 __u32 count;
353
354 /* determine rule count */
Ben Hutchings29766372011-12-17 01:18:51 +0000355 err = rxclass_get_dev_info(ctx, &count, NULL);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700356 if (err < 0)
357 return err;
358
359 fprintf(stdout, "Total %d rules\n\n", count);
360
361 /* alloc memory for request of location list */
362 nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
363 if (!nfccmd) {
364 perror("rxclass: Cannot allocate memory for"
365 " RX class rule locations");
366 return -ENOMEM;
367 }
368
369 /* request location list */
370 nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
371 nfccmd->rule_cnt = count;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100372 err = send_ioctl(ctx, nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700373 if (err < 0) {
374 perror("rxclass: Cannot get RX class rules");
375 free(nfccmd);
376 return err;
377 }
378
379 /* write locations to bitmap */
380 rule_locs = nfccmd->rule_locs;
381 for (i = 0; i < count; i++) {
Ben Hutchings37897ca2011-10-29 02:33:30 +0100382 err = rxclass_rule_get(ctx, rule_locs[i]);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700383 if (err < 0)
384 break;
385 }
386
387 /* free memory and set flag to avoid reinit */
388 free(nfccmd);
389
390 return err;
391}
392
393/*
394 * This is a simple rule manager implementation for ordering rx flow
395 * classification rules based on newest rules being first in the list.
396 * The assumption is that this rule manager is the only one adding rules to
397 * the device's hardware classifier.
398 */
399
400struct rmgr_ctrl {
Ben Hutchings29766372011-12-17 01:18:51 +0000401 /* flag for device/driver that can select locations itself */
402 int driver_select;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700403 /* slot contains a bitmap indicating which filters are valid */
404 unsigned long *slot;
405 __u32 n_rules;
406 __u32 size;
407};
408
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000409static int rmgr_ins(struct rmgr_ctrl *rmgr, __u32 loc)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700410{
411 /* verify location is in rule manager range */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000412 if (loc >= rmgr->size) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700413 fprintf(stderr, "rmgr: Location out of range\n");
414 return -1;
415 }
416
417 /* set bit for the rule */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000418 set_bit(loc, rmgr->slot);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700419
420 return 0;
421}
422
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000423static int rmgr_find_empty_slot(struct rmgr_ctrl *rmgr,
424 struct ethtool_rx_flow_spec *fsp)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700425{
426 __u32 loc;
427 __u32 slot_num;
428
Ben Hutchings29766372011-12-17 01:18:51 +0000429 /* leave this to the driver if possible */
430 if (rmgr->driver_select)
431 return 0;
432
Alexander Duyck8d63f722011-05-04 11:41:51 -0700433 /* start at the end of the list since it is lowest priority */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000434 loc = rmgr->size - 1;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700435
436 /* locate the first slot a rule can be placed in */
437 slot_num = loc / BITS_PER_LONG;
438
439 /*
440 * Avoid testing individual bits by inverting the word and checking
441 * to see if any bits are left set, if so there are empty spots. By
442 * moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
443 * in the previous word.
444 *
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000445 * If loc rolls over it should be greater than or equal to rmgr->size
Alexander Duyck8d63f722011-05-04 11:41:51 -0700446 * and as such we know we have reached the end of the list.
447 */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000448 if (!~(rmgr->slot[slot_num] | (~1UL << rmgr->size % BITS_PER_LONG))) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700449 loc -= 1 + (loc % BITS_PER_LONG);
450 slot_num--;
451 }
452
453 /*
454 * Now that we are aligned with the last bit in each long we can just
455 * go though and eliminate all the longs with no free bits
456 */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000457 while (loc < rmgr->size && !~(rmgr->slot[slot_num])) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700458 loc -= BITS_PER_LONG;
459 slot_num--;
460 }
461
462 /*
463 * If we still are inside the range, test individual bits as one is
464 * likely available for our use.
465 */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000466 while (loc < rmgr->size && test_bit(loc, rmgr->slot))
Alexander Duyck8d63f722011-05-04 11:41:51 -0700467 loc--;
468
469 /* location found, insert rule */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000470 if (loc < rmgr->size) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700471 fsp->location = loc;
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000472 return rmgr_ins(rmgr, loc);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700473 }
474
475 /* No space to add this rule */
476 fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
477
478 return -1;
479}
480
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000481static int rmgr_init(struct cmd_context *ctx, struct rmgr_ctrl *rmgr)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700482{
483 struct ethtool_rxnfc *nfccmd;
484 int err, i;
485 __u32 *rule_locs;
486
Alexander Duyck8d63f722011-05-04 11:41:51 -0700487 /* clear rule manager settings */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000488 memset(rmgr, 0, sizeof(*rmgr));
Alexander Duyck8d63f722011-05-04 11:41:51 -0700489
Ben Hutchings29766372011-12-17 01:18:51 +0000490 /* request device/driver information */
491 err = rxclass_get_dev_info(ctx, &rmgr->n_rules, &rmgr->driver_select);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700492 if (err < 0)
493 return err;
494
Ben Hutchings29766372011-12-17 01:18:51 +0000495 /* do not get the table if the device/driver can select locations */
496 if (rmgr->driver_select)
497 return 0;
498
Alexander Duyck8d63f722011-05-04 11:41:51 -0700499 /* alloc memory for request of location list */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000500 nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr->n_rules * sizeof(__u32)));
Alexander Duyck8d63f722011-05-04 11:41:51 -0700501 if (!nfccmd) {
502 perror("rmgr: Cannot allocate memory for"
503 " RX class rule locations");
504 return -1;
505 }
506
507 /* request location list */
508 nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000509 nfccmd->rule_cnt = rmgr->n_rules;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100510 err = send_ioctl(ctx, nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700511 if (err < 0) {
512 perror("rmgr: Cannot get RX class rules");
513 free(nfccmd);
514 return err;
515 }
516
517 /* make certain the table size is valid */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000518 rmgr->size = nfccmd->data;
519 if (rmgr->size == 0 || rmgr->size < rmgr->n_rules) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700520 perror("rmgr: Invalid RX class rules table size");
521 return -1;
522 }
523
524 /* initialize bitmap for storage of valid locations */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000525 rmgr->slot = calloc(1, BITS_TO_LONGS(rmgr->size) * sizeof(long));
526 if (!rmgr->slot) {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700527 perror("rmgr: Cannot allocate memory for RX class rules");
528 return -1;
529 }
530
531 /* write locations to bitmap */
532 rule_locs = nfccmd->rule_locs;
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000533 for (i = 0; i < rmgr->n_rules; i++) {
534 err = rmgr_ins(rmgr, rule_locs[i]);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700535 if (err < 0)
536 break;
537 }
538
Alexander Duyck8d63f722011-05-04 11:41:51 -0700539 free(nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700540
541 return err;
542}
543
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000544static void rmgr_cleanup(struct rmgr_ctrl *rmgr)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700545{
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000546 free(rmgr->slot);
547 rmgr->slot = NULL;
548 rmgr->size = 0;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700549}
550
Ben Hutchings37897ca2011-10-29 02:33:30 +0100551static int rmgr_set_location(struct cmd_context *ctx,
Alexander Duyck8d63f722011-05-04 11:41:51 -0700552 struct ethtool_rx_flow_spec *fsp)
553{
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000554 struct rmgr_ctrl rmgr;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700555 int err;
556
557 /* init table of available rules */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000558 err = rmgr_init(ctx, &rmgr);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700559 if (err < 0)
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000560 goto out;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700561
562 /* verify rule location */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000563 err = rmgr_find_empty_slot(&rmgr, fsp);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700564
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000565out:
Alexander Duyck8d63f722011-05-04 11:41:51 -0700566 /* cleanup table and free resources */
Ben Hutchings5a3279e2011-10-31 23:19:51 +0000567 rmgr_cleanup(&rmgr);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700568
569 return err;
570}
571
Ben Hutchings37897ca2011-10-29 02:33:30 +0100572int rxclass_rule_ins(struct cmd_context *ctx,
Edward Creef5d55b92018-03-09 15:04:12 +0000573 struct ethtool_rx_flow_spec *fsp, __u32 rss_context)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700574{
575 struct ethtool_rxnfc nfccmd;
576 __u32 loc = fsp->location;
577 int err;
578
579 /*
Ben Hutchings29766372011-12-17 01:18:51 +0000580 * if location is unspecified and driver cannot select locations, pull
581 * rules from device and allocate a free rule for our use
Alexander Duyck8d63f722011-05-04 11:41:51 -0700582 */
Ben Hutchings578e6a52012-01-03 20:21:45 +0000583 if (loc & RX_CLS_LOC_SPECIAL) {
Ben Hutchings37897ca2011-10-29 02:33:30 +0100584 err = rmgr_set_location(ctx, fsp);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700585 if (err < 0)
586 return err;
587 }
588
589 /* notify netdev of new rule */
590 nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
Edward Creef5d55b92018-03-09 15:04:12 +0000591 nfccmd.rss_context = rss_context;
Alexander Duyck8d63f722011-05-04 11:41:51 -0700592 nfccmd.fs = *fsp;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100593 err = send_ioctl(ctx, &nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700594 if (err < 0)
595 perror("rmgr: Cannot insert RX class rule");
Ben Hutchings578e6a52012-01-03 20:21:45 +0000596 else if (loc & RX_CLS_LOC_SPECIAL)
Ben Hutchings29766372011-12-17 01:18:51 +0000597 printf("Added rule with ID %d\n", nfccmd.fs.location);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700598
599 return 0;
600}
601
Ben Hutchings37897ca2011-10-29 02:33:30 +0100602int rxclass_rule_del(struct cmd_context *ctx, __u32 loc)
Alexander Duyck8d63f722011-05-04 11:41:51 -0700603{
604 struct ethtool_rxnfc nfccmd;
605 int err;
606
607 /* notify netdev of rule removal */
608 nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
609 nfccmd.fs.location = loc;
Ben Hutchings37897ca2011-10-29 02:33:30 +0100610 err = send_ioctl(ctx, &nfccmd);
Alexander Duyck8d63f722011-05-04 11:41:51 -0700611 if (err < 0)
612 perror("rmgr: Cannot delete RX class rule");
613
614 return err;
615}
616
617typedef enum {
618 OPT_NONE = 0,
619 OPT_S32,
620 OPT_U8,
621 OPT_U16,
622 OPT_U32,
623 OPT_U64,
Jacob Keller36ee7122017-03-23 23:07:13 -0700624 OPT_RING_VF,
625 OPT_RING_QUEUE,
Alexander Duyck8d63f722011-05-04 11:41:51 -0700626 OPT_BE16,
627 OPT_BE32,
628 OPT_BE64,
629 OPT_IP4,
Edward Creeb56b9512016-03-17 19:17:16 +0000630 OPT_IP6,
Alexander Duyck8d63f722011-05-04 11:41:51 -0700631 OPT_MAC,
632} rule_opt_type_t;
633
Jacob Keller36ee7122017-03-23 23:07:13 -0700634#define NFC_FLAG_RING 0x0001
635#define NFC_FLAG_LOC 0x0002
636#define NFC_FLAG_SADDR 0x0004
637#define NFC_FLAG_DADDR 0x0008
638#define NFC_FLAG_SPORT 0x0010
639#define NFC_FLAG_DPORT 0x0020
640#define NFC_FLAG_SPI 0x0030
641#define NFC_FLAG_TOS 0x0040
642#define NFC_FLAG_PROTO 0x0080
643#define NTUPLE_FLAG_VLAN 0x0100
644#define NTUPLE_FLAG_UDEF 0x0200
645#define NTUPLE_FLAG_VETH 0x0400
646#define NFC_FLAG_MAC_ADDR 0x0800
647#define NFC_FLAG_RING_VF 0x1000
648#define NFC_FLAG_RING_QUEUE 0x2000
Alexander Duyck8d63f722011-05-04 11:41:51 -0700649
650struct rule_opts {
651 const char *name;
652 rule_opt_type_t type;
653 u32 flag;
654 int offset;
655 int moffset;
656};
657
Ben Hutchings02af8c22011-10-31 23:06:52 +0000658static const struct rule_opts rule_nfc_tcp_ip4[] = {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700659 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
660 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
661 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
662 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
663 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4dst),
664 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4dst) },
665 { "tos", OPT_U8, NFC_FLAG_TOS,
666 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.tos),
667 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.tos) },
668 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
669 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.psrc),
670 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.psrc) },
671 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
672 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.pdst),
673 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.pdst) },
674 { "action", OPT_U64, NFC_FLAG_RING,
675 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700676 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
677 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
678 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
679 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700680 { "loc", OPT_U32, NFC_FLAG_LOC,
681 offsetof(struct ethtool_rx_flow_spec, location), -1 },
682 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
683 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
684 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
685 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
686 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
687 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
688 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
689 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
690 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
Yan Burmanb29aa902012-12-11 14:03:56 +0200691 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
692 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
693 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700694};
695
Ben Hutchings02af8c22011-10-31 23:06:52 +0000696static const struct rule_opts rule_nfc_esp_ip4[] = {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700697 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
698 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
699 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
700 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
701 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4dst),
702 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4dst) },
703 { "tos", OPT_U8, NFC_FLAG_TOS,
704 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.tos),
705 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.tos) },
706 { "spi", OPT_BE32, NFC_FLAG_SPI,
707 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.spi),
708 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.spi) },
709 { "action", OPT_U64, NFC_FLAG_RING,
710 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700711 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
712 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
713 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
714 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700715 { "loc", OPT_U32, NFC_FLAG_LOC,
716 offsetof(struct ethtool_rx_flow_spec, location), -1 },
717 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
718 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
719 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
720 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
721 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
722 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
723 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
724 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
725 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
Yan Burmanb29aa902012-12-11 14:03:56 +0200726 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
727 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
728 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700729};
730
Ben Hutchings02af8c22011-10-31 23:06:52 +0000731static const struct rule_opts rule_nfc_usr_ip4[] = {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700732 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
733 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
734 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
735 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
736 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4dst),
737 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4dst) },
738 { "tos", OPT_U8, NFC_FLAG_TOS,
739 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.tos),
740 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.tos) },
741 { "l4proto", OPT_U8, NFC_FLAG_PROTO,
742 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.proto),
743 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.proto) },
Sebastian Pöhn5ab18de2011-06-30 10:41:20 +0200744 { "l4data", OPT_BE32, NFC_FLAG_SPI,
745 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
746 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700747 { "spi", OPT_BE32, NFC_FLAG_SPI,
748 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
749 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
750 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
751 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
752 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
753 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
754 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes) + 2,
755 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) + 2 },
756 { "action", OPT_U64, NFC_FLAG_RING,
757 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700758 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
759 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
760 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
761 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700762 { "loc", OPT_U32, NFC_FLAG_LOC,
763 offsetof(struct ethtool_rx_flow_spec, location), -1 },
764 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
765 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
766 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
767 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
768 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
769 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
770 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
771 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
772 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
Yan Burmanb29aa902012-12-11 14:03:56 +0200773 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
774 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
775 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700776};
777
Edward Creeb56b9512016-03-17 19:17:16 +0000778static const struct rule_opts rule_nfc_tcp_ip6[] = {
779 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
780 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6src),
781 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6src) },
782 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
783 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6dst),
784 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6dst) },
785 { "tclass", OPT_U8, NFC_FLAG_TOS,
786 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.tclass),
787 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.tclass) },
788 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
789 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.psrc),
790 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.psrc) },
791 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
792 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.pdst),
793 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.pdst) },
794 { "action", OPT_U64, NFC_FLAG_RING,
795 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700796 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
797 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
798 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
799 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Edward Creeb56b9512016-03-17 19:17:16 +0000800 { "loc", OPT_U32, NFC_FLAG_LOC,
801 offsetof(struct ethtool_rx_flow_spec, location), -1 },
802 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
803 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
804 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
805 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
806 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
807 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
808 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
809 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
810 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
811 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
812 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
813 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
814};
815
816static const struct rule_opts rule_nfc_esp_ip6[] = {
817 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
818 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6src),
819 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6src) },
820 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
821 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6dst),
822 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6dst) },
823 { "tclass", OPT_U8, NFC_FLAG_TOS,
824 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.tclass),
825 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.tclass) },
826 { "spi", OPT_BE32, NFC_FLAG_SPI,
827 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.spi),
828 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.spi) },
829 { "action", OPT_U64, NFC_FLAG_RING,
830 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700831 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
832 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
833 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
834 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Edward Creeb56b9512016-03-17 19:17:16 +0000835 { "loc", OPT_U32, NFC_FLAG_LOC,
836 offsetof(struct ethtool_rx_flow_spec, location), -1 },
837 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
838 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
839 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
840 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
841 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
842 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
843 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
844 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
845 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
846 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
847 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
848 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
849};
850
851static const struct rule_opts rule_nfc_usr_ip6[] = {
852 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
853 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6src),
854 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6src) },
855 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
856 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6dst),
857 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6dst) },
858 { "tclass", OPT_U8, NFC_FLAG_TOS,
859 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.tclass),
860 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.tclass) },
861 { "l4proto", OPT_U8, NFC_FLAG_PROTO,
862 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_proto),
863 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_proto) },
864 { "l4data", OPT_BE32, NFC_FLAG_SPI,
865 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
866 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
867 { "spi", OPT_BE32, NFC_FLAG_SPI,
868 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
869 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
870 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
871 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
872 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
873 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
874 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes) + 2,
875 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) + 2 },
876 { "action", OPT_U64, NFC_FLAG_RING,
877 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700878 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
879 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
880 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
881 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Edward Creeb56b9512016-03-17 19:17:16 +0000882 { "loc", OPT_U32, NFC_FLAG_LOC,
883 offsetof(struct ethtool_rx_flow_spec, location), -1 },
884 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
885 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
886 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
887 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
888 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
889 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
890 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
891 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
892 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
893 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
894 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
895 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
896};
897
Ben Hutchings02af8c22011-10-31 23:06:52 +0000898static const struct rule_opts rule_nfc_ether[] = {
Alexander Duyck8d63f722011-05-04 11:41:51 -0700899 { "src", OPT_MAC, NFC_FLAG_SADDR,
Alexander Duyck8d63f722011-05-04 11:41:51 -0700900 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
901 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
Sebastian Pöhn5ab18de2011-06-30 10:41:20 +0200902 { "dst", OPT_MAC, NFC_FLAG_DADDR,
903 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
904 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700905 { "proto", OPT_BE16, NFC_FLAG_PROTO,
906 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_proto),
907 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_proto) },
908 { "action", OPT_U64, NFC_FLAG_RING,
909 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Jacob Keller36ee7122017-03-23 23:07:13 -0700910 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
911 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
912 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
913 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
Alexander Duyck8d63f722011-05-04 11:41:51 -0700914 { "loc", OPT_U32, NFC_FLAG_LOC,
915 offsetof(struct ethtool_rx_flow_spec, location), -1 },
916 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
917 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
918 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
919 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
920 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
921 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
922 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
923 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
924 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
925};
926
927static int rxclass_get_long(char *str, long long *val, int size)
928{
929 long long max = ~0ULL >> (65 - size);
930 char *endp;
931
932 errno = 0;
933
934 *val = strtoll(str, &endp, 0);
935
936 if (*endp || errno || (*val > max) || (*val < ~max))
937 return -1;
938
939 return 0;
940}
941
942static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
943{
944 long long max = ~0ULL >> (64 - size);
945 char *endp;
946
947 errno = 0;
948
949 *val = strtoull(str, &endp, 0);
950
951 if (*endp || errno || (*val > max))
952 return -1;
953
954 return 0;
955}
956
957static int rxclass_get_ipv4(char *str, __be32 *val)
958{
959 if (!inet_pton(AF_INET, str, val))
960 return -1;
961
962 return 0;
963}
964
Edward Creeb56b9512016-03-17 19:17:16 +0000965static int rxclass_get_ipv6(char *str, __be32 *val)
966{
967 if (!inet_pton(AF_INET6, str, val))
968 return -1;
969
970 return 0;
971}
972
Alexander Duyck8d63f722011-05-04 11:41:51 -0700973static int rxclass_get_ether(char *str, unsigned char *val)
974{
975 unsigned int buf[ETH_ALEN];
976 int count;
977
978 if (!strchr(str, ':'))
979 return -1;
980
981 count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
982 &buf[0], &buf[1], &buf[2],
983 &buf[3], &buf[4], &buf[5]);
984
985 if (count != ETH_ALEN)
986 return -1;
987
988 do {
989 count--;
990 val[count] = buf[count];
991 } while (count);
992
993 return 0;
994}
995
996static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
997 const struct rule_opts *opt)
998{
999 unsigned long long mask = ~0ULL;
1000 int err = 0;
1001
1002 if (*flags & opt->flag)
1003 return -1;
1004
1005 *flags |= opt->flag;
1006
1007 switch (opt->type) {
1008 case OPT_S32: {
1009 long long val;
1010 err = rxclass_get_long(str, &val, 32);
1011 if (err)
1012 return -1;
1013 *(int *)&p[opt->offset] = (int)val;
1014 if (opt->moffset >= 0)
1015 *(int *)&p[opt->moffset] = (int)mask;
1016 break;
1017 }
1018 case OPT_U8: {
1019 unsigned long long val;
1020 err = rxclass_get_ulong(str, &val, 8);
1021 if (err)
1022 return -1;
1023 *(u8 *)&p[opt->offset] = (u8)val;
1024 if (opt->moffset >= 0)
1025 *(u8 *)&p[opt->moffset] = (u8)mask;
1026 break;
1027 }
1028 case OPT_U16: {
1029 unsigned long long val;
1030 err = rxclass_get_ulong(str, &val, 16);
1031 if (err)
1032 return -1;
1033 *(u16 *)&p[opt->offset] = (u16)val;
1034 if (opt->moffset >= 0)
1035 *(u16 *)&p[opt->moffset] = (u16)mask;
1036 break;
1037 }
1038 case OPT_U32: {
1039 unsigned long long val;
1040 err = rxclass_get_ulong(str, &val, 32);
1041 if (err)
1042 return -1;
1043 *(u32 *)&p[opt->offset] = (u32)val;
1044 if (opt->moffset >= 0)
1045 *(u32 *)&p[opt->moffset] = (u32)mask;
1046 break;
1047 }
1048 case OPT_U64: {
1049 unsigned long long val;
1050 err = rxclass_get_ulong(str, &val, 64);
1051 if (err)
1052 return -1;
1053 *(u64 *)&p[opt->offset] = (u64)val;
1054 if (opt->moffset >= 0)
1055 *(u64 *)&p[opt->moffset] = (u64)mask;
1056 break;
1057 }
Jacob Keller36ee7122017-03-23 23:07:13 -07001058 case OPT_RING_VF: {
1059 unsigned long long val;
1060 err = rxclass_get_ulong(str, &val, 8);
1061 if (err)
1062 return -1;
Jacob Kellerd7b70e52018-02-26 10:49:56 -08001063
1064 /* The ring_cookie uses 0 to indicate the rule targets the
1065 * main function, so add 1 to the value in order to target the
1066 * correct virtual function.
1067 */
1068 val++;
1069
Jacob Keller36ee7122017-03-23 23:07:13 -07001070 *(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING_VF;
Ivan Vecera1286ea02018-06-08 11:20:06 +02001071 *(u64 *)&p[opt->offset] |= (u64)val << ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
Jacob Keller36ee7122017-03-23 23:07:13 -07001072 break;
1073 }
1074 case OPT_RING_QUEUE: {
1075 unsigned long long val;
1076 err = rxclass_get_ulong(str, &val, 32);
1077 if (err)
1078 return -1;
1079 *(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING;
1080 *(u64 *)&p[opt->offset] |= (u64)val;
1081 break;
1082 }
Alexander Duyck8d63f722011-05-04 11:41:51 -07001083 case OPT_BE16: {
1084 unsigned long long val;
1085 err = rxclass_get_ulong(str, &val, 16);
1086 if (err)
1087 return -1;
1088 *(__be16 *)&p[opt->offset] = htons((u16)val);
1089 if (opt->moffset >= 0)
1090 *(__be16 *)&p[opt->moffset] = (__be16)mask;
1091 break;
1092 }
1093 case OPT_BE32: {
1094 unsigned long long val;
1095 err = rxclass_get_ulong(str, &val, 32);
1096 if (err)
1097 return -1;
1098 *(__be32 *)&p[opt->offset] = htonl((u32)val);
1099 if (opt->moffset >= 0)
1100 *(__be32 *)&p[opt->moffset] = (__be32)mask;
1101 break;
1102 }
1103 case OPT_BE64: {
1104 unsigned long long val;
1105 err = rxclass_get_ulong(str, &val, 64);
1106 if (err)
1107 return -1;
1108 *(__be64 *)&p[opt->offset] = htonll((u64)val);
1109 if (opt->moffset >= 0)
1110 *(__be64 *)&p[opt->moffset] = (__be64)mask;
1111 break;
1112 }
1113 case OPT_IP4: {
1114 __be32 val;
1115 err = rxclass_get_ipv4(str, &val);
1116 if (err)
1117 return -1;
1118 *(__be32 *)&p[opt->offset] = val;
1119 if (opt->moffset >= 0)
1120 *(__be32 *)&p[opt->moffset] = (__be32)mask;
1121 break;
1122 }
Edward Creeb56b9512016-03-17 19:17:16 +00001123 case OPT_IP6: {
1124 __be32 val[4];
1125 err = rxclass_get_ipv6(str, val);
1126 if (err)
1127 return -1;
1128 memcpy(&p[opt->offset], val, sizeof(val));
1129 if (opt->moffset >= 0)
1130 memset(&p[opt->moffset], mask, sizeof(val));
1131 break;
1132 }
Alexander Duyck8d63f722011-05-04 11:41:51 -07001133 case OPT_MAC: {
1134 unsigned char val[ETH_ALEN];
1135 err = rxclass_get_ether(str, val);
1136 if (err)
1137 return -1;
1138 memcpy(&p[opt->offset], val, ETH_ALEN);
1139 if (opt->moffset >= 0)
1140 memcpy(&p[opt->moffset], &mask, ETH_ALEN);
1141 break;
1142 }
1143 case OPT_NONE:
1144 default:
1145 return -1;
1146 }
1147
1148 return 0;
1149}
1150
1151static int rxclass_get_mask(char *str, unsigned char *p,
1152 const struct rule_opts *opt)
1153{
1154 int err = 0;
1155
1156 if (opt->moffset < 0)
1157 return -1;
1158
1159 switch (opt->type) {
1160 case OPT_S32: {
1161 long long val;
1162 err = rxclass_get_long(str, &val, 32);
1163 if (err)
1164 return -1;
1165 *(int *)&p[opt->moffset] = ~(int)val;
1166 break;
1167 }
1168 case OPT_U8: {
1169 unsigned long long val;
1170 err = rxclass_get_ulong(str, &val, 8);
1171 if (err)
1172 return -1;
1173 *(u8 *)&p[opt->moffset] = ~(u8)val;
1174 break;
1175 }
1176 case OPT_U16: {
1177 unsigned long long val;
1178 err = rxclass_get_ulong(str, &val, 16);
1179 if (err)
1180 return -1;
1181 *(u16 *)&p[opt->moffset] = ~(u16)val;
1182 break;
1183 }
1184 case OPT_U32: {
1185 unsigned long long val;
1186 err = rxclass_get_ulong(str, &val, 32);
1187 if (err)
1188 return -1;
1189 *(u32 *)&p[opt->moffset] = ~(u32)val;
1190 break;
1191 }
1192 case OPT_U64: {
1193 unsigned long long val;
1194 err = rxclass_get_ulong(str, &val, 64);
1195 if (err)
1196 return -1;
1197 *(u64 *)&p[opt->moffset] = ~(u64)val;
1198 break;
1199 }
1200 case OPT_BE16: {
1201 unsigned long long val;
1202 err = rxclass_get_ulong(str, &val, 16);
1203 if (err)
1204 return -1;
1205 *(__be16 *)&p[opt->moffset] = ~htons((u16)val);
1206 break;
1207 }
1208 case OPT_BE32: {
1209 unsigned long long val;
1210 err = rxclass_get_ulong(str, &val, 32);
1211 if (err)
1212 return -1;
1213 *(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
1214 break;
1215 }
1216 case OPT_BE64: {
1217 unsigned long long val;
1218 err = rxclass_get_ulong(str, &val, 64);
1219 if (err)
1220 return -1;
1221 *(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
1222 break;
1223 }
1224 case OPT_IP4: {
1225 __be32 val;
1226 err = rxclass_get_ipv4(str, &val);
1227 if (err)
1228 return -1;
1229 *(__be32 *)&p[opt->moffset] = ~val;
1230 break;
1231 }
Edward Creeb56b9512016-03-17 19:17:16 +00001232 case OPT_IP6: {
1233 __be32 val[4], *field;
1234 int i;
1235 err = rxclass_get_ipv6(str, val);
1236 if (err)
1237 return -1;
1238 field = (__be32 *)&p[opt->moffset];
1239 for (i = 0; i < 4; i++)
1240 field[i] = ~val[i];
1241 break;
1242 }
Alexander Duyck8d63f722011-05-04 11:41:51 -07001243 case OPT_MAC: {
1244 unsigned char val[ETH_ALEN];
1245 int i;
1246 err = rxclass_get_ether(str, val);
1247 if (err)
1248 return -1;
1249
1250 for (i = 0; i < ETH_ALEN; i++)
1251 val[i] = ~val[i];
1252
1253 memcpy(&p[opt->moffset], val, ETH_ALEN);
1254 break;
1255 }
1256 case OPT_NONE:
1257 default:
1258 return -1;
1259 }
1260
1261 return 0;
1262}
1263
Ben Hutchings127f8062011-10-29 01:15:34 +01001264int rxclass_parse_ruleopts(struct cmd_context *ctx,
Edward Creef5d55b92018-03-09 15:04:12 +00001265 struct ethtool_rx_flow_spec *fsp, __u32 *rss_context)
Alexander Duyck8d63f722011-05-04 11:41:51 -07001266{
1267 const struct rule_opts *options;
1268 unsigned char *p = (unsigned char *)fsp;
1269 int i = 0, n_opts, err;
1270 u32 flags = 0;
1271 int flow_type;
Ben Hutchings127f8062011-10-29 01:15:34 +01001272 int argc = ctx->argc;
1273 char **argp = ctx->argp;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001274
1275 if (argc < 1)
1276 goto syntax_err;
1277
1278 if (!strcmp(argp[0], "tcp4"))
1279 flow_type = TCP_V4_FLOW;
1280 else if (!strcmp(argp[0], "udp4"))
1281 flow_type = UDP_V4_FLOW;
1282 else if (!strcmp(argp[0], "sctp4"))
1283 flow_type = SCTP_V4_FLOW;
1284 else if (!strcmp(argp[0], "ah4"))
1285 flow_type = AH_V4_FLOW;
1286 else if (!strcmp(argp[0], "esp4"))
1287 flow_type = ESP_V4_FLOW;
1288 else if (!strcmp(argp[0], "ip4"))
Edward Creeb56b9512016-03-17 19:17:16 +00001289 flow_type = IPV4_USER_FLOW;
1290 else if (!strcmp(argp[0], "tcp6"))
1291 flow_type = TCP_V6_FLOW;
1292 else if (!strcmp(argp[0], "udp6"))
1293 flow_type = UDP_V6_FLOW;
1294 else if (!strcmp(argp[0], "sctp6"))
1295 flow_type = SCTP_V6_FLOW;
1296 else if (!strcmp(argp[0], "ah6"))
1297 flow_type = AH_V6_FLOW;
1298 else if (!strcmp(argp[0], "esp6"))
1299 flow_type = ESP_V6_FLOW;
1300 else if (!strcmp(argp[0], "ip6"))
1301 flow_type = IPV6_USER_FLOW;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001302 else if (!strcmp(argp[0], "ether"))
1303 flow_type = ETHER_FLOW;
1304 else
1305 goto syntax_err;
1306
1307 switch (flow_type) {
1308 case TCP_V4_FLOW:
1309 case UDP_V4_FLOW:
1310 case SCTP_V4_FLOW:
1311 options = rule_nfc_tcp_ip4;
1312 n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
1313 break;
1314 case AH_V4_FLOW:
1315 case ESP_V4_FLOW:
1316 options = rule_nfc_esp_ip4;
1317 n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
1318 break;
Edward Creeb56b9512016-03-17 19:17:16 +00001319 case IPV4_USER_FLOW:
Alexander Duyck8d63f722011-05-04 11:41:51 -07001320 options = rule_nfc_usr_ip4;
1321 n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
1322 break;
Edward Creeb56b9512016-03-17 19:17:16 +00001323 case TCP_V6_FLOW:
1324 case UDP_V6_FLOW:
1325 case SCTP_V6_FLOW:
1326 options = rule_nfc_tcp_ip6;
1327 n_opts = ARRAY_SIZE(rule_nfc_tcp_ip6);
1328 break;
1329 case AH_V6_FLOW:
1330 case ESP_V6_FLOW:
1331 options = rule_nfc_esp_ip6;
1332 n_opts = ARRAY_SIZE(rule_nfc_esp_ip6);
1333 break;
1334 case IPV6_USER_FLOW:
1335 options = rule_nfc_usr_ip6;
1336 n_opts = ARRAY_SIZE(rule_nfc_usr_ip6);
1337 break;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001338 case ETHER_FLOW:
1339 options = rule_nfc_ether;
1340 n_opts = ARRAY_SIZE(rule_nfc_ether);
1341 break;
1342 default:
1343 fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
1344 return -1;
1345 }
1346
1347 memset(p, 0, sizeof(*fsp));
1348 fsp->flow_type = flow_type;
Ben Hutchings578e6a52012-01-03 20:21:45 +00001349 fsp->location = RX_CLS_LOC_ANY;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001350
1351 for (i = 1; i < argc;) {
1352 const struct rule_opts *opt;
1353 int idx;
Edward Creef5d55b92018-03-09 15:04:12 +00001354
1355 /* special handling for 'context %d' as it doesn't go in
1356 * the struct ethtool_rx_flow_spec
1357 */
1358 if (!strcmp(argp[i], "context")) {
1359 unsigned long long val;
1360
1361 i++;
1362 if (i >= argc) {
1363 fprintf(stderr, "'context' missing value\n");
1364 return -1;
1365 }
1366
1367 if (rxclass_get_ulong(argp[i], &val, 32)) {
1368 fprintf(stderr, "Invalid context value[%s]\n",
1369 argp[i]);
1370 return -1;
1371 }
1372
1373 /* Can't use the ALLOC special value as the context ID
1374 * of a filter to insert
1375 */
1376 if ((__u32)val == ETH_RXFH_CONTEXT_ALLOC) {
1377 fprintf(stderr, "Bad context value %x\n",
1378 (__u32)val);
1379 return -1;
1380 }
1381
1382 *rss_context = (__u32)val;
1383 fsp->flow_type |= FLOW_RSS;
1384 i++;
1385 continue;
1386 }
1387
Alexander Duyck8d63f722011-05-04 11:41:51 -07001388 for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
1389 char mask_name[16];
1390
1391 if (strcmp(argp[i], opt->name))
1392 continue;
1393
1394 i++;
1395 if (i >= argc)
1396 break;
1397
1398 err = rxclass_get_val(argp[i], p, &flags, opt);
1399 if (err) {
1400 fprintf(stderr, "Invalid %s value[%s]\n",
1401 opt->name, argp[i]);
1402 return -1;
1403 }
1404
1405 i++;
1406 if (i >= argc)
1407 break;
1408
1409 sprintf(mask_name, "%s-mask", opt->name);
1410 if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
1411 break;
1412
1413 i++;
1414 if (i >= argc)
1415 goto syntax_err;
1416
1417 err = rxclass_get_mask(argp[i], p, opt);
1418 if (err) {
1419 fprintf(stderr, "Invalid %s mask[%s]\n",
1420 opt->name, argp[i]);
1421 return -1;
1422 }
1423
1424 i++;
1425
1426 break;
1427 }
1428 if (idx == n_opts) {
1429 fprintf(stdout, "Add rule, unrecognized option[%s]\n",
1430 argp[i]);
1431 return -1;
1432 }
1433 }
1434
Jacob Keller36ee7122017-03-23 23:07:13 -07001435 if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_QUEUE)) {
1436 fprintf(stderr, "action and queue are not compatible\n");
1437 return -1;
1438 }
1439
1440 if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_VF)) {
1441 fprintf(stderr, "action and vf are not compatible\n");
1442 return -1;
1443 }
1444
Edward Creeb56b9512016-03-17 19:17:16 +00001445 if (flow_type == IPV4_USER_FLOW)
Sebastian Pöhn5ab18de2011-06-30 10:41:20 +02001446 fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001447 if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
1448 fsp->flow_type |= FLOW_EXT;
Yan Burmanb29aa902012-12-11 14:03:56 +02001449 if (flags & NFC_FLAG_MAC_ADDR)
1450 fsp->flow_type |= FLOW_MAC_EXT;
Alexander Duyck8d63f722011-05-04 11:41:51 -07001451
1452 return 0;
1453
1454syntax_err:
1455 fprintf(stderr, "Add rule, invalid syntax\n");
1456 return -1;
1457}