[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180914175941.213950-5-willemdebruijn.kernel@gmail.com>
Date: Fri, 14 Sep 2018 13:59:37 -0400
From: Willem de Bruijn <willemdebruijn.kernel@...il.com>
To: netdev@...r.kernel.org
Cc: pabeni@...hat.com, steffen.klassert@...unet.com,
davem@...emloft.net, Willem de Bruijn <willemb@...gle.com>
Subject: [PATCH net-next RFC 4/8] ipv6: remove offload exception for hopopts
From: Willem de Bruijn <willemb@...gle.com>
Extension headers in ipv6 are pulled without calling a callback
function. An inet6_offload signals this feature with flag
INET6_PROTO_GSO_EXTHDR.
Add net_has_flag helper to hide implementation details and in
prepartion for configurable gro.
Convert NEXTHDR_HOP from a special case branch to a standard
extension header offload.
Signed-off-by: Willem de Bruijn <willemb@...gle.com>
---
include/linux/netdevice.h | 9 +++++++++
net/ipv6/exthdrs_offload.c | 17 ++++++++++++++---
net/ipv6/ip6_offload.c | 36 +++++++++++++-----------------------
3 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0be594f8d1ce..1c97a048506f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3567,6 +3567,15 @@ static inline u8 net_offload_from_type(u16 type)
return type & 0xFF;
}
+static inline bool net_offload_has_flag(const struct net_offload __rcu **offs,
+ u16 type, u16 flag)
+{
+ const struct net_offload *off;
+
+ off = offs ? rcu_dereference(offs[net_offload_from_type(type)]) : NULL;
+ return off && off->flags & flag;
+}
+
static inline const struct net_offload *
net_gro_receive(const struct net_offload __rcu **offs, u16 type)
{
diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c
index f5e2ba1c18bf..2230331c6012 100644
--- a/net/ipv6/exthdrs_offload.c
+++ b/net/ipv6/exthdrs_offload.c
@@ -12,11 +12,15 @@
#include <net/protocol.h>
#include "ip6_offload.h"
-static const struct net_offload rthdr_offload = {
+static struct net_offload hophdr_offload = {
.flags = INET6_PROTO_GSO_EXTHDR,
};
-static const struct net_offload dstopt_offload = {
+static struct net_offload rthdr_offload = {
+ .flags = INET6_PROTO_GSO_EXTHDR,
+};
+
+static struct net_offload dstopt_offload = {
.flags = INET6_PROTO_GSO_EXTHDR,
};
@@ -24,10 +28,14 @@ int __init ipv6_exthdrs_offload_init(void)
{
int ret;
- ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
+ ret = inet6_add_offload(&hophdr_offload, IPPROTO_HOPOPTS);
if (ret)
goto out;
+ ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
+ if (ret)
+ goto out_hop;
+
ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
if (ret)
goto out_rt;
@@ -37,5 +45,8 @@ int __init ipv6_exthdrs_offload_init(void)
out_rt:
inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+
+out_hop:
+ inet6_del_offload(&rthdr_offload, IPPROTO_HOPOPTS);
goto out;
}
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 9d301bef0e23..4854509a2c5d 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -22,21 +22,13 @@
static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
{
- const struct net_offload *ops = NULL;
-
for (;;) {
struct ipv6_opt_hdr *opth;
int len;
- if (proto != NEXTHDR_HOP) {
- ops = rcu_dereference(inet6_offloads[proto]);
-
- if (unlikely(!ops))
- break;
-
- if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
- break;
- }
+ if (!net_offload_has_flag(inet6_offloads, proto,
+ INET6_PROTO_GSO_EXTHDR))
+ break;
if (unlikely(!pskb_may_pull(skb, 8)))
break;
@@ -141,26 +133,24 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
/* Return the total length of all the extension hdrs, following the same
* logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs.
*/
-static int ipv6_exthdrs_len(struct ipv6hdr *iph,
- const struct net_offload **opps)
+static int ipv6_exthdrs_len(struct ipv6hdr *iph, u8 *pproto)
{
struct ipv6_opt_hdr *opth = (void *)iph;
int len = 0, proto, optlen = sizeof(*iph);
proto = iph->nexthdr;
for (;;) {
- if (proto != NEXTHDR_HOP) {
- *opps = rcu_dereference(inet6_offloads[proto]);
- if (unlikely(!(*opps)))
- break;
- if (!((*opps)->flags & INET6_PROTO_GSO_EXTHDR))
- break;
- }
+ if (!net_offload_has_flag(inet6_offloads, proto,
+ INET6_PROTO_GSO_EXTHDR))
+ break;
+
opth = (void *)opth + optlen;
optlen = ipv6_optlen(opth);
len += optlen;
proto = opth->nexthdr;
}
+
+ *pproto = proto;
return len;
}
@@ -296,8 +286,8 @@ static struct sk_buff *ip4ip6_gro_receive(struct list_head *head,
static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
{
- const struct net_offload *ops;
struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + nhoff);
+ u8 proto;
if (skb->encapsulation) {
skb_set_inner_protocol(skb, cpu_to_be16(ETH_P_IPV6));
@@ -306,8 +296,8 @@ static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
iph->payload_len = htons(skb->len - nhoff - sizeof(*iph));
- nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops);
- return net_gro_complete(inet6_offloads, ops->type, skb, nhoff);
+ nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &proto);
+ return net_gro_complete(inet6_offloads, proto, skb, nhoff);
}
static int sit_gro_complete(struct sk_buff *skb, int nhoff)
--
2.19.0.397.gdd90340f6a-goog
Powered by blists - more mailing lists