diff options
Diffstat (limited to 'net/core/netpoll.c')
| -rw-r--r-- | net/core/netpoll.c | 179 |
1 files changed, 113 insertions, 66 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0b4d0d35ef40..a58f59b97597 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/rcupdate.h> | 23 | #include <linux/rcupdate.h> |
| 24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
| 25 | #include <linux/slab.h> | ||
| 25 | #include <net/tcp.h> | 26 | #include <net/tcp.h> |
| 26 | #include <net/udp.h> | 27 | #include <net/udp.h> |
| 27 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
| @@ -407,11 +408,24 @@ static void arp_reply(struct sk_buff *skb) | |||
| 407 | __be32 sip, tip; | 408 | __be32 sip, tip; |
| 408 | unsigned char *sha; | 409 | unsigned char *sha; |
| 409 | struct sk_buff *send_skb; | 410 | struct sk_buff *send_skb; |
| 410 | struct netpoll *np = NULL; | 411 | struct netpoll *np, *tmp; |
| 412 | unsigned long flags; | ||
| 413 | int hits = 0; | ||
| 414 | |||
| 415 | if (list_empty(&npinfo->rx_np)) | ||
| 416 | return; | ||
| 417 | |||
| 418 | /* Before checking the packet, we do some early | ||
| 419 | inspection whether this is interesting at all */ | ||
| 420 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
| 421 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { | ||
| 422 | if (np->dev == skb->dev) | ||
| 423 | hits++; | ||
| 424 | } | ||
| 425 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 411 | 426 | ||
| 412 | if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) | 427 | /* No netpoll struct is using this dev */ |
| 413 | np = npinfo->rx_np; | 428 | if (!hits) |
| 414 | if (!np) | ||
| 415 | return; | 429 | return; |
| 416 | 430 | ||
| 417 | /* No arp on this interface */ | 431 | /* No arp on this interface */ |
| @@ -437,77 +451,91 @@ static void arp_reply(struct sk_buff *skb) | |||
| 437 | arp_ptr += skb->dev->addr_len; | 451 | arp_ptr += skb->dev->addr_len; |
| 438 | memcpy(&sip, arp_ptr, 4); | 452 | memcpy(&sip, arp_ptr, 4); |
| 439 | arp_ptr += 4; | 453 | arp_ptr += 4; |
| 440 | /* if we actually cared about dst hw addr, it would get copied here */ | 454 | /* If we actually cared about dst hw addr, |
| 455 | it would get copied here */ | ||
| 441 | arp_ptr += skb->dev->addr_len; | 456 | arp_ptr += skb->dev->addr_len; |
| 442 | memcpy(&tip, arp_ptr, 4); | 457 | memcpy(&tip, arp_ptr, 4); |
| 443 | 458 | ||
| 444 | /* Should we ignore arp? */ | 459 | /* Should we ignore arp? */ |
| 445 | if (tip != np->local_ip || | 460 | if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) |
| 446 | ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) | ||
| 447 | return; | 461 | return; |
| 448 | 462 | ||
| 449 | size = arp_hdr_len(skb->dev); | 463 | size = arp_hdr_len(skb->dev); |
| 450 | send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), | ||
| 451 | LL_RESERVED_SPACE(np->dev)); | ||
| 452 | 464 | ||
| 453 | if (!send_skb) | 465 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 454 | return; | 466 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { |
| 455 | 467 | if (tip != np->local_ip) | |
| 456 | skb_reset_network_header(send_skb); | 468 | continue; |
| 457 | arp = (struct arphdr *) skb_put(send_skb, size); | ||
| 458 | send_skb->dev = skb->dev; | ||
| 459 | send_skb->protocol = htons(ETH_P_ARP); | ||
| 460 | 469 | ||
| 461 | /* Fill the device header for the ARP frame */ | 470 | send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), |
| 462 | if (dev_hard_header(send_skb, skb->dev, ptype, | 471 | LL_RESERVED_SPACE(np->dev)); |
| 463 | sha, np->dev->dev_addr, | 472 | if (!send_skb) |
| 464 | send_skb->len) < 0) { | 473 | continue; |
| 465 | kfree_skb(send_skb); | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | 474 | ||
| 469 | /* | 475 | skb_reset_network_header(send_skb); |
| 470 | * Fill out the arp protocol part. | 476 | arp = (struct arphdr *) skb_put(send_skb, size); |
| 471 | * | 477 | send_skb->dev = skb->dev; |
| 472 | * we only support ethernet device type, | 478 | send_skb->protocol = htons(ETH_P_ARP); |
| 473 | * which (according to RFC 1390) should always equal 1 (Ethernet). | ||
| 474 | */ | ||
| 475 | 479 | ||
| 476 | arp->ar_hrd = htons(np->dev->type); | 480 | /* Fill the device header for the ARP frame */ |
| 477 | arp->ar_pro = htons(ETH_P_IP); | 481 | if (dev_hard_header(send_skb, skb->dev, ptype, |
| 478 | arp->ar_hln = np->dev->addr_len; | 482 | sha, np->dev->dev_addr, |
| 479 | arp->ar_pln = 4; | 483 | send_skb->len) < 0) { |
| 480 | arp->ar_op = htons(type); | 484 | kfree_skb(send_skb); |
| 485 | continue; | ||
| 486 | } | ||
| 481 | 487 | ||
| 482 | arp_ptr=(unsigned char *)(arp + 1); | 488 | /* |
| 483 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | 489 | * Fill out the arp protocol part. |
| 484 | arp_ptr += np->dev->addr_len; | 490 | * |
| 485 | memcpy(arp_ptr, &tip, 4); | 491 | * we only support ethernet device type, |
| 486 | arp_ptr += 4; | 492 | * which (according to RFC 1390) should |
| 487 | memcpy(arp_ptr, sha, np->dev->addr_len); | 493 | * always equal 1 (Ethernet). |
| 488 | arp_ptr += np->dev->addr_len; | 494 | */ |
| 489 | memcpy(arp_ptr, &sip, 4); | ||
| 490 | 495 | ||
| 491 | netpoll_send_skb(np, send_skb); | 496 | arp->ar_hrd = htons(np->dev->type); |
| 497 | arp->ar_pro = htons(ETH_P_IP); | ||
| 498 | arp->ar_hln = np->dev->addr_len; | ||
| 499 | arp->ar_pln = 4; | ||
| 500 | arp->ar_op = htons(type); | ||
| 501 | |||
| 502 | arp_ptr = (unsigned char *)(arp + 1); | ||
| 503 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | ||
| 504 | arp_ptr += np->dev->addr_len; | ||
| 505 | memcpy(arp_ptr, &tip, 4); | ||
| 506 | arp_ptr += 4; | ||
| 507 | memcpy(arp_ptr, sha, np->dev->addr_len); | ||
| 508 | arp_ptr += np->dev->addr_len; | ||
| 509 | memcpy(arp_ptr, &sip, 4); | ||
| 510 | |||
| 511 | netpoll_send_skb(np, send_skb); | ||
| 512 | |||
| 513 | /* If there are several rx_hooks for the same address, | ||
| 514 | we're fine by sending a single reply */ | ||
| 515 | break; | ||
| 516 | } | ||
| 517 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 492 | } | 518 | } |
| 493 | 519 | ||
| 494 | int __netpoll_rx(struct sk_buff *skb) | 520 | int __netpoll_rx(struct sk_buff *skb) |
| 495 | { | 521 | { |
| 496 | int proto, len, ulen; | 522 | int proto, len, ulen; |
| 523 | int hits = 0; | ||
| 497 | struct iphdr *iph; | 524 | struct iphdr *iph; |
| 498 | struct udphdr *uh; | 525 | struct udphdr *uh; |
| 499 | struct netpoll_info *npi = skb->dev->npinfo; | 526 | struct netpoll_info *npinfo = skb->dev->npinfo; |
| 500 | struct netpoll *np = npi->rx_np; | 527 | struct netpoll *np, *tmp; |
| 501 | 528 | ||
| 502 | if (!np) | 529 | if (list_empty(&npinfo->rx_np)) |
| 503 | goto out; | 530 | goto out; |
| 531 | |||
| 504 | if (skb->dev->type != ARPHRD_ETHER) | 532 | if (skb->dev->type != ARPHRD_ETHER) |
| 505 | goto out; | 533 | goto out; |
| 506 | 534 | ||
| 507 | /* check if netpoll clients need ARP */ | 535 | /* check if netpoll clients need ARP */ |
| 508 | if (skb->protocol == htons(ETH_P_ARP) && | 536 | if (skb->protocol == htons(ETH_P_ARP) && |
| 509 | atomic_read(&trapped)) { | 537 | atomic_read(&trapped)) { |
| 510 | skb_queue_tail(&npi->arp_tx, skb); | 538 | skb_queue_tail(&npinfo->arp_tx, skb); |
| 511 | return 1; | 539 | return 1; |
| 512 | } | 540 | } |
| 513 | 541 | ||
| @@ -551,16 +579,23 @@ int __netpoll_rx(struct sk_buff *skb) | |||
| 551 | goto out; | 579 | goto out; |
| 552 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) | 580 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) |
| 553 | goto out; | 581 | goto out; |
| 554 | if (np->local_ip && np->local_ip != iph->daddr) | ||
| 555 | goto out; | ||
| 556 | if (np->remote_ip && np->remote_ip != iph->saddr) | ||
| 557 | goto out; | ||
| 558 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
| 559 | goto out; | ||
| 560 | 582 | ||
| 561 | np->rx_hook(np, ntohs(uh->source), | 583 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { |
| 562 | (char *)(uh+1), | 584 | if (np->local_ip && np->local_ip != iph->daddr) |
| 563 | ulen - sizeof(struct udphdr)); | 585 | continue; |
| 586 | if (np->remote_ip && np->remote_ip != iph->saddr) | ||
| 587 | continue; | ||
| 588 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
| 589 | continue; | ||
| 590 | |||
| 591 | np->rx_hook(np, ntohs(uh->source), | ||
| 592 | (char *)(uh+1), | ||
| 593 | ulen - sizeof(struct udphdr)); | ||
| 594 | hits++; | ||
| 595 | } | ||
| 596 | |||
| 597 | if (!hits) | ||
| 598 | goto out; | ||
| 564 | 599 | ||
| 565 | kfree_skb(skb); | 600 | kfree_skb(skb); |
| 566 | return 1; | 601 | return 1; |
| @@ -580,7 +615,7 @@ void netpoll_print_options(struct netpoll *np) | |||
| 580 | np->name, np->local_port); | 615 | np->name, np->local_port); |
| 581 | printk(KERN_INFO "%s: local IP %pI4\n", | 616 | printk(KERN_INFO "%s: local IP %pI4\n", |
| 582 | np->name, &np->local_ip); | 617 | np->name, &np->local_ip); |
| 583 | printk(KERN_INFO "%s: interface %s\n", | 618 | printk(KERN_INFO "%s: interface '%s'\n", |
| 584 | np->name, np->dev_name); | 619 | np->name, np->dev_name); |
| 585 | printk(KERN_INFO "%s: remote port %d\n", | 620 | printk(KERN_INFO "%s: remote port %d\n", |
| 586 | np->name, np->remote_port); | 621 | np->name, np->remote_port); |
| @@ -627,6 +662,9 @@ int netpoll_parse_options(struct netpoll *np, char *opt) | |||
| 627 | if ((delim = strchr(cur, '@')) == NULL) | 662 | if ((delim = strchr(cur, '@')) == NULL) |
| 628 | goto parse_failed; | 663 | goto parse_failed; |
| 629 | *delim = 0; | 664 | *delim = 0; |
| 665 | if (*cur == ' ' || *cur == '\t') | ||
| 666 | printk(KERN_INFO "%s: warning: whitespace" | ||
| 667 | "is not allowed\n", np->name); | ||
| 630 | np->remote_port = simple_strtol(cur, NULL, 10); | 668 | np->remote_port = simple_strtol(cur, NULL, 10); |
| 631 | cur = delim; | 669 | cur = delim; |
| 632 | } | 670 | } |
| @@ -674,7 +712,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) | |||
| 674 | return 0; | 712 | return 0; |
| 675 | 713 | ||
| 676 | parse_failed: | 714 | parse_failed: |
| 677 | printk(KERN_INFO "%s: couldn't parse config at %s!\n", | 715 | printk(KERN_INFO "%s: couldn't parse config at '%s'!\n", |
| 678 | np->name, cur); | 716 | np->name, cur); |
| 679 | return -1; | 717 | return -1; |
| 680 | } | 718 | } |
| @@ -684,6 +722,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 684 | struct net_device *ndev = NULL; | 722 | struct net_device *ndev = NULL; |
| 685 | struct in_device *in_dev; | 723 | struct in_device *in_dev; |
| 686 | struct netpoll_info *npinfo; | 724 | struct netpoll_info *npinfo; |
| 725 | struct netpoll *npe, *tmp; | ||
| 687 | unsigned long flags; | 726 | unsigned long flags; |
| 688 | int err; | 727 | int err; |
| 689 | 728 | ||
| @@ -700,11 +739,11 @@ int netpoll_setup(struct netpoll *np) | |||
| 700 | npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL); | 739 | npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL); |
| 701 | if (!npinfo) { | 740 | if (!npinfo) { |
| 702 | err = -ENOMEM; | 741 | err = -ENOMEM; |
| 703 | goto release; | 742 | goto put; |
| 704 | } | 743 | } |
| 705 | 744 | ||
| 706 | npinfo->rx_flags = 0; | 745 | npinfo->rx_flags = 0; |
| 707 | npinfo->rx_np = NULL; | 746 | INIT_LIST_HEAD(&npinfo->rx_np); |
| 708 | 747 | ||
| 709 | spin_lock_init(&npinfo->rx_lock); | 748 | spin_lock_init(&npinfo->rx_lock); |
| 710 | skb_queue_head_init(&npinfo->arp_tx); | 749 | skb_queue_head_init(&npinfo->arp_tx); |
| @@ -785,7 +824,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 785 | if (np->rx_hook) { | 824 | if (np->rx_hook) { |
| 786 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 825 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 787 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; | 826 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; |
| 788 | npinfo->rx_np = np; | 827 | list_add_tail(&np->rx, &npinfo->rx_np); |
| 789 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 828 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
| 790 | } | 829 | } |
| 791 | 830 | ||
| @@ -801,9 +840,16 @@ int netpoll_setup(struct netpoll *np) | |||
| 801 | return 0; | 840 | return 0; |
| 802 | 841 | ||
| 803 | release: | 842 | release: |
| 804 | if (!ndev->npinfo) | 843 | if (!ndev->npinfo) { |
| 844 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
| 845 | list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { | ||
| 846 | npe->dev = NULL; | ||
| 847 | } | ||
| 848 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 849 | |||
| 805 | kfree(npinfo); | 850 | kfree(npinfo); |
| 806 | np->dev = NULL; | 851 | } |
| 852 | put: | ||
| 807 | dev_put(ndev); | 853 | dev_put(ndev); |
| 808 | return err; | 854 | return err; |
| 809 | } | 855 | } |
| @@ -823,10 +869,11 @@ void netpoll_cleanup(struct netpoll *np) | |||
| 823 | if (np->dev) { | 869 | if (np->dev) { |
| 824 | npinfo = np->dev->npinfo; | 870 | npinfo = np->dev->npinfo; |
| 825 | if (npinfo) { | 871 | if (npinfo) { |
| 826 | if (npinfo->rx_np == np) { | 872 | if (!list_empty(&npinfo->rx_np)) { |
| 827 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 873 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 828 | npinfo->rx_np = NULL; | 874 | list_del(&np->rx); |
| 829 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | 875 | if (list_empty(&npinfo->rx_np)) |
| 876 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | ||
| 830 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 877 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
| 831 | } | 878 | } |
| 832 | 879 | ||
