Skip to content

Commit

Permalink
Merge branch 'inet_csums_part3'
Browse files Browse the repository at this point in the history
Tom Herbert says:

====================
net: Checksum offload changes - Part III

I am working on overhauling RX checksum offload. Goals of this effort
are:

- Specify what exactly it means when driver returns CHECKSUM_UNNECESSARY
- Preserve CHECKSUM_COMPLETE through encapsulation layers
- Don't do skb_checksum more than once per packet
- Unify GRO and non-GRO csum verification as much as possible
- Unify the checksum functions (checksum_init)
- Simply code

What is in this third patch set:

- Remove sk_no_check from sunrpc (doesn't seem to have any effect)
- Eliminate no_check from protosw. All protocols are using default of
  zero for this
- Split sk_no_check into sk_no_check_tx and sk_no_check_rx
- Make enabling of UDP6 more restrictive and explicit
- Support zero UDP6 checksums in l2tp

V2: Took out vxlan changes to set zero csums in IPv6, this will
    be in a later patch set.
V3: Fixed bug in restricting UDP6 checksums.

Please review carefully and test if possible, mucking with basic
checksum functions is always a little precarious :-)
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 23, 2014
2 parents 0c3592b + 6b649fe commit 76fcee2
Show file tree
Hide file tree
Showing 31 changed files with 86 additions and 59 deletions.
2 changes: 1 addition & 1 deletion drivers/scsi/iscsi_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
sk->sk_data_ready = tcp_sw_conn->old_data_ready;
sk->sk_state_change = tcp_sw_conn->old_state_change;
sk->sk_write_space = tcp_sw_conn->old_write_space;
sk->sk_no_check = 0;
sk->sk_no_check_tx = 0;
write_unlock_bh(&sk->sk_callback_lock);
}

Expand Down
24 changes: 23 additions & 1 deletion include/linux/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ struct udp_sock {
#define udp_portaddr_node inet.sk.__sk_common.skc_portaddr_node
int pending; /* Any pending frames ? */
unsigned int corkflag; /* Cork is required */
__u16 encap_type; /* Is this an Encapsulation socket? */
__u8 encap_type; /* Is this an Encapsulation socket? */
unsigned char no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
/*
* Following member retains the information to create a UDP header
* when the socket is uncorked.
Expand Down Expand Up @@ -76,6 +78,26 @@ static inline struct udp_sock *udp_sk(const struct sock *sk)
return (struct udp_sock *)sk;
}

static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
{
udp_sk(sk)->no_check6_tx = val;
}

static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
{
udp_sk(sk)->no_check6_rx = val;
}

static inline bool udp_get_no_check6_tx(struct sock *sk)
{
return udp_sk(sk)->no_check6_tx;
}

static inline bool udp_get_no_check6_rx(struct sock *sk)
{
return udp_sk(sk)->no_check6_rx;
}

#define udp_portaddr_for_each_entry(__sk, node, list) \
hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node)

Expand Down
1 change: 0 additions & 1 deletion include/net/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ struct inet_protosw {
struct proto *prot;
const struct proto_ops *ops;

char no_check; /* checksum on rcv/xmit/none? */
unsigned char flags; /* See INET_PROTOSW_* below. */
};
#define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */
Expand Down
6 changes: 4 additions & 2 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ struct cg_proto;
* @sk_sndbuf: size of send buffer in bytes
* @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
* %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
* @sk_no_check: %SO_NO_CHECK setting, whether or not checkup packets
* @sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets
* @sk_no_check_rx: allow zero checksum in RX packets
* @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
* @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
* @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
Expand Down Expand Up @@ -371,7 +372,8 @@ struct sock {
struct sk_buff_head sk_write_queue;
kmemcheck_bitfield_begin(flags);
unsigned int sk_shutdown : 2,
sk_no_check : 2,
sk_no_check_tx : 1,
sk_no_check_rx : 1,
sk_userlocks : 4,
sk_protocol : 8,
sk_type : 16;
Expand Down
9 changes: 0 additions & 9 deletions include/net/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,6 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
return &table->hash2[hash & table->mask];
}

/* Note: this must match 'valbool' in sock_setsockopt */
#define UDP_CSUM_NOXMIT 1

/* Used by SunRPC/xprt layer. */
#define UDP_CSUM_NORCV 2

/* Default, as per the RFC, is to always do csums. */
#define UDP_CSUM_DEFAULT 0

extern struct proto udp_prot;

extern atomic_long_t udp_memory_allocated;
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/l2tp.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ enum {
L2TP_ATTR_STATS, /* nested */
L2TP_ATTR_IP6_SADDR, /* struct in6_addr */
L2TP_ATTR_IP6_DADDR, /* struct in6_addr */
L2TP_ATTR_UDP_ZERO_CSUM6_TX, /* u8 */
L2TP_ATTR_UDP_ZERO_CSUM6_RX, /* u8 */
__L2TP_ATTR_MAX,
};

Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct udphdr {
/* UDP socket options */
#define UDP_CORK 1 /* Never send partially complete segments */
#define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */
#define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */
#define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */

/* UDP encapsulation types */
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
Expand Down
2 changes: 1 addition & 1 deletion net/appletalk/ddp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
goto out;
}

if (sk->sk_no_check == 1)
if (sk->sk_no_check_tx)
ddp->deh_sum = 0;
else
ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp));
Expand Down
4 changes: 2 additions & 2 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
break;

case SO_NO_CHECK:
sk->sk_no_check = valbool;
sk->sk_no_check_tx = valbool;
break;

case SO_PRIORITY:
Expand Down Expand Up @@ -1064,7 +1064,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;

case SO_NO_CHECK:
v.val = sk->sk_no_check;
v.val = sk->sk_no_check_tx;
break;

case SO_PRIORITY:
Expand Down
1 change: 0 additions & 1 deletion net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,6 @@ static struct inet_protosw dccp_v4_protosw = {
.protocol = IPPROTO_DCCP,
.prot = &dccp_v4_prot,
.ops = &inet_dccp_ops,
.no_check = 0,
.flags = INET_PROTOSW_ICSK,
};

Expand Down
2 changes: 1 addition & 1 deletion net/decnet/af_decnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gf

sk->sk_backlog_rcv = dn_nsp_backlog_rcv;
sk->sk_destruct = dn_destruct;
sk->sk_no_check = 1;
sk->sk_no_check_tx = 1;
sk->sk_family = PF_DECnet;
sk->sk_protocol = 0;
sk->sk_allocation = gfp;
Expand Down
7 changes: 0 additions & 7 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
struct inet_sock *inet;
struct proto *answer_prot;
unsigned char answer_flags;
char answer_no_check;
int try_loading_module = 0;
int err;

Expand Down Expand Up @@ -312,7 +311,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,

sock->ops = answer->ops;
answer_prot = answer->prot;
answer_no_check = answer->no_check;
answer_flags = answer->flags;
rcu_read_unlock();

Expand All @@ -324,7 +322,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
goto out;

err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = SK_CAN_REUSE;

Expand Down Expand Up @@ -1002,7 +999,6 @@ static struct inet_protosw inetsw_array[] =
.protocol = IPPROTO_TCP,
.prot = &tcp_prot,
.ops = &inet_stream_ops,
.no_check = 0,
.flags = INET_PROTOSW_PERMANENT |
INET_PROTOSW_ICSK,
},
Expand All @@ -1012,7 +1008,6 @@ static struct inet_protosw inetsw_array[] =
.protocol = IPPROTO_UDP,
.prot = &udp_prot,
.ops = &inet_dgram_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_PERMANENT,
},

Expand All @@ -1021,7 +1016,6 @@ static struct inet_protosw inetsw_array[] =
.protocol = IPPROTO_ICMP,
.prot = &ping_prot,
.ops = &inet_dgram_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
},

Expand All @@ -1030,7 +1024,6 @@ static struct inet_protosw inetsw_array[] =
.protocol = IPPROTO_IP, /* wild card */
.prot = &raw_prot,
.ops = &inet_sockraw_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
}
};
Expand Down
22 changes: 20 additions & 2 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
if (is_udplite) /* UDP-Lite */
csum = udplite_csum(skb);

else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */
else if (sk->sk_no_check_tx) { /* UDP csum disabled */

skb->ip_summed = CHECKSUM_NONE;
goto send;
Expand Down Expand Up @@ -1968,7 +1968,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
int (*push_pending_frames)(struct sock *))
{
struct udp_sock *up = udp_sk(sk);
int val;
int val, valbool;
int err = 0;
int is_udplite = IS_UDPLITE(sk);

Expand All @@ -1978,6 +1978,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
if (get_user(val, (int __user *)optval))
return -EFAULT;

valbool = val ? 1 : 0;

switch (optname) {
case UDP_CORK:
if (val != 0) {
Expand Down Expand Up @@ -2007,6 +2009,14 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
}
break;

case UDP_NO_CHECK6_TX:
up->no_check6_tx = valbool;
break;

case UDP_NO_CHECK6_RX:
up->no_check6_rx = valbool;
break;

/*
* UDP-Lite's partial checksum coverage (RFC 3828).
*/
Expand Down Expand Up @@ -2089,6 +2099,14 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
val = up->encap_type;
break;

case UDP_NO_CHECK6_TX:
val = up->no_check6_tx;
break;

case UDP_NO_CHECK6_RX:
val = up->no_check6_rx;
break;

/* The following two cannot be changed on UDP sockets, the return is
* always 0 (which corresponds to the full checksum coverage of UDP). */
case UDPLITE_SEND_CSCOV:
Expand Down
1 change: 0 additions & 1 deletion net/ipv4/udplite.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ static struct inet_protosw udplite4_protosw = {
.protocol = IPPROTO_UDPLITE,
.prot = &udplite_prot,
.ops = &inet_dgram_ops,
.no_check = 0, /* must checksum (RFC 3828) */
.flags = INET_PROTOSW_PERMANENT,
};

Expand Down
3 changes: 0 additions & 3 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
struct inet_protosw *answer;
struct proto *answer_prot;
unsigned char answer_flags;
char answer_no_check;
int try_loading_module = 0;
int err;

Expand Down Expand Up @@ -162,7 +161,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,

sock->ops = answer->ops;
answer_prot = answer->prot;
answer_no_check = answer->no_check;
answer_flags = answer->flags;
rcu_read_unlock();

Expand All @@ -176,7 +174,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
sock_init_data(sock, sk);

err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = SK_CAN_REUSE;

Expand Down
1 change: 0 additions & 1 deletion net/ipv6/ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ static struct inet_protosw pingv6_protosw = {
.protocol = IPPROTO_ICMPV6,
.prot = &pingv6_prot,
.ops = &inet6_dgram_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
};

Expand Down
1 change: 0 additions & 1 deletion net/ipv6/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1322,7 +1322,6 @@ static struct inet_protosw rawv6_protosw = {
.protocol = IPPROTO_IP, /* wild card */
.prot = &rawv6_prot,
.ops = &inet6_sockraw_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
};

Expand Down
1 change: 0 additions & 1 deletion net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1992,7 +1992,6 @@ static struct inet_protosw tcpv6_protosw = {
.protocol = IPPROTO_TCP,
.prot = &tcpv6_prot,
.ops = &inet6_stream_ops,
.no_check = 0,
.flags = INET_PROTOSW_PERMANENT |
INET_PROTOSW_ICSK,
};
Expand Down
9 changes: 4 additions & 5 deletions net/ipv6/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,10 +794,10 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
dif = inet6_iif(skb);
sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
while (sk) {
/* If zero checksum and sk_no_check is not on for
/* If zero checksum and no_check is not on for
* the socket then skip it.
*/
if (uh->check || sk->sk_no_check)
if (uh->check || udp_sk(sk)->no_check6_rx)
stack[count++] = sk;

sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr,
Expand Down Expand Up @@ -887,7 +887,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
if (sk != NULL) {
int ret;

if (!uh->check && !sk->sk_no_check) {
if (!uh->check && !udp_sk(sk)->no_check6_rx) {
sock_put(sk);
udp6_csum_zero_error(skb);
goto csum_error;
Expand Down Expand Up @@ -1037,7 +1037,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)

if (is_udplite)
csum = udplite_csum_outgoing(sk, skb);
else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */
else if (up->no_check6_tx) { /* UDP csum disabled */
skb->ip_summed = CHECKSUM_NONE;
goto send;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
Expand Down Expand Up @@ -1507,7 +1507,6 @@ static struct inet_protosw udpv6_protosw = {
.protocol = IPPROTO_UDP,
.prot = &udpv6_prot,
.ops = &inet6_dgram_ops,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_PERMANENT,
};

Expand Down
1 change: 0 additions & 1 deletion net/ipv6/udplite.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ static struct inet_protosw udplite6_protosw = {
.protocol = IPPROTO_UDPLITE,
.prot = &udplitev6_prot,
.ops = &inet6_dgram_ops,
.no_check = 0,
.flags = INET_PROTOSW_PERMANENT,
};

Expand Down
2 changes: 1 addition & 1 deletion net/ipx/af_ipx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ static int ipx_create(struct net *net, struct socket *sock, int protocol,

sk_refcnt_debug_inc(sk);
sock_init_data(sock, sk);
sk->sk_no_check = 1; /* Checksum off by default */
sk->sk_no_check_tx = 1; /* Checksum off by default */
sock->ops = &ipx_dgram_ops;
rc = 0;
out:
Expand Down
3 changes: 2 additions & 1 deletion net/ipx/ipx_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
}

/* Apply checksum. Not allowed on 802.3 links. */
if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023))
if (sk->sk_no_check_tx ||
intrfc->if_dlink_type == htons(IPX_FRAME_8023))
ipx->ipx_checksum = htons(0xFFFF);
else
ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
Expand Down
Loading

0 comments on commit 76fcee2

Please sign in to comment.