* if_vmove() performs a limited version of if_detach() in current * vnet and if_attach()es the ifnet to the vnet specified as 2nd arg. * An attempt is made to shrink if_index in current vnet, find an * unused if_index in target vnet and calls if_grow() if necessary, * and finally find an unused if_xname for the target vnet. */
| 1299 | * and finally find an unused if_xname for the target vnet. |
| 1300 | */ |
| 1301 | static int |
| 1302 | if_vmove(struct ifnet *ifp, struct vnet *new_vnet) |
| 1303 | { |
| 1304 | struct if_clone *ifc; |
| 1305 | #ifdef DEV_BPF |
| 1306 | u_int bif_dlt, bif_hdrlen; |
| 1307 | #endif |
| 1308 | void *old; |
| 1309 | int rc; |
| 1310 | |
| 1311 | #ifdef DEV_BPF |
| 1312 | /* |
| 1313 | * if_detach_internal() will call the eventhandler to notify |
| 1314 | * interface departure. That will detach if_bpf. We need to |
| 1315 | * safe the dlt and hdrlen so we can re-attach it later. |
| 1316 | */ |
| 1317 | bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen); |
| 1318 | #endif |
| 1319 | |
| 1320 | /* |
| 1321 | * Detach from current vnet, but preserve LLADDR info, do not |
| 1322 | * mark as dead etc. so that the ifnet can be reattached later. |
| 1323 | * If we cannot find it, we lost the race to someone else. |
| 1324 | */ |
| 1325 | rc = if_detach_internal(ifp, 1, &ifc); |
| 1326 | if (rc != 0) |
| 1327 | return (rc); |
| 1328 | |
| 1329 | /* |
| 1330 | * Unlink the ifnet from ifindex_table[] in current vnet, and shrink |
| 1331 | * the if_index for that vnet if possible. |
| 1332 | * |
| 1333 | * NOTE: IFNET_WLOCK/IFNET_WUNLOCK() are assumed to be unvirtualized, |
| 1334 | * or we'd lock on one vnet and unlock on another. |
| 1335 | */ |
| 1336 | IFNET_WLOCK(); |
| 1337 | ifindex_free_locked(ifp->if_index); |
| 1338 | IFNET_WUNLOCK(); |
| 1339 | |
| 1340 | /* |
| 1341 | * Perform interface-specific reassignment tasks, if provided by |
| 1342 | * the driver. |
| 1343 | */ |
| 1344 | if (ifp->if_reassign != NULL) |
| 1345 | ifp->if_reassign(ifp, new_vnet, NULL); |
| 1346 | |
| 1347 | /* |
| 1348 | * Switch to the context of the target vnet. |
| 1349 | */ |
| 1350 | CURVNET_SET_QUIET(new_vnet); |
| 1351 | restart: |
| 1352 | IFNET_WLOCK(); |
| 1353 | ifp->if_index = ifindex_alloc(&old); |
| 1354 | if (__predict_false(ifp->if_index == USHRT_MAX)) { |
| 1355 | IFNET_WUNLOCK(); |
| 1356 | epoch_wait_preempt(net_epoch_preempt); |
| 1357 | free(old, M_IFNET); |
| 1358 | goto restart; |
no test coverage detected