[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <56C1E7EC.8020700@solarflare.com>
Date: Mon, 15 Feb 2016 14:59:56 +0000
From: Edward Cree <ecree@...arflare.com>
To: Ben Hutchings <bwh@...nel.org>
CC: <netdev@...r.kernel.org>
Subject: [PATCH ethtool 2/3] Add IPv6 support to NFC
Signed-off-by: Edward Cree <ecree@...arflare.com>
---
ethtool.c | 21 +++++
rxclass.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 279 insertions(+), 14 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 92c40b8..f18ad73 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <stdio.h>
#include <stddef.h>
+#include <stdbool.h>
#include <errno.h>
#include <sys/utsname.h>
#include <limits.h>
@@ -3492,6 +3493,22 @@ static int do_permaddr(struct cmd_context *ctx)
return err;
}
+static bool flow_type_is_ntuple_supported(__u32 flow_type)
+{
+ switch (flow_type) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ case IPV4_USER_FLOW:
+ case ETHER_FLOW:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
struct ethtool_rx_ntuple_flow_spec *ntuple)
{
@@ -3515,6 +3532,10 @@ static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
fsp->m_ext.vlan_etype)
return -1;
+ /* IPv6 flow types are not supported by ntuple */
+ if (!flow_type_is_ntuple_supported(fsp->flow_type & ~FLOW_EXT))
+ return -1;
+
/* Set entire ntuple to ~0 to guarantee all masks are set */
memset(ntuple, ~0, sizeof(*ntuple));
diff --git a/rxclass.c b/rxclass.c
index cd686a3..d3150d5 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -39,6 +39,25 @@ static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
tos, tosm);
}
+static void rxclass_print_ipv6_rule(__be32 *sip, __be32 *sipm, __be32 *dip,
+ __be32 *dipm, u8 tclass, u8 tclassm)
+{
+ char sip_str[INET6_ADDRSTRLEN];
+ char sipm_str[INET6_ADDRSTRLEN];
+ char dip_str[INET6_ADDRSTRLEN];
+ char dipm_str[INET6_ADDRSTRLEN];
+
+ fprintf(stdout,
+ "\tSrc IP addr: %s mask: %s\n"
+ "\tDest IP addr: %s mask: %s\n"
+ "\tTraffic Class: 0x%x mask: 0x%x\n",
+ inet_ntop(AF_INET6, sip, sip_str, INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, sipm, sipm_str, INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, dip, dip_str, INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, dipm, dipm_str, INET6_ADDRSTRLEN),
+ tclass, tclassm);
+}
+
static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
{
if (fsp->flow_type & FLOW_EXT) {
@@ -127,7 +146,7 @@ static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
ntohl(fsp->h_u.esp_ip4_spec.spi),
ntohl(fsp->m_u.esp_ip4_spec.spi));
break;
- case IP_USER_FLOW:
+ case IPV4_USER_FLOW:
fprintf(stdout, "\tRule Type: Raw IPv4\n");
rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
fsp->m_u.usr_ip4_spec.ip4src,
@@ -143,6 +162,62 @@ static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ if (flow_type == TCP_V6_FLOW)
+ fprintf(stdout, "\tRule Type: TCP over IPv6\n");
+ else if (flow_type == UDP_V6_FLOW)
+ fprintf(stdout, "\tRule Type: UDP over IPv6\n");
+ else
+ fprintf(stdout, "\tRule Type: SCTP over IPv6\n");
+ rxclass_print_ipv6_rule(fsp->h_u.tcp_ip6_spec.ip6src,
+ fsp->m_u.tcp_ip6_spec.ip6src,
+ fsp->h_u.tcp_ip6_spec.ip6dst,
+ fsp->m_u.tcp_ip6_spec.ip6dst,
+ fsp->h_u.tcp_ip6_spec.tclass,
+ fsp->m_u.tcp_ip6_spec.tclass);
+ fprintf(stdout,
+ "\tSrc port: %d mask: 0x%x\n"
+ "\tDest port: %d mask: 0x%x\n",
+ ntohs(fsp->h_u.tcp_ip6_spec.psrc),
+ ntohs(fsp->m_u.tcp_ip6_spec.psrc),
+ ntohs(fsp->h_u.tcp_ip6_spec.pdst),
+ ntohs(fsp->m_u.tcp_ip6_spec.pdst));
+ break;
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ if (flow_type == AH_V6_FLOW)
+ fprintf(stdout, "\tRule Type: IPSEC AH over IPv6\n");
+ else
+ fprintf(stdout, "\tRule Type: IPSEC ESP over IPv6\n");
+ rxclass_print_ipv6_rule(fsp->h_u.ah_ip6_spec.ip6src,
+ fsp->m_u.ah_ip6_spec.ip6src,
+ fsp->h_u.ah_ip6_spec.ip6dst,
+ fsp->m_u.ah_ip6_spec.ip6dst,
+ fsp->h_u.ah_ip6_spec.tclass,
+ fsp->m_u.ah_ip6_spec.tclass);
+ fprintf(stdout,
+ "\tSPI: %d mask: 0x%x\n",
+ ntohl(fsp->h_u.esp_ip6_spec.spi),
+ ntohl(fsp->m_u.esp_ip6_spec.spi));
+ break;
+ case IPV6_USER_FLOW:
+ fprintf(stdout, "\tRule Type: Raw IPv6\n");
+ rxclass_print_ipv6_rule(fsp->h_u.usr_ip6_spec.ip6src,
+ fsp->m_u.usr_ip6_spec.ip6src,
+ fsp->h_u.usr_ip6_spec.ip6dst,
+ fsp->m_u.usr_ip6_spec.ip6dst,
+ fsp->h_u.usr_ip6_spec.tclass,
+ fsp->m_u.usr_ip6_spec.tclass);
+ fprintf(stdout,
+ "\tProtocol: %d mask: 0x%x\n"
+ "\tL4 bytes: 0x%x mask: 0x%x\n",
+ fsp->h_u.usr_ip6_spec.l4_proto,
+ fsp->m_u.usr_ip6_spec.l4_proto,
+ ntohl(fsp->h_u.usr_ip6_spec.l4_4_bytes),
+ ntohl(fsp->m_u.usr_ip6_spec.l4_4_bytes));
+ break;
case ETHER_FLOW:
dmac = fsp->h_u.ether_spec.h_dest;
dmacm = fsp->m_u.ether_spec.h_dest;
@@ -190,21 +265,20 @@ static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
case SCTP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
- case ETHER_FLOW:
- rxclass_print_nfc_rule(fsp);
- break;
- case IP_USER_FLOW:
- if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
- rxclass_print_nfc_rule(fsp);
- break;
- }
- /* IPv6 User Flow falls through to the case below */
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
- fprintf(stderr, "IPv6 flows not implemented\n");
+ case IPV6_USER_FLOW:
+ case ETHER_FLOW:
+ rxclass_print_nfc_rule(fsp);
+ break;
+ case IPV4_USER_FLOW:
+ if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
+ rxclass_print_nfc_rule(fsp);
+ else /* IPv6 uses IPV6_USER_FLOW */
+ fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
break;
default:
fprintf(stderr, "rxclass: Unknown flow type\n");
@@ -530,6 +604,7 @@ typedef enum {
OPT_BE32,
OPT_BE64,
OPT_IP4,
+ OPT_IP6,
OPT_MAC,
} rule_opt_type_t;
@@ -663,6 +738,114 @@ static const struct rule_opts rule_nfc_usr_ip4[] = {
offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
};
+static const struct rule_opts rule_nfc_tcp_ip6[] = {
+ { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6src),
+ offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6src) },
+ { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6dst),
+ offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6dst) },
+ { "tclass", OPT_U8, NFC_FLAG_TOS,
+ offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.tclass),
+ offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.tclass) },
+ { "src-port", OPT_BE16, NFC_FLAG_SPORT,
+ offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.psrc),
+ offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.psrc) },
+ { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+ offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.pdst),
+ offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.pdst) },
+ { "action", OPT_U64, NFC_FLAG_RING,
+ offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+ { "loc", OPT_U32, NFC_FLAG_LOC,
+ offsetof(struct ethtool_rx_flow_spec, location), -1 },
+ { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+ { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+ { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+ { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_esp_ip6[] = {
+ { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6src),
+ offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6src) },
+ { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6dst),
+ offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6dst) },
+ { "tclass", OPT_U8, NFC_FLAG_TOS,
+ offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.tclass),
+ offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.tclass) },
+ { "spi", OPT_BE32, NFC_FLAG_SPI,
+ offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.spi),
+ offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.spi) },
+ { "action", OPT_U64, NFC_FLAG_RING,
+ offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+ { "loc", OPT_U32, NFC_FLAG_LOC,
+ offsetof(struct ethtool_rx_flow_spec, location), -1 },
+ { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+ { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+ { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+ { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_usr_ip6[] = {
+ { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6src),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6src) },
+ { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6dst),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6dst) },
+ { "tclass", OPT_U8, NFC_FLAG_TOS,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.tclass),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.tclass) },
+ { "l4proto", OPT_U8, NFC_FLAG_PROTO,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_proto),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_proto) },
+ { "l4data", OPT_BE32, NFC_FLAG_SPI,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+ { "spi", OPT_BE32, NFC_FLAG_SPI,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+ { "src-port", OPT_BE16, NFC_FLAG_SPORT,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+ { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+ offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes) + 2,
+ offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) + 2 },
+ { "action", OPT_U64, NFC_FLAG_RING,
+ offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+ { "loc", OPT_U32, NFC_FLAG_LOC,
+ offsetof(struct ethtool_rx_flow_spec, location), -1 },
+ { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+ { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+ { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+ { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+ offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+ offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
static const struct rule_opts rule_nfc_ether[] = {
{ "src", OPT_MAC, NFC_FLAG_SADDR,
offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
@@ -726,6 +909,14 @@ static int rxclass_get_ipv4(char *str, __be32 *val)
return 0;
}
+static int rxclass_get_ipv6(char *str, __be32 *val)
+{
+ if (!inet_pton(AF_INET6, str, val))
+ return -1;
+
+ return 0;
+}
+
static int rxclass_get_ether(char *str, unsigned char *val)
{
unsigned int buf[ETH_ALEN];
@@ -851,6 +1042,19 @@ static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
*(__be32 *)&p[opt->moffset] = (__be32)mask;
break;
}
+ case OPT_IP6: {
+ __be32 val[4];
+ int i;
+ err = rxclass_get_ipv6(str, val);
+ if (err)
+ return -1;
+ for (i = 0; i < 4; i++) {
+ ((__be32 *)&p[opt->offset])[i] = val[i];
+ if (opt->moffset >= 0)
+ ((__be32 *)&p[opt->moffset])[i] = (__be32)mask;
+ }
+ break;
+ }
case OPT_MAC: {
unsigned char val[ETH_ALEN];
err = rxclass_get_ether(str, val);
@@ -950,6 +1154,19 @@ static int rxclass_get_mask(char *str, unsigned char *p,
*(__be32 *)&p[opt->moffset] = ~val;
break;
}
+ case OPT_IP6: {
+ __be32 val[4];
+ int i;
+ err = rxclass_get_ipv6(str, val);
+ if (err)
+ return -1;
+ for (i = 0; i < 4; i++) {
+ ((__be32 *)&p[opt->offset])[i] = val[i];
+ if (opt->moffset >= 0)
+ ((__be32 *)&p[opt->moffset])[i] = ~val[i];
+ }
+ break;
+ }
case OPT_MAC: {
unsigned char val[ETH_ALEN];
int i;
@@ -996,7 +1213,19 @@ int rxclass_parse_ruleopts(struct cmd_context *ctx,
else if (!strcmp(argp[0], "esp4"))
flow_type = ESP_V4_FLOW;
else if (!strcmp(argp[0], "ip4"))
- flow_type = IP_USER_FLOW;
+ flow_type = IPV4_USER_FLOW;
+ else if (!strcmp(argp[0], "tcp6"))
+ flow_type = TCP_V6_FLOW;
+ else if (!strcmp(argp[0], "udp6"))
+ flow_type = UDP_V6_FLOW;
+ else if (!strcmp(argp[0], "sctp6"))
+ flow_type = SCTP_V6_FLOW;
+ else if (!strcmp(argp[0], "ah6"))
+ flow_type = AH_V6_FLOW;
+ else if (!strcmp(argp[0], "esp6"))
+ flow_type = ESP_V6_FLOW;
+ else if (!strcmp(argp[0], "ip6"))
+ flow_type = IPV6_USER_FLOW;
else if (!strcmp(argp[0], "ether"))
flow_type = ETHER_FLOW;
else
@@ -1014,10 +1243,25 @@ int rxclass_parse_ruleopts(struct cmd_context *ctx,
options = rule_nfc_esp_ip4;
n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
break;
- case IP_USER_FLOW:
+ case IPV4_USER_FLOW:
options = rule_nfc_usr_ip4;
n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ options = rule_nfc_tcp_ip6;
+ n_opts = ARRAY_SIZE(rule_nfc_tcp_ip6);
+ break;
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ options = rule_nfc_esp_ip6;
+ n_opts = ARRAY_SIZE(rule_nfc_esp_ip6);
+ break;
+ case IPV6_USER_FLOW:
+ options = rule_nfc_usr_ip6;
+ n_opts = ARRAY_SIZE(rule_nfc_usr_ip6);
+ break;
case ETHER_FLOW:
options = rule_nfc_ether;
n_opts = ARRAY_SIZE(rule_nfc_ether);
@@ -1081,7 +1325,7 @@ int rxclass_parse_ruleopts(struct cmd_context *ctx,
}
}
- if (flow_type == IP_USER_FLOW)
+ if (flow_type == IPV4_USER_FLOW)
fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
fsp->flow_type |= FLOW_EXT;
Powered by blists - more mailing lists