From f3f121359caa069cefbc48008e94bcd862ca21e2 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 22 Oct 2012 21:41:48 +0000 Subject: ipv6: tcp: clean up tcp_v6_early_demux() icsk variable Remove an icsk variable, which by convention should refer to an inet_connection_sock rather than an inet_sock. In the process, make the tcp_v6_early_demux() code and formatting a bit more like tcp_v4_early_demux(), to ease comparisons and maintenance. Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 26175bffbaa0..bb6782e84996 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1741,11 +1741,11 @@ static void tcp_v6_early_demux(struct sk_buff *skb) skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { struct dst_entry *dst = sk->sk_rx_dst; - struct inet_sock *icsk = inet_sk(sk); + if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); if (dst && - icsk->rx_dst_ifindex == skb->skb_iif) + inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) skb_dst_set_noref(skb, dst); } } -- cgit v1.2.3 From e6c022a4fa2d2d9ca9d0a7ac3b05ad988f39fc30 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 27 Oct 2012 23:16:46 +0000 Subject: tcp: better retrans tracking for defer-accept For passive TCP connections using TCP_DEFER_ACCEPT facility, we incorrectly increment req->retrans each time timeout triggers while no SYNACK is sent. SYNACK are not sent for TCP_DEFER_ACCEPT that were established (for which we received the ACK from client). Only the last SYNACK is sent so that we can receive again an ACK from client, to move the req into accept queue. We plan to change this later to avoid the useless retransmit (and potential problem as this SYNACK could be lost) TCP_INFO later gives wrong information to user, claiming imaginary retransmits. Decouple req->retrans field into two independent fields : num_retrans : number of retransmit num_timeout : number of timeouts num_timeout is the counter that is incremented at each timeout, regardless of actual SYNACK being sent or not, and used to compute the exponential timeout. Introduce inet_rtx_syn_ack() helper to increment num_retrans only if ->rtx_syn_ack() succeeded. Use inet_rtx_syn_ack() from tcp_check_req() to increment num_retrans when we re-send a SYNACK in answer to a (retransmitted) SYN. Prior to this patch, we were not counting these retransmits. Change tcp_v[46]_rtx_synack() to increment TCP_MIB_RETRANSSEGS only if a synack packet was successfully queued. Reported-by: Yuchung Cheng Signed-off-by: Eric Dumazet Cc: Julian Anastasov Cc: Vijay Subramanian Cc: Elliott Hughes Cc: Neal Cardwell Signed-off-by: David S. Miller --- include/net/request_sock.h | 12 ++++++++---- net/dccp/minisocks.c | 3 +-- net/ipv4/inet_connection_sock.c | 25 ++++++++++++++++++------- net/ipv4/inet_diag.c | 2 +- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_ipv4.c | 16 ++++++++++------ net/ipv4/tcp_minisocks.c | 8 ++++---- net/ipv4/tcp_timer.c | 8 ++++---- net/ipv6/syncookies.c | 2 +- net/ipv6/tcp_ipv6.c | 11 +++++++---- 11 files changed, 56 insertions(+), 35 deletions(-) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/include/net/request_sock.h b/include/net/request_sock.h index b01d8dd9ee7c..a51dbd17c2de 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -49,13 +49,16 @@ struct request_sock_ops { struct request_sock *req); }; +extern int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req); + /* struct request_sock - mini sock to represent a connection request */ struct request_sock { struct request_sock *dl_next; /* Must be first member! */ u16 mss; - u8 retrans; - u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */ + u8 num_retrans; /* number of retransmits */ + u8 cookie_ts:1; /* syncookie: encode tcpopts in timestamp */ + u8 num_timeout:7; /* number of timeouts */ /* The following two fields can be easily recomputed I think -AK */ u32 window_clamp; /* window clamp at creation time */ u32 rcv_wnd; /* rcv_wnd offered first time */ @@ -231,7 +234,7 @@ static inline int reqsk_queue_removed(struct request_sock_queue *queue, { struct listen_sock *lopt = queue->listen_opt; - if (req->retrans == 0) + if (req->num_timeout == 0) --lopt->qlen_young; return --lopt->qlen; @@ -269,7 +272,8 @@ static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, struct listen_sock *lopt = queue->listen_opt; req->expires = jiffies + timeout; - req->retrans = 0; + req->num_retrans = 0; + req->num_timeout = 0; req->sk = NULL; req->dl_next = lopt->syn_table[hash]; diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index ea850ce35d4a..662071b249cc 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -174,8 +174,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, * To protect against Request floods, increment retrans * counter (backoff, monitored by dccp_response_timer). */ - req->retrans++; - req->rsk_ops->rtx_syn_ack(sk, req, NULL); + inet_rtx_syn_ack(sk, req); } /* Network Duplicate, discard packet */ return NULL; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d34ce2972c8f..2026542d6836 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -521,21 +521,31 @@ static inline void syn_ack_recalc(struct request_sock *req, const int thresh, int *expire, int *resend) { if (!rskq_defer_accept) { - *expire = req->retrans >= thresh; + *expire = req->num_timeout >= thresh; *resend = 1; return; } - *expire = req->retrans >= thresh && - (!inet_rsk(req)->acked || req->retrans >= max_retries); + *expire = req->num_timeout >= thresh && + (!inet_rsk(req)->acked || req->num_timeout >= max_retries); /* * Do not resend while waiting for data after ACK, * start to resend on end of deferring period to give * last chance for data or ACK to create established socket. */ *resend = !inet_rsk(req)->acked || - req->retrans >= rskq_defer_accept - 1; + req->num_timeout >= rskq_defer_accept - 1; } +int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req) +{ + int err = req->rsk_ops->rtx_syn_ack(parent, req, NULL); + + if (!err) + req->num_retrans++; + return err; +} +EXPORT_SYMBOL(inet_rtx_syn_ack); + void inet_csk_reqsk_queue_prune(struct sock *parent, const unsigned long interval, const unsigned long timeout, @@ -599,13 +609,14 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, req->rsk_ops->syn_ack_timeout(parent, req); if (!expire && (!resend || - !req->rsk_ops->rtx_syn_ack(parent, req, NULL) || + !inet_rtx_syn_ack(parent, req) || inet_rsk(req)->acked)) { unsigned long timeo; - if (req->retrans++ == 0) + if (req->num_timeout++ == 0) lopt->qlen_young--; - timeo = min((timeout << req->retrans), max_rto); + timeo = min(timeout << req->num_timeout, + max_rto); req->expires = now + timeo; reqp = &req->dl_next; continue; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index e5bad82d3584..b5e781b529aa 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -620,7 +620,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, r->idiag_family = sk->sk_family; r->idiag_state = TCP_SYN_RECV; r->idiag_timer = 1; - r->idiag_retrans = req->retrans; + r->idiag_retrans = req->num_retrans; r->id.idiag_if = sk->sk_bound_dev_if; sock_diag_save_cookie(req, r->id.idiag_cookie); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index ba48e799b031..b236ef04914f 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -340,7 +340,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } req->expires = 0UL; - req->retrans = 0; + req->num_retrans = 0; /* * We need to lookup the route here to get at the correct diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 60cf836120a1..e95b4e508afe 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5991,7 +5991,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, */ if (req) { tcp_synack_rtt_meas(sk, req); - tp->total_retrans = req->retrans; + tp->total_retrans = req->num_retrans; reqsk_fastopen_remove(sk, req, false); } else { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 60e2e5d3ce29..e3607669064e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -877,10 +877,13 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, } static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req, - struct request_values *rvp) + struct request_values *rvp) { - TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); - return tcp_v4_send_synack(sk, NULL, req, rvp, 0, false); + int res = tcp_v4_send_synack(sk, NULL, req, rvp, 0, false); + + if (!res) + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); + return res; } /* @@ -1386,7 +1389,8 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk, struct sock *child; int err; - req->retrans = 0; + req->num_retrans = 0; + req->num_timeout = 0; req->sk = NULL; child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL); @@ -1740,7 +1744,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, tcp_initialize_rcv_mss(newsk); tcp_synack_rtt_meas(newsk, req); - newtp->total_retrans = req->retrans; + newtp->total_retrans = req->num_retrans; #ifdef CONFIG_TCP_MD5SIG /* Copy over the MD5 key from the original socket */ @@ -2638,7 +2642,7 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req, 0, 0, /* could print option size, but that is af dependent. */ 1, /* timers active (only the expire timer) */ jiffies_delta_to_clock_t(delta), - req->retrans, + req->num_timeout, from_kuid_munged(seq_user_ns(f), uid), 0, /* non standard timer */ 0, /* open_requests have no inode */ diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 27536ba16c9d..0404b3f4c959 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -552,7 +552,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * it can be estimated (approximately) * from another data. */ - tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<retrans); + tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<num_timeout); paws_reject = tcp_paws_reject(&tmp_opt, th->rst); } } @@ -581,7 +581,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * Note that even if there is new data in the SYN packet * they will be thrown away too. */ - req->rsk_ops->rtx_syn_ack(sk, req, NULL); + inet_rtx_syn_ack(sk, req); return NULL; } @@ -695,7 +695,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, /* Got ACK for our SYNACK, so update baseline for SYNACK RTT sample. */ if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr) tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr; - else if (req->retrans) /* don't take RTT sample if retrans && ~TS */ + else if (req->num_retrans) /* don't take RTT sample if retrans && ~TS */ tcp_rsk(req)->snt_synack = 0; /* For Fast Open no more processing is needed (sk is the @@ -705,7 +705,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, return sk; /* While TCP_DEFER_ACCEPT is active, drop bare ACK. */ - if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && + if (req->num_timeout < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { inet_rsk(req)->acked = 1; NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index fc04711e80c8..62c69ab19fdf 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -318,7 +318,7 @@ static void tcp_fastopen_synack_timer(struct sock *sk) req = tcp_sk(sk)->fastopen_rsk; req->rsk_ops->syn_ack_timeout(sk, req); - if (req->retrans >= max_retries) { + if (req->num_timeout >= max_retries) { tcp_write_err(sk); return; } @@ -327,10 +327,10 @@ static void tcp_fastopen_synack_timer(struct sock *sk) * regular retransmit because if the child socket has been accepted * it's not good to give up too easily. */ - req->rsk_ops->rtx_syn_ack(sk, req, NULL); - req->retrans++; + inet_rtx_syn_ack(sk, req); + req->num_timeout++; inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - TCP_TIMEOUT_INIT << req->retrans, TCP_RTO_MAX); + TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX); } /* diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 182ab9a85d6c..40161977f7cf 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -214,7 +214,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq6->iif = inet6_iif(skb); req->expires = 0UL; - req->retrans = 0; + req->num_retrans = 0; ireq->ecn_ok = ecn_ok; ireq->snd_wscale = tcp_opt.snd_wscale; ireq->sack_ok = tcp_opt.sack_ok; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bb6782e84996..c73d0ebde9c8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -495,9 +495,12 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, struct request_values *rvp) { struct flowi6 fl6; + int res; - TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); - return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); + res = tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); + if (!res) + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); + return res; } static void tcp_v6_reqsk_destructor(struct request_sock *req) @@ -1364,7 +1367,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, tcp_initialize_rcv_mss(newsk); tcp_synack_rtt_meas(newsk, req); - newtp->total_retrans = req->retrans; + newtp->total_retrans = req->num_retrans; newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; newinet->inet_rcv_saddr = LOOPBACK4_IPV6; @@ -1866,7 +1869,7 @@ static void get_openreq6(struct seq_file *seq, 0,0, /* could print option size, but that is af dependent. */ 1, /* timers active (only the expire timer) */ jiffies_to_clock_t(ttd), - req->retrans, + req->num_timeout, from_kuid_munged(seq_user_ns(seq), uid), 0, /* non standard timer */ 0, /* open_requests have no inode */ -- cgit v1.2.3 From 8ca896cfdd17f32f5aa2747644733ebf3725360d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 15 Nov 2012 08:49:13 +0000 Subject: ipv6: Add new offload registration infrastructure. Create a new data structure for IPv6 protocols that holds GRO/GSO callbacks and a new array to track the protocols that register GRO/GSO. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/protocol.h | 4 ++++ net/ipv6/exthdrs.c | 8 ++++++++ net/ipv6/protocol.c | 21 +++++++++++++++++++++ net/ipv6/tcp_ipv6.c | 7 +++++++ net/ipv6/udp.c | 5 +++++ 5 files changed, 45 insertions(+) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/include/net/protocol.h b/include/net/protocol.h index d8ecb17b1231..637e1bb6a76e 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -84,6 +84,7 @@ struct net_offload { struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); + unsigned int flags; /* Flags used by IPv6 for now */ }; /* This is used to register socket interfaces for IP protocols. */ @@ -109,6 +110,7 @@ extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS]; #if IS_ENABLED(CONFIG_IPV6) extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS]; +extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS]; #endif extern int inet_add_protocol(const struct net_protocol *prot, unsigned char num); @@ -121,6 +123,8 @@ extern void inet_unregister_protosw(struct inet_protosw *p); #if IS_ENABLED(CONFIG_IPV6) extern int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num); extern int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num); +extern int inet6_add_offload(const struct net_offload *prot, unsigned char num); +extern int inet6_del_offload(const struct net_offload *prot, unsigned char num); extern int inet6_register_protosw(struct inet_protosw *p); extern void inet6_unregister_protosw(struct inet_protosw *p); #endif diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index f005acc58b2a..cb6f0828ca44 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -531,11 +531,19 @@ static const struct inet6_protocol rthdr_protocol = { .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; +static const struct net_offload rthdr_offload = { + .flags = INET6_PROTO_GSO_EXTHDR, +}; + static const struct inet6_protocol destopt_protocol = { .handler = ipv6_destopt_rcv, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; +static const struct net_offload dstopt_offload = { + .flags = INET6_PROTO_GSO_EXTHDR, +}; + static const struct inet6_protocol nodata_protocol = { .handler = dst_discard, .flags = INET6_PROTO_NOPOLICY, diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 053082dfc93e..f7c53a7d5cb0 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -26,6 +26,7 @@ #include const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; +const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) { @@ -34,6 +35,13 @@ int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol } EXPORT_SYMBOL(inet6_add_protocol); +int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) +{ + return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol], + NULL, prot) ? 0 : -1; +} +EXPORT_SYMBOL(inet6_add_offload); + /* * Remove a protocol from the hash tables. */ @@ -50,3 +58,16 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol return ret; } EXPORT_SYMBOL(inet6_del_protocol); + +int inet6_del_offload(const struct net_offload *prot, unsigned char protocol) +{ + int ret; + + ret = (cmpxchg((const struct net_offload **)&inet6_offloads[protocol], + prot, NULL) == prot) ? 0 : -1; + + synchronize_net(); + + return ret; +} +EXPORT_SYMBOL(inet6_del_offload); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c73d0ebde9c8..6884a95be433 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2073,6 +2073,13 @@ static const struct inet6_protocol tcpv6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; +static const struct net_offload tcpv6_offload = { + .gso_send_check = tcp_v6_gso_send_check, + .gso_segment = tcp_tso_segment, + .gro_receive = tcp6_gro_receive, + .gro_complete = tcp6_gro_complete, +}; + static struct inet_protosw tcpv6_protosw = { .type = SOCK_STREAM, .protocol = IPPROTO_TCP, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index fc9997260a6b..3ad44e176503 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1443,6 +1443,11 @@ static const struct inet6_protocol udpv6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; +static const struct net_offload udpv6_offload = { + .gso_send_check = udp6_ufo_send_check, + .gso_segment = udp6_ufo_fragment, +}; + /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS -- cgit v1.2.3 From 3336288a9feaa809839adbaf05778dc2f16665dc Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 15 Nov 2012 08:49:15 +0000 Subject: ipv6: Switch to using new offload infrastructure. Switch IPv6 protocol to using the new GRO/GSO calls and data. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/protocol.h | 8 -------- net/ipv6/af_inet6.c | 22 +++++++++++----------- net/ipv6/exthdrs.c | 38 +++++++++++++++++++++++++++++++++++--- net/ipv6/tcp_ipv6.c | 17 ++++++++++------- net/ipv6/udp.c | 11 ++++++++--- 5 files changed, 64 insertions(+), 32 deletions(-) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/include/net/protocol.h b/include/net/protocol.h index 3bb70510b686..7019c1637848 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -54,14 +54,6 @@ struct inet6_protocol { 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 */ }; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6e245177608c..eb63dac68728 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -701,14 +701,14 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted); 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; @@ -736,7 +736,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) 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)))) @@ -747,7 +747,7 @@ static int ipv6_gso_send_check(struct sk_buff *skb) 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)) { @@ -765,7 +765,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, { 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; @@ -792,7 +792,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, 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); @@ -825,7 +825,7 @@ out: 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; @@ -852,7 +852,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, 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); @@ -860,7 +860,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, 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; @@ -915,7 +915,7 @@ out: 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; @@ -923,7 +923,7 @@ static int ipv6_gro_complete(struct sk_buff *skb) 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; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index cb6f0828ca44..de6559e3aa0a 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -549,14 +549,44 @@ static const struct inet6_protocol nodata_protocol = { .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; @@ -567,10 +597,12 @@ int __init ipv6_exthdrs_init(void) 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; }; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6884a95be433..635206e8987e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2066,10 +2066,6 @@ static const struct inet6_protocol tcpv6_protocol = { .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, }; @@ -2116,10 +2112,14 @@ int __init tcpv6_init(void) { 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) @@ -2131,10 +2131,12 @@ int __init tcpv6_init(void) 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; } @@ -2143,4 +2145,5 @@ void tcpv6_exit(void) 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); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3ad44e176503..e4cc1f41012d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1438,8 +1438,6 @@ out: 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, }; @@ -1570,10 +1568,14 @@ int __init udpv6_init(void) { 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; @@ -1582,6 +1584,8 @@ out: out_udpv6_protocol: inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); +out_offload: + inet6_del_offload(&udpv6_offload, IPPROTO_UDP); goto out; } @@ -1589,4 +1593,5 @@ void udpv6_exit(void) { inet6_unregister_protosw(&udpv6_protosw); inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); + inet6_del_offload(&udpv6_offload, IPPROTO_UDP); } -- cgit v1.2.3 From 8663e02aba154e04679c9bb1665af52021d32547 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 15 Nov 2012 08:49:17 +0000 Subject: ipv6: Separate tcp offload functionality Pull TCPv6 offload functionality into its won file in preparation for moving it out of the module. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/ip6_checksum.h | 35 ++++++++++++++ net/ipv6/Makefile | 2 +- net/ipv6/ip6_offload.h | 3 ++ net/ipv6/tcp_ipv6.c | 113 ++------------------------------------------- net/ipv6/tcpv6_offload.c | 98 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+), 110 deletions(-) create mode 100644 net/ipv6/tcpv6_offload.c (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h index bc1b0fda2b04..652d3d309357 100644 --- a/include/net/ip6_checksum.h +++ b/include/net/ip6_checksum.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifndef _HAVE_ARCH_IPV6_CSUM @@ -91,4 +93,37 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, } #endif + +static __inline__ __sum16 tcp_v6_check(int len, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + __wsum base) +{ + return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); +} + +static inline void __tcp_v6_send_check(struct sk_buff *skb, + const struct in6_addr *saddr, + const struct in6_addr *daddr) +{ + struct tcphdr *th = tcp_hdr(skb); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct tcphdr, check); + } else { + th->check = tcp_v6_check(skb->len, saddr, daddr, + csum_partial(th, th->doff << 2, + skb->csum)); + } +} + +static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + + __tcp_v6_send_check(skb, &np->saddr, &np->daddr); +} + #endif diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 45bd9cdd9244..f47ad9f6ea2c 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -10,7 +10,7 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o -ipv6-offload := ip6_offload.o +ipv6-offload := ip6_offload.o tcpv6_offload.o ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h index c09614eaa929..1891946ceedb 100644 --- a/net/ipv6/ip6_offload.h +++ b/net/ipv6/ip6_offload.h @@ -11,6 +11,9 @@ #ifndef __ip6_offload_h #define __ip6_offload_h +int tcpv6_offload_init(void); +void tcpv6_offload_cleanup(void); + extern void ipv6_offload_init(void); extern void ipv6_offload_cleanup(void); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 635206e8987e..5bed594b429d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -71,15 +71,13 @@ #include #include +#include "ip6_offload.h" static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, struct request_sock *req); static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); -static void __tcp_v6_send_check(struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr); static const struct inet_connection_sock_af_ops ipv6_mapped; static const struct inet_connection_sock_af_ops ipv6_specific; @@ -119,14 +117,6 @@ static void tcp_v6_hash(struct sock *sk) } } -static __inline__ __sum16 tcp_v6_check(int len, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - __wsum base) -{ - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); -} - static __u32 tcp_v6_init_sequence(const struct sk_buff *skb) { return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, @@ -722,94 +712,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { }; #endif -static void __tcp_v6_send_check(struct sk_buff *skb, - const struct in6_addr *saddr, const struct in6_addr *daddr) -{ - struct tcphdr *th = tcp_hdr(skb); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct tcphdr, check); - } else { - th->check = tcp_v6_check(skb->len, saddr, daddr, - csum_partial(th, th->doff << 2, - skb->csum)); - } -} - -static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - - __tcp_v6_send_check(skb, &np->saddr, &np->daddr); -} - -static int tcp_v6_gso_send_check(struct sk_buff *skb) -{ - const struct ipv6hdr *ipv6h; - struct tcphdr *th; - - if (!pskb_may_pull(skb, sizeof(*th))) - return -EINVAL; - - ipv6h = ipv6_hdr(skb); - th = tcp_hdr(skb); - - th->check = 0; - skb->ip_summed = CHECKSUM_PARTIAL; - __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); - return 0; -} - -static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - const struct ipv6hdr *iph = skb_gro_network_header(skb); - __wsum wsum; - __sum16 sum; - - switch (skb->ip_summed) { - case CHECKSUM_COMPLETE: - if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, - skb->csum)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - break; - } -flush: - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - - case CHECKSUM_NONE: - wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, - skb_gro_len(skb), - IPPROTO_TCP, 0)); - sum = csum_fold(skb_checksum(skb, - skb_gro_offset(skb), - skb_gro_len(skb), - wsum)); - if (sum) - goto flush; - - skb->ip_summed = CHECKSUM_UNNECESSARY; - break; - } - - return tcp_gro_receive(head, skb); -} - -static int tcp6_gro_complete(struct sk_buff *skb) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - struct tcphdr *th = tcp_hdr(skb); - - th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), - &iph->saddr, &iph->daddr, 0); - skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; - - return tcp_gro_complete(skb); -} - static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass) { @@ -2069,13 +1971,6 @@ static const struct inet6_protocol tcpv6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static const struct net_offload tcpv6_offload = { - .gso_send_check = tcp_v6_gso_send_check, - .gso_segment = tcp_tso_segment, - .gro_receive = tcp6_gro_receive, - .gro_complete = tcp6_gro_complete, -}; - static struct inet_protosw tcpv6_protosw = { .type = SOCK_STREAM, .protocol = IPPROTO_TCP, @@ -2112,7 +2007,7 @@ int __init tcpv6_init(void) { int ret; - ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP); + ret = tcpv6_offload_init(); if (ret) goto out; @@ -2136,7 +2031,7 @@ out_tcpv6_protosw: out_tcpv6_protocol: inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); out_offload: - inet6_del_offload(&tcpv6_offload, IPPROTO_TCP); + tcpv6_offload_cleanup(); goto out; } @@ -2145,5 +2040,5 @@ void tcpv6_exit(void) 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); + tcpv6_offload_cleanup(); } diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c new file mode 100644 index 000000000000..edeafedba470 --- /dev/null +++ b/net/ipv6/tcpv6_offload.c @@ -0,0 +1,98 @@ +/* + * IPV6 GSO/GRO offload support + * Linux INET6 implementation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * TCPv6 GSO/GRO support + */ +#include +#include +#include +#include +#include "ip6_offload.h" + +static int tcp_v6_gso_send_check(struct sk_buff *skb) +{ + const struct ipv6hdr *ipv6h; + struct tcphdr *th; + + if (!pskb_may_pull(skb, sizeof(*th))) + return -EINVAL; + + ipv6h = ipv6_hdr(skb); + th = tcp_hdr(skb); + + th->check = 0; + skb->ip_summed = CHECKSUM_PARTIAL; + __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); + return 0; +} + +static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, + struct sk_buff *skb) +{ + const struct ipv6hdr *iph = skb_gro_network_header(skb); + __wsum wsum; + __sum16 sum; + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, + skb->csum)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } +flush: + NAPI_GRO_CB(skb)->flush = 1; + return NULL; + + case CHECKSUM_NONE: + wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, + skb_gro_len(skb), + IPPROTO_TCP, 0)); + sum = csum_fold(skb_checksum(skb, + skb_gro_offset(skb), + skb_gro_len(skb), + wsum)); + if (sum) + goto flush; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + + return tcp_gro_receive(head, skb); +} + +static int tcp6_gro_complete(struct sk_buff *skb) +{ + const struct ipv6hdr *iph = ipv6_hdr(skb); + struct tcphdr *th = tcp_hdr(skb); + + th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), + &iph->saddr, &iph->daddr, 0); + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; + + return tcp_gro_complete(skb); +} + +static const struct net_offload tcpv6_offload = { + .gso_send_check = tcp_v6_gso_send_check, + .gso_segment = tcp_tso_segment, + .gro_receive = tcp6_gro_receive, + .gro_complete = tcp6_gro_complete, +}; + +int __init tcpv6_offload_init(void) +{ + return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP); +} + +void tcpv6_offload_cleanup(void) +{ + inet6_del_offload(&tcpv6_offload, IPPROTO_TCP); +} -- cgit v1.2.3 From c6b641a4c6b32f39db678c2441cb1ef824110d74 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 15 Nov 2012 08:49:22 +0000 Subject: ipv6: Pull IPv6 GSO registration out of the module Sing GSO support is now separate, pull it out of the module and make it its own init call. Remove the cleanup functions as they are no longer called. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/protocol.h | 11 ++++++----- net/ipv6/Makefile | 6 +++--- net/ipv6/af_inet6.c | 3 --- net/ipv6/exthdrs.c | 10 +--------- net/ipv6/exthdrs_offload.c | 6 ------ net/ipv6/ip6_offload.c | 17 ++++++++++++----- net/ipv6/ip6_offload.h | 8 -------- net/ipv6/protocol.c | 20 ++++++++++++-------- net/ipv6/tcp_ipv6.c | 10 +--------- net/ipv6/tcpv6_offload.c | 5 ----- net/ipv6/udp.c | 10 +--------- net/ipv6/udp_offload.c | 5 ----- 12 files changed, 36 insertions(+), 75 deletions(-) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/include/net/protocol.h b/include/net/protocol.h index 7019c1637848..2c90794c139d 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -25,6 +25,7 @@ #define _PROTOCOL_H #include +#include #if IS_ENABLED(CONFIG_IPV6) #include #endif @@ -59,8 +60,6 @@ struct inet6_protocol { #define INET6_PROTO_NOPOLICY 0x1 #define INET6_PROTO_FINAL 0x2 -/* This should be set for any extension header which is compatible with GSO. */ -#define INET6_PROTO_GSO_EXTHDR 0x4 #endif struct net_offload { @@ -72,6 +71,8 @@ struct net_offload { int (*gro_complete)(struct sk_buff *skb); unsigned int flags; /* Flags used by IPv6 for now */ }; +/* This should be set for any extension header which is compatible with GSO. */ +#define INET6_PROTO_GSO_EXTHDR 0x1 /* This is used to register socket interfaces for IP protocols. */ struct inet_protosw { @@ -93,10 +94,10 @@ struct inet_protosw { extern const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS]; extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS]; +extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS]; #if IS_ENABLED(CONFIG_IPV6) extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS]; -extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS]; #endif extern int inet_add_protocol(const struct net_protocol *prot, unsigned char num); @@ -109,10 +110,10 @@ extern void inet_unregister_protosw(struct inet_protosw *p); #if IS_ENABLED(CONFIG_IPV6) extern int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num); extern int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num); -extern int inet6_add_offload(const struct net_offload *prot, unsigned char num); -extern int inet6_del_offload(const struct net_offload *prot, unsigned char num); extern int inet6_register_protosw(struct inet_protosw *p); extern void inet6_unregister_protosw(struct inet_protosw *p); #endif +extern int inet6_add_offload(const struct net_offload *prot, unsigned char num); +extern int inet6_del_offload(const struct net_offload *prot, unsigned char num); #endif /* _PROTOCOL_H */ diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index cdca302f395c..04a475df98ad 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ - raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ + raw.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o ipv6-offload := ip6_offload.o tcpv6_offload.o udp_offload.o exthdrs_offload.o @@ -23,7 +23,6 @@ ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o ipv6-objs += $(ipv6-y) -ipv6-objs += $(ipv6-offload) obj-$(CONFIG_INET6_AH) += ah6.o obj-$(CONFIG_INET6_ESP) += esp6.o @@ -41,6 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o obj-$(CONFIG_IPV6_GRE) += ip6_gre.o -obj-y += addrconf_core.o exthdrs_core.o output_core.o +obj-y += addrconf_core.o exthdrs_core.o output_core.o protocol.o +obj-y += $(ipv6-offload) obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index c84d5ba60cdd..7bafc51cda11 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -62,7 +62,6 @@ #include #include -#include "ip6_offload.h" MODULE_AUTHOR("Cast of dozens"); MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); @@ -707,14 +706,12 @@ static struct packet_type ipv6_packet_type __read_mostly = { static int __init ipv6_packet_init(void) { - ipv6_offload_init(); dev_add_pack(&ipv6_packet_type); return 0; } static void ipv6_packet_cleanup(void) { - ipv6_offload_cleanup(); dev_remove_pack(&ipv6_packet_type); } diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a786a20ad823..473f628f9f20 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -48,7 +48,6 @@ #endif #include -#include "ip6_offload.h" /* * Parsing tlv encoded headers. @@ -502,13 +501,9 @@ int __init ipv6_exthdrs_init(void) { int ret; - ret = ipv6_exthdrs_offload_init(); - if (ret) - goto out; - ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING); if (ret) - goto out_offload; + goto out; ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS); if (ret) @@ -524,14 +519,11 @@ 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; }; void ipv6_exthdrs_exit(void) { - ipv6_exthdrs_offload_exit(); inet6_del_protocol(&nodata_protocol, IPPROTO_NONE); inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING); diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c index 271bf4a97023..cf77f3abfd06 100644 --- a/net/ipv6/exthdrs_offload.c +++ b/net/ipv6/exthdrs_offload.c @@ -39,9 +39,3 @@ out_rt: inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); goto out; } - -void ipv6_exthdrs_offload_exit(void) -{ - inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); - inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS); -} diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 01cf9835a581..63d79d9005bd 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -262,12 +263,18 @@ static struct packet_offload ipv6_packet_offload __read_mostly = { .gro_complete = ipv6_gro_complete, }; -void __init ipv6_offload_init(void) +static int __init ipv6_offload_init(void) { + + if (tcpv6_offload_init() < 0) + pr_crit("%s: Cannot add TCP protocol offload\n", __func__); + if (udp_offload_init() < 0) + pr_crit("%s: Cannot add UDP protocol offload\n", __func__); + if (ipv6_exthdrs_offload_init() < 0) + pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__); + dev_add_offload(&ipv6_packet_offload); + return 0; } -void ipv6_offload_cleanup(void) -{ - dev_remove_offload(&ipv6_packet_offload); -} +fs_initcall(ipv6_offload_init); diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h index 4e88ddb52a2c..2e155c651b35 100644 --- a/net/ipv6/ip6_offload.h +++ b/net/ipv6/ip6_offload.h @@ -12,15 +12,7 @@ #define __ip6_offload_h int ipv6_exthdrs_offload_init(void); -void ipv6_exthdrs_offload_exit(void); - int udp_offload_init(void); -void udp_offload_cleanup(void); - int tcpv6_offload_init(void); -void tcpv6_offload_cleanup(void); - -extern void ipv6_offload_init(void); -extern void ipv6_offload_cleanup(void); #endif diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index f7c53a7d5cb0..22d1bd4670da 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -25,8 +25,9 @@ #include #include +#if IS_ENABLED(CONFIG_IPV6) const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; -const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; +EXPORT_SYMBOL(inet6_protos); int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) { @@ -35,13 +36,6 @@ int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol } EXPORT_SYMBOL(inet6_add_protocol); -int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) -{ - return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol], - NULL, prot) ? 0 : -1; -} -EXPORT_SYMBOL(inet6_add_offload); - /* * Remove a protocol from the hash tables. */ @@ -58,6 +52,16 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol return ret; } EXPORT_SYMBOL(inet6_del_protocol); +#endif + +const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; + +int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) +{ + return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol], + NULL, prot) ? 0 : -1; +} +EXPORT_SYMBOL(inet6_add_offload); int inet6_del_offload(const struct net_offload *prot, unsigned char protocol) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5bed594b429d..6c0f2526f3f1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -71,7 +71,6 @@ #include #include -#include "ip6_offload.h" static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, @@ -2007,13 +2006,9 @@ int __init tcpv6_init(void) { int ret; - ret = tcpv6_offload_init(); - if (ret) - goto out; - ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP); if (ret) - goto out_offload; + goto out; /* register inet6 protocol */ ret = inet6_register_protosw(&tcpv6_protosw); @@ -2030,8 +2025,6 @@ out_tcpv6_protosw: inet6_unregister_protosw(&tcpv6_protosw); out_tcpv6_protocol: inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); -out_offload: - tcpv6_offload_cleanup(); goto out; } @@ -2040,5 +2033,4 @@ void tcpv6_exit(void) unregister_pernet_subsys(&tcpv6_net_ops); inet6_unregister_protosw(&tcpv6_protosw); inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); - tcpv6_offload_cleanup(); } diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index edeafedba470..3a27fe685c8e 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -91,8 +91,3 @@ int __init tcpv6_offload_init(void) { return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP); } - -void tcpv6_offload_cleanup(void) -{ - inet6_del_offload(&tcpv6_offload, IPPROTO_TCP); -} diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 013fef740d51..dfaa29b8b293 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -50,7 +50,6 @@ #include #include #include "udp_impl.h" -#include "ip6_offload.h" int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) { @@ -1472,13 +1471,9 @@ int __init udpv6_init(void) { int ret; - ret = udp_offload_init(); - if (ret) - goto out; - ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); if (ret) - goto out_offload; + goto out; ret = inet6_register_protosw(&udpv6_protosw); if (ret) @@ -1488,8 +1483,6 @@ out: out_udpv6_protocol: inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); -out_offload: - udp_offload_cleanup(); goto out; } @@ -1497,5 +1490,4 @@ void udpv6_exit(void) { inet6_unregister_protosw(&udpv6_protosw); inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); - udp_offload_cleanup(); } diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index f964d2b366c8..979e4ab63a8b 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -115,8 +115,3 @@ int __init udp_offload_init(void) { return inet6_add_offload(&udpv6_offload, IPPROTO_UDP); } - -void udp_offload_cleanup(void) -{ - inet6_del_offload(&udpv6_offload, IPPROTO_UDP); -} -- cgit v1.2.3 From 2b9164771efe191c4ef266ae53c8c05ab92dd115 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 22 Nov 2012 01:13:58 +0000 Subject: ipv6: adapt connect for repair move This is work the same as for ipv4. All other hacks about tcp repair are in common code for ipv4 and ipv6, so this patch is enough for repairing ipv6 connections. Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Cc: Pavel Emelyanov Signed-off-by: Andrey Vagin Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 13 +------------ net/ipv4/tcp_output.c | 5 +++++ net/ipv6/tcp_ipv6.c | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) (limited to 'net/ipv6/tcp_ipv6.c') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9dd5b34eb112..1ed230716d51 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -138,14 +138,6 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) } EXPORT_SYMBOL_GPL(tcp_twsk_unique); -static int tcp_repair_connect(struct sock *sk) -{ - tcp_connect_init(sk); - tcp_finish_connect(sk, NULL); - - return 0; -} - /* This will initiate an outgoing connection. */ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -250,10 +242,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->inet_id = tp->write_seq ^ jiffies; - if (likely(!tp->repair)) - err = tcp_connect(sk); - else - err = tcp_repair_connect(sk); + err = tcp_connect(sk); rt = NULL; if (err) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2798706cb063..8ac085573217 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2987,6 +2987,11 @@ int tcp_connect(struct sock *sk) tcp_connect_init(sk); + if (unlikely(tp->repair)) { + tcp_finish_connect(sk, NULL); + return 0; + } + buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation); if (unlikely(buff == NULL)) return -ENOBUFS; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6c0f2526f3f1..6565cf55eb1e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -295,7 +295,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (err) goto late_failure; - if (!tp->write_seq) + if (!tp->write_seq && likely(!tp->repair)) tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, np->daddr.s6_addr32, inet->inet_sport, -- cgit v1.2.3