Switch IPv6 protocol to using the new GRO/GSO calls and data.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
struct inet6_skb_parm *opt,
u8 type, u8 code, int offset,
__be32 info);
-
- int (*gso_send_check)(struct sk_buff *skb);
- struct sk_buff *(*gso_segment)(struct sk_buff *skb,
- netdev_features_t features);
- struct sk_buff **(*gro_receive)(struct sk_buff **head,
- struct sk_buff *skb);
- int (*gro_complete)(struct sk_buff *skb);
-
unsigned int flags; /* INET6_PROTO_xxx */
};
static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
{
- const struct inet6_protocol *ops = NULL;
+ const struct net_offload *ops = NULL;
for (;;) {
struct ipv6_opt_hdr *opth;
int len;
if (proto != NEXTHDR_HOP) {
- ops = rcu_dereference(inet6_protos[proto]);
+ ops = rcu_dereference(inet6_offloads[proto]);
if (unlikely(!ops))
break;
static int ipv6_gso_send_check(struct sk_buff *skb)
{
const struct ipv6hdr *ipv6h;
- const struct inet6_protocol *ops;
+ const struct net_offload *ops;
int err = -EINVAL;
if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
err = -EPROTONOSUPPORT;
rcu_read_lock();
- ops = rcu_dereference(inet6_protos[
+ ops = rcu_dereference(inet6_offloads[
ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
if (likely(ops && ops->gso_send_check)) {
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
struct ipv6hdr *ipv6h;
- const struct inet6_protocol *ops;
+ const struct net_offload *ops;
int proto;
struct frag_hdr *fptr;
unsigned int unfrag_ip6hlen;
proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
rcu_read_lock();
- ops = rcu_dereference(inet6_protos[proto]);
+ ops = rcu_dereference(inet6_offloads[proto]);
if (likely(ops && ops->gso_segment)) {
skb_reset_transport_header(skb);
segs = ops->gso_segment(skb, features);
static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
- const struct inet6_protocol *ops;
+ const struct net_offload *ops;
struct sk_buff **pp = NULL;
struct sk_buff *p;
struct ipv6hdr *iph;
rcu_read_lock();
proto = iph->nexthdr;
- ops = rcu_dereference(inet6_protos[proto]);
+ ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->gro_receive) {
__pskb_pull(skb, skb_gro_offset(skb));
proto = ipv6_gso_pull_exthdrs(skb, proto);
skb_reset_transport_header(skb);
__skb_push(skb, skb_gro_offset(skb));
- ops = rcu_dereference(inet6_protos[proto]);
+ ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->gro_receive)
goto out_unlock;
static int ipv6_gro_complete(struct sk_buff *skb)
{
- const struct inet6_protocol *ops;
+ const struct net_offload *ops;
struct ipv6hdr *iph = ipv6_hdr(skb);
int err = -ENOSYS;
sizeof(*iph));
rcu_read_lock();
- ops = rcu_dereference(inet6_protos[NAPI_GRO_CB(skb)->proto]);
+ ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]);
if (WARN_ON(!ops || !ops->gro_complete))
goto out_unlock;
.flags = INET6_PROTO_NOPOLICY,
};
+static int ipv6_exthdrs_offload_init(void)
+{
+ int ret;
+
+ ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
+ if (!ret)
+ goto out;
+
+ ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
+ if (!ret)
+ goto out_rt;
+
+out:
+ return ret;
+
+out_rt:
+ inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+ goto out;
+}
+
+static void ipv6_exthdrs_offload_exit(void)
+{
+ inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+ inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
+}
+
int __init ipv6_exthdrs_init(void)
{
int ret;
- ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+ ret = ipv6_exthdrs_offload_init();
if (ret)
goto out;
+ ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+ if (ret)
+ goto out_offload;
+
ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
if (ret)
goto out_rthdr;
out:
return ret;
-out_rthdr:
- inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
out_destopt:
inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
+out_rthdr:
+ inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+out_offload:
+ ipv6_exthdrs_offload_exit();
goto out;
};
.early_demux = tcp_v6_early_demux,
.handler = tcp_v6_rcv,
.err_handler = tcp_v6_err,
- .gso_send_check = tcp_v6_gso_send_check,
- .gso_segment = tcp_tso_segment,
- .gro_receive = tcp6_gro_receive,
- .gro_complete = tcp6_gro_complete,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
{
int ret;
- ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+ ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
if (ret)
goto out;
+ ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+ if (ret)
+ goto out_offload;
+
/* register inet6 protocol */
ret = inet6_register_protosw(&tcpv6_protosw);
if (ret)
out:
return ret;
-out_tcpv6_protocol:
- inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
out_tcpv6_protosw:
inet6_unregister_protosw(&tcpv6_protosw);
+out_tcpv6_protocol:
+ inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+out_offload:
+ inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
goto out;
}
unregister_pernet_subsys(&tcpv6_net_ops);
inet6_unregister_protosw(&tcpv6_protosw);
inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+ inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
}
static const struct inet6_protocol udpv6_protocol = {
.handler = udpv6_rcv,
.err_handler = udpv6_err,
- .gso_send_check = udp6_ufo_send_check,
- .gso_segment = udp6_ufo_fragment,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
{
int ret;
- ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
+ ret = inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
if (ret)
goto out;
+ ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
+ if (ret)
+ goto out_offload;
+
ret = inet6_register_protosw(&udpv6_protosw);
if (ret)
goto out_udpv6_protocol;
out_udpv6_protocol:
inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
+out_offload:
+ inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
goto out;
}
{
inet6_unregister_protosw(&udpv6_protosw);
inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
+ inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
}