Changeset 28153 in vbox for trunk/src/VBox/HostDrivers/VBoxNetFlt
- Timestamp:
- Apr 9, 2010 5:58:51 PM (15 years ago)
- Location:
- trunk/src/VBox/HostDrivers/VBoxNetFlt/linux
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
r28140 r28153 35 35 #include <VBox/err.h> 36 36 #include <VBox/intnetinline.h> 37 #include <VBox/pdmnetinline.h> 38 #include <VBox/param.h> 37 39 #include <iprt/alloca.h> 38 40 #include <iprt/assert.h> … … 42 44 #include <iprt/process.h> 43 45 #include <iprt/mem.h> 46 #include <iprt/net.h> 44 47 #include <iprt/log.h> 45 48 #include <iprt/mp.h> … … 349 352 * This should match the number in the mbuf exactly! 350 353 * @param fSrc The source of the frame. 351 */ 352 DECLINLINE(void) vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc) 354 * @param pGso Pointer to the GSO context if it's a GSO 355 * internal network frame. NULL if regular frame. 356 */ 357 DECLINLINE(void) vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG, 358 unsigned cSegs, uint32_t fSrc, PCPDMNETWORKGSO pGsoCtx) 353 359 { 354 360 int i; … … 366 372 } 367 373 368 INTNETSgInitTempSegs(pSG, pBuf->len, cSegs, 0 /*cSegsUsed*/); 374 if (!pGsoCtx) 375 INTNETSgInitTempSegs(pSG, pBuf->len, cSegs, 0 /*cSegsUsed*/); 376 else 377 INTNETSgInitTempSegsGso(pSG, pBuf->len, cSegs, 0 /*cSegsUsed*/, pGsoCtx); 369 378 370 379 #ifdef VBOXNETFLT_SG_SUPPORT … … 532 541 /** 533 542 * Destroy the intnet scatter / gather buffer created by 534 * vboxNetFltLinuxSkBufToSG and free the associated socket buffer.535 */ 536 static void vboxNetFltLinuxFreeSkBuff(struct sk_buff *pBuf,PINTNETSG pSG)543 * vboxNetFltLinuxSkBufToSG. 544 */ 545 static void vboxNetFltLinuxDestroySG(PINTNETSG pSG) 537 546 { 538 547 #ifdef VBOXNETFLT_SG_SUPPORT … … 545 554 } 546 555 #endif 547 548 dev_kfree_skb(pBuf); 556 NOREF(pSG); 549 557 } 550 558 551 559 #ifndef LOG_ENABLED 552 # define vboxNetFltDumpPacket(a, b, c, d) do {} while (0)560 # define VBOXNETFLT_DUMP_PACKET(a, b, c, d) do {} while (0) 553 561 #else 554 562 static void vboxNetFltDumpPacket(PINTNETSG pSG, bool fEgress, const char *pszWhere, int iIncrement) … … 575 583 Log3(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv)); 576 584 } 577 #endif 585 #endif /* LOG_ENABLED */ 586 587 #ifdef VBOXNETFLT_WITH_GSO 588 589 /** 590 * Worker for vboxNetFltLinuxForwardToIntNet that checks if we can forwards a 591 * GSO socket buffer without having to segment it. 592 * 593 * @returns true on success, false if needs segmenting. 594 * @param pThis The net filter instance. 595 * @param pSkb The GSO socket buffer. 596 * @param fSrc The source. 597 * @param pGsoCtx Where to return the GSO context on success. 598 */ 599 static bool vboxNetFltLinuxCanForwardAsGso(PVBOXNETFLTINS pThis, struct sk_buff *pSkb, uint32_t fSrc, 600 PPDMNETWORKGSO pGsoCtx) 601 { 602 PDMNETWORKGSOTYPE enmGsoType; 603 uint16_t uEtherType; 604 unsigned int cbTransport; 605 unsigned int offTransport; 606 unsigned int cbTransportHdr; 607 unsigned uProtocol; 608 union 609 { 610 RTNETIPV4 IPv4; 611 RTNETIPV6 IPv6; 612 RTNETTCP Tcp; 613 uint8_t ab[40]; 614 uint16_t au16[40/2]; 615 uint32_t au32[40/4]; 616 } Buf; 617 618 /* 619 * Check the GSO properties of the socket buffer and make sure it fits. 620 */ 621 /** @todo Figure out how to handle SKB_GSO_TCP_ECN! */ 622 if (RT_UNLIKELY( skb_shinfo(pSkb)->gso_type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | SKB_GSO_TCPV6 | SKB_GSO_TCPV4) )) 623 { 624 Log5(("vboxNetFltLinuxCanForwardAsGso: gso_type=%#x\n", skb_shinfo(pSkb)->gso_type)); 625 return false; 626 } 627 if (RT_UNLIKELY( skb_shinfo(pSkb)->gso_size < 1 628 || pSkb->len > VBOX_MAX_GSO_SIZE )) 629 { 630 Log5(("vboxNetFltLinuxCanForwardAsGso: gso_size=%#x skb_len=%#x (max=%#x)\n", skb_shinfo(pSkb)->gso_size, pSkb->len, VBOX_MAX_GSO_SIZE)); 631 return false; 632 } 633 if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE)) 634 { 635 Log5(("vboxNetFltLinuxCanForwardAsGso: fSrc=wire\n")); 636 return false; 637 } 638 639 /* 640 * skb_gso_segment does the following. Do we need to do it as well? 641 */ 642 skb_reset_mac_header(pSkb); 643 pSkb->mac_len = pSkb->network_header - pSkb->mac_header; 644 645 /* 646 * Switch on the ethertype. 647 */ 648 uEtherType = pSkb->protocol; 649 if ( uEtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_VLAN) 650 && pSkb->mac_len == sizeof(RTNETETHERHDR) + sizeof(uint32_t)) 651 { 652 uint16_t const *puEtherType = skb_header_pointer(pSkb, sizeof(RTNETETHERHDR) + sizeof(uint16_t), sizeof(uint16_t), &Buf); 653 if (puEtherType) 654 uEtherType = *puEtherType; 655 } 656 switch (uEtherType) 657 { 658 case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4): 659 { 660 unsigned int cbHdr; 661 PCRTNETIPV4 pIPv4 = (PCRTNETIPV4)skb_header_pointer(pSkb, pSkb->mac_len, sizeof(Buf.IPv4), &Buf); 662 if (RT_UNLIKELY(!pIPv4)) 663 { 664 Log5(("vboxNetFltLinuxCanForwardAsGso: failed to access IPv4 hdr\n")); 665 return false; 666 } 667 668 cbHdr = pIPv4->ip_hl * 4; 669 cbTransport = RT_N2H_U16(pIPv4->ip_len); 670 if (RT_UNLIKELY( cbHdr < RTNETIPV4_MIN_LEN 671 || cbHdr > cbTransport )) 672 { 673 Log5(("vboxNetFltLinuxCanForwardAsGso: invalid IPv4 lengths: ip_hl=%u ip_len=%u\n", pIPv4->ip_hl, RT_N2H_U16(pIPv4->ip_len))); 674 return false; 675 } 676 cbTransport -= cbHdr; 677 offTransport = pSkb->mac_len + cbHdr; 678 uProtocol = pIPv4->ip_p; 679 if (uProtocol == RTNETIPV4_PROT_TCP) 680 enmGsoType = PDMNETWORKGSOTYPE_IPV4_TCP; 681 else if (uProtocol == RTNETIPV4_PROT_UDP) 682 enmGsoType = PDMNETWORKGSOTYPE_IPV4_UDP; 683 else /** @todo IPv6: 4to6 tunneling */ 684 enmGsoType = PDMNETWORKGSOTYPE_INVALID; 685 break; 686 } 687 688 case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV6): 689 { 690 PCRTNETIPV6 pIPv6 = (PCRTNETIPV6)skb_header_pointer(pSkb, pSkb->mac_len, sizeof(Buf.IPv6), &Buf); 691 if (RT_UNLIKELY(!pIPv6)) 692 { 693 Log5(("vboxNetFltLinuxCanForwardAsGso: failed to access IPv6 hdr\n")); 694 return false; 695 } 696 697 cbTransport = RT_N2H_U16(pIPv6->ip6_plen); 698 offTransport = pSkb->mac_len + sizeof(RTNETIPV6); 699 uProtocol = pIPv6->ip6_nxt; 700 /** @todo IPv6: Dig our way out of the other headers. */ 701 if (uProtocol == RTNETIPV4_PROT_TCP) 702 enmGsoType = PDMNETWORKGSOTYPE_IPV6_TCP; 703 else if (uProtocol == RTNETIPV4_PROT_UDP) 704 enmGsoType = PDMNETWORKGSOTYPE_IPV4_UDP; 705 else 706 enmGsoType = PDMNETWORKGSOTYPE_INVALID; 707 break; 708 } 709 710 default: 711 Log5(("vboxNetFltLinuxCanForwardAsGso: uEtherType=%#x\n", RT_H2N_U16(uEtherType))); 712 return false; 713 } 714 715 if (enmGsoType == PDMNETWORKGSOTYPE_INVALID) 716 { 717 Log5(("vboxNetFltLinuxCanForwardAsGso: Unsupported protocol %d\n", uProtocol)); 718 return false; 719 } 720 721 if (RT_UNLIKELY( offTransport + cbTransport <= offTransport 722 || offTransport + cbTransport > pSkb->len 723 || cbTransport < (uProtocol == RTNETIPV4_PROT_TCP ? RTNETTCP_MIN_LEN : RTNETUDP_MIN_LEN)) ) 724 { 725 Log5(("vboxNetFltLinuxCanForwardAsGso: Bad transport length; off=%#x + cb=%#x => %#x; skb_len=%#x (%s)\n", 726 offTransport, cbTransport, offTransport + cbTransport, pSkb->len, PDMNetGsoTypeName(enmGsoType) )); 727 return false; 728 } 729 730 /* 731 * Check the TCP/UDP bits. 732 */ 733 if (uProtocol == RTNETIPV4_PROT_TCP) 734 { 735 PCRTNETTCP pTcp = (PCRTNETTCP)skb_header_pointer(pSkb, offTransport, sizeof(Buf.Tcp), &Buf); 736 if (RT_UNLIKELY(!pTcp)) 737 { 738 Log5(("vboxNetFltLinuxCanForwardAsGso: failed to access TCP hdr\n")); 739 return false; 740 } 741 742 cbTransportHdr = pTcp->th_off * 4; 743 if (RT_UNLIKELY( cbTransportHdr < RTNETTCP_MIN_LEN 744 || cbTransportHdr > cbTransport 745 || offTransport + cbTransportHdr >= UINT8_MAX 746 || offTransport + cbTransportHdr >= pSkb->len )) 747 { 748 Log5(("vboxNetFltLinuxCanForwardAsGso: No space for TCP header; off=%#x cb=%#x skb_len=%#x\n", offTransport, cbTransportHdr, pSkb->len)); 749 return false; 750 } 751 752 } 753 else 754 { 755 Assert(uProtocol == RTNETIPV4_PROT_UDP); 756 cbTransportHdr = sizeof(RTNETUDP); 757 if (RT_UNLIKELY( offTransport + cbTransportHdr >= UINT8_MAX 758 || offTransport + cbTransportHdr >= pSkb->len )) 759 { 760 Log5(("vboxNetFltLinuxCanForwardAsGso: No space for UDP header; off=%#x skb_len=%#x\n", offTransport, pSkb->len)); 761 return false; 762 } 763 } 764 765 /* 766 * We're good, init the GSO context. 767 */ 768 pGsoCtx->u8Type = enmGsoType; 769 pGsoCtx->cbHdrs = offTransport + cbTransportHdr; 770 pGsoCtx->cbMaxSeg = skb_shinfo(pSkb)->gso_size; 771 pGsoCtx->offHdr1 = pSkb->mac_len; 772 pGsoCtx->offHdr2 = offTransport; 773 pGsoCtx->au8Unused[0] = 0; 774 pGsoCtx->au8Unused[1] = 0; 775 776 return true; 777 } 778 779 /** 780 * Forward the socket buffer as a GSO internal network frame. 781 * 782 * @returns IPRT status code. 783 * @param pThis The net filter instance. 784 * @param pSkb The GSO socket buffer. 785 * @param fSrc The source. 786 * @param pGsoCtx Where to return the GSO context on success. 787 */ 788 static int vboxNetFltLinuxForwardAsGso(PVBOXNETFLTINS pThis, struct sk_buff *pSkb, uint32_t fSrc, PCPDMNETWORKGSO pGsoCtx) 789 { 790 int rc; 791 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pSkb); 792 if (RT_LIKELY(cSegs <= MAX_SKB_FRAGS + 1)) 793 { 794 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); 795 if (RT_LIKELY(pSG)) 796 { 797 vboxNetFltLinuxSkBufToSG(pThis, pSkb, pSG, cSegs, fSrc, pGsoCtx); 798 799 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 800 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc); 801 802 vboxNetFltLinuxDestroySG(pSG); 803 rc = VINF_SUCCESS; 804 } 805 else 806 { 807 Log(("VBoxNetFlt: Dropping the sk_buff (failure case).\n")); 808 rc = VERR_NO_MEMORY; 809 } 810 } 811 else 812 { 813 Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs)); 814 rc = VERR_INTERNAL_ERROR_3; 815 } 816 817 Log4(("VBoxNetFlt: Dropping the sk_buff.\n")); 818 dev_kfree_skb(pSkb); 819 return rc; 820 } 821 822 #endif /* VBOXNETFLT_WITH_GSO */ 578 823 579 824 /** … … 587 832 static int vboxNetFltLinuxForwardSegment(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc) 588 833 { 589 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf); 590 if (cSegs < MAX_SKB_FRAGS + 1) 834 int rc; 835 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf); 836 if (cSegs <= MAX_SKB_FRAGS + 1) 591 837 { 592 838 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); 593 if (!pSG) 839 if (RT_LIKELY(pSG)) 840 { 841 vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc, NULL /*pGsoCtx*/); 842 843 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 844 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc); 845 846 vboxNetFltLinuxDestroySG(pSG); 847 rc = VINF_SUCCESS; 848 } 849 else 594 850 { 595 851 Log(("VBoxNetFlt: Failed to allocate SG buffer.\n")); 596 return VERR_NO_MEMORY; 597 } 598 vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc); 599 600 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 601 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc); 602 Log4(("VBoxNetFlt: Dropping the sk_buff.\n")); 603 vboxNetFltLinuxFreeSkBuff(pBuf, pSG); 604 } 605 606 return VINF_SUCCESS; 852 rc = VERR_NO_MEMORY; 853 } 854 } 855 else 856 { 857 Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs)); 858 rc = VERR_INTERNAL_ERROR_3; 859 } 860 861 Log4(("VBoxNetFlt: Dropping the sk_buff.\n")); 862 dev_kfree_skb(pBuf); 863 return rc; 607 864 } 608 865 … … 614 871 if (skb_is_gso(pBuf)) 615 872 { 873 PDMNETWORKGSO GsoCtx; 616 874 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 875 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 () 620 { 621 Log3(("vboxNetFltLinuxForwardToIntNet: GSO SG\n")); 622 vboxNetFltLinuxForwardGso(pThis, pBuf, fSrc); 623 } 876 if ( (skb_shinfo(pBuf)->gso_type & (SKB_GSO_UDP | SKB_GSO_TCPV6 | SKB_GSO_TCPV4)) 877 && vboxNetFltLinuxCanForwardAsGso(pThis, pBuf, fSrc, &GsoCtx) ) 878 vboxNetFltLinuxForwardAsGso(pThis, pBuf, fSrc, &GsoCtx); 624 879 else 625 # endif626 880 { 627 881 /* Need to segment the packet */ … … 634 888 return; 635 889 } 890 636 891 for (; pSegment; pSegment = pNext) 637 892 { -
trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/files_vboxnetflt
r28025 r28153 37 37 ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \ 38 38 ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \ 39 ${PATH_ROOT}/include/iprt/net.h=>include/iprt/net.h \ 39 40 ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \ 40 41 ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \ … … 56 57 ${PATH_ROOT}/include/VBox/intnet.h=>include/VBox/intnet.h \ 57 58 ${PATH_ROOT}/include/VBox/intnetinline.h=>include/VBox/intnetinline.h \ 59 ${PATH_ROOT}/include/VBox/pdmnetinline.h=>include/VBox/pdmnetinline.h \ 60 ${PATH_ROOT}/include/VBox/param.h=>include/VBox/param.h \ 58 61 ${PATH_ROOT}/include/VBox/stam.h=>include/VBox/stam.h \ 59 62 ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
Note:
See TracChangeset
for help on using the changeset viewer.