Changeset 28140 in vbox for trunk/src/VBox
- Timestamp:
- Apr 9, 2010 12:16:23 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
r28070 r28140 50 50 #include "../VBoxNetFltInternal.h" 51 51 52 #define VBOX_FLT_NB_TO_INST(pNB) ((PVBOXNETFLTINS)((uint8_t *)pNB - \ 53 RT_OFFSETOF(VBOXNETFLTINS, u.s.Notifier))) 54 #define VBOX_FLT_PT_TO_INST(pPT) ((PVBOXNETFLTINS)((uint8_t *)pPT - \ 55 RT_OFFSETOF(VBOXNETFLTINS, u.s.PacketType))) 56 #define VBOX_FLT_XT_TO_INST(pXT) ((PVBOXNETFLTINS)((uint8_t *)pXT - \ 57 RT_OFFSETOF(VBOXNETFLTINS, u.s.XmitTask))) 58 59 #define VBOX_GET_PCOUNT(pDev) (pDev->promiscuity) 52 53 /******************************************************************************* 54 * Defined Constants And Macros * 55 *******************************************************************************/ 56 #define VBOX_FLT_NB_TO_INST(pNB) ((PVBOXNETFLTINS)((uint8_t *)pNB - RT_OFFSETOF(VBOXNETFLTINS, u.s.Notifier))) 57 #define VBOX_FLT_PT_TO_INST(pPT) ((PVBOXNETFLTINS)((uint8_t *)pPT - RT_OFFSETOF(VBOXNETFLTINS, u.s.PacketType))) 58 #define VBOX_FLT_XT_TO_INST(pXT) ((PVBOXNETFLTINS)((uint8_t *)pXT - RT_OFFSETOF(VBOXNETFLTINS, u.s.XmitTask))) 60 59 61 60 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) 62 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb_reset_network_header(skb)63 # define VBOX_SKB_RESET_MAC_HDR(skb) skb_reset_mac_header(skb)64 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */65 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb->nh.raw = skb->data66 # define VBOX_SKB_RESET_MAC_HDR(skb) skb->mac.raw = skb->data67 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */61 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb_reset_network_header(skb) 62 # define VBOX_SKB_RESET_MAC_HDR(skb) skb_reset_mac_header(skb) 63 #else 64 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb->nh.raw = skb->data 65 # define VBOX_SKB_RESET_MAC_HDR(skb) skb->mac.raw = skb->data 66 #endif 68 67 69 68 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) 70 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb)71 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */72 # define CHECKSUM_PARTIAL CHECKSUM_HW69 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb) 70 #else 71 # define CHECKSUM_PARTIAL CHECKSUM_HW 73 72 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) 74 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb, 0)75 # else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */73 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb, 0) 74 # else 76 75 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7) 77 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(&skb, 0)78 # else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */79 # define VBOX_SKB_CHECKSUM_HELP(skb) (!skb_checksum_help(skb))80 # endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */81 # endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */82 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */76 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(&skb, 0) 77 # else 78 # define VBOX_SKB_CHECKSUM_HELP(skb) (!skb_checksum_help(skb)) 79 # endif 80 # endif 81 #endif 83 82 84 83 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) 85 # define VBOX_SKB_IS_GSO(skb) skb_is_gso(skb) 86 /* No features, very dumb device */ 87 # define VBOX_SKB_GSO_SEGMENT(skb) skb_gso_segment(skb, 0) 88 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ 89 # define VBOX_SKB_IS_GSO(skb) false 90 # define VBOX_SKB_GSO_SEGMENT(skb) NULL 91 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ 84 /** Indicates that the linux kernel may send us GSO frames. */ 85 # define VBOXNETFLT_WITH_GSO 1 86 #endif 92 87 93 88 #ifndef NET_IP_ALIGN … … 95 90 #endif 96 91 97 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) 98 unsigned dev_get_flags(const struct net_device *dev) 99 { 100 unsigned flags; 101 102 flags = (dev->flags & ~(IFF_PROMISC | 103 IFF_ALLMULTI | 104 IFF_RUNNING)) | 105 (dev->gflags & (IFF_PROMISC | 106 IFF_ALLMULTI)); 107 108 if (netif_running(dev) && netif_carrier_ok(dev)) 109 flags |= IFF_RUNNING; 110 111 return flags; 112 } 113 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) */ 92 #if 0 93 /** Create scatter / gather segments for fragments. When not used, we will 94 * linearize the socket buffer before creating the internal networking SG. */ 95 # define VBOXNETFLT_SG_SUPPORT 1 96 #endif 97 114 98 115 99 /******************************************************************************* … … 137 121 MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(INTNETTRUNKIFPORT_VERSION) ")"); 138 122 #endif 123 124 125 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) && defined(LOG_ENABLED) 126 unsigned dev_get_flags(const struct net_device *dev) 127 { 128 unsigned flags; 129 130 flags = (dev->flags & ~(IFF_PROMISC | 131 IFF_ALLMULTI | 132 IFF_RUNNING)) | 133 (dev->gflags & (IFF_PROMISC | 134 IFF_ALLMULTI)); 135 136 if (netif_running(dev) && netif_carrier_ok(dev)) 137 flags |= IFF_RUNNING; 138 139 return flags; 140 } 141 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) */ 139 142 140 143 … … 486 489 } 487 490 pBuf = pCopy; 488 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)491 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) 489 492 Log3(("vboxNetFltLinuxPacketHandler: skb copy len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n", 490 493 pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type)); 491 # else494 # else 492 495 Log3(("vboxNetFltLinuxPacketHandler: skb copy len=%u data_len=%u truesize=%u next=%p nr_frags=%u tso_size=%u tso_seqs=%u frag_list=%p pkt_type=%x\n", 493 496 pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->tso_size, skb_shinfo(pBuf)->tso_segs, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type)); 494 # endif497 # endif 495 498 } 496 499 #endif … … 501 504 Log4(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n", 502 505 &pThis->u.s.XmitTask, pBuf)); 506 503 507 /* It does not really matter what we return, it is ignored by the kernel. */ 504 508 return 0; 505 509 } 506 510 507 static unsigned vboxNetFltLinuxSGSegments(PVBOXNETFLTINS pThis, struct sk_buff *pBuf) 511 /** 512 * Calculate the number of INTNETSEG segments the socket buffer will need. 513 * 514 * @returns Segment count. 515 * @param pBuf The socket buffer. 516 */ 517 DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf) 508 518 { 509 519 #ifdef VBOXNETFLT_SG_SUPPORT … … 513 523 #endif 514 524 #ifdef PADD_RUNT_FRAMES_FROM_HOST 515 /* 516 * Add a trailer if the frame is too small. 517 */ 525 /* vboxNetFltLinuxSkBufToSG adds a padding segment if it's a runt. */ 518 526 if (pBuf->len < 60) 519 527 cSegs++; … … 522 530 } 523 531 524 /* WARNING! This function should only be called after vboxNetFltLinuxSkBufToSG()! */ 532 /** 533 * Destroy the intnet scatter / gather buffer created by 534 * vboxNetFltLinuxSkBufToSG and free the associated socket buffer. 535 */ 525 536 static void vboxNetFltLinuxFreeSkBuff(struct sk_buff *pBuf, PINTNETSG pSG) 526 537 { … … 566 577 #endif 567 578 579 /** 580 * Worker for vboxNetFltLinuxForwardToIntNet. 581 * 582 * @returns VINF_SUCCESS or VERR_NO_MEMORY. 583 * @param pThis The net filter instance. 584 * @param pBuf The socket buffer. 585 * @param fSrc The source. 586 */ 568 587 static int vboxNetFltLinuxForwardSegment(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc) 569 588 { 570 unsigned cSegs = vboxNetFltLinuxSGSegments(pThis, pBuf); 571 if (cSegs < MAX_SKB_FRAGS) 572 { 573 uint8_t *pTmp; 589 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf); 590 if (cSegs < MAX_SKB_FRAGS + 1) 591 { 574 592 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); 575 593 if (!pSG) … … 580 598 vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc); 581 599 582 pTmp = pSG->aSegs[0].pv;583 600 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 584 601 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc); … … 594 611 uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE; 595 612 596 if (VBOX_SKB_IS_GSO(pBuf)) 597 { 598 /* Need to segment the packet */ 599 struct sk_buff *pNext, *pSegment; 600 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) 601 Log3(("vboxNetFltLinuxForwardToIntNet: skb len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x ip_summed=%d\n", 602 pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, pBuf->ip_summed)); 603 #endif 604 605 pSegment = VBOX_SKB_GSO_SEGMENT(pBuf); 606 if (IS_ERR(pSegment)) 613 #ifdef VBOXNETFLT_WITH_GSO 614 if (skb_is_gso(pBuf)) 615 { 616 Log3(("vboxNetFltLinuxForwardToIntNet: skb len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x ip_summed=%d\n", 617 pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, pBuf->ip_summed)); 618 # if 0 /** @todo receive -> GSO SGs. */ 619 if () 607 620 { 621 Log3(("vboxNetFltLinuxForwardToIntNet: GSO SG\n")); 622 vboxNetFltLinuxForwardGso(pThis, pBuf, fSrc); 623 } 624 else 625 # endif 626 { 627 /* Need to segment the packet */ 628 struct sk_buff *pNext; 629 struct sk_buff *pSegment = skb_gso_segment(pBuf, 0 /*supported features*/); 630 if (IS_ERR(pSegment)) 631 { 632 dev_kfree_skb(pBuf); 633 LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pSegment))); 634 return; 635 } 636 for (; pSegment; pSegment = pNext) 637 { 638 Log3(("vboxNetFltLinuxForwardToIntNet: segment len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n", 639 pSegment->len, pSegment->data_len, pSegment->truesize, pSegment->next, skb_shinfo(pSegment)->nr_frags, skb_shinfo(pSegment)->gso_size, skb_shinfo(pSegment)->gso_segs, skb_shinfo(pSegment)->gso_type, skb_shinfo(pSegment)->frag_list, pSegment->pkt_type)); 640 pNext = pSegment->next; 641 pSegment->next = 0; 642 vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc); 643 } 608 644 dev_kfree_skb(pBuf); 609 LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pBuf)));610 return;611 645 } 612 for (; pSegment; pSegment = pNext)613 {614 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)615 Log3(("vboxNetFltLinuxForwardToIntNet: segment len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n",616 pSegment->len, pSegment->data_len, pSegment->truesize, pSegment->next, skb_shinfo(pSegment)->nr_frags, skb_shinfo(pSegment)->gso_size, skb_shinfo(pSegment)->gso_segs, skb_shinfo(pSegment)->gso_type, skb_shinfo(pSegment)->frag_list, pSegment->pkt_type));617 #endif618 pNext = pSegment->next;619 pSegment->next = 0;620 vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc);621 }622 dev_kfree_skb(pBuf);623 646 } 624 647 else 648 #endif /* VBOXNETFLT_WITH_GSO */ 625 649 { 626 650 if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING) … … 650 674 vboxNetFltLinuxForwardSegment(pThis, pBuf, fSrc); 651 675 } 652 /* 653 * Create a (scatter/)gather list for the sk_buff and feed it to the internal network. 654 */ 655 } 656 676 } 677 678 /** 679 * Work queue handler that forwards the socket buffers queued by 680 * vboxNetFltLinuxPacketHandler to the internal network. 681 * 682 * @param pWork The work queue. 683 */ 657 684 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) 658 685 static void vboxNetFltLinuxXmitTask(struct work_struct *pWork) … … 661 688 #endif 662 689 { 690 PVBOXNETFLTINS pThis = VBOX_FLT_XT_TO_INST(pWork); 691 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 663 692 struct sk_buff *pBuf; 664 bool fActive;665 PVBOXNETFLTINS pThis;666 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;667 693 668 694 Log4(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork)); 669 pThis = VBOX_FLT_XT_TO_INST(pWork); 695 670 696 /* 671 697 * Active? Retain the instance and increment the busy counter. 672 698 */ 673 699 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 674 fActive = ASMAtomicUoReadBool(&pThis->fActive);675 if (fActive)700 if (ASMAtomicUoReadBool(&pThis->fActive)) 701 { 676 702 vboxNetFltRetain(pThis, true /* fBusy */); 677 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 678 if (!fActive) 679 return; 680 681 while ((pBuf = skb_dequeue(&pThis->u.s.XmitQueue)) != 0) 682 vboxNetFltLinuxForwardToIntNet(pThis, pBuf); 683 684 vboxNetFltRelease(pThis, true /* fBusy */); 703 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 704 705 while ((pBuf = skb_dequeue(&pThis->u.s.XmitQueue)) != NULL) 706 vboxNetFltLinuxForwardToIntNet(pThis, pBuf); 707 708 vboxNetFltRelease(pThis, true /* fBusy */); 709 } 710 else 711 { 712 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 713 /** @todo Shouldn't we just drop the packets here? There is little point in 714 * making them accumulate when the VM is paused and it'll only waste 715 * kernel memory anyway... Hmm. maybe wait a short while (2-5 secs) 716 * before start draining the packets (goes for the intnet ring buf 717 * too)? */ 718 } 685 719 } 686 720 … … 777 811 dev_set_promiscuity(pDev, 1); 778 812 ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, true); 779 Log(("vboxNetFltLinuxDeviceIsUp: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));813 Log(("vboxNetFltLinuxDeviceIsUp: enabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 780 814 } 781 815 else 782 Log(("vboxNetFltLinuxDeviceIsUp: no need to enable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));816 Log(("vboxNetFltLinuxDeviceIsUp: no need to enable promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 783 817 return NOTIFY_OK; 784 818 } … … 792 826 dev_set_promiscuity(pDev, -1); 793 827 ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, false); 794 Log(("vboxNetFltLinuxDeviceGoingDown: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));828 Log(("vboxNetFltLinuxDeviceGoingDown: disabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 795 829 } 796 830 else 797 Log(("vboxNetFltLinuxDeviceGoingDown: no need to disable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));831 Log(("vboxNetFltLinuxDeviceGoingDown: no need to disable promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 798 832 return NOTIFY_OK; 799 833 } … … 968 1002 #ifdef LOG_ENABLED 969 1003 u_int16_t fIf; 970 unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pDev);1004 unsigned const cPromiscBefore = pDev->promiscuity; 971 1005 #endif 972 1006 if (fActive) … … 978 1012 rtnl_unlock(); 979 1013 pThis->u.s.fPromiscuousSet = true; 980 Log(("vboxNetFltPortOsSetActive: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));1014 Log(("vboxNetFltPortOsSetActive: enabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 981 1015 } 982 1016 else … … 987 1021 dev_set_promiscuity(pDev, -1); 988 1022 rtnl_unlock(); 989 Log(("vboxNetFltPortOsSetActive: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));1023 Log(("vboxNetFltPortOsSetActive: disabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity)); 990 1024 } 991 1025 pThis->u.s.fPromiscuousSet = false; … … 993 1027 #ifdef LOG_ENABLED 994 1028 fIf = dev_get_flags(pDev); 995 Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));1029 Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, pDev->promiscuity)); 996 1030 #endif 997 1031 }
Note:
See TracChangeset
for help on using the changeset viewer.