Skip to content

Commit a49da88

Browse files
committed
Merge branch 'skb_checksum_help'
Paul Durrant says: ==================== make skb_checksum_setup generally available Both xen-netfront and xen-netback need to be able to set up the partial checksum offset of an skb and may also need to recalculate the pseudo- header checksum in the process. This functionality is currently private and duplicated between the two drivers. Patch #1 of this series moves the implementation into the core network code as there is nothing xen-specific about it and it is potentially useful to any network driver. Patch #2 removes the private implementation from netback. Patch #3 removes the private implementation from netfront. v2: - Put skb_checksum_setup in skbuff.c rather than dev.c - remove inline ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents b86f81c + b5cf66c commit a49da88

File tree

4 files changed

+281
-302
lines changed

4 files changed

+281
-302
lines changed

drivers/net/xen-netback/netback.c

Lines changed: 3 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
#include <linux/udp.h>
4040

4141
#include <net/tcp.h>
42-
#include <net/ip6_checksum.h>
4342

4443
#include <xen/xen.h>
4544
#include <xen/events.h>
@@ -1051,257 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
10511050
return 0;
10521051
}
10531052

1054-
static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len,
1055-
unsigned int max)
1056-
{
1057-
if (skb_headlen(skb) >= len)
1058-
return 0;
1059-
1060-
/* If we need to pullup then pullup to the max, so we
1061-
* won't need to do it again.
1062-
*/
1063-
if (max > skb->len)
1064-
max = skb->len;
1065-
1066-
if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
1067-
return -ENOMEM;
1068-
1069-
if (skb_headlen(skb) < len)
1070-
return -EPROTO;
1071-
1072-
return 0;
1073-
}
1074-
1075-
/* This value should be large enough to cover a tagged ethernet header plus
1076-
* maximally sized IP and TCP or UDP headers.
1077-
*/
1078-
#define MAX_IP_HDR_LEN 128
1079-
1080-
static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
1081-
int recalculate_partial_csum)
1082-
{
1083-
unsigned int off;
1084-
bool fragment;
1085-
int err;
1086-
1087-
fragment = false;
1088-
1089-
err = maybe_pull_tail(skb,
1090-
sizeof(struct iphdr),
1091-
MAX_IP_HDR_LEN);
1092-
if (err < 0)
1093-
goto out;
1094-
1095-
if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
1096-
fragment = true;
1097-
1098-
off = ip_hdrlen(skb);
1099-
1100-
err = -EPROTO;
1101-
1102-
if (fragment)
1103-
goto out;
1104-
1105-
switch (ip_hdr(skb)->protocol) {
1106-
case IPPROTO_TCP:
1107-
err = maybe_pull_tail(skb,
1108-
off + sizeof(struct tcphdr),
1109-
MAX_IP_HDR_LEN);
1110-
if (err < 0)
1111-
goto out;
1112-
1113-
if (!skb_partial_csum_set(skb, off,
1114-
offsetof(struct tcphdr, check))) {
1115-
err = -EPROTO;
1116-
goto out;
1117-
}
1118-
1119-
if (recalculate_partial_csum)
1120-
tcp_hdr(skb)->check =
1121-
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1122-
ip_hdr(skb)->daddr,
1123-
skb->len - off,
1124-
IPPROTO_TCP, 0);
1125-
break;
1126-
case IPPROTO_UDP:
1127-
err = maybe_pull_tail(skb,
1128-
off + sizeof(struct udphdr),
1129-
MAX_IP_HDR_LEN);
1130-
if (err < 0)
1131-
goto out;
1132-
1133-
if (!skb_partial_csum_set(skb, off,
1134-
offsetof(struct udphdr, check))) {
1135-
err = -EPROTO;
1136-
goto out;
1137-
}
1138-
1139-
if (recalculate_partial_csum)
1140-
udp_hdr(skb)->check =
1141-
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1142-
ip_hdr(skb)->daddr,
1143-
skb->len - off,
1144-
IPPROTO_UDP, 0);
1145-
break;
1146-
default:
1147-
goto out;
1148-
}
1149-
1150-
err = 0;
1151-
1152-
out:
1153-
return err;
1154-
}
1155-
1156-
/* This value should be large enough to cover a tagged ethernet header plus
1157-
* an IPv6 header, all options, and a maximal TCP or UDP header.
1158-
*/
1159-
#define MAX_IPV6_HDR_LEN 256
1160-
1161-
#define OPT_HDR(type, skb, off) \
1162-
(type *)(skb_network_header(skb) + (off))
1163-
1164-
static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1165-
int recalculate_partial_csum)
1166-
{
1167-
int err;
1168-
u8 nexthdr;
1169-
unsigned int off;
1170-
unsigned int len;
1171-
bool fragment;
1172-
bool done;
1173-
1174-
fragment = false;
1175-
done = false;
1176-
1177-
off = sizeof(struct ipv6hdr);
1178-
1179-
err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
1180-
if (err < 0)
1181-
goto out;
1182-
1183-
nexthdr = ipv6_hdr(skb)->nexthdr;
1184-
1185-
len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
1186-
while (off <= len && !done) {
1187-
switch (nexthdr) {
1188-
case IPPROTO_DSTOPTS:
1189-
case IPPROTO_HOPOPTS:
1190-
case IPPROTO_ROUTING: {
1191-
struct ipv6_opt_hdr *hp;
1192-
1193-
err = maybe_pull_tail(skb,
1194-
off +
1195-
sizeof(struct ipv6_opt_hdr),
1196-
MAX_IPV6_HDR_LEN);
1197-
if (err < 0)
1198-
goto out;
1199-
1200-
hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
1201-
nexthdr = hp->nexthdr;
1202-
off += ipv6_optlen(hp);
1203-
break;
1204-
}
1205-
case IPPROTO_AH: {
1206-
struct ip_auth_hdr *hp;
1207-
1208-
err = maybe_pull_tail(skb,
1209-
off +
1210-
sizeof(struct ip_auth_hdr),
1211-
MAX_IPV6_HDR_LEN);
1212-
if (err < 0)
1213-
goto out;
1214-
1215-
hp = OPT_HDR(struct ip_auth_hdr, skb, off);
1216-
nexthdr = hp->nexthdr;
1217-
off += ipv6_authlen(hp);
1218-
break;
1219-
}
1220-
case IPPROTO_FRAGMENT: {
1221-
struct frag_hdr *hp;
1222-
1223-
err = maybe_pull_tail(skb,
1224-
off +
1225-
sizeof(struct frag_hdr),
1226-
MAX_IPV6_HDR_LEN);
1227-
if (err < 0)
1228-
goto out;
1229-
1230-
hp = OPT_HDR(struct frag_hdr, skb, off);
1231-
1232-
if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
1233-
fragment = true;
1234-
1235-
nexthdr = hp->nexthdr;
1236-
off += sizeof(struct frag_hdr);
1237-
break;
1238-
}
1239-
default:
1240-
done = true;
1241-
break;
1242-
}
1243-
}
1244-
1245-
err = -EPROTO;
1246-
1247-
if (!done || fragment)
1248-
goto out;
1249-
1250-
switch (nexthdr) {
1251-
case IPPROTO_TCP:
1252-
err = maybe_pull_tail(skb,
1253-
off + sizeof(struct tcphdr),
1254-
MAX_IPV6_HDR_LEN);
1255-
if (err < 0)
1256-
goto out;
1257-
1258-
if (!skb_partial_csum_set(skb, off,
1259-
offsetof(struct tcphdr, check))) {
1260-
err = -EPROTO;
1261-
goto out;
1262-
}
1263-
1264-
if (recalculate_partial_csum)
1265-
tcp_hdr(skb)->check =
1266-
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1267-
&ipv6_hdr(skb)->daddr,
1268-
skb->len - off,
1269-
IPPROTO_TCP, 0);
1270-
break;
1271-
case IPPROTO_UDP:
1272-
err = maybe_pull_tail(skb,
1273-
off + sizeof(struct udphdr),
1274-
MAX_IPV6_HDR_LEN);
1275-
if (err < 0)
1276-
goto out;
1277-
1278-
if (!skb_partial_csum_set(skb, off,
1279-
offsetof(struct udphdr, check))) {
1280-
err = -EPROTO;
1281-
goto out;
1282-
}
1283-
1284-
if (recalculate_partial_csum)
1285-
udp_hdr(skb)->check =
1286-
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1287-
&ipv6_hdr(skb)->daddr,
1288-
skb->len - off,
1289-
IPPROTO_UDP, 0);
1290-
break;
1291-
default:
1292-
goto out;
1293-
}
1294-
1295-
err = 0;
1296-
1297-
out:
1298-
return err;
1299-
}
1300-
13011053
static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
13021054
{
1303-
int err = -EPROTO;
1304-
int recalculate_partial_csum = 0;
1055+
bool recalculate_partial_csum = false;
13051056

13061057
/* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
13071058
* peers can fail to set NETRXF_csum_blank when sending a GSO
@@ -1311,19 +1062,14 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
13111062
if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
13121063
vif->rx_gso_checksum_fixup++;
13131064
skb->ip_summed = CHECKSUM_PARTIAL;
1314-
recalculate_partial_csum = 1;
1065+
recalculate_partial_csum = true;
13151066
}
13161067

13171068
/* A non-CHECKSUM_PARTIAL SKB does not require setup. */
13181069
if (skb->ip_summed != CHECKSUM_PARTIAL)
13191070
return 0;
13201071

1321-
if (skb->protocol == htons(ETH_P_IP))
1322-
err = checksum_setup_ip(vif, skb, recalculate_partial_csum);
1323-
else if (skb->protocol == htons(ETH_P_IPV6))
1324-
err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum);
1325-
1326-
return err;
1072+
return skb_checksum_setup(skb, recalculate_partial_csum);
13271073
}
13281074

13291075
static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)

drivers/net/xen-netfront.c

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -859,9 +859,7 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
859859

860860
static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
861861
{
862-
struct iphdr *iph;
863-
int err = -EPROTO;
864-
int recalculate_partial_csum = 0;
862+
bool recalculate_partial_csum = false;
865863

866864
/*
867865
* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
@@ -873,54 +871,14 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
873871
struct netfront_info *np = netdev_priv(dev);
874872
np->rx_gso_checksum_fixup++;
875873
skb->ip_summed = CHECKSUM_PARTIAL;
876-
recalculate_partial_csum = 1;
874+
recalculate_partial_csum = true;
877875
}
878876

879877
/* A non-CHECKSUM_PARTIAL SKB does not require setup. */
880878
if (skb->ip_summed != CHECKSUM_PARTIAL)
881879
return 0;
882880

883-
if (skb->protocol != htons(ETH_P_IP))
884-
goto out;
885-
886-
iph = (void *)skb->data;
887-
888-
switch (iph->protocol) {
889-
case IPPROTO_TCP:
890-
if (!skb_partial_csum_set(skb, 4 * iph->ihl,
891-
offsetof(struct tcphdr, check)))
892-
goto out;
893-
894-
if (recalculate_partial_csum) {
895-
struct tcphdr *tcph = tcp_hdr(skb);
896-
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
897-
skb->len - iph->ihl*4,
898-
IPPROTO_TCP, 0);
899-
}
900-
break;
901-
case IPPROTO_UDP:
902-
if (!skb_partial_csum_set(skb, 4 * iph->ihl,
903-
offsetof(struct udphdr, check)))
904-
goto out;
905-
906-
if (recalculate_partial_csum) {
907-
struct udphdr *udph = udp_hdr(skb);
908-
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
909-
skb->len - iph->ihl*4,
910-
IPPROTO_UDP, 0);
911-
}
912-
break;
913-
default:
914-
if (net_ratelimit())
915-
pr_err("Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n",
916-
iph->protocol);
917-
goto out;
918-
}
919-
920-
err = 0;
921-
922-
out:
923-
return err;
881+
return skb_checksum_setup(skb, recalculate_partial_csum);
924882
}
925883

926884
static int handle_incoming_queue(struct net_device *dev,

include/linux/skbuff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,6 +2893,8 @@ static inline void skb_checksum_none_assert(const struct sk_buff *skb)
28932893

28942894
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
28952895

2896+
int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
2897+
28962898
u32 __skb_get_poff(const struct sk_buff *skb);
28972899

28982900
/**

0 commit comments

Comments
 (0)