aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPaul Durrant <Paul.Durrant@citrix.com>2014-01-09 05:02:47 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-14 17:24:19 -0500
commit2721637c1c0f644d7d67d0698c4a32b440d7f0f8 (patch)
tree1abb9f02e806fe06b87563dc1c0127ac6aedd254 /drivers
parented1f50c3a7c1ad1b1b4d584308eab77d57a330f8 (diff)
xen-netback: use new skb_checksum_setup function
Use skb_checksum_setup to set up partial checksum offsets rather then a private implementation. Signed-off-by: Paul Durrant <paul.durrant@citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> Acked-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/xen-netback/netback.c260
1 files changed, 3 insertions, 257 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 27385639b6e5..6b62c3eb8e18 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -39,7 +39,6 @@
39#include <linux/udp.h> 39#include <linux/udp.h>
40 40
41#include <net/tcp.h> 41#include <net/tcp.h>
42#include <net/ip6_checksum.h>
43 42
44#include <xen/xen.h> 43#include <xen/xen.h>
45#include <xen/events.h> 44#include <xen/events.h>
@@ -1051,257 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
1051 return 0; 1050 return 0;
1052} 1051}
1053 1052
1054static 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
1080static 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
1152out:
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
1164static 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
1297out:
1298 return err;
1299}
1300
1301static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) 1053static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
1302{ 1054{
1303 int err = -EPROTO; 1055 bool recalculate_partial_csum = false;
1304 int recalculate_partial_csum = 0;
1305 1056
1306 /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy 1057 /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
1307 * peers can fail to set NETRXF_csum_blank when sending a GSO 1058 * 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)
1311 if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { 1062 if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
1312 vif->rx_gso_checksum_fixup++; 1063 vif->rx_gso_checksum_fixup++;
1313 skb->ip_summed = CHECKSUM_PARTIAL; 1064 skb->ip_summed = CHECKSUM_PARTIAL;
1314 recalculate_partial_csum = 1; 1065 recalculate_partial_csum = true;
1315 } 1066 }
1316 1067
1317 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ 1068 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
1318 if (skb->ip_summed != CHECKSUM_PARTIAL) 1069 if (skb->ip_summed != CHECKSUM_PARTIAL)
1319 return 0; 1070 return 0;
1320 1071
1321 if (skb->protocol == htons(ETH_P_IP)) 1072 return skb_checksum_setup(skb, recalculate_partial_csum);
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;
1327} 1073}
1328 1074
1329static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) 1075static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)