IPv6 NFC
Subsystems (4)
v2 cover IPv6 NFC
This series adds support for steering IPv6 flows using the ethtool NFC
interface, and implements it for sfc devices.
Tested using an in-development patch to the ethtool utility.
Edward Cree (2):
ethtool: add IPv6 to the NFC API
sfc: implement IPv6 NFC (and IPV4_USER_FLOW)
drivers/net/ethernet/sfc/ethtool.c | 184 +++++++++++++++++++++++++++++++++++++ include/uapi/linux/ethtool.h | 70 ++++++++++++-- 2 files changed, 248 insertions(+), 6 deletions(-)
PATCH v2 1/2 ethtool: add IPv6 to the NFC API
--- include/uapi/linux/ethtool.h | 70 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-)
include/uapi/linux/ethtool.h +64 -6
@@ -748,6 +748,56 @@ struct ethtool_usrip4_spec {__u8 proto; }; +/** +* struct ethtool_tcpip6_spec - flow specification for TCP/IPv6 etc. +* @ip6src: Source host +* @ip6dst: Destination host +* @psrc: Source port +* @pdst: Destination port +* @tclass: Traffic Class +* +* This can be used to specify a TCP/IPv6, UDP/IPv6 or SCTP/IPv6 flow. +*/ +struct ethtool_tcpip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be16 psrc; +__be16 pdst; +__u8 tclass; +}; + +/** +* struct ethtool_ah_espip6_spec - flow specification for IPsec/IPv6 +* @ip6src: Source host +* @ip6dst: Destination host +* @spi: Security parameters index +* @tclass: Traffic Class +* +* This can be used to specify an IPsec transport or tunnel over IPv6. +*/ +struct ethtool_ah_espip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be32 spi; +__u8 tclass; +}; + +/** +* struct ethtool_usrip6_spec - general flow specification for IPv6 +* @ip6src: Source host +* @ip6dst: Destination host +* @l4_4_bytes: First 4 bytes of transport (layer 4) header +* @tclass: Traffic Class +* @l4_proto: Transport protocol number (nexthdr after any Extension Headers) +*/ +struct ethtool_usrip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be32 l4_4_bytes; +__u8 tclass; +__u8 l4_proto; +}; +union ethtool_flow_union {struct ethtool_tcpip4_spec tcp_ip4_spec;struct ethtool_tcpip4_spec udp_ip4_spec;
@@ -755,6 +805,12 @@ union ethtool_flow_union {struct ethtool_ah_espip4_spec ah_ip4_spec;struct ethtool_ah_espip4_spec esp_ip4_spec;struct ethtool_usrip4_spec usr_ip4_spec; +struct ethtool_tcpip6_spec tcp_ip6_spec; +struct ethtool_tcpip6_spec udp_ip6_spec; +struct ethtool_tcpip6_spec sctp_ip6_spec; +struct ethtool_ah_espip6_spec ah_ip6_spec; +struct ethtool_ah_espip6_spec esp_ip6_spec; +struct ethtool_usrip6_spec usr_ip6_spec;struct ethhdr ether_spec;__u8 hdata[52 ]; };
@@ -1367,15 +1423,17 @@ enum ethtool_sfeatures_retval_bits {#define UDP_V4_FLOW 0x02/* hash or spec (udp_ip4_spec) */ #define SCTP_V4_FLOW 0x03/* hash or spec (sctp_ip4_spec) */ #define AH_ESP_V4_FLOW 0x04/* hash only */ -#define TCP_V6_FLOW 0x05/* hash only */ -#define UDP_V6_FLOW 0x06/* hash only */ -#define SCTP_V6_FLOW 0x07/* hash only */ +#define TCP_V6_FLOW 0x05/* hash or spec (tcp_ip6_spec; nfc only) */ +#define UDP_V6_FLOW 0x06/* hash or spec (udp_ip6_spec; nfc only) */ +#define SCTP_V6_FLOW 0x07/* hash or spec (sctp_ip6_spec; nfc only) */ #define AH_ESP_V6_FLOW 0x08/* hash only */ #define AH_V4_FLOW 0x09/* hash or spec (ah_ip4_spec) */ #define ESP_V4_FLOW 0x0a/* hash or spec (esp_ip4_spec) */ -#define AH_V6_FLOW 0x0b/* hash only */ -#define ESP_V6_FLOW 0x0c/* hash only */ -#define IP_USER_FLOW 0x0d/* spec only (usr_ip4_spec) */ +#define AH_V6_FLOW 0x0b/* hash or spec (ah_ip6_spec; nfc only) */ +#define ESP_V6_FLOW 0x0c/* hash or spec (esp_ip6_spec; nfc only) */ +#define IPV4_USER_FLOW 0x0d/* spec only (usr_ip4_spec) */ +#define IP_USER_FLOW IPV4_USER_FLOW +#define IPV6_USER_FLOW 0x0e/* spec only (usr_ip6_spec; nfc only) */ #define IPV4_FLOW 0x10/* hash only */ #define IPV6_FLOW 0x11/* hash only */ #define ETHER_FLOW 0x12/* spec only (ether_spec) */
Re: [PATCH net-next 1/2] ethtool: add IPv6 to the NFC API
Quoted 1 line · Edward Cree
Signed-off-by Edward Cree <[email protected]>
Quoted 103 lines
---
include/uapi/linux/ethtool.h | 70 ++++++++++++++++++++++++++++++++++++++++----1 file changed, 64 insertions(+), 6 deletions(-)include/uapi/linux/ethtool.h +0
-0@@ -748,6 +748,56 @@ struct ethtool_usrip4_spec { __u8 proto; };include/uapi/linux/ethtool.h +50
-0+/** +* struct ethtool_tcpip6_spec - flow specification for TCP/IPv6 etc. +* @ip6src: Source host +* @ip6dst: Destination host +* @psrc: Source port +* @pdst: Destination port +* @tclass: Traffic Class +* +* This can be used to specify a TCP/IPv6, UDP/IPv6 or SCTP/IPv6 flow. +*/ +struct ethtool_tcpip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be16 psrc; +__be16 pdst; + __u8 tclass; +}; + +/** +* struct ethtool_ah_espip6_spec - flow specification for IPsec/IPv6 +* @ip6src: Source host +* @ip6dst: Destination host +* @spi: Security parameters index +* @tclass: Traffic Class +* +* This can be used to specify an IPsec transport or tunnel over IPv6. +*/ +struct ethtool_ah_espip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be32 spi; + __u8 tclass; +}; + +/** +* struct ethtool_usrip6_spec - general flow specification for IPv6 +* @ip6src: Source host +* @ip6dst: Destination host +* @l4_4_bytes: First 4 bytes of transport (layer 4) header +* @tclass: Traffic Class +* @l4_proto: Transport protocol number (nexthdr after any Extension Headers) +*/ +struct ethtool_usrip6_spec { +__be32 ip6src[4 ]; +__be32 ip6dst[4 ]; +__be32 l4_4_bytes; + __u8 tclass; + __u8 l4_proto; +}; +union
ethtool_flow_union{
structethtool_tcpip4_spectcp_ip4_spec;
structethtool_tcpip4_specudp_ip4_spec;include/uapi/linux/ethtool.h +14
-6@@ -755,6 +805,12 @@ union ethtool_flow_union { struct ethtool_ah_espip4_spec ah_ip4_spec; struct ethtool_ah_espip4_spec esp_ip4_spec; struct ethtool_usrip4_spec usr_ip4_spec; +struct ethtool_tcpip6_spec tcp_ip6_spec; +struct ethtool_tcpip6_spec udp_ip6_spec; +struct ethtool_tcpip6_spec sctp_ip6_spec; +struct ethtool_ah_espip6_spec ah_ip6_spec; +struct ethtool_ah_espip6_spec esp_ip6_spec; +struct ethtool_usrip6_spec usr_ip6_spec; struct ethhdr ether_spec; __u8 hdata[52]; };@@ -1367,15 +1423,17 @@ enum ethtool_sfeatures_retval_bits { #define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */ #define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */ #define AH_ESP_V4_FLOW 0x04 /* hash only */ -#define TCP_V6_FLOW 0x05/* hash only */ -#define UDP_V6_FLOW 0x06/* hash only */ -#define SCTP_V6_FLOW 0x07/* hash only */ +#define TCP_V6_FLOW 0x05/* hash or spec (tcp_ip6_spec; nfc only) */ +#define UDP_V6_FLOW 0x06/* hash or spec (udp_ip6_spec; nfc only) */ +#define SCTP_V6_FLOW 0x07/* hash or spec (sctp_ip6_spec; nfc only) */ #define AH_ESP_V6_FLOW 0x08 /* hash only */ #define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */ #define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */ -#define AH_V6_FLOW 0x0b/* hash only */ -#define ESP_V6_FLOW 0x0c/* hash only */ -#define IP_USER_FLOW 0x0d/* spec only (usr_ip4_spec) */ +#define AH_V6_FLOW 0x0b/* hash or spec (ah_ip6_spec; nfc only) */ +#define ESP_V6_FLOW 0x0c/* hash or spec (esp_ip6_spec; nfc only) */ +#define IPV4_USER_FLOW 0x0d/* spec only (usr_ip4_spec) */ +#define IP_USER_FLOW IPV4_USER_FLOW +#define IPV6_USER_FLOW 0x0e/* spec only (usr_ip6_spec; nfc only) */ #define IPV4_FLOW 0x10 /* hash only */ #define IPV6_FLOW 0x11 /* hash only */ #define ETHER_FLOW 0x12 /* spec only (ether_spec) */
Signature · 2 lines
Ben Hutchings It is a miracle that curiosity survives formal education. - Albert Einstein
PATCH v2 2/2 sfc: implement IPv6 NFC (and IPV4_USER_FLOW)
In reply to Edward Cree--- drivers/net/ethernet/sfc/ethtool.c | 184 +++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+)
drivers/net/ethernet/sfc/ethtool.c +184 -0
@@ -783,14 +783,26 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)static const u8 mac_addr_ig_mask[ETH_ALEN ]__aligned(2) = {0x01 ,0 ,0 ,0 ,0 ,0 };#define IP4_ADDR_FULL_MASK ((__force __be32)~0) +#define IP_PROTO_FULL_MASK 0xFF#define PORT_FULL_MASK ((__force __be16)~0)#define ETHER_TYPE_FULL_MASK ((__force __be16)~0) +static inline void ip6_fill_mask (__be32 *mask) +{ + mask[0 ] = mask[1 ] = mask[2 ] = mask[3 ] = ~(__be32 )0 ; +} +static int efx_ethtool_get_class_rule (struct efx_nic *efx,struct ethtool_rx_flow_spec *rule) {struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; +struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; +struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; +struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; +struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; +struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; +struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;struct ethhdr *mac_entry = &rule->h_u.ether_spec;struct ethhdr *mac_mask = &rule->m_u.ether_spec;struct efx_filter_spec spec;
@@ -833,6 +845,35 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, ip_entry->psrc = spec.rem_port; ip_mask->psrc =PORT_FULL_MASK ; } + }else if ((spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE ) && + spec.ether_type ==htons (ETH_P_IPV6 ) && + (spec.match_flags &EFX_FILTER_MATCH_IP_PROTO ) && + (spec.ip_proto ==IPPROTO_TCP || spec.ip_proto ==IPPROTO_UDP ) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE |EFX_FILTER_MATCH_OUTER_VID | +EFX_FILTER_MATCH_LOC_HOST |EFX_FILTER_MATCH_REM_HOST | +EFX_FILTER_MATCH_IP_PROTO | +EFX_FILTER_MATCH_LOC_PORT |EFX_FILTER_MATCH_REM_PORT ))) { + rule->flow_type = ((spec.ip_proto ==IPPROTO_TCP ) ? +TCP_V6_FLOW :UDP_V6_FLOW ); +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { +memcpy (ip6_entry->ip6dst, spec.loc_host, +sizeof (ip6_entry->ip6dst)); +ip6_fill_mask (ip6_mask->ip6dst); + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { +memcpy (ip6_entry->ip6src, spec.rem_host, +sizeof (ip6_entry->ip6src)); +ip6_fill_mask (ip6_mask->ip6src); + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_PORT ) { + ip6_entry->pdst = spec.loc_port; + ip6_mask->pdst =PORT_FULL_MASK ; + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_PORT ) { + ip6_entry->psrc = spec.rem_port; + ip6_mask->psrc =PORT_FULL_MASK ; + } } else if (!(spec.match_flags & ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG | EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE |
@@ -855,6 +896,47 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, mac_entry->h_proto = spec.ether_type; mac_mask->h_proto =ETHER_TYPE_FULL_MASK ; } + }else if (spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE && + spec.ether_type ==htons (ETH_P_IP ) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE |EFX_FILTER_MATCH_OUTER_VID | +EFX_FILTER_MATCH_LOC_HOST |EFX_FILTER_MATCH_REM_HOST | +EFX_FILTER_MATCH_IP_PROTO ))) { + rule->flow_type =IPV4_USER_FLOW ; + uip_entry->ip_ver =ETH_RX_NFC_IP4 ; +if (spec.match_flags &EFX_FILTER_MATCH_IP_PROTO ) { + uip_mask->proto =IP_PROTO_FULL_MASK ; + uip_entry->proto = spec.ip_proto; + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { + uip_entry->ip4dst = spec.loc_host[0 ]; + uip_mask->ip4dst =IP4_ADDR_FULL_MASK ; + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { + uip_entry->ip4src = spec.rem_host[0 ]; + uip_mask->ip4src =IP4_ADDR_FULL_MASK ; + } + }else if (spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE && + spec.ether_type ==htons (ETH_P_IPV6 ) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE |EFX_FILTER_MATCH_OUTER_VID | +EFX_FILTER_MATCH_LOC_HOST |EFX_FILTER_MATCH_REM_HOST | +EFX_FILTER_MATCH_IP_PROTO ))) { + rule->flow_type =IPV6_USER_FLOW ; +if (spec.match_flags &EFX_FILTER_MATCH_IP_PROTO ) { + uip6_mask->l4_proto =IP_PROTO_FULL_MASK ; + uip6_entry->l4_proto = spec.ip_proto; + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { +memcpy (uip6_entry->ip6dst, spec.loc_host, +sizeof (uip6_entry->ip6dst)); +ip6_fill_mask (uip6_mask->ip6dst); + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { +memcpy (uip6_entry->ip6src, spec.rem_host, +sizeof (uip6_entry->ip6src)); +ip6_fill_mask (uip6_mask->ip6src); + } }else {/* The above should handle all filters that we insert */ WARN_ON (1 );
@@ -946,11 +1028,27 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, } } +static inline bool ip6_mask_is_full (__be32 mask[4 ]) +{ +return !~(mask[0 ] & mask[1 ] & mask[2 ] & mask[3 ]); +} + +static inline bool ip6_mask_is_empty (__be32 mask[4 ]) +{ +return !(mask[0 ] | mask[1 ] | mask[2 ] | mask[3 ]); +} +static int efx_ethtool_set_class_rule (struct efx_nic *efx,struct ethtool_rx_flow_spec *rule) {struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; +struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; +struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; +struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; +struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; +struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; +struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;struct ethhdr *mac_entry = &rule->h_u.ether_spec;struct ethhdr *mac_mask = &rule->m_u.ether_spec;struct efx_filter_spec spec;
@@ -1012,6 +1110,92 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,return -EINVAL ;break ; +case TCP_V6_FLOW : +case UDP_V6_FLOW : + spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | +EFX_FILTER_MATCH_IP_PROTO ); + spec.ether_type =htons (ETH_P_IPV6 ); + spec.ip_proto = ((rule->flow_type & ~FLOW_EXT ) ==TCP_V6_FLOW ? +IPPROTO_TCP :IPPROTO_UDP ); +if (!ip6_mask_is_empty (ip6_mask->ip6dst)) { +if (!ip6_mask_is_full (ip6_mask->ip6dst)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; +memcpy (spec.loc_host, ip6_entry->ip6dst,sizeof (spec.loc_host)); + } +if (!ip6_mask_is_empty (ip6_mask->ip6src)) { +if (!ip6_mask_is_full (ip6_mask->ip6src)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; +memcpy (spec.rem_host, ip6_entry->ip6src,sizeof (spec.rem_host)); + } +if (ip6_mask->pdst) { +if (ip6_mask->pdst !=PORT_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_PORT ; + spec.loc_port = ip6_entry->pdst; + } +if (ip6_mask->psrc) { +if (ip6_mask->psrc !=PORT_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_PORT ; + spec.rem_port = ip6_entry->psrc; + } +if (ip6_mask->tclass) +return -EINVAL ; +break ; + +case IPV4_USER_FLOW : +if (uip_mask->l4_4_bytes || uip_mask->tos || uip_mask->ip_ver || + uip_entry->ip_ver !=ETH_RX_NFC_IP4 ) +return -EINVAL ; + spec.match_flags =EFX_FILTER_MATCH_ETHER_TYPE ; + spec.ether_type =htons (ETH_P_IP ); +if (uip_mask->ip4dst) { +if (uip_mask->ip4dst !=IP4_ADDR_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; + spec.loc_host[0 ] = uip_entry->ip4dst; + } +if (uip_mask->ip4src) { +if (uip_mask->ip4src !=IP4_ADDR_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; + spec.rem_host[0 ] = uip_entry->ip4src; + } +if (uip_mask->proto) { +if (uip_mask->proto !=IP_PROTO_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_IP_PROTO ; + spec.ip_proto = uip_entry->proto; + } +break ; + +case IPV6_USER_FLOW : +if (uip6_mask->l4_4_bytes || uip6_mask->tclass) +return -EINVAL ; + spec.match_flags =EFX_FILTER_MATCH_ETHER_TYPE ; + spec.ether_type =htons (ETH_P_IPV6 ); +if (!ip6_mask_is_empty (uip6_mask->ip6dst)) { +if (!ip6_mask_is_full (uip6_mask->ip6dst)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; +memcpy (spec.loc_host, uip6_entry->ip6dst,sizeof (spec.loc_host)); + } +if (!ip6_mask_is_empty (uip6_mask->ip6src)) { +if (!ip6_mask_is_full (uip6_mask->ip6src)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; +memcpy (spec.rem_host, uip6_entry->ip6src,sizeof (spec.rem_host)); + } +if (uip6_mask->l4_proto) { +if (uip6_mask->l4_proto !=IP_PROTO_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_IP_PROTO ; + spec.ip_proto = uip6_entry->l4_proto; + } +break ; +case ETHER_FLOW :if (!is_zero_ether_addr (mac_mask->h_dest)) { if (ether_addr_equal(mac_mask->h_dest,
Re: [PATCH net-next 2/2] sfc: implement IPv6 NFC (and IPV4_USER_FLOW)
Quoted 1 line · Edward Cree
Signed-off-by Edward Cree <[email protected]>
Quoted 240 lines
---
drivers/net/ethernet/sfc/ethtool.c | 184 +++++++++++++++++++++++++++++++++++++1 file changed, 184 insertions(+)drivers/net/ethernet/sfc/ethtool.c +0
-0@@ -783,14 +783,26 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0};
#defineIP4_ADDR_FULL_MASK((__force__be32)~0)
+#defineIP_PROTO_FULL_MASK0xFF
#definePORT_FULL_MASK((__force__be16)~0)
#defineETHER_TYPE_FULL_MASK((__force__be16)~0)drivers/net/ethernet/sfc/ethtool.c +5
-0+static inline void ip6_fill_mask (__be32 *mask) +{ + mask[0 ] = mask[1 ] = mask[2 ] = mask[3 ] = ~(__be32 )0 ; +} +static int
efx_ethtool_get_class_rule(struct efx_nic *efx, struct ethtool_rx_flow_spec *rule){
structethtool_tcpip4_spec*ip_entry=&rule->h_u.tcp_ip4_spec; structethtool_tcpip4_spec*ip_mask=&rule->m_u.tcp_ip4_spec;drivers/net/ethernet/sfc/ethtool.c +6
-0+struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; +struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; +struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; +struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; +struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; +struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;struct ethhdr
*mac_entry=&rule->h_u.ether_spec; struct ethhdr*mac_mask=&rule->m_u.ether_spec; structefx_filter_specspec;drivers/net/ethernet/sfc/ethtool.c +29
-0@@ -833,6 +845,35 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, ip_entry->psrc = spec.rem_port; ip_mask->psrc = PORT_FULL_MASK; } + }else if ((spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE ) && + spec.ether_type == htons(ETH_P_IPV6) && + (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) && + (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | +EFX_FILTER_MATCH_LOC_HOST |EFX_FILTER_MATCH_REM_HOST | +EFX_FILTER_MATCH_IP_PROTO | + EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) { + rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? + TCP_V6_FLOW : UDP_V6_FLOW); +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { +memcpy (ip6_entry->ip6dst, spec.loc_host, + sizeof(ip6_entry->ip6dst)); +ip6_fill_mask (ip6_mask->ip6dst); + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { +memcpy (ip6_entry->ip6src, spec.rem_host, + sizeof(ip6_entry->ip6src)); +ip6_fill_mask (ip6_mask->ip6src); + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_PORT ) { + ip6_entry->pdst = spec.loc_port; + ip6_mask->pdst =PORT_FULL_MASK ; + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_PORT ) { + ip6_entry->psrc = spec.rem_port; + ip6_mask->psrc =PORT_FULL_MASK ; + } } else if (!(spec.match_flags &~(EFX_FILTER_MATCH_LOC_MAC |
EFX_FILTER_MATCH_LOC_MAC_IG|EFX_FILTER_MATCH_REM_MAC|EFX_FILTER_MATCH_ETHER_TYPE|drivers/net/ethernet/sfc/ethtool.c +41
-0@@ -855,6 +896,47 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, mac_entry->h_proto = spec.ether_type; mac_mask->h_proto = ETHER_TYPE_FULL_MASK; } + }else if (spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE && + spec.ether_type == htons(ETH_P_IP) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | + EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | + EFX_FILTER_MATCH_IP_PROTO))) { + rule->flow_type =IPV4_USER_FLOW ; + uip_entry->ip_ver =ETH_RX_NFC_IP4 ; +if (spec.match_flags &EFX_FILTER_MATCH_IP_PROTO ) { + uip_mask->proto =IP_PROTO_FULL_MASK ; + uip_entry->proto = spec.ip_proto; + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { + uip_entry->ip4dst = spec.loc_host[0 ]; + uip_mask->ip4dst =IP4_ADDR_FULL_MASK ; + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { + uip_entry->ip4src = spec.rem_host[0 ]; + uip_mask->ip4src =IP4_ADDR_FULL_MASK ; + } + }else if (spec.match_flags &EFX_FILTER_MATCH_ETHER_TYPE && + spec.ether_type == htons(ETH_P_IPV6) && + !(spec.match_flags & + ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | + EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | + EFX_FILTER_MATCH_IP_PROTO))) { + rule->flow_type =IPV6_USER_FLOW ; +if (spec.match_flags &EFX_FILTER_MATCH_IP_PROTO ) { + uip6_mask->l4_proto =IP_PROTO_FULL_MASK ; + uip6_entry->l4_proto = spec.ip_proto; + } +if (spec.match_flags &EFX_FILTER_MATCH_LOC_HOST ) { +memcpy (uip6_entry->ip6dst, spec.loc_host, + sizeof(uip6_entry->ip6dst)); +ip6_fill_mask (uip6_mask->ip6dst); + } +if (spec.match_flags &EFX_FILTER_MATCH_REM_HOST ) { +memcpy (uip6_entry->ip6src, spec.rem_host, + sizeof(uip6_entry->ip6src)); +ip6_fill_mask (uip6_mask->ip6src); + } } else { /* The above should handle all filters that we insert */ WARN_ON(1);@@ -946,11 +1028,27 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, } }drivers/net/ethernet/sfc/ethtool.c +10
-0+static inline bool ip6_mask_is_full (__be32 mask[4 ]) +{ +return !~(mask[0 ] & mask[1 ] & mask[2 ] & mask[3 ]); +} + +static inline bool ip6_mask_is_empty (__be32 mask[4 ]) +{ +return !(mask[0 ] | mask[1 ] | mask[2 ] | mask[3 ]); +} +static int
efx_ethtool_set_class_rule(struct efx_nic *efx, struct ethtool_rx_flow_spec *rule){
structethtool_tcpip4_spec*ip_entry=&rule->h_u.tcp_ip4_spec; structethtool_tcpip4_spec*ip_mask=&rule->m_u.tcp_ip4_spec;drivers/net/ethernet/sfc/ethtool.c +6
-0+struct ethtool_usrip4_spec *uip_entry = &rule->h_u.usr_ip4_spec; +struct ethtool_usrip4_spec *uip_mask = &rule->m_u.usr_ip4_spec; +struct ethtool_tcpip6_spec *ip6_entry = &rule->h_u.tcp_ip6_spec; +struct ethtool_tcpip6_spec *ip6_mask = &rule->m_u.tcp_ip6_spec; +struct ethtool_usrip6_spec *uip6_entry = &rule->h_u.usr_ip6_spec; +struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;struct ethhdr
*mac_entry=&rule->h_u.ether_spec; struct ethhdr*mac_mask=&rule->m_u.ether_spec; structefx_filter_specspec;drivers/net/ethernet/sfc/ethtool.c +0
-0@@ -1012,6 +1110,92 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, return -EINVAL; break;drivers/net/ethernet/sfc/ethtool.c +86
-0+case TCP_V6_FLOW : +case UDP_V6_FLOW : + spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | + EFX_FILTER_MATCH_IP_PROTO); + spec.ether_type =htons (ETH_P_IPV6 ); + spec.ip_proto = ((rule->flow_type & ~FLOW_EXT ) ==TCP_V6_FLOW ? + IPPROTO_TCP : IPPROTO_UDP); +if (!ip6_mask_is_empty (ip6_mask->ip6dst)) { +if (!ip6_mask_is_full (ip6_mask->ip6dst)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; +memcpy (spec.loc_host, ip6_entry->ip6dst,sizeof (spec.loc_host)); + } +if (!ip6_mask_is_empty (ip6_mask->ip6src)) { +if (!ip6_mask_is_full (ip6_mask->ip6src)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; +memcpy (spec.rem_host, ip6_entry->ip6src,sizeof (spec.rem_host)); + } +if (ip6_mask->pdst) { +if (ip6_mask->pdst !=PORT_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_PORT ; + spec.loc_port = ip6_entry->pdst; + } +if (ip6_mask->psrc) { +if (ip6_mask->psrc !=PORT_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_PORT ; + spec.rem_port = ip6_entry->psrc; + } +if (ip6_mask->tclass) +return -EINVAL ; +break ; + +case IPV4_USER_FLOW : +if (uip_mask->l4_4_bytes || uip_mask->tos || uip_mask->ip_ver || + uip_entry->ip_ver != ETH_RX_NFC_IP4) +return -EINVAL ; + spec.match_flags =EFX_FILTER_MATCH_ETHER_TYPE ; + spec.ether_type =htons (ETH_P_IP ); +if (uip_mask->ip4dst) { +if (uip_mask->ip4dst !=IP4_ADDR_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; + spec.loc_host[0 ] = uip_entry->ip4dst; + } +if (uip_mask->ip4src) { +if (uip_mask->ip4src !=IP4_ADDR_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; + spec.rem_host[0 ] = uip_entry->ip4src; + } +if (uip_mask->proto) { +if (uip_mask->proto !=IP_PROTO_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_IP_PROTO ; + spec.ip_proto = uip_entry->proto; + } +break ; + +case IPV6_USER_FLOW : +if (uip6_mask->l4_4_bytes || uip6_mask->tclass) +return -EINVAL ; + spec.match_flags =EFX_FILTER_MATCH_ETHER_TYPE ; + spec.ether_type =htons (ETH_P_IPV6 ); +if (!ip6_mask_is_empty (uip6_mask->ip6dst)) { +if (!ip6_mask_is_full (uip6_mask->ip6dst)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_LOC_HOST ; +memcpy (spec.loc_host, uip6_entry->ip6dst,sizeof (spec.loc_host)); + } +if (!ip6_mask_is_empty (uip6_mask->ip6src)) { +if (!ip6_mask_is_full (uip6_mask->ip6src)) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_REM_HOST ; +memcpy (spec.rem_host, uip6_entry->ip6src,sizeof (spec.rem_host)); + } +if (uip6_mask->l4_proto) { +if (uip6_mask->l4_proto !=IP_PROTO_FULL_MASK ) +return -EINVAL ; + spec.match_flags |=EFX_FILTER_MATCH_IP_PROTO ; + spec.ip_proto = uip6_entry->l4_proto; + } +break ; +case
ETHER_FLOW:
if (!is_zero_ether_addr(mac_mask->h_dest)) { if (ether_addr_equal(mac_mask->h_dest,
Signature · 2 lines
Ben Hutchings It is a miracle that curiosity survives formal education. - Albert Einstein
David Miller
maintainerFrom: Edward Cree <[email protected]>
Date: Fri, 5 Feb 2016 11:12:33 +0000
Quoted 3 lines
This series adds support for steering IPv6 flows using the ethtool NFC
interface, and implements it for sfc devices.
Tested using an in-development patch to the ethtool utility.
Series applied, thanks.