diff options
Diffstat (limited to 'drivers/net/xen-netback/netback.c')
-rw-r--r-- | drivers/net/xen-netback/netback.c | 288 |
1 files changed, 167 insertions, 121 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 919b6509455c..78425554a537 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -39,6 +39,7 @@ | |||
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> | ||
42 | 43 | ||
43 | #include <xen/xen.h> | 44 | #include <xen/xen.h> |
44 | #include <xen/events.h> | 45 | #include <xen/events.h> |
@@ -451,7 +452,7 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
451 | } | 452 | } |
452 | 453 | ||
453 | /* Set up a GSO prefix descriptor, if necessary */ | 454 | /* Set up a GSO prefix descriptor, if necessary */ |
454 | if ((1 << skb_shinfo(skb)->gso_type) & vif->gso_prefix_mask) { | 455 | if ((1 << gso_type) & vif->gso_prefix_mask) { |
455 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); | 456 | req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++); |
456 | meta = npo->meta + npo->meta_prod++; | 457 | meta = npo->meta + npo->meta_prod++; |
457 | meta->gso_type = gso_type; | 458 | meta->gso_type = gso_type; |
@@ -607,7 +608,7 @@ void xenvif_rx_action(struct xenvif *vif) | |||
607 | if (!npo.copy_prod) | 608 | if (!npo.copy_prod) |
608 | return; | 609 | return; |
609 | 610 | ||
610 | BUG_ON(npo.copy_prod > ARRAY_SIZE(vif->grant_copy_op)); | 611 | BUG_ON(npo.copy_prod > MAX_GRANT_COPY_OPS); |
611 | gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); | 612 | gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); |
612 | 613 | ||
613 | while ((skb = __skb_dequeue(&rxq)) != NULL) { | 614 | while ((skb = __skb_dequeue(&rxq)) != NULL) { |
@@ -1148,75 +1149,99 @@ static int xenvif_set_skb_gso(struct xenvif *vif, | |||
1148 | return 0; | 1149 | return 0; |
1149 | } | 1150 | } |
1150 | 1151 | ||
1151 | static inline void maybe_pull_tail(struct sk_buff *skb, unsigned int len) | 1152 | static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len, |
1153 | unsigned int max) | ||
1152 | { | 1154 | { |
1153 | if (skb_is_nonlinear(skb) && skb_headlen(skb) < len) { | 1155 | if (skb_headlen(skb) >= len) |
1154 | /* If we need to pullup then pullup to the max, so we | 1156 | return 0; |
1155 | * won't need to do it again. | 1157 | |
1156 | */ | 1158 | /* If we need to pullup then pullup to the max, so we |
1157 | int target = min_t(int, skb->len, MAX_TCP_HEADER); | 1159 | * won't need to do it again. |
1158 | __pskb_pull_tail(skb, target - skb_headlen(skb)); | 1160 | */ |
1159 | } | 1161 | if (max > skb->len) |
1162 | max = skb->len; | ||
1163 | |||
1164 | if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) | ||
1165 | return -ENOMEM; | ||
1166 | |||
1167 | if (skb_headlen(skb) < len) | ||
1168 | return -EPROTO; | ||
1169 | |||
1170 | return 0; | ||
1160 | } | 1171 | } |
1161 | 1172 | ||
1173 | /* This value should be large enough to cover a tagged ethernet header plus | ||
1174 | * maximally sized IP and TCP or UDP headers. | ||
1175 | */ | ||
1176 | #define MAX_IP_HDR_LEN 128 | ||
1177 | |||
1162 | static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, | 1178 | static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, |
1163 | int recalculate_partial_csum) | 1179 | int recalculate_partial_csum) |
1164 | { | 1180 | { |
1165 | struct iphdr *iph = (void *)skb->data; | ||
1166 | unsigned int header_size; | ||
1167 | unsigned int off; | 1181 | unsigned int off; |
1168 | int err = -EPROTO; | 1182 | bool fragment; |
1183 | int err; | ||
1169 | 1184 | ||
1170 | off = sizeof(struct iphdr); | 1185 | fragment = false; |
1171 | 1186 | ||
1172 | header_size = skb->network_header + off + MAX_IPOPTLEN; | 1187 | err = maybe_pull_tail(skb, |
1173 | maybe_pull_tail(skb, header_size); | 1188 | sizeof(struct iphdr), |
1189 | MAX_IP_HDR_LEN); | ||
1190 | if (err < 0) | ||
1191 | goto out; | ||
1174 | 1192 | ||
1175 | off = iph->ihl * 4; | 1193 | if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) |
1194 | fragment = true; | ||
1176 | 1195 | ||
1177 | switch (iph->protocol) { | 1196 | off = ip_hdrlen(skb); |
1178 | case IPPROTO_TCP: | ||
1179 | if (!skb_partial_csum_set(skb, off, | ||
1180 | offsetof(struct tcphdr, check))) | ||
1181 | goto out; | ||
1182 | 1197 | ||
1183 | if (recalculate_partial_csum) { | 1198 | err = -EPROTO; |
1184 | struct tcphdr *tcph = tcp_hdr(skb); | 1199 | |
1200 | if (fragment) | ||
1201 | goto out; | ||
1185 | 1202 | ||
1186 | header_size = skb->network_header + | 1203 | switch (ip_hdr(skb)->protocol) { |
1187 | off + | 1204 | case IPPROTO_TCP: |
1188 | sizeof(struct tcphdr); | 1205 | err = maybe_pull_tail(skb, |
1189 | maybe_pull_tail(skb, header_size); | 1206 | off + sizeof(struct tcphdr), |
1207 | MAX_IP_HDR_LEN); | ||
1208 | if (err < 0) | ||
1209 | goto out; | ||
1190 | 1210 | ||
1191 | tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | 1211 | if (!skb_partial_csum_set(skb, off, |
1192 | skb->len - off, | 1212 | offsetof(struct tcphdr, check))) { |
1193 | IPPROTO_TCP, 0); | 1213 | err = -EPROTO; |
1214 | goto out; | ||
1194 | } | 1215 | } |
1216 | |||
1217 | if (recalculate_partial_csum) | ||
1218 | tcp_hdr(skb)->check = | ||
1219 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
1220 | ip_hdr(skb)->daddr, | ||
1221 | skb->len - off, | ||
1222 | IPPROTO_TCP, 0); | ||
1195 | break; | 1223 | break; |
1196 | case IPPROTO_UDP: | 1224 | case IPPROTO_UDP: |
1197 | if (!skb_partial_csum_set(skb, off, | 1225 | err = maybe_pull_tail(skb, |
1198 | offsetof(struct udphdr, check))) | 1226 | off + sizeof(struct udphdr), |
1227 | MAX_IP_HDR_LEN); | ||
1228 | if (err < 0) | ||
1199 | goto out; | 1229 | goto out; |
1200 | 1230 | ||
1201 | if (recalculate_partial_csum) { | 1231 | if (!skb_partial_csum_set(skb, off, |
1202 | struct udphdr *udph = udp_hdr(skb); | 1232 | offsetof(struct udphdr, check))) { |
1203 | 1233 | err = -EPROTO; | |
1204 | header_size = skb->network_header + | 1234 | goto out; |
1205 | off + | ||
1206 | sizeof(struct udphdr); | ||
1207 | maybe_pull_tail(skb, header_size); | ||
1208 | |||
1209 | udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
1210 | skb->len - off, | ||
1211 | IPPROTO_UDP, 0); | ||
1212 | } | 1235 | } |
1236 | |||
1237 | if (recalculate_partial_csum) | ||
1238 | udp_hdr(skb)->check = | ||
1239 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
1240 | ip_hdr(skb)->daddr, | ||
1241 | skb->len - off, | ||
1242 | IPPROTO_UDP, 0); | ||
1213 | break; | 1243 | break; |
1214 | default: | 1244 | default: |
1215 | if (net_ratelimit()) | ||
1216 | netdev_err(vif->dev, | ||
1217 | "Attempting to checksum a non-TCP/UDP packet, " | ||
1218 | "dropping a protocol %d packet\n", | ||
1219 | iph->protocol); | ||
1220 | goto out; | 1245 | goto out; |
1221 | } | 1246 | } |
1222 | 1247 | ||
@@ -1226,121 +1251,142 @@ out: | |||
1226 | return err; | 1251 | return err; |
1227 | } | 1252 | } |
1228 | 1253 | ||
1254 | /* This value should be large enough to cover a tagged ethernet header plus | ||
1255 | * an IPv6 header, all options, and a maximal TCP or UDP header. | ||
1256 | */ | ||
1257 | #define MAX_IPV6_HDR_LEN 256 | ||
1258 | |||
1259 | #define OPT_HDR(type, skb, off) \ | ||
1260 | (type *)(skb_network_header(skb) + (off)) | ||
1261 | |||
1229 | static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, | 1262 | static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, |
1230 | int recalculate_partial_csum) | 1263 | int recalculate_partial_csum) |
1231 | { | 1264 | { |
1232 | int err = -EPROTO; | 1265 | int err; |
1233 | struct ipv6hdr *ipv6h = (void *)skb->data; | ||
1234 | u8 nexthdr; | 1266 | u8 nexthdr; |
1235 | unsigned int header_size; | ||
1236 | unsigned int off; | 1267 | unsigned int off; |
1268 | unsigned int len; | ||
1237 | bool fragment; | 1269 | bool fragment; |
1238 | bool done; | 1270 | bool done; |
1239 | 1271 | ||
1272 | fragment = false; | ||
1240 | done = false; | 1273 | done = false; |
1241 | 1274 | ||
1242 | off = sizeof(struct ipv6hdr); | 1275 | off = sizeof(struct ipv6hdr); |
1243 | 1276 | ||
1244 | header_size = skb->network_header + off; | 1277 | err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); |
1245 | maybe_pull_tail(skb, header_size); | 1278 | if (err < 0) |
1279 | goto out; | ||
1246 | 1280 | ||
1247 | nexthdr = ipv6h->nexthdr; | 1281 | nexthdr = ipv6_hdr(skb)->nexthdr; |
1248 | 1282 | ||
1249 | while ((off <= sizeof(struct ipv6hdr) + ntohs(ipv6h->payload_len)) && | 1283 | len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); |
1250 | !done) { | 1284 | while (off <= len && !done) { |
1251 | switch (nexthdr) { | 1285 | switch (nexthdr) { |
1252 | case IPPROTO_DSTOPTS: | 1286 | case IPPROTO_DSTOPTS: |
1253 | case IPPROTO_HOPOPTS: | 1287 | case IPPROTO_HOPOPTS: |
1254 | case IPPROTO_ROUTING: { | 1288 | case IPPROTO_ROUTING: { |
1255 | struct ipv6_opt_hdr *hp = (void *)(skb->data + off); | 1289 | struct ipv6_opt_hdr *hp; |
1256 | 1290 | ||
1257 | header_size = skb->network_header + | 1291 | err = maybe_pull_tail(skb, |
1258 | off + | 1292 | off + |
1259 | sizeof(struct ipv6_opt_hdr); | 1293 | sizeof(struct ipv6_opt_hdr), |
1260 | maybe_pull_tail(skb, header_size); | 1294 | MAX_IPV6_HDR_LEN); |
1295 | if (err < 0) | ||
1296 | goto out; | ||
1261 | 1297 | ||
1298 | hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); | ||
1262 | nexthdr = hp->nexthdr; | 1299 | nexthdr = hp->nexthdr; |
1263 | off += ipv6_optlen(hp); | 1300 | off += ipv6_optlen(hp); |
1264 | break; | 1301 | break; |
1265 | } | 1302 | } |
1266 | case IPPROTO_AH: { | 1303 | case IPPROTO_AH: { |
1267 | struct ip_auth_hdr *hp = (void *)(skb->data + off); | 1304 | struct ip_auth_hdr *hp; |
1268 | 1305 | ||
1269 | header_size = skb->network_header + | 1306 | err = maybe_pull_tail(skb, |
1270 | off + | 1307 | off + |
1271 | sizeof(struct ip_auth_hdr); | 1308 | sizeof(struct ip_auth_hdr), |
1272 | maybe_pull_tail(skb, header_size); | 1309 | MAX_IPV6_HDR_LEN); |
1310 | if (err < 0) | ||
1311 | goto out; | ||
1273 | 1312 | ||
1313 | hp = OPT_HDR(struct ip_auth_hdr, skb, off); | ||
1274 | nexthdr = hp->nexthdr; | 1314 | nexthdr = hp->nexthdr; |
1275 | off += (hp->hdrlen+2)<<2; | 1315 | off += ipv6_authlen(hp); |
1316 | break; | ||
1317 | } | ||
1318 | case IPPROTO_FRAGMENT: { | ||
1319 | struct frag_hdr *hp; | ||
1320 | |||
1321 | err = maybe_pull_tail(skb, | ||
1322 | off + | ||
1323 | sizeof(struct frag_hdr), | ||
1324 | MAX_IPV6_HDR_LEN); | ||
1325 | if (err < 0) | ||
1326 | goto out; | ||
1327 | |||
1328 | hp = OPT_HDR(struct frag_hdr, skb, off); | ||
1329 | |||
1330 | if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) | ||
1331 | fragment = true; | ||
1332 | |||
1333 | nexthdr = hp->nexthdr; | ||
1334 | off += sizeof(struct frag_hdr); | ||
1276 | break; | 1335 | break; |
1277 | } | 1336 | } |
1278 | case IPPROTO_FRAGMENT: | ||
1279 | fragment = true; | ||
1280 | /* fall through */ | ||
1281 | default: | 1337 | default: |
1282 | done = true; | 1338 | done = true; |
1283 | break; | 1339 | break; |
1284 | } | 1340 | } |
1285 | } | 1341 | } |
1286 | 1342 | ||
1287 | if (!done) { | 1343 | err = -EPROTO; |
1288 | if (net_ratelimit()) | ||
1289 | netdev_err(vif->dev, "Failed to parse packet header\n"); | ||
1290 | goto out; | ||
1291 | } | ||
1292 | 1344 | ||
1293 | if (fragment) { | 1345 | if (!done || fragment) |
1294 | if (net_ratelimit()) | ||
1295 | netdev_err(vif->dev, "Packet is a fragment!\n"); | ||
1296 | goto out; | 1346 | goto out; |
1297 | } | ||
1298 | 1347 | ||
1299 | switch (nexthdr) { | 1348 | switch (nexthdr) { |
1300 | case IPPROTO_TCP: | 1349 | case IPPROTO_TCP: |
1301 | if (!skb_partial_csum_set(skb, off, | 1350 | err = maybe_pull_tail(skb, |
1302 | offsetof(struct tcphdr, check))) | 1351 | off + sizeof(struct tcphdr), |
1352 | MAX_IPV6_HDR_LEN); | ||
1353 | if (err < 0) | ||
1303 | goto out; | 1354 | goto out; |
1304 | 1355 | ||
1305 | if (recalculate_partial_csum) { | 1356 | if (!skb_partial_csum_set(skb, off, |
1306 | struct tcphdr *tcph = tcp_hdr(skb); | 1357 | offsetof(struct tcphdr, check))) { |
1307 | 1358 | err = -EPROTO; | |
1308 | header_size = skb->network_header + | 1359 | goto out; |
1309 | off + | ||
1310 | sizeof(struct tcphdr); | ||
1311 | maybe_pull_tail(skb, header_size); | ||
1312 | |||
1313 | tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, | ||
1314 | &ipv6h->daddr, | ||
1315 | skb->len - off, | ||
1316 | IPPROTO_TCP, 0); | ||
1317 | } | 1360 | } |
1361 | |||
1362 | if (recalculate_partial_csum) | ||
1363 | tcp_hdr(skb)->check = | ||
1364 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
1365 | &ipv6_hdr(skb)->daddr, | ||
1366 | skb->len - off, | ||
1367 | IPPROTO_TCP, 0); | ||
1318 | break; | 1368 | break; |
1319 | case IPPROTO_UDP: | 1369 | case IPPROTO_UDP: |
1320 | if (!skb_partial_csum_set(skb, off, | 1370 | err = maybe_pull_tail(skb, |
1321 | offsetof(struct udphdr, check))) | 1371 | off + sizeof(struct udphdr), |
1372 | MAX_IPV6_HDR_LEN); | ||
1373 | if (err < 0) | ||
1322 | goto out; | 1374 | goto out; |
1323 | 1375 | ||
1324 | if (recalculate_partial_csum) { | 1376 | if (!skb_partial_csum_set(skb, off, |
1325 | struct udphdr *udph = udp_hdr(skb); | 1377 | offsetof(struct udphdr, check))) { |
1326 | 1378 | err = -EPROTO; | |
1327 | header_size = skb->network_header + | 1379 | goto out; |
1328 | off + | ||
1329 | sizeof(struct udphdr); | ||
1330 | maybe_pull_tail(skb, header_size); | ||
1331 | |||
1332 | udph->check = ~csum_ipv6_magic(&ipv6h->saddr, | ||
1333 | &ipv6h->daddr, | ||
1334 | skb->len - off, | ||
1335 | IPPROTO_UDP, 0); | ||
1336 | } | 1380 | } |
1381 | |||
1382 | if (recalculate_partial_csum) | ||
1383 | udp_hdr(skb)->check = | ||
1384 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
1385 | &ipv6_hdr(skb)->daddr, | ||
1386 | skb->len - off, | ||
1387 | IPPROTO_UDP, 0); | ||
1337 | break; | 1388 | break; |
1338 | default: | 1389 | default: |
1339 | if (net_ratelimit()) | ||
1340 | netdev_err(vif->dev, | ||
1341 | "Attempting to checksum a non-TCP/UDP packet, " | ||
1342 | "dropping a protocol %d packet\n", | ||
1343 | nexthdr); | ||
1344 | goto out; | 1390 | goto out; |
1345 | } | 1391 | } |
1346 | 1392 | ||
@@ -1410,14 +1456,15 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | |||
1410 | return false; | 1456 | return false; |
1411 | } | 1457 | } |
1412 | 1458 | ||
1413 | static unsigned xenvif_tx_build_gops(struct xenvif *vif) | 1459 | static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) |
1414 | { | 1460 | { |
1415 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; | 1461 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; |
1416 | struct sk_buff *skb; | 1462 | struct sk_buff *skb; |
1417 | int ret; | 1463 | int ret; |
1418 | 1464 | ||
1419 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX | 1465 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX |
1420 | < MAX_PENDING_REQS)) { | 1466 | < MAX_PENDING_REQS) && |
1467 | (skb_queue_len(&vif->tx_queue) < budget)) { | ||
1421 | struct xen_netif_tx_request txreq; | 1468 | struct xen_netif_tx_request txreq; |
1422 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; | 1469 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; |
1423 | struct page *page; | 1470 | struct page *page; |
@@ -1439,7 +1486,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
1439 | continue; | 1486 | continue; |
1440 | } | 1487 | } |
1441 | 1488 | ||
1442 | RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do); | 1489 | work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); |
1443 | if (!work_to_do) | 1490 | if (!work_to_do) |
1444 | break; | 1491 | break; |
1445 | 1492 | ||
@@ -1579,14 +1626,13 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
1579 | } | 1626 | } |
1580 | 1627 | ||
1581 | 1628 | ||
1582 | static int xenvif_tx_submit(struct xenvif *vif, int budget) | 1629 | static int xenvif_tx_submit(struct xenvif *vif) |
1583 | { | 1630 | { |
1584 | struct gnttab_copy *gop = vif->tx_copy_ops; | 1631 | struct gnttab_copy *gop = vif->tx_copy_ops; |
1585 | struct sk_buff *skb; | 1632 | struct sk_buff *skb; |
1586 | int work_done = 0; | 1633 | int work_done = 0; |
1587 | 1634 | ||
1588 | while (work_done < budget && | 1635 | while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) { |
1589 | (skb = __skb_dequeue(&vif->tx_queue)) != NULL) { | ||
1590 | struct xen_netif_tx_request *txp; | 1636 | struct xen_netif_tx_request *txp; |
1591 | u16 pending_idx; | 1637 | u16 pending_idx; |
1592 | unsigned data_len; | 1638 | unsigned data_len; |
@@ -1661,14 +1707,14 @@ int xenvif_tx_action(struct xenvif *vif, int budget) | |||
1661 | if (unlikely(!tx_work_todo(vif))) | 1707 | if (unlikely(!tx_work_todo(vif))) |
1662 | return 0; | 1708 | return 0; |
1663 | 1709 | ||
1664 | nr_gops = xenvif_tx_build_gops(vif); | 1710 | nr_gops = xenvif_tx_build_gops(vif, budget); |
1665 | 1711 | ||
1666 | if (nr_gops == 0) | 1712 | if (nr_gops == 0) |
1667 | return 0; | 1713 | return 0; |
1668 | 1714 | ||
1669 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); | 1715 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); |
1670 | 1716 | ||
1671 | work_done = xenvif_tx_submit(vif, nr_gops); | 1717 | work_done = xenvif_tx_submit(vif); |
1672 | 1718 | ||
1673 | return work_done; | 1719 | return work_done; |
1674 | } | 1720 | } |