diff options
Diffstat (limited to 'drivers/net/xen-netback/netback.c')
-rw-r--r-- | drivers/net/xen-netback/netback.c | 270 |
1 files changed, 154 insertions, 116 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 919b6509455c..27bbe58dcbe7 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; |
@@ -1148,75 +1149,95 @@ 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; | ||
1184 | |||
1185 | fragment = false; | ||
1169 | 1186 | ||
1170 | off = sizeof(struct iphdr); | 1187 | err = maybe_pull_tail(skb, |
1188 | sizeof(struct iphdr), | ||
1189 | MAX_IP_HDR_LEN); | ||
1190 | if (err < 0) | ||
1191 | goto out; | ||
1192 | |||
1193 | if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) | ||
1194 | fragment = true; | ||
1171 | 1195 | ||
1172 | header_size = skb->network_header + off + MAX_IPOPTLEN; | 1196 | off = ip_hdrlen(skb); |
1173 | maybe_pull_tail(skb, header_size); | ||
1174 | 1197 | ||
1175 | off = iph->ihl * 4; | 1198 | err = -EPROTO; |
1199 | |||
1200 | if (fragment) | ||
1201 | goto out; | ||
1176 | 1202 | ||
1177 | switch (iph->protocol) { | 1203 | switch (ip_hdr(skb)->protocol) { |
1178 | case IPPROTO_TCP: | 1204 | case IPPROTO_TCP: |
1205 | err = maybe_pull_tail(skb, | ||
1206 | off + sizeof(struct tcphdr), | ||
1207 | MAX_IP_HDR_LEN); | ||
1208 | if (err < 0) | ||
1209 | goto out; | ||
1210 | |||
1179 | if (!skb_partial_csum_set(skb, off, | 1211 | if (!skb_partial_csum_set(skb, off, |
1180 | offsetof(struct tcphdr, check))) | 1212 | offsetof(struct tcphdr, check))) |
1181 | goto out; | 1213 | goto out; |
1182 | 1214 | ||
1183 | if (recalculate_partial_csum) { | 1215 | if (recalculate_partial_csum) |
1184 | struct tcphdr *tcph = tcp_hdr(skb); | 1216 | tcp_hdr(skb)->check = |
1185 | 1217 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | |
1186 | header_size = skb->network_header + | 1218 | ip_hdr(skb)->daddr, |
1187 | off + | 1219 | skb->len - off, |
1188 | sizeof(struct tcphdr); | 1220 | IPPROTO_TCP, 0); |
1189 | maybe_pull_tail(skb, header_size); | ||
1190 | |||
1191 | tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
1192 | skb->len - off, | ||
1193 | IPPROTO_TCP, 0); | ||
1194 | } | ||
1195 | break; | 1221 | break; |
1196 | case IPPROTO_UDP: | 1222 | case IPPROTO_UDP: |
1223 | err = maybe_pull_tail(skb, | ||
1224 | off + sizeof(struct udphdr), | ||
1225 | MAX_IP_HDR_LEN); | ||
1226 | if (err < 0) | ||
1227 | goto out; | ||
1228 | |||
1197 | if (!skb_partial_csum_set(skb, off, | 1229 | if (!skb_partial_csum_set(skb, off, |
1198 | offsetof(struct udphdr, check))) | 1230 | offsetof(struct udphdr, check))) |
1199 | goto out; | 1231 | goto out; |
1200 | 1232 | ||
1201 | if (recalculate_partial_csum) { | 1233 | if (recalculate_partial_csum) |
1202 | struct udphdr *udph = udp_hdr(skb); | 1234 | udp_hdr(skb)->check = |
1203 | 1235 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | |
1204 | header_size = skb->network_header + | 1236 | ip_hdr(skb)->daddr, |
1205 | off + | 1237 | skb->len - off, |
1206 | sizeof(struct udphdr); | 1238 | IPPROTO_UDP, 0); |
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 | } | ||
1213 | break; | 1239 | break; |
1214 | default: | 1240 | 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; | 1241 | goto out; |
1221 | } | 1242 | } |
1222 | 1243 | ||
@@ -1226,121 +1247,138 @@ out: | |||
1226 | return err; | 1247 | return err; |
1227 | } | 1248 | } |
1228 | 1249 | ||
1250 | /* This value should be large enough to cover a tagged ethernet header plus | ||
1251 | * an IPv6 header, all options, and a maximal TCP or UDP header. | ||
1252 | */ | ||
1253 | #define MAX_IPV6_HDR_LEN 256 | ||
1254 | |||
1255 | #define OPT_HDR(type, skb, off) \ | ||
1256 | (type *)(skb_network_header(skb) + (off)) | ||
1257 | |||
1229 | static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, | 1258 | static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, |
1230 | int recalculate_partial_csum) | 1259 | int recalculate_partial_csum) |
1231 | { | 1260 | { |
1232 | int err = -EPROTO; | 1261 | int err; |
1233 | struct ipv6hdr *ipv6h = (void *)skb->data; | ||
1234 | u8 nexthdr; | 1262 | u8 nexthdr; |
1235 | unsigned int header_size; | ||
1236 | unsigned int off; | 1263 | unsigned int off; |
1264 | unsigned int len; | ||
1237 | bool fragment; | 1265 | bool fragment; |
1238 | bool done; | 1266 | bool done; |
1239 | 1267 | ||
1268 | fragment = false; | ||
1240 | done = false; | 1269 | done = false; |
1241 | 1270 | ||
1242 | off = sizeof(struct ipv6hdr); | 1271 | off = sizeof(struct ipv6hdr); |
1243 | 1272 | ||
1244 | header_size = skb->network_header + off; | 1273 | err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); |
1245 | maybe_pull_tail(skb, header_size); | 1274 | if (err < 0) |
1275 | goto out; | ||
1246 | 1276 | ||
1247 | nexthdr = ipv6h->nexthdr; | 1277 | nexthdr = ipv6_hdr(skb)->nexthdr; |
1248 | 1278 | ||
1249 | while ((off <= sizeof(struct ipv6hdr) + ntohs(ipv6h->payload_len)) && | 1279 | len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); |
1250 | !done) { | 1280 | while (off <= len && !done) { |
1251 | switch (nexthdr) { | 1281 | switch (nexthdr) { |
1252 | case IPPROTO_DSTOPTS: | 1282 | case IPPROTO_DSTOPTS: |
1253 | case IPPROTO_HOPOPTS: | 1283 | case IPPROTO_HOPOPTS: |
1254 | case IPPROTO_ROUTING: { | 1284 | case IPPROTO_ROUTING: { |
1255 | struct ipv6_opt_hdr *hp = (void *)(skb->data + off); | 1285 | struct ipv6_opt_hdr *hp; |
1256 | 1286 | ||
1257 | header_size = skb->network_header + | 1287 | err = maybe_pull_tail(skb, |
1258 | off + | 1288 | off + |
1259 | sizeof(struct ipv6_opt_hdr); | 1289 | sizeof(struct ipv6_opt_hdr), |
1260 | maybe_pull_tail(skb, header_size); | 1290 | MAX_IPV6_HDR_LEN); |
1291 | if (err < 0) | ||
1292 | goto out; | ||
1261 | 1293 | ||
1294 | hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); | ||
1262 | nexthdr = hp->nexthdr; | 1295 | nexthdr = hp->nexthdr; |
1263 | off += ipv6_optlen(hp); | 1296 | off += ipv6_optlen(hp); |
1264 | break; | 1297 | break; |
1265 | } | 1298 | } |
1266 | case IPPROTO_AH: { | 1299 | case IPPROTO_AH: { |
1267 | struct ip_auth_hdr *hp = (void *)(skb->data + off); | 1300 | struct ip_auth_hdr *hp; |
1301 | |||
1302 | err = maybe_pull_tail(skb, | ||
1303 | off + | ||
1304 | sizeof(struct ip_auth_hdr), | ||
1305 | MAX_IPV6_HDR_LEN); | ||
1306 | if (err < 0) | ||
1307 | goto out; | ||
1268 | 1308 | ||
1269 | header_size = skb->network_header + | 1309 | hp = OPT_HDR(struct ip_auth_hdr, skb, off); |
1270 | off + | 1310 | nexthdr = hp->nexthdr; |
1271 | sizeof(struct ip_auth_hdr); | 1311 | off += ipv6_authlen(hp); |
1272 | maybe_pull_tail(skb, header_size); | 1312 | break; |
1313 | } | ||
1314 | case IPPROTO_FRAGMENT: { | ||
1315 | struct frag_hdr *hp; | ||
1316 | |||
1317 | err = maybe_pull_tail(skb, | ||
1318 | off + | ||
1319 | sizeof(struct frag_hdr), | ||
1320 | MAX_IPV6_HDR_LEN); | ||
1321 | if (err < 0) | ||
1322 | goto out; | ||
1323 | |||
1324 | hp = OPT_HDR(struct frag_hdr, skb, off); | ||
1325 | |||
1326 | if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) | ||
1327 | fragment = true; | ||
1273 | 1328 | ||
1274 | nexthdr = hp->nexthdr; | 1329 | nexthdr = hp->nexthdr; |
1275 | off += (hp->hdrlen+2)<<2; | 1330 | off += sizeof(struct frag_hdr); |
1276 | break; | 1331 | break; |
1277 | } | 1332 | } |
1278 | case IPPROTO_FRAGMENT: | ||
1279 | fragment = true; | ||
1280 | /* fall through */ | ||
1281 | default: | 1333 | default: |
1282 | done = true; | 1334 | done = true; |
1283 | break; | 1335 | break; |
1284 | } | 1336 | } |
1285 | } | 1337 | } |
1286 | 1338 | ||
1287 | if (!done) { | 1339 | err = -EPROTO; |
1288 | if (net_ratelimit()) | ||
1289 | netdev_err(vif->dev, "Failed to parse packet header\n"); | ||
1290 | goto out; | ||
1291 | } | ||
1292 | 1340 | ||
1293 | if (fragment) { | 1341 | if (!done || fragment) |
1294 | if (net_ratelimit()) | ||
1295 | netdev_err(vif->dev, "Packet is a fragment!\n"); | ||
1296 | goto out; | 1342 | goto out; |
1297 | } | ||
1298 | 1343 | ||
1299 | switch (nexthdr) { | 1344 | switch (nexthdr) { |
1300 | case IPPROTO_TCP: | 1345 | case IPPROTO_TCP: |
1346 | err = maybe_pull_tail(skb, | ||
1347 | off + sizeof(struct tcphdr), | ||
1348 | MAX_IPV6_HDR_LEN); | ||
1349 | if (err < 0) | ||
1350 | goto out; | ||
1351 | |||
1301 | if (!skb_partial_csum_set(skb, off, | 1352 | if (!skb_partial_csum_set(skb, off, |
1302 | offsetof(struct tcphdr, check))) | 1353 | offsetof(struct tcphdr, check))) |
1303 | goto out; | 1354 | goto out; |
1304 | 1355 | ||
1305 | if (recalculate_partial_csum) { | 1356 | if (recalculate_partial_csum) |
1306 | struct tcphdr *tcph = tcp_hdr(skb); | 1357 | tcp_hdr(skb)->check = |
1307 | 1358 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
1308 | header_size = skb->network_header + | 1359 | &ipv6_hdr(skb)->daddr, |
1309 | off + | 1360 | skb->len - off, |
1310 | sizeof(struct tcphdr); | 1361 | IPPROTO_TCP, 0); |
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 | } | ||
1318 | break; | 1362 | break; |
1319 | case IPPROTO_UDP: | 1363 | case IPPROTO_UDP: |
1364 | err = maybe_pull_tail(skb, | ||
1365 | off + sizeof(struct udphdr), | ||
1366 | MAX_IPV6_HDR_LEN); | ||
1367 | if (err < 0) | ||
1368 | goto out; | ||
1369 | |||
1320 | if (!skb_partial_csum_set(skb, off, | 1370 | if (!skb_partial_csum_set(skb, off, |
1321 | offsetof(struct udphdr, check))) | 1371 | offsetof(struct udphdr, check))) |
1322 | goto out; | 1372 | goto out; |
1323 | 1373 | ||
1324 | if (recalculate_partial_csum) { | 1374 | if (recalculate_partial_csum) |
1325 | struct udphdr *udph = udp_hdr(skb); | 1375 | udp_hdr(skb)->check = |
1326 | 1376 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
1327 | header_size = skb->network_header + | 1377 | &ipv6_hdr(skb)->daddr, |
1328 | off + | 1378 | skb->len - off, |
1329 | sizeof(struct udphdr); | 1379 | IPPROTO_UDP, 0); |
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 | } | ||
1337 | break; | 1380 | break; |
1338 | default: | 1381 | 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; | 1382 | goto out; |
1345 | } | 1383 | } |
1346 | 1384 | ||
@@ -1410,14 +1448,15 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) | |||
1410 | return false; | 1448 | return false; |
1411 | } | 1449 | } |
1412 | 1450 | ||
1413 | static unsigned xenvif_tx_build_gops(struct xenvif *vif) | 1451 | static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) |
1414 | { | 1452 | { |
1415 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; | 1453 | struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; |
1416 | struct sk_buff *skb; | 1454 | struct sk_buff *skb; |
1417 | int ret; | 1455 | int ret; |
1418 | 1456 | ||
1419 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX | 1457 | while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX |
1420 | < MAX_PENDING_REQS)) { | 1458 | < MAX_PENDING_REQS) && |
1459 | (skb_queue_len(&vif->tx_queue) < budget)) { | ||
1421 | struct xen_netif_tx_request txreq; | 1460 | struct xen_netif_tx_request txreq; |
1422 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; | 1461 | struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; |
1423 | struct page *page; | 1462 | struct page *page; |
@@ -1439,7 +1478,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
1439 | continue; | 1478 | continue; |
1440 | } | 1479 | } |
1441 | 1480 | ||
1442 | RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do); | 1481 | work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx); |
1443 | if (!work_to_do) | 1482 | if (!work_to_do) |
1444 | break; | 1483 | break; |
1445 | 1484 | ||
@@ -1579,14 +1618,13 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif) | |||
1579 | } | 1618 | } |
1580 | 1619 | ||
1581 | 1620 | ||
1582 | static int xenvif_tx_submit(struct xenvif *vif, int budget) | 1621 | static int xenvif_tx_submit(struct xenvif *vif) |
1583 | { | 1622 | { |
1584 | struct gnttab_copy *gop = vif->tx_copy_ops; | 1623 | struct gnttab_copy *gop = vif->tx_copy_ops; |
1585 | struct sk_buff *skb; | 1624 | struct sk_buff *skb; |
1586 | int work_done = 0; | 1625 | int work_done = 0; |
1587 | 1626 | ||
1588 | while (work_done < budget && | 1627 | while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) { |
1589 | (skb = __skb_dequeue(&vif->tx_queue)) != NULL) { | ||
1590 | struct xen_netif_tx_request *txp; | 1628 | struct xen_netif_tx_request *txp; |
1591 | u16 pending_idx; | 1629 | u16 pending_idx; |
1592 | unsigned data_len; | 1630 | unsigned data_len; |
@@ -1661,14 +1699,14 @@ int xenvif_tx_action(struct xenvif *vif, int budget) | |||
1661 | if (unlikely(!tx_work_todo(vif))) | 1699 | if (unlikely(!tx_work_todo(vif))) |
1662 | return 0; | 1700 | return 0; |
1663 | 1701 | ||
1664 | nr_gops = xenvif_tx_build_gops(vif); | 1702 | nr_gops = xenvif_tx_build_gops(vif, budget); |
1665 | 1703 | ||
1666 | if (nr_gops == 0) | 1704 | if (nr_gops == 0) |
1667 | return 0; | 1705 | return 0; |
1668 | 1706 | ||
1669 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); | 1707 | gnttab_batch_copy(vif->tx_copy_ops, nr_gops); |
1670 | 1708 | ||
1671 | work_done = xenvif_tx_submit(vif, nr_gops); | 1709 | work_done = xenvif_tx_submit(vif); |
1672 | 1710 | ||
1673 | return work_done; | 1711 | return work_done; |
1674 | } | 1712 | } |