summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2011-05-04 11:41:51 -0700
committerBen Hutchings <bhutchings@solarflare.com>2011-05-13 02:13:07 +0100
commit8d63f72ccdcb1b19358d753a8f48f08dcd2136f0 (patch)
tree0f832dc5abc322355eb045a07b321e918b187497 /ethtool.c
parent9a7baa6c15344dee34d5a9dd0308dc43fc29c488 (diff)
downloadethtool-8d63f72ccdcb1b19358d753a8f48f08dcd2136f0.tar.gz
Add RX packet classification interface
This patch was originally introduced as: [PATCH 1/3] [ethtool] Add rx pkt classification interface Signed-off-by: Santwona Behera <santwona.behera@sun.com> http://patchwork.ozlabs.org/patch/23223/ I removed the local caching of rules. I dropped the use of regions as there were multiple issues found. A network flow classifier is defined using the exact same syntax as n-tuple, and the tool will correct for the fact that NFC uses the 1's compliment of the n-tuple mask. I also updated the ordering of new rules being added. All new rules will take the highest numbered open rule when no location is specified. I split out the addition of bitops and the updates to documentation into separate patches. This makes the total patch size a bit more manageable since the addition of NFC and the merging of it with n-tuple were combined into this patch. If we setup a rule and the device has the NTUPLE flag set we will first try to use set_rx_ntuple. If that fails with EOPNOTSUPP we then will attempt to use the network flow classifier rule insertion. Updated the output to make use of the updated network flow classifier extensions that have been accepted into the kernel. Merged the documentation update into this patch. In addition the documentation changes were made such that there is only one listing of the individual options and they are all listed as optional. Several fixes to address things such as the fact that we were maintaining the table logic even though we only need it for displaying all of the rules, or when adding a rule with no location specified. As such all of the logic for deleting or finding rules in the table has been removed. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> [bwh: Abbreviated the above commit message. Fixed a minor formatting error in the manual page additions.] Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c400
1 files changed, 227 insertions, 173 deletions
diff --git a/ethtool.c b/ethtool.c
index 24d4e4f..2e04d87 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -6,6 +6,7 @@
* Kernel 2.4 update Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
* Wake-on-LAN,natsemi,misc support by Tim Hockin <thockin@sun.com>
* Portions Copyright 2002 Intel
+ * Portions Copyright (C) Sun Microsystems 2008
* do_test support by Eli Kupermann <eli.kupermann@intel.com>
* ETHTOOL_PHYS_ID support by Chris Leech <christopher.leech@intel.com>
* e1000 support by Scott Feldman <scott.feldman@intel.com>
@@ -14,6 +15,7 @@
* amd8111e support by Reeja John <reeja.john@amd.com>
* long arguments by Andi Kleen.
* SMSC LAN911x support by Steve Glendinning <steve.glendinning@smsc.com>
+ * Rx Network Flow Control configuration support <santwona.behera@sun.com>
* Various features by Ben Hutchings <bhutchings@solarflare.com>;
* Copyright 2009, 2010 Solarflare Communications
*
@@ -85,14 +87,13 @@ static int do_gstats(int fd, struct ifreq *ifr);
static int rxflow_str_to_type(const char *str);
static int parse_rxfhashopts(char *optstr, u32 *data);
static char *unparse_rxfhashopts(u64 opts);
-static void parse_rxntupleopts(int argc, char **argp, int first_arg);
static int dump_rxfhash(int fhash, u64 val);
static int do_srxclass(int fd, struct ifreq *ifr);
static int do_grxclass(int fd, struct ifreq *ifr);
static int do_grxfhindir(int fd, struct ifreq *ifr);
static int do_srxfhindir(int fd, struct ifreq *ifr);
-static int do_srxntuple(int fd, struct ifreq *ifr);
-static int do_grxntuple(int fd, struct ifreq *ifr);
+static int do_srxclsrule(int fd, struct ifreq *ifr);
+static int do_grxclsrule(int fd, struct ifreq *ifr);
static int do_flash(int fd, struct ifreq *ifr);
static int do_permaddr(int fd, struct ifreq *ifr);
@@ -123,8 +124,8 @@ static enum {
MODE_SNFC,
MODE_GRXFHINDIR,
MODE_SRXFHINDIR,
- MODE_SNTUPLE,
- MODE_GNTUPLE,
+ MODE_SCLSRULE,
+ MODE_GCLSRULE,
MODE_FLASHDEV,
MODE_PERMADDR,
} mode = MODE_GSET;
@@ -230,22 +231,28 @@ static struct option {
"indirection" },
{ "-X", "--set-rxfh-indir", MODE_SRXFHINDIR, "Set Rx flow hash indirection",
" equal N | weight W0 W1 ...\n" },
- { "-U", "--config-ntuple", MODE_SNTUPLE, "Configure Rx ntuple filters "
+ { "-U", "--config-ntuple", MODE_SCLSRULE, "Configure Rx ntuple filters "
"and actions",
- " { flow-type tcp4|udp4|sctp4\n"
- " [ src-ip ADDR [src-ip-mask MASK] ]\n"
- " [ dst-ip ADDR [dst-ip-mask MASK] ]\n"
- " [ src-port PORT [src-port-mask MASK] ]\n"
- " [ dst-port PORT [dst-port-mask MASK] ]\n"
- " | flow-type ether\n"
- " [ src MAC-ADDR [src-mask MASK] ]\n"
- " [ dst MAC-ADDR [dst-mask MASK] ]\n"
- " [ proto N [proto-mask MASK] ] }\n"
- " [ vlan VLAN-TAG [vlan-mask MASK] ]\n"
- " [ user-def DATA [user-def-mask MASK] ]\n"
- " action N\n" },
- { "-u", "--show-ntuple", MODE_GNTUPLE,
- "Get Rx ntuple filters and actions\n" },
+ " [ delete %d ] |\n"
+ " [ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
+ " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+ " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+ " [ proto %d [m %x] ]\n"
+ " [ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+ " [ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+ " [ tos %d [m %x] ]\n"
+ " [ l4proto %d [m %x] ]\n"
+ " [ src-port %d [m %x] ]\n"
+ " [ dst-port %d [m %x] ]\n"
+ " [ spi %d [m %x] ]\n"
+ " [ vlan-etype %x [m %x] ]\n"
+ " [ vlan %x [m %x] ]\n"
+ " [ user-def %x [m %x] ]\n"
+ " [ action %d ]\n"
+ " [ loc %d]]\n" },
+ { "-u", "--show-ntuple", MODE_GCLSRULE,
+ "Get Rx ntuple filters and actions",
+ " [ rule %d ]\n"},
{ "-P", "--show-permaddr", MODE_PERMADDR,
"Show permanent hardware address" },
{ "-h", "--help", MODE_HELP, "Show this help" },
@@ -371,26 +378,6 @@ static u32 rx_fhash_val = 0;
static int rx_fhash_changed = 0;
static int rxfhindir_equal = 0;
static char **rxfhindir_weight = NULL;
-static int sntuple_changed = 0;
-static struct ethtool_rx_ntuple_flow_spec ntuple_fs;
-static int ntuple_ip4src_seen = 0;
-static int ntuple_ip4src_mask_seen = 0;
-static int ntuple_ip4dst_seen = 0;
-static int ntuple_ip4dst_mask_seen = 0;
-static int ntuple_psrc_seen = 0;
-static int ntuple_psrc_mask_seen = 0;
-static int ntuple_pdst_seen = 0;
-static int ntuple_pdst_mask_seen = 0;
-static int ntuple_ether_dst_seen = 0;
-static int ntuple_ether_dst_mask_seen = 0;
-static int ntuple_ether_src_seen = 0;
-static int ntuple_ether_src_mask_seen = 0;
-static int ntuple_ether_proto_seen = 0;
-static int ntuple_ether_proto_mask_seen = 0;
-static int ntuple_vlan_tag_seen = 0;
-static int ntuple_vlan_tag_mask_seen = 0;
-static int ntuple_user_def_seen = 0;
-static int ntuple_user_def_mask_seen = 0;
static char *flash_file = NULL;
static int flash = -1;
static int flash_region = -1;
@@ -399,6 +386,11 @@ static int msglvl_changed;
static u32 msglvl_wanted = 0;
static u32 msglvl_mask = 0;
+static int rx_class_rule_get = -1;
+static int rx_class_rule_del = -1;
+static int rx_class_rule_added = 0;
+static struct ethtool_rx_flow_spec rx_rule_fs;
+
static enum {
ONLINE=0,
OFFLINE,
@@ -511,58 +503,6 @@ static struct cmdline_info cmdline_coalesce[] = {
{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, &ecoal.tx_max_coalesced_frames_high },
};
-static struct cmdline_info cmdline_ntuple_tcp_ip4[] = {
- { "src-ip", CMDL_IP4, &ntuple_fs.h_u.tcp_ip4_spec.ip4src, NULL,
- 0, &ntuple_ip4src_seen },
- { "src-ip-mask", CMDL_IP4, &ntuple_fs.m_u.tcp_ip4_spec.ip4src, NULL,
- 0, &ntuple_ip4src_mask_seen },
- { "dst-ip", CMDL_IP4, &ntuple_fs.h_u.tcp_ip4_spec.ip4dst, NULL,
- 0, &ntuple_ip4dst_seen },
- { "dst-ip-mask", CMDL_IP4, &ntuple_fs.m_u.tcp_ip4_spec.ip4dst, NULL,
- 0, &ntuple_ip4dst_mask_seen },
- { "src-port", CMDL_BE16, &ntuple_fs.h_u.tcp_ip4_spec.psrc, NULL,
- 0, &ntuple_psrc_seen },
- { "src-port-mask", CMDL_BE16, &ntuple_fs.m_u.tcp_ip4_spec.psrc, NULL,
- 0, &ntuple_psrc_mask_seen },
- { "dst-port", CMDL_BE16, &ntuple_fs.h_u.tcp_ip4_spec.pdst, NULL,
- 0, &ntuple_pdst_seen },
- { "dst-port-mask", CMDL_BE16, &ntuple_fs.m_u.tcp_ip4_spec.pdst, NULL,
- 0, &ntuple_pdst_mask_seen },
- { "vlan", CMDL_U16, &ntuple_fs.vlan_tag, NULL,
- 0, &ntuple_vlan_tag_seen },
- { "vlan-mask", CMDL_U16, &ntuple_fs.vlan_tag_mask, NULL,
- 0, &ntuple_vlan_tag_mask_seen },
- { "user-def", CMDL_U64, &ntuple_fs.data, NULL,
- 0, &ntuple_user_def_seen },
- { "user-def-mask", CMDL_U64, &ntuple_fs.data_mask, NULL,
- 0, &ntuple_user_def_mask_seen },
- { "action", CMDL_S32, &ntuple_fs.action, NULL },
-};
-
-static struct cmdline_info cmdline_ntuple_ether[] = {
- { "dst", CMDL_MAC, ntuple_fs.h_u.ether_spec.h_dest, NULL,
- 0, &ntuple_ether_dst_seen },
- { "dst-mask", CMDL_MAC, ntuple_fs.m_u.ether_spec.h_dest, NULL,
- 0, &ntuple_ether_dst_mask_seen },
- { "src", CMDL_MAC, ntuple_fs.h_u.ether_spec.h_source, NULL,
- 0, &ntuple_ether_src_seen },
- { "src-mask", CMDL_MAC, ntuple_fs.m_u.ether_spec.h_source, NULL,
- 0, &ntuple_ether_src_mask_seen },
- { "proto", CMDL_BE16, &ntuple_fs.h_u.ether_spec.h_proto, NULL,
- 0, &ntuple_ether_proto_seen },
- { "proto-mask", CMDL_BE16, &ntuple_fs.m_u.ether_spec.h_proto, NULL,
- 0, &ntuple_ether_proto_mask_seen },
- { "vlan", CMDL_U16, &ntuple_fs.vlan_tag, NULL,
- 0, &ntuple_vlan_tag_seen },
- { "vlan-mask", CMDL_U16, &ntuple_fs.vlan_tag_mask, NULL,
- 0, &ntuple_vlan_tag_mask_seen },
- { "user-def", CMDL_U64, &ntuple_fs.data, NULL,
- 0, &ntuple_user_def_seen },
- { "user-def-mask", CMDL_U64, &ntuple_fs.data_mask, NULL,
- 0, &ntuple_user_def_mask_seen },
- { "action", CMDL_S32, &ntuple_fs.action, NULL },
-};
-
static struct cmdline_info cmdline_msglvl[] = {
{ "drv", CMDL_FLAG, &msglvl_wanted, NULL,
NETIF_MSG_DRV, &msglvl_mask },
@@ -833,8 +773,8 @@ static void parse_cmdline(int argc, char **argp)
(mode == MODE_SNFC) ||
(mode == MODE_GRXFHINDIR) ||
(mode == MODE_SRXFHINDIR) ||
- (mode == MODE_SNTUPLE) ||
- (mode == MODE_GNTUPLE) ||
+ (mode == MODE_SCLSRULE) ||
+ (mode == MODE_GCLSRULE) ||
(mode == MODE_PHYS_ID) ||
(mode == MODE_FLASHDEV) ||
(mode == MODE_PERMADDR)) {
@@ -918,16 +858,45 @@ static void parse_cmdline(int argc, char **argp)
i = argc;
break;
}
- if (mode == MODE_SNTUPLE) {
+ if (mode == MODE_SCLSRULE) {
if (!strcmp(argp[i], "flow-type")) {
i += 1;
if (i >= argc) {
exit_bad_args();
break;
}
- parse_rxntupleopts(argc, argp, i);
- i = argc;
- break;
+ if (rxclass_parse_ruleopts(&argp[i],
+ argc - i,
+ &rx_rule_fs) < 0) {
+ exit_bad_args();
+ } else {
+ i = argc;
+ rx_class_rule_added = 1;
+ }
+ } else if (!strcmp(argp[i], "delete")) {
+ i += 1;
+ if (i >= argc) {
+ exit_bad_args();
+ break;
+ }
+ rx_class_rule_del =
+ get_uint_range(argp[i], 0,
+ INT_MAX);
+ } else {
+ exit_bad_args();
+ }
+ break;
+ }
+ if (mode == MODE_GCLSRULE) {
+ if (!strcmp(argp[i], "rule")) {
+ i += 1;
+ if (i >= argc) {
+ exit_bad_args();
+ break;
+ }
+ rx_class_rule_get =
+ get_uint_range(argp[i], 0,
+ INT_MAX);
} else {
exit_bad_args();
}
@@ -1598,66 +1567,6 @@ static char *unparse_rxfhashopts(u64 opts)
return buf;
}
-static void parse_rxntupleopts(int argc, char **argp, int i)
-{
- ntuple_fs.flow_type = rxflow_str_to_type(argp[i]);
-
- switch (ntuple_fs.flow_type) {
- case TCP_V4_FLOW:
- case UDP_V4_FLOW:
- case SCTP_V4_FLOW:
- parse_generic_cmdline(argc, argp, i + 1,
- &sntuple_changed,
- cmdline_ntuple_tcp_ip4,
- ARRAY_SIZE(cmdline_ntuple_tcp_ip4));
- if (!ntuple_ip4src_seen)
- ntuple_fs.m_u.tcp_ip4_spec.ip4src = 0xffffffff;
- if (!ntuple_ip4dst_seen)
- ntuple_fs.m_u.tcp_ip4_spec.ip4dst = 0xffffffff;
- if (!ntuple_psrc_seen)
- ntuple_fs.m_u.tcp_ip4_spec.psrc = 0xffff;
- if (!ntuple_pdst_seen)
- ntuple_fs.m_u.tcp_ip4_spec.pdst = 0xffff;
- ntuple_fs.m_u.tcp_ip4_spec.tos = 0xff;
- break;
- case ETHER_FLOW:
- parse_generic_cmdline(argc, argp, i + 1,
- &sntuple_changed,
- cmdline_ntuple_ether,
- ARRAY_SIZE(cmdline_ntuple_ether));
- if (!ntuple_ether_dst_seen)
- memset(ntuple_fs.m_u.ether_spec.h_dest, 0xff, ETH_ALEN);
- if (!ntuple_ether_src_seen)
- memset(ntuple_fs.m_u.ether_spec.h_source, 0xff,
- ETH_ALEN);
- if (!ntuple_ether_proto_seen)
- ntuple_fs.m_u.ether_spec.h_proto = 0xffff;
- break;
- default:
- fprintf(stderr, "Unsupported flow type \"%s\"\n", argp[i]);
- exit(106);
- break;
- }
-
- if (!ntuple_vlan_tag_seen)
- ntuple_fs.vlan_tag_mask = 0xffff;
- if (!ntuple_user_def_seen)
- ntuple_fs.data_mask = 0xffffffffffffffffULL;
-
- if ((ntuple_ip4src_mask_seen && !ntuple_ip4src_seen) ||
- (ntuple_ip4dst_mask_seen && !ntuple_ip4dst_seen) ||
- (ntuple_psrc_mask_seen && !ntuple_psrc_seen) ||
- (ntuple_pdst_mask_seen && !ntuple_pdst_seen) ||
- (ntuple_ether_dst_mask_seen && !ntuple_ether_dst_seen) ||
- (ntuple_ether_src_mask_seen && !ntuple_ether_src_seen) ||
- (ntuple_ether_proto_mask_seen && !ntuple_ether_proto_seen) ||
- (ntuple_vlan_tag_mask_seen && !ntuple_vlan_tag_seen) ||
- (ntuple_user_def_mask_seen && !ntuple_user_def_seen)) {
- fprintf(stderr, "Cannot specify mask without value\n");
- exit(107);
- }
-}
-
static struct {
const char *name;
int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
@@ -2019,10 +1928,10 @@ static int doit(void)
return do_grxfhindir(fd, &ifr);
} else if (mode == MODE_SRXFHINDIR) {
return do_srxfhindir(fd, &ifr);
- } else if (mode == MODE_SNTUPLE) {
- return do_srxntuple(fd, &ifr);
- } else if (mode == MODE_GNTUPLE) {
- return do_grxntuple(fd, &ifr);
+ } else if (mode == MODE_SCLSRULE) {
+ return do_srxclsrule(fd, &ifr);
+ } else if (mode == MODE_GCLSRULE) {
+ return do_grxclsrule(fd, &ifr);
} else if (mode == MODE_FLASHDEV) {
return do_flash(fd, &ifr);
} else if (mode == MODE_PERMADDR) {
@@ -3155,21 +3064,143 @@ static int do_permaddr(int fd, struct ifreq *ifr)
return err;
}
+static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
+ struct ethtool_rx_ntuple_flow_spec *ntuple)
+{
+ size_t i;
+
+ /* verify location is not specified */
+ if (fsp->location != RX_CLS_LOC_UNSPEC)
+ return -1;
+
+ /* verify ring cookie can transfer to action */
+ if (fsp->ring_cookie > INT_MAX && fsp->ring_cookie < (u64)(-2))
+ return -1;
+
+ /* verify only one field is setting data field */
+ if ((fsp->flow_type & FLOW_EXT) &&
+ (fsp->m_ext.data[0] || fsp->m_ext.data[1]) &&
+ fsp->m_ext.vlan_etype)
+ return -1;
+
+ /* Set entire ntuple to ~0 to guarantee all masks are set */
+ memset(ntuple, ~0, sizeof(*ntuple));
+
+ /* set non-filter values */
+ ntuple->flow_type = fsp->flow_type;
+ ntuple->action = fsp->ring_cookie;
+
+ /*
+ * Copy over header union, they are identical in layout however
+ * the ntuple union contains additional padding on the end
+ */
+ memcpy(&ntuple->h_u, &fsp->h_u, sizeof(fsp->h_u));
+
+ /*
+ * The same rule mentioned above applies to the mask union. However,
+ * in addition we need to invert the mask bits to match the ntuple
+ * mask which is 1 for masked, versus 0 for masked as seen in nfc.
+ */
+ memcpy(&ntuple->m_u, &fsp->m_u, sizeof(fsp->m_u));
+ for (i = 0; i < sizeof(fsp->m_u); i++)
+ ntuple->m_u.hdata[i] ^= 0xFF;
+
+ /* copy extended fields */
+ if (fsp->flow_type & FLOW_EXT) {
+ ntuple->vlan_tag =
+ ntohs(fsp->h_ext.vlan_tci);
+ ntuple->vlan_tag_mask =
+ ~ntohs(fsp->m_ext.vlan_tci);
+ if (fsp->m_ext.vlan_etype) {
+ /*
+ * vlan_etype and user data are mutually exclusive
+ * in ntuple configuration as they occupy the same
+ * space.
+ */
+ if (fsp->m_ext.data[0] || fsp->m_ext.data[1])
+ return -1;
+ ntuple->data =
+ ntohl(fsp->h_ext.vlan_etype);
+ ntuple->data_mask =
+ ~(u64)ntohl(fsp->m_ext.vlan_etype);
+ } else {
+ ntuple->data =
+ (u64)ntohl(fsp->h_ext.data[0]) << 32;
+ ntuple->data |=
+ (u64)ntohl(fsp->h_ext.data[1]);
+ ntuple->data_mask =
+ (u64)ntohl(~fsp->m_ext.data[0]) << 32;
+ ntuple->data_mask |=
+ (u64)ntohl(~fsp->m_ext.data[1]);
+ }
+ }
+
+ return 0;
+}
+
static int do_srxntuple(int fd, struct ifreq *ifr)
{
+ struct ethtool_rx_ntuple ntuplecmd;
+ struct ethtool_value eval;
int err;
- if (sntuple_changed) {
- struct ethtool_rx_ntuple ntuplecmd;
+ /* attempt to convert the flow classifier to an ntuple classifier */
+ err = flow_spec_to_ntuple(&rx_rule_fs, &ntuplecmd.fs);
+ if (err)
+ return -1;
- ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
- memcpy(&ntuplecmd.fs, &ntuple_fs,
- sizeof(struct ethtool_rx_ntuple_flow_spec));
+ /*
+ * Check to see if the flag is set for N-tuple, this allows
+ * us to avoid the possible EINVAL response for the N-tuple
+ * flag not being set on the device
+ */
+ eval.cmd = ETHTOOL_GFLAGS;
+ ifr->ifr_data = (caddr_t)&eval;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+ if (err || !(eval.data & ETH_FLAG_NTUPLE))
+ return -1;
- ifr->ifr_data = (caddr_t)&ntuplecmd;
- err = ioctl(fd, SIOCETHTOOL, ifr);
- if (err < 0)
- perror("Cannot add new RX n-tuple filter");
+ /* send rule via N-tuple */
+ ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
+ ifr->ifr_data = (caddr_t)&ntuplecmd;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+
+ /*
+ * Display error only if reponse is something other than op not
+ * supported. It is possible that the interface uses the network
+ * flow classifier interface instead of N-tuple.
+ */
+ if (err && errno != EOPNOTSUPP)
+ perror("Cannot add new rule via N-tuple");
+
+ return err;
+}
+
+static int do_srxclsrule(int fd, struct ifreq *ifr)
+{
+ int err;
+
+ if (rx_class_rule_added) {
+ /* attempt to add rule via N-tuple specifier */
+ err = do_srxntuple(fd, ifr);
+ if (!err)
+ return 0;
+
+ /* attempt to add rule via network flow classifier */
+ err = rxclass_rule_ins(fd, ifr, &rx_rule_fs);
+ if (err < 0) {
+ fprintf(stderr, "Cannot insert"
+ " classification rule\n");
+ return 1;
+ }
+ } else if (rx_class_rule_del >= 0) {
+ err = rxclass_rule_del(fd, ifr, rx_class_rule_del);
+
+ if (err < 0) {
+ fprintf(stderr, "Cannot delete"
+ " classification rule\n");
+ return 1;
+ }
} else {
exit_bad_args();
}
@@ -3177,9 +3208,32 @@ static int do_srxntuple(int fd, struct ifreq *ifr)
return 0;
}
-static int do_grxntuple(int fd, struct ifreq *ifr)
+static int do_grxclsrule(int fd, struct ifreq *ifr)
{
- return 0;
+ struct ethtool_rxnfc nfccmd;
+ int err;
+
+ if (rx_class_rule_get >= 0) {
+ err = rxclass_rule_get(fd, ifr, rx_class_rule_get);
+ if (err < 0)
+ fprintf(stderr, "Cannot get RX classification rule\n");
+ return err ? 1 : 0;
+ }
+
+ nfccmd.cmd = ETHTOOL_GRXRINGS;
+ ifr->ifr_data = (caddr_t)&nfccmd;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+ if (err < 0)
+ perror("Cannot get RX rings");
+ else
+ fprintf(stdout, "%d RX rings available\n",
+ (int)nfccmd.data);
+
+ err = rxclass_rule_getall(fd, ifr);
+ if (err < 0)
+ fprintf(stderr, "RX classification rule retrieval failed\n");
+
+ return err ? 1 : 0;
}
static int send_ioctl(int fd, struct ifreq *ifr)