- Timestamp:
- Oct 11, 2016 6:48:49 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
r62490 r64194 147 147 #endif 148 148 149 #if 0149 #if 1 150 150 /** Create scatter / gather segments for fragments. When not used, we will 151 151 * linearize the socket buffer before creating the internal networking SG. */ … … 781 781 782 782 /** 783 * Return the offset where to start checksum computation from. 784 * 785 * @returns the offset relative to pBuf->data. 786 * @param pBuf The socket buffer. 787 */ 788 DECLINLINE(unsigned) vboxNetFltLinuxGetChecksumStartOffset(struct sk_buff *pBuf) 789 { 790 # if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21) 791 unsigned char *pTransportHdr = pBuf->h.raw; 792 # if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) 793 /* 794 * Try to work around the problem with CentOS 4.7 and 5.2 (2.6.9 795 * and 2.6.18 kernels), they pass wrong 'h' pointer down. We take IP 796 * header length from the header itself and reconstruct 'h' pointer 797 * to TCP (or whatever) header. 798 */ 799 if (pBuf->h.raw == pBuf->nh.raw && pBuf->protocol == htons(ETH_P_IP)) 800 pTransportHdr = pBuf->nh.raw + pBuf->nh.iph->ihl * 4; 801 # endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */ 802 return pTransportHdr - pBuf->data; 803 # else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 21) */ 804 return skb_checksum_start_offset(pBuf); 805 # endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 21) */ 806 } 807 808 809 /** 783 810 * Initializes a SG list from an sk_buff. 784 811 * … … 787 814 * @param pBuf The sk_buff. 788 815 * @param pSG The SG. 816 * @param cExtra The number of bytes of extra space allocated immediately after the SG. 789 817 * @param cSegs The number of segments allocated for the SG. 790 818 * This should match the number in the mbuf exactly! … … 793 821 * internal network frame. NULL if regular frame. 794 822 */ 795 DECLINLINE(void)vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG,796 823 static void vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG, 824 unsigned cbExtra, unsigned cSegs, uint32_t fSrc, PCPDMNETWORKGSO pGsoCtx) 797 825 { 798 826 int i; 799 827 NOREF(pThis); 800 828 829 #ifndef VBOXNETFLT_SG_SUPPORT 801 830 Assert(!skb_shinfo(pBuf)->frag_list); 831 #else /* VBOXNETFLT_SG_SUPPORT */ 832 uint8_t *pExtra = (uint8_t *)&pSG->aSegs[cSegs]; 833 unsigned cbConsumed = 0; 834 unsigned cbProduced = 0; 835 836 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) 837 /* Restore VLAN tag stripped by host hardware */ 838 if (vlan_tx_tag_present(pBuf)) 839 { 840 uint8_t *pMac = pBuf->data; 841 struct vlan_ethhdr *pVHdr = (struct vlan_ethhdr *)pExtra; 842 Assert(ETH_ALEN * 2 + VLAN_HLEN <= cbExtra); 843 memmove(pVHdr, pMac, ETH_ALEN * 2); 844 cbConsumed += ETH_ALEN * 2; 845 pVHdr->h_vlan_proto = RT_H2N_U16(ETH_P_8021Q); 846 pVHdr->h_vlan_TCI = RT_H2N_U16(vlan_tx_tag_get(pBuf)); 847 pVHdr->h_vlan_encapsulated_proto = *(uint16_t*)(pMac + ETH_ALEN * 2); 848 cbProduced += VLAN_ETH_HLEN; 849 } 850 # endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ 851 852 if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING) 853 { 854 unsigned uCsumStartOffset = vboxNetFltLinuxGetChecksumStartOffset(pBuf); 855 unsigned uCsumStoreOffset = uCsumStartOffset + pBuf->csum_offset - cbConsumed; 856 Log3(("cbConsumed=%u cbProduced=%u uCsumStartOffset=%u uCsumStoreOffset=%u\n", 857 cbConsumed, cbProduced, uCsumStartOffset, uCsumStoreOffset)); 858 Assert(cbProduced + uCsumStoreOffset + sizeof(uint16_t) <= cbExtra); 859 /* 860 * We assume that the checksum is stored at the very end of the transport header 861 * so we will have all headers in a single fragment. If our assumption is wrong 862 * we may see suboptimal performance. 863 */ 864 memmove(pExtra + cbProduced, 865 pBuf->data + cbConsumed, 866 uCsumStoreOffset); 867 unsigned uChecksum = skb_checksum(pBuf, uCsumStartOffset, pBuf->len - uCsumStartOffset, 0); 868 *(uint16_t*)(pExtra + cbProduced + uCsumStoreOffset) = csum_fold(uChecksum); 869 cbProduced += uCsumStoreOffset + sizeof(uint16_t); 870 cbConsumed += uCsumStoreOffset + sizeof(uint16_t); 871 } 872 #endif /* VBOXNETFLT_SG_SUPPORT */ 802 873 803 874 if (!pGsoCtx) … … 806 877 IntNetSgInitTempSegsGso(pSG, pBuf->len, cSegs, 0 /*cSegsUsed*/, pGsoCtx); 807 878 879 int iSeg = 0; 808 880 #ifdef VBOXNETFLT_SG_SUPPORT 809 pSG->aSegs[0].cb = skb_headlen(pBuf); 810 pSG->aSegs[0].pv = pBuf->data; 811 pSG->aSegs[0].Phys = NIL_RTHCPHYS; 812 881 if (cbProduced) 882 { 883 pSG->aSegs[iSeg].cb = cbProduced; 884 pSG->aSegs[iSeg].pv = pExtra; 885 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 886 } 887 pSG->aSegs[iSeg].cb = skb_headlen(pBuf) - cbConsumed; 888 pSG->aSegs[iSeg].pv = pBuf->data + cbConsumed; 889 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 890 Assert(iSeg <= pSG->cSegsAlloc); 891 892 # ifdef LOG_ENABLED 893 if (pBuf->data_len) 894 Log6((" kmap_atomic:")); 895 # endif /* LOG_ENABLED */ 813 896 for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++) 814 897 { 815 898 skb_frag_t *pFrag = &skb_shinfo(pBuf)->frags[i]; 816 pSG->aSegs[i+1].cb = pFrag->size; 817 pSG->aSegs[i+1].pv = kmap(pFrag->page); 818 printk("%p = kmap()\n", pSG->aSegs[i+1].pv); 819 pSG->aSegs[i+1].Phys = NIL_RTHCPHYS; 820 } 821 ++i; 822 899 pSG->aSegs[iSeg].cb = pFrag->size; 900 pSG->aSegs[iSeg].pv = kmap_atomic(pFrag->page.p) + pFrag->page_offset; 901 Log6((" %p", pSG->aSegs[iSeg].pv)); 902 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 903 Assert(iSeg <= pSG->cSegsAlloc); 904 } 905 struct sk_buff *pFragBuf; 906 for (pFragBuf = skb_shinfo(pBuf)->frag_list; pFragBuf; pFragBuf = pFragBuf->next) 907 { 908 pSG->aSegs[iSeg].cb = skb_headlen(pFragBuf); 909 pSG->aSegs[iSeg].pv = pFragBuf->data; 910 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 911 Assert(iSeg <= pSG->cSegsAlloc); 912 for (i = 0; i < skb_shinfo(pFragBuf)->nr_frags; i++) 913 { 914 skb_frag_t *pFrag = &skb_shinfo(pFragBuf)->frags[i]; 915 pSG->aSegs[iSeg].cb = pFrag->size; 916 pSG->aSegs[iSeg].pv = kmap_atomic(pFrag->page.p) + pFrag->page_offset; 917 Log6((" %p", pSG->aSegs[iSeg].pv)); 918 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 919 Assert(iSeg <= pSG->cSegsAlloc); 920 } 921 } 922 # ifdef LOG_ENABLED 923 if (pBuf->data_len) 924 Log6(("\n")); 925 # endif /* LOG_ENABLED */ 823 926 #else 824 pSG->aSegs[0].cb = pBuf->len; 825 pSG->aSegs[0].pv = pBuf->data; 826 pSG->aSegs[0].Phys = NIL_RTHCPHYS; 827 i = 1; 828 #endif 829 830 pSG->cSegsUsed = i; 927 pSG->aSegs[iSeg].cb = pBuf->len; 928 pSG->aSegs[iSeg].pv = pBuf->data; 929 pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS; 930 #endif 931 932 pSG->cSegsUsed = iSeg; 831 933 832 934 #ifdef PADD_RUNT_FRAMES_FROM_HOST … … 840 942 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST)) 841 943 { 944 Assert(pBuf->data_len == 0); /* Packets with fragments are never small! */ 842 945 static uint8_t const s_abZero[128] = {0}; 843 946 844 AssertReturnVoid(i < cSegs);845 846 pSG->aSegs[i ].Phys = NIL_RTHCPHYS;847 pSG->aSegs[i ].pv = (void *)&s_abZero[0];848 pSG->aSegs[i ].cb = 60 - pSG->cbTotal;947 AssertReturnVoid(iSeg < cSegs); 948 949 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS; 950 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0]; 951 pSG->aSegs[iSeg++].cb = 60 - pSG->cbTotal; 849 952 pSG->cbTotal = 60; 850 953 pSG->cSegsUsed++; 851 Assert(i + 1<= pSG->cSegsAlloc)852 } 853 #endif 854 855 Log 4(("vboxNetFltLinuxSkBufToSG: allocated=%d, segments=%d frags=%d next=%p frag_list=%p pkt_type=%x fSrc=%x\n",954 Assert(iSeg <= pSG->cSegsAlloc) 955 } 956 #endif 957 958 Log6(("vboxNetFltLinuxSkBufToSG: allocated=%d, segments=%d frags=%d next=%p frag_list=%p pkt_type=%x fSrc=%x\n", 856 959 pSG->cSegsAlloc, pSG->cSegsUsed, skb_shinfo(pBuf)->nr_frags, pBuf->next, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, fSrc)); 857 960 for (i = 0; i < pSG->cSegsUsed; i++) 858 Log 4(("vboxNetFltLinuxSkBufToSG: #%d: cb=%d pv=%p\n",961 Log6(("vboxNetFltLinuxSkBufToSG: #%d: cb=%d pv=%p\n", 859 962 i, pSG->aSegs[i].cb, pSG->aSegs[i].pv)); 860 963 } … … 884 987 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)); 885 988 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) 886 Log 4(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));989 Log6(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf))); 887 990 # endif 888 991 #else … … 916 1019 } 917 1020 918 Log 4(("vboxNetFltLinuxPacketHandler: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));1021 Log6(("vboxNetFltLinuxPacketHandler: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb)); 919 1022 if (vboxNetFltLinuxSkBufIsOur(pBuf)) 920 1023 { … … 958 1061 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)); 959 1062 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) 960 Log 4(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));961 # endif 962 # else 1063 Log6(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf))); 1064 # endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ 1065 # else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ 963 1066 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", 964 1067 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)); 965 # endif 966 } 967 #endif 1068 # endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ 1069 } 1070 #endif /* !VBOXNETFLT_SG_SUPPORT */ 968 1071 969 1072 #ifdef VBOXNETFLT_LINUX_NO_XMIT_QUEUE 970 1073 /* Forward it to the internal network. */ 971 1074 vboxNetFltLinuxForwardToIntNet(pThis, pBuf); 972 #else 1075 #else /* !VBOXNETFLT_LINUX_NO_XMIT_QUEUE */ 973 1076 /* Add the packet to transmit queue and schedule the bottom half. */ 974 1077 skb_queue_tail(&pThis->u.s.XmitQueue, pBuf); 975 1078 schedule_work(&pThis->u.s.XmitTask); 976 Log 4(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n",1079 Log6(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n", 977 1080 &pThis->u.s.XmitTask, pBuf)); 978 #endif 1081 #endif /* !VBOXNETFLT_LINUX_NO_XMIT_QUEUE */ 979 1082 980 1083 /* It does not really matter what we return, it is ignored by the kernel. */ … … 987 1090 * @returns Segment count. 988 1091 * @param pBuf The socket buffer. 989 */ 990 DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf) 991 { 1092 * @param pcbTemp Where to store the number of bytes of the part 1093 * of the socket buffer that will be copied to 1094 * a temporary storage. 1095 */ 1096 DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf, unsigned *pcbTemp) 1097 { 1098 *pcbTemp = 0; 992 1099 #ifdef VBOXNETFLT_SG_SUPPORT 993 1100 unsigned cSegs = 1 + skb_shinfo(pBuf)->nr_frags; 1101 if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING) 1102 { 1103 *pcbTemp = vboxNetFltLinuxGetChecksumStartOffset(pBuf) + pBuf->csum_offset + sizeof(uint16_t); 1104 } 1105 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) 1106 if (vlan_tx_tag_present(pBuf)) 1107 { 1108 if (*pcbTemp) 1109 *pcbTemp += VLAN_HLEN; 1110 else 1111 *pcbTemp = VLAN_ETH_HLEN; 1112 } 1113 # endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ 1114 if (*pcbTemp) 1115 ++cSegs; 1116 struct sk_buff *pFrag; 1117 for (pFrag = skb_shinfo(pBuf)->frag_list; pFrag; pFrag = pFrag->next) 1118 { 1119 Log6(("vboxNetFltLinuxCalcSGSegments: frag=%p len=%d data_len=%d frags=%d frag_list=%p next=%p\n", 1120 pFrag, pFrag->len, pFrag->data_len, skb_shinfo(pFrag)->nr_frags, skb_shinfo(pFrag)->frag_list, pFrag->next)); 1121 cSegs += 1 + skb_shinfo(pFrag)->nr_frags; 1122 } 994 1123 #else 995 1124 unsigned cSegs = 1; … … 1003 1132 } 1004 1133 1134 1005 1135 /** 1006 1136 * Destroy the intnet scatter / gather buffer created by 1007 1137 * vboxNetFltLinuxSkBufToSG. 1008 */ 1009 static void vboxNetFltLinuxDestroySG(PINTNETSG pSG) 1138 * 1139 * @param pSG The (scatter/)gather list. 1140 * @param pBuf The original socket buffer that was used to create 1141 * the scatter/gather list. 1142 */ 1143 static void vboxNetFltLinuxDestroySG(PINTNETSG pSG, struct sk_buff *pBuf) 1010 1144 { 1011 1145 #ifdef VBOXNETFLT_SG_SUPPORT 1012 int i; 1013 1146 int i, iSeg = 1; /* Skip non-paged part of SKB */ 1147 /* Check if the extra buffer behind SG structure was used for modified packet header */ 1148 if (pBuf->data != pSG->aSegs[0].pv) 1149 ++iSeg; /* Skip it as well */ 1150 # ifdef LOG_ENABLED 1151 if (pBuf->data_len) 1152 Log6(("kunmap_atomic:")); 1153 # endif /* LOG_ENABLED */ 1154 /* iSeg now points to the first mapped fragment if there are any */ 1014 1155 for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++) 1015 1156 { 1016 printk("kunmap(%p)\n", pSG->aSegs[i+1].pv); 1017 kunmap(pSG->aSegs[i+1].pv); 1018 } 1157 Log6((" %p", pSG->aSegs[iSeg].pv)); 1158 kunmap_atomic(pSG->aSegs[iSeg++].pv); 1159 } 1160 struct sk_buff *pFragBuf; 1161 for (pFragBuf = skb_shinfo(pBuf)->frag_list; pFragBuf; pFragBuf = pFragBuf->next) 1162 { 1163 ++iSeg; /* Non-fragment (unmapped) portion of chained SKB */ 1164 for (i = 0; i < skb_shinfo(pFragBuf)->nr_frags; i++) 1165 { 1166 Log6((" %p", pSG->aSegs[iSeg].pv)); 1167 kunmap_atomic(pSG->aSegs[iSeg++].pv); 1168 } 1169 } 1170 # ifdef LOG_ENABLED 1171 if (pBuf->data_len) 1172 Log6(("\n")); 1173 # endif /* LOG_ENABLED */ 1019 1174 #endif 1020 1175 NOREF(pSG); … … 1049 1204 if (pSG->cSegsUsed == 1) 1050 1205 { 1051 Log 3(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv));1206 Log4(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv)); 1052 1207 } 1053 1208 else … … 1055 1210 for (i = 0, offSeg = 0; i < pSG->cSegsUsed; i++) 1056 1211 { 1057 Log 3(("-- segment %d at 0x%x (%d bytes)--\n%.*Rhxd\n",1212 Log4(("-- segment %d at 0x%x (%d bytes)\n --\n%.*Rhxd\n", 1058 1213 i, offSeg, pSG->aSegs[i].cb, pSG->aSegs[i].cb, pSG->aSegs[i].pv)); 1059 1214 offSeg += pSG->aSegs[i].cb; 1060 1215 } 1061 1216 } 1062 1063 1217 } 1064 1218 #else … … 1111 1265 Log5(("vboxNetFltLinuxCanForwardAsGso: gso_size=%#x skb_len=%#x (max=%#x)\n", skb_shinfo(pSkb)->gso_size, pSkb->len, VBOX_MAX_GSO_SIZE)); 1112 1266 return false; 1113 }1114 /*1115 * It is possible to receive GSO packets from wire if GRO is enabled.1116 */1117 if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE))1118 {1119 Log5(("vboxNetFltLinuxCanForwardAsGso: fSrc=wire\n"));1120 #ifdef VBOXNETFLT_WITH_GRO1121 /*1122 * The packet came from the wire and the driver has already consumed1123 * mac header. We need to restore it back.1124 */1125 pSkb->mac_len = skb_network_header(pSkb) - skb_mac_header(pSkb);1126 skb_push(pSkb, pSkb->mac_len);1127 Log5(("vboxNetFltLinuxCanForwardAsGso: mac_len=%d data=%p mac_header=%p network_header=%p\n",1128 pSkb->mac_len, pSkb->data, skb_mac_header(pSkb), skb_network_header(pSkb)));1129 #else /* !VBOXNETFLT_WITH_GRO */1130 /* Older kernels didn't have GRO. */1131 return false;1132 #endif /* !VBOXNETFLT_WITH_GRO */1133 }1134 else1135 {1136 /*1137 * skb_gso_segment does the following. Do we need to do it as well?1138 */1139 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)1140 skb_reset_mac_header(pSkb);1141 pSkb->mac_len = pSkb->network_header - pSkb->mac_header;1142 #else1143 pSkb->mac.raw = pSkb->data;1144 pSkb->mac_len = pSkb->nh.raw - pSkb->data;1145 #endif1146 1267 } 1147 1268 … … 1293 1414 { 1294 1415 int rc; 1295 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pSkb); 1296 if (RT_LIKELY(cSegs <= MAX_SKB_FRAGS + 1)) 1297 { 1298 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); 1299 if (RT_LIKELY(pSG)) 1300 { 1301 vboxNetFltLinuxSkBufToSG(pThis, pSkb, pSG, cSegs, fSrc, pGsoCtx); 1302 1303 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 1304 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc); 1305 1306 vboxNetFltLinuxDestroySG(pSG); 1307 rc = VINF_SUCCESS; 1308 } 1309 else 1310 { 1311 Log(("VBoxNetFlt: Dropping the sk_buff (failure case).\n")); 1312 rc = VERR_NO_MEMORY; 1313 } 1416 unsigned cbExtra; 1417 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pSkb, &cbExtra); 1418 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]) + cbExtra); 1419 if (RT_LIKELY(pSG)) 1420 { 1421 vboxNetFltLinuxSkBufToSG(pThis, pSkb, pSG, cbExtra, cSegs, fSrc, pGsoCtx); 1422 1423 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 1424 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc); 1425 1426 vboxNetFltLinuxDestroySG(pSG, pSkb); 1427 rc = VINF_SUCCESS; 1314 1428 } 1315 1429 else 1316 1430 { 1317 Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs)); 1318 rc = VERR_INTERNAL_ERROR_3; 1319 } 1320 1321 Log4(("VBoxNetFlt: Dropping the sk_buff.\n")); 1322 dev_kfree_skb(pSkb); 1431 Log(("VBoxNetFlt: Dropping the sk_buff (failure case).\n")); 1432 rc = VERR_NO_MEMORY; 1433 } 1323 1434 return rc; 1324 1435 } … … 1337 1448 { 1338 1449 int rc; 1339 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf); 1340 if (cSegs <= MAX_SKB_FRAGS + 1) 1341 { 1342 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); 1343 if (RT_LIKELY(pSG)) 1344 { 1345 if (fSrc & INTNETTRUNKDIR_WIRE) 1346 { 1347 /* 1348 * The packet came from wire, ethernet header was removed by device driver. 1349 * Restore it using mac_len field. This takes into account VLAN headers too. 1350 */ 1351 skb_push(pBuf, pBuf->mac_len); 1352 } 1353 1354 vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc, NULL /*pGsoCtx*/); 1355 1356 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 1357 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc); 1358 1359 vboxNetFltLinuxDestroySG(pSG); 1360 rc = VINF_SUCCESS; 1361 } 1362 else 1363 { 1364 Log(("VBoxNetFlt: Failed to allocate SG buffer.\n")); 1365 rc = VERR_NO_MEMORY; 1366 } 1450 unsigned cbExtra; 1451 unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf, &cbExtra); 1452 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]) + cbExtra); 1453 if (RT_LIKELY(pSG)) 1454 { 1455 vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cbExtra, cSegs, fSrc, NULL /*pGsoCtx*/); 1456 1457 vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1); 1458 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc); 1459 1460 vboxNetFltLinuxDestroySG(pSG, pBuf); 1461 rc = VINF_SUCCESS; 1367 1462 } 1368 1463 else 1369 1464 { 1370 Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs)); 1371 rc = VERR_INTERNAL_ERROR_3; 1372 } 1373 1374 Log4(("VBoxNetFlt: Dropping the sk_buff.\n")); 1375 dev_kfree_skb(pBuf); 1465 Log(("VBoxNetFlt: Failed to allocate SG buffer.\n")); 1466 rc = VERR_NO_MEMORY; 1467 } 1376 1468 return rc; 1377 1469 } 1378 1470 1471 1379 1472 /** 1380 1473 * I won't disclose what I do, figure it out yourself, including pThis referencing. 1381 1474 * 1382 1475 * @param pThis The net filter instance. 1383 * @param pBuf The socket buffer. This is consumed by this function. 1384 */ 1385 static void vboxNetFltLinuxForwardToIntNet(PVBOXNETFLTINS pThis, struct sk_buff *pBuf) 1386 { 1387 uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE; 1388 1476 * @param pBuf The socket buffer. 1477 * @param fSrc Where the packet comes from. 1478 */ 1479 static void vboxNetFltLinuxForwardToIntNetInner(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc) 1480 { 1389 1481 #ifdef VBOXNETFLT_WITH_GSO 1390 1482 if (skb_is_gso(pBuf)) 1391 1483 { 1392 1484 PDMNETWORKGSO GsoCtx; 1393 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", 1394 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)); 1485 Log6(("vboxNetFltLinuxForwardToIntNetInner: skb len=%u data_len=%u truesize=%u next=%p" 1486 " nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x ip_summed=%d\n", 1487 pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, 1488 skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, 1489 skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, 1490 skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, pBuf->ip_summed)); 1491 #ifndef VBOXNETFLT_SG_SUPPORT 1492 if (RT_LIKELY(fSrc & INTNETTRUNKDIR_HOST)) 1493 { 1494 /* 1495 * skb_gso_segment does the following. Do we need to do it as well? 1496 */ 1497 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) 1498 skb_reset_mac_header(pBuf); 1499 pBuf->mac_len = pBuf->network_header - pBuf->mac_header; 1500 # else 1501 pBuf->mac.raw = pBuf->data; 1502 pBuf->mac_len = pBuf->nh.raw - pBuf->data; 1503 # endif 1504 } 1505 #endif /* !VBOXNETFLT_SG_SUPPORT */ 1395 1506 # ifdef VBOXNETFLT_WITH_GSO_RECV 1396 1507 if ( (skb_shinfo(pBuf)->gso_type & (SKB_GSO_UDP | SKB_GSO_TCPV6 | SKB_GSO_TCPV4)) … … 1398 1509 vboxNetFltLinuxForwardAsGso(pThis, pBuf, fSrc, &GsoCtx); 1399 1510 else 1400 # endif 1511 # endif /* VBOXNETFLT_WITH_GSO_RECV */ 1401 1512 { 1402 1513 /* Need to segment the packet */ … … 1405 1516 if (IS_ERR(pSegment)) 1406 1517 { 1407 dev_kfree_skb(pBuf);1408 1518 LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pSegment))); 1409 1519 return; … … 1412 1522 for (; pSegment; pSegment = pNext) 1413 1523 { 1414 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", 1415 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)); 1524 Log6(("vboxNetFltLinuxForwardToIntNetInner: segment len=%u data_len=%u truesize=%u next=%p" 1525 " nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n", 1526 pSegment->len, pSegment->data_len, pSegment->truesize, pSegment->next, 1527 skb_shinfo(pSegment)->nr_frags, skb_shinfo(pSegment)->gso_size, 1528 skb_shinfo(pSegment)->gso_segs, skb_shinfo(pSegment)->gso_type, 1529 skb_shinfo(pSegment)->frag_list, pSegment->pkt_type)); 1416 1530 pNext = pSegment->next; 1417 1531 pSegment->next = 0; 1418 1532 vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc); 1533 dev_kfree_skb(pSegment); 1419 1534 } 1420 dev_kfree_skb(pBuf);1421 1535 } 1422 1536 } … … 1424 1538 #endif /* VBOXNETFLT_WITH_GSO */ 1425 1539 { 1540 Log6(("vboxNetFltLinuxForwardToIntNetInner: ptk_type=%d ip_summed=%d len=%d" 1541 " data_len=%d headroom=%d hdr_len=%d csum_offset=%d\n", 1542 pBuf->pkt_type, pBuf->ip_summed, pBuf->len, pBuf->data_len, skb_headroom(pBuf), 1543 skb_headlen(pBuf), skb_checksum_start_offset(pBuf))); 1544 #ifndef VBOXNETFLT_SG_SUPPORT 1426 1545 if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING) 1427 1546 { … … 1437 1556 pBuf->h.raw = pBuf->nh.raw + pBuf->nh.iph->ihl * 4; 1438 1557 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */ 1439 if (VBOX_SKB_CHECKSUM_HELP(pBuf)) 1440 { 1441 LogRel(("VBoxNetFlt: Failed to compute checksum, dropping the packet.\n")); 1442 dev_kfree_skb(pBuf); 1443 return; 1444 } 1558 int rc = VBOX_SKB_CHECKSUM_HELP(pBuf); 1445 1559 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) 1446 1560 /* Restore the original (wrong) pointer. */ 1447 1561 pBuf->h.raw = tmp; 1448 1562 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */ 1449 } 1563 if (rc) { 1564 LogRel(("VBoxNetFlt: Failed to compute checksum, dropping the packet.\n")); 1565 return; 1566 } 1567 } 1568 #endif /* !VBOXNETFLT_SG_SUPPORT */ 1450 1569 vboxNetFltLinuxForwardSegment(pThis, pBuf, fSrc); 1451 1570 } 1452 1571 } 1572 1573 1574 /** 1575 * Temporarily adjust pBuf->data so it always points to the Ethernet header, 1576 * then forward it to the internal network. 1577 * 1578 * @param pThis The net filter instance. 1579 * @param pBuf The socket buffer. This is consumed by this function. 1580 */ 1581 static void vboxNetFltLinuxForwardToIntNet(PVBOXNETFLTINS pThis, struct sk_buff *pBuf) 1582 { 1583 uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE; 1584 1585 if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE)) 1586 { 1587 /* 1588 * The packet came from the wire and the driver has already consumed 1589 * mac header. We need to restore it back. Moreover, after we are 1590 * through with this skb we need to restore its original state! 1591 */ 1592 skb_push(pBuf, pBuf->mac_len); 1593 Log5(("vboxNetFltLinuxForwardToIntNet: mac_len=%d data=%p mac_header=%p network_header=%p\n", 1594 pBuf->mac_len, pBuf->data, skb_mac_header(pBuf), skb_network_header(pBuf))); 1595 } 1596 1597 vboxNetFltLinuxForwardToIntNetInner(pThis, pBuf, fSrc); 1598 1599 /* 1600 * Restore the original state of skb as there are other handlers this skb 1601 * will be provided to. 1602 */ 1603 if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE)) 1604 skb_pull(pBuf, pBuf->mac_len); 1605 1606 dev_kfree_skb(pBuf); 1607 } 1608 1453 1609 1454 1610 #ifndef VBOXNETFLT_LINUX_NO_XMIT_QUEUE … … 1468 1624 struct sk_buff *pBuf; 1469 1625 1470 Log 4(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork));1626 Log6(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork)); 1471 1627 1472 1628 /* … … 2107 2263 { 2108 2264 vboxNetFltDumpPacket(pSG, true, "wire", 1); 2109 Log 4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));2110 Log 4(("vboxNetFltPortOsXmit: dev_queue_xmit(%p)\n", pBuf));2265 Log6(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb)); 2266 Log6(("vboxNetFltPortOsXmit: dev_queue_xmit(%p)\n", pBuf)); 2111 2267 err = dev_queue_xmit(pBuf); 2112 2268 if (err) … … 2126 2282 { 2127 2283 vboxNetFltDumpPacket(pSG, true, "host", (fDst & INTNETTRUNKDIR_WIRE) ? 0 : 1); 2128 Log 4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));2129 Log 4(("vboxNetFltPortOsXmit: netif_rx_ni(%p)\n", pBuf));2284 Log6(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb)); 2285 Log6(("vboxNetFltPortOsXmit: netif_rx_ni(%p)\n", pBuf)); 2130 2286 err = netif_rx_ni(pBuf); 2131 2287 if (err)
Note:
See TracChangeset
for help on using the changeset viewer.