Changeset 28159 in vbox
- Timestamp:
- Apr 10, 2010 8:06:17 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
r28157 r28159 220 220 Log(("VBoxNetFltLinuxUnload - done\n")); 221 221 } 222 223 /** 224 * Experiment where we filter trafic from the host to the internal network 225 * before it reaches the NIC driver. 226 * 227 * The current code uses a very ugly hack and only works on kernels using the 228 * net_device_ops (2.6.30 or something). It has been shown to give us a 229 * performance boost of 60-100% though. So, we have to find some less hacky way 230 * of getting this job done eventually. 231 * 232 * #define VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 233 */ 234 #ifdef VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 235 236 /** 237 * The overridden net_device_ops of the device we're attached to. 238 * 239 * Requires Linux 2.6.30 or something. 240 * 241 * This is a very dirty hack that was create to explore how much we can improve 242 * the host to guest transfers by not CC'ing the NIC. 243 */ 244 typedef struct VBoxNetDeviceOpsOverride 245 { 246 /** Our overridden ops. */ 247 struct net_device_ops Ops; 248 /** Pointer to the original ops. */ 249 struct net_device_ops const *pOrgOps; 250 /** Magic word. */ 251 uint32_t u32Magic; 252 /** The number of filtered packages. */ 253 uint64_t cFiltered; 254 /** The total number of packets */ 255 uint64_t cTotal; 256 } VBOXNETDEVICEOPSOVERRIDE, *PVBOXNETDEVICEOPSOVERRIDE; 257 /** VBOXNETDEVICEOPSOVERRIDE::u32Magic value. */ 258 #define VBOXNETDEVICEOPSOVERRIDE_MAGIC UINT32_C(0x00c0ffee) 259 260 /** 261 * ndo_start_xmit wrapper that drops packets that shouldn't go to the wire 262 * because they belong on the internal network. 263 * 264 * @returns NETDEV_TX_XXX. 265 * @param pSkb The socket buffer to transmit. 266 * @param pDev The net device. 267 */ 268 static int vboxNetFltLinuxStartXmitFilter(struct sk_buff *pSkb, struct net_device *pDev) 269 { 270 PVBOXNETDEVICEOPSOVERRIDE pOverride = (PVBOXNETDEVICEOPSOVERRIDE)pDev->netdev_ops; 271 RTNETETHERHDR EtherHdrBuf; 272 PCRTNETETHERHDR pEtherHdr; 273 274 /* 275 * Validate the override structure. 276 * 277 * Note! We're racing vboxNetFltLinuxUnhookDev here. If this was supposed 278 * to be production quality code, we would have to be much more 279 * careful here and avoid the race. 280 */ 281 if ( !VALID_PTR(pOverride) 282 || pOverride->u32Magic != VBOXNETDEVICEOPSOVERRIDE_MAGIC 283 || !VALID_PTR(pOverride->pOrgOps)) 284 { 285 printk("vboxNetFltLinuxStartXmitFilter: bad override %p\n", pOverride); 286 dev_kfree_skb(pSkb); 287 return NETDEV_TX_OK; 288 } 289 pOverride->cTotal++; 290 291 /* 292 * Do the filtering base on the defaul OUI of our virtual NICs 293 * 294 * Note! In a real solution, we would ask the switch whether the 295 * destination MAC is 100% to be on the internal network and then 296 * drop it. 297 */ 298 pEtherHdr = (PCRTNETETHERHDR)skb_header_pointer(pSkb, 0, sizeof(EtherHdrBuf), &EtherHdrBuf); 299 if ( pEtherHdr 300 && pEtherHdr->DstMac.au8[0] == 0x08 301 && pEtherHdr->DstMac.au8[1] == 0x00 302 && pEtherHdr->DstMac.au8[2] == 0x27 303 ) 304 { 305 dev_kfree_skb(pSkb); 306 pOverride->cFiltered++; 307 return NETDEV_TX_OK; 308 } 309 310 return pOverride->pOrgOps->ndo_start_xmit(pSkb, pDev); 311 } 312 313 /** 314 * Hooks the device ndo_start_xmit operation of the device. 315 * 316 * @param pThis The net filter instance. 317 * @param pDev The net device. 318 */ 319 static void vboxNetFltLinuxHookDev(PVBOXNETFLTINS pThis, struct net_device *pDev) 320 { 321 PVBOXNETDEVICEOPSOVERRIDE pOverride; 322 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 323 324 pOverride = RTMemAlloc(sizeof(*pOverride)); 325 if (!pOverride) 326 return; 327 pOverride->pOrgOps = pDev->netdev_ops; 328 pOverride->Ops = *pDev->netdev_ops; 329 pOverride->Ops.ndo_start_xmit = vboxNetFltLinuxStartXmitFilter; 330 pOverride->u32Magic = VBOXNETDEVICEOPSOVERRIDE_MAGIC; 331 332 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); /* (this isn't necessary, but so what) */ 333 ASMAtomicXchgPtr((void * volatile *)&pDev->netdev_ops, pOverride); 334 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 335 } 336 337 /** 338 * Undos what vboxNetFltLinuxHookDev did. 339 * 340 * @param pThis The net filter instance. 341 * @param pDev The net device. Can be NULL, in which case 342 * we'll try retrieve it from @a pThis. 343 */ 344 static void vboxNetFltLinuxUnhookDev(PVBOXNETFLTINS pThis, struct net_device *pDev) 345 { 346 PVBOXNETDEVICEOPSOVERRIDE pOverride; 347 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 348 349 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 350 if (!pDev) 351 pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev); 352 if (VALID_PTR(pDev)) 353 { 354 pOverride = (PVBOXNETDEVICEOPSOVERRIDE)pDev->netdev_ops; 355 if ( VALID_PTR(pOverride) 356 && pOverride->u32Magic == VBOXNETDEVICEOPSOVERRIDE_MAGIC 357 && VALID_PTR(pOverride->pOrgOps) 358 ) 359 { 360 ASMAtomicXchgPtr((void * volatile *)&pDev->netdev_ops, pOverride->pOrgOps); 361 ASMAtomicWriteU32(&pOverride->u32Magic, 0); 362 } 363 else 364 pOverride = NULL; 365 } 366 else 367 pOverride = NULL; 368 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 369 370 if (pOverride) 371 { 372 printk("vboxnetflt: dropped %llu out of %llu packets\n", pOverride->cFiltered, pOverride->cTotal); 373 RTMemFree(pOverride); 374 } 375 } 376 377 #endif /* VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT */ 222 378 223 379 … … 1125 1281 dev_add_pack(&pThis->u.s.PacketType); 1126 1282 1283 #ifdef VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 1284 vboxNetFltLinuxHookDev(pThis, pDev); 1285 #endif 1286 1127 1287 /* 1128 1288 * Set indicators that require the spinlock. Be abit paranoid about racing … … 1148 1308 else 1149 1309 { 1310 #ifdef VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 1311 vboxNetFltLinuxUnhookDev(pThis, pDev); 1312 #endif 1150 1313 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 1151 1314 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pDev, NULL); … … 1165 1328 1166 1329 Assert(!pThis->fDisconnectedFromHost); 1330 1331 #ifdef VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 1332 vboxNetFltLinuxUnhookDev(pThis, pDev); 1333 #endif 1334 1167 1335 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 1168 1336 ASMAtomicWriteBool(&pThis->u.s.fRegistered, false); … … 1470 1638 void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) 1471 1639 { 1472 struct net_device *pDev; 1473 bool fRegistered; 1474 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1640 struct net_device *pDev; 1641 bool fRegistered; 1642 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1643 1644 #ifdef VBOXNETFLT_WITH_FILTER_HOST2GUEST_SKBS_EXPERIMENT 1645 vboxNetFltLinuxUnhookDev(pThis, NULL); 1646 #endif 1647 1648 /** @todo This code may race vboxNetFltLinuxUnregisterDevice (very very 1649 * unlikely, but none the less). Since it doesn't actually update the 1650 * state (just reads it), it is likely to panic in some interesting 1651 * ways. */ 1475 1652 1476 1653 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); … … 1478 1655 fRegistered = ASMAtomicUoReadBool(&pThis->u.s.fRegistered); 1479 1656 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 1657 1480 1658 if (fRegistered) 1481 1659 {
Note:
See TracChangeset
for help on using the changeset viewer.