diff options
Diffstat (limited to 'sys/dev/netmap/netmap_vale.c')
| -rw-r--r-- | sys/dev/netmap/netmap_vale.c | 231 |
1 files changed, 159 insertions, 72 deletions
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index 71b3aedddd46e..d20f384c48d7b 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -161,7 +161,8 @@ SYSCTL_DECL(_dev_netmap); SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , ""); SYSEND; -static int netmap_vp_create(struct nmreq *, struct ifnet *, struct netmap_vp_adapter **); +static int netmap_vp_create(struct nmreq *, struct ifnet *, + struct netmap_mem_d *nmd, struct netmap_vp_adapter **); static int netmap_vp_reg(struct netmap_adapter *na, int onoff); static int netmap_bwrap_reg(struct netmap_adapter *, int onoff); @@ -393,7 +394,7 @@ nm_free_bdgfwd(struct netmap_adapter *na) kring = na->tx_rings; for (i = 0; i < nrings; i++) { if (kring[i].nkr_ft) { - free(kring[i].nkr_ft, M_DEVBUF); + nm_os_free(kring[i].nkr_ft); kring[i].nkr_ft = NULL; /* protect from freeing twice */ } } @@ -423,7 +424,7 @@ nm_alloc_bdgfwd(struct netmap_adapter *na) struct nm_bdg_q *dstq; int j; - ft = malloc(l, M_DEVBUF, M_NOWAIT | M_ZERO); + ft = nm_os_malloc(l); if (!ft) { nm_free_bdgfwd(na); return ENOMEM; @@ -538,6 +539,13 @@ netmap_vp_dtor(struct netmap_adapter *na) if (b) { netmap_bdg_detach_common(b, vpna->bdg_port, -1); } + + if (vpna->autodelete && na->ifp != NULL) { + ND("releasing %s", na->ifp->if_xname); + NMG_UNLOCK(); + nm_os_vi_detach(na->ifp); + NMG_LOCK(); + } } /* remove a persistent VALE port from the system */ @@ -545,6 +553,7 @@ static int nm_vi_destroy(const char *name) { struct ifnet *ifp; + struct netmap_vp_adapter *vpna; int error; ifp = ifunit_ref(name); @@ -557,18 +566,29 @@ nm_vi_destroy(const char *name) goto err; } - if (NA(ifp)->na_refcount > 1) { + vpna = (struct netmap_vp_adapter *)NA(ifp); + + /* we can only destroy ports that were created via NETMAP_BDG_NEWIF */ + if (vpna->autodelete) { + error = EINVAL; + goto err; + } + + /* also make sure that nobody is using the inferface */ + if (NETMAP_OWNED_BY_ANY(&vpna->up) || + vpna->up.na_refcount > 1 /* any ref besides the one in nm_vi_create()? */) { error = EBUSY; goto err; } + NMG_UNLOCK(); D("destroying a persistent vale interface %s", ifp->if_xname); /* Linux requires all the references are released * before unregister */ - if_rele(ifp); netmap_detach(ifp); + if_rele(ifp); nm_os_vi_detach(ifp); return 0; @@ -578,15 +598,26 @@ err: return error; } +static int +nm_update_info(struct nmreq *nmr, struct netmap_adapter *na) +{ + nmr->nr_rx_rings = na->num_rx_rings; + nmr->nr_tx_rings = na->num_tx_rings; + nmr->nr_rx_slots = na->num_rx_desc; + nmr->nr_tx_slots = na->num_tx_desc; + return netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, NULL, &nmr->nr_arg2); +} + /* * Create a virtual interface registered to the system. * The interface will be attached to a bridge later. */ -static int -nm_vi_create(struct nmreq *nmr) +int +netmap_vi_create(struct nmreq *nmr, int autodelete) { struct ifnet *ifp; struct netmap_vp_adapter *vpna; + struct netmap_mem_d *nmd = NULL; int error; /* don't include VALE prefix */ @@ -594,28 +625,64 @@ nm_vi_create(struct nmreq *nmr) return EINVAL; ifp = ifunit_ref(nmr->nr_name); if (ifp) { /* already exist, cannot create new one */ + error = EEXIST; + NMG_LOCK(); + if (NM_NA_VALID(ifp)) { + int update_err = nm_update_info(nmr, NA(ifp)); + if (update_err) + error = update_err; + } + NMG_UNLOCK(); if_rele(ifp); - return EEXIST; + return error; } error = nm_os_vi_persist(nmr->nr_name, &ifp); if (error) return error; NMG_LOCK(); + if (nmr->nr_arg2) { + nmd = netmap_mem_find(nmr->nr_arg2); + if (nmd == NULL) { + error = EINVAL; + goto err_1; + } + } /* netmap_vp_create creates a struct netmap_vp_adapter */ - error = netmap_vp_create(nmr, ifp, &vpna); + error = netmap_vp_create(nmr, ifp, nmd, &vpna); if (error) { D("error %d", error); - nm_os_vi_detach(ifp); - return error; + goto err_1; } /* persist-specific routines */ vpna->up.nm_bdg_ctl = netmap_vp_bdg_ctl; - netmap_adapter_get(&vpna->up); + if (!autodelete) { + netmap_adapter_get(&vpna->up); + } else { + vpna->autodelete = 1; + } NM_ATTACH_NA(ifp, &vpna->up); + /* return the updated info */ + error = nm_update_info(nmr, &vpna->up); + if (error) { + goto err_2; + } + D("returning nr_arg2 %d", nmr->nr_arg2); + if (nmd) + netmap_mem_put(nmd); NMG_UNLOCK(); D("created %s", ifp->if_xname); return 0; + +err_2: + netmap_detach(ifp); +err_1: + if (nmd) + netmap_mem_put(nmd); + NMG_UNLOCK(); + nm_os_vi_detach(ifp); + + return error; } /* Try to get a reference to a netmap adapter attached to a VALE switch. @@ -628,11 +695,12 @@ nm_vi_create(struct nmreq *nmr) * (*na != NULL && return == 0). */ int -netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) +netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, + struct netmap_mem_d *nmd, int create) { char *nr_name = nmr->nr_name; const char *ifname; - struct ifnet *ifp; + struct ifnet *ifp = NULL; int error = 0; struct netmap_vp_adapter *vpna, *hostna = NULL; struct nm_bridge *b; @@ -702,15 +770,15 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) */ if (nmr->nr_cmd) { /* nr_cmd must be 0 for a virtual port */ - return EINVAL; + error = EINVAL; + goto out; } /* bdg_netmap_attach creates a struct netmap_adapter */ - error = netmap_vp_create(nmr, NULL, &vpna); + error = netmap_vp_create(nmr, NULL, nmd, &vpna); if (error) { D("error %d", error); - free(ifp, M_DEVBUF); - return error; + goto out; } /* shortcut - we can skip get_hw_na(), * ownership check and nm_bdg_attach() @@ -718,7 +786,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) } else { struct netmap_adapter *hw; - error = netmap_get_hw_na(ifp, &hw); + error = netmap_get_hw_na(ifp, nmd, &hw); if (error || hw == NULL) goto out; @@ -751,10 +819,10 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) BDG_WUNLOCK(b); *na = &vpna->up; netmap_adapter_get(*na); - return 0; out: - if_rele(ifp); + if (ifp) + if_rele(ifp); return error; } @@ -765,11 +833,20 @@ static int nm_bdg_ctl_attach(struct nmreq *nmr) { struct netmap_adapter *na; + struct netmap_mem_d *nmd = NULL; int error; NMG_LOCK(); - error = netmap_get_bdg_na(nmr, &na, 1 /* create if not exists */); + if (nmr->nr_arg2) { + nmd = netmap_mem_find(nmr->nr_arg2); + if (nmd == NULL) { + error = EINVAL; + goto unlock_exit; + } + } + + error = netmap_get_bdg_na(nmr, &na, nmd, 1 /* create if not exists */); if (error) /* no device */ goto unlock_exit; @@ -816,7 +893,7 @@ nm_bdg_ctl_detach(struct nmreq *nmr) int error; NMG_LOCK(); - error = netmap_get_bdg_na(nmr, &na, 0 /* don't create */); + error = netmap_get_bdg_na(nmr, &na, NULL, 0 /* don't create */); if (error) { /* no device, or another bridge or user owns the device */ goto unlock_exit; } @@ -848,7 +925,7 @@ unlock_exit: struct nm_bdg_polling_state; struct nm_bdg_kthread { - struct nm_kthread *nmk; + struct nm_kctx *nmk; u_int qfirst; u_int qlast; struct nm_bdg_polling_state *bps; @@ -867,7 +944,7 @@ struct nm_bdg_polling_state { }; static void -netmap_bwrap_polling(void *data) +netmap_bwrap_polling(void *data, int is_kthread) { struct nm_bdg_kthread *nbk = data; struct netmap_bwrap_adapter *bna; @@ -890,16 +967,16 @@ netmap_bwrap_polling(void *data) static int nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) { - struct nm_kthread_cfg kcfg; + struct nm_kctx_cfg kcfg; int i, j; - bps->kthreads = malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus, - M_DEVBUF, M_NOWAIT | M_ZERO); + bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus); if (bps->kthreads == NULL) return ENOMEM; bzero(&kcfg, sizeof(kcfg)); kcfg.worker_fn = netmap_bwrap_polling; + kcfg.use_kthread = 1; for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; int all = (bps->ncpus == 1 && bps->reg == NR_REG_ALL_NIC); @@ -913,24 +990,24 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) kcfg.type = i; kcfg.worker_private = t; - t->nmk = nm_os_kthread_create(&kcfg, 0, NULL); + t->nmk = nm_os_kctx_create(&kcfg, 0, NULL); if (t->nmk == NULL) { goto cleanup; } - nm_os_kthread_set_affinity(t->nmk, affinity); + nm_os_kctx_worker_setaff(t->nmk, affinity); } return 0; cleanup: for (j = 0; j < i; j++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_delete(t->nmk); + nm_os_kctx_destroy(t->nmk); } - free(bps->kthreads, M_DEVBUF); + nm_os_free(bps->kthreads); return EFAULT; } -/* a version of ptnetmap_start_kthreads() */ +/* A variant of ptnetmap_start_kthreads() */ static int nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) { @@ -944,7 +1021,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; - error = nm_os_kthread_start(t->nmk); + error = nm_os_kctx_worker_start(t->nmk); if (error) { D("error in nm_kthread_start()"); goto cleanup; @@ -955,7 +1032,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) cleanup: for (j = 0; j < i; j++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_stop(t->nmk); + nm_os_kctx_worker_stop(t->nmk); } bps->stopped = true; return error; @@ -971,8 +1048,8 @@ nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps) for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_stop(t->nmk); - nm_os_kthread_delete(t->nmk); + nm_os_kctx_worker_stop(t->nmk); + nm_os_kctx_destroy(t->nmk); } bps->stopped = true; } @@ -1050,19 +1127,19 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na) return EFAULT; } - bps = malloc(sizeof(*bps), M_DEVBUF, M_NOWAIT | M_ZERO); + bps = nm_os_malloc(sizeof(*bps)); if (!bps) return ENOMEM; bps->configured = false; bps->stopped = true; if (get_polling_cfg(nmr, na, bps)) { - free(bps, M_DEVBUF); + nm_os_free(bps); return EINVAL; } if (nm_bdg_create_kthreads(bps)) { - free(bps, M_DEVBUF); + nm_os_free(bps); return EFAULT; } @@ -1077,8 +1154,8 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na) error = nm_bdg_polling_start_kthreads(bps); if (error) { D("ERROR nm_bdg_polling_start_kthread()"); - free(bps->kthreads, M_DEVBUF); - free(bps, M_DEVBUF); + nm_os_free(bps->kthreads); + nm_os_free(bps); bna->na_polling_state = NULL; if (bna->hwna->nm_intr) bna->hwna->nm_intr(bna->hwna, 1); @@ -1099,7 +1176,7 @@ nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na) bps = bna->na_polling_state; nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state); bps->configured = false; - free(bps, M_DEVBUF); + nm_os_free(bps); bna->na_polling_state = NULL; /* reenable interrupt */ if (bna->hwna->nm_intr) @@ -1130,7 +1207,7 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) switch (cmd) { case NETMAP_BDG_NEWIF: - error = nm_vi_create(nmr); + error = netmap_vi_create(nmr, 0 /* no autodelete */); break; case NETMAP_BDG_DELIF: @@ -1193,18 +1270,19 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) NMG_LOCK(); for (error = ENOENT; i < NM_BRIDGES; i++) { b = bridges + i; - if (j >= b->bdg_active_ports) { - j = 0; /* following bridges scan from 0 */ - continue; + for ( ; j < NM_BDG_MAXPORTS; j++) { + if (b->bdg_ports[j] == NULL) + continue; + vpna = b->bdg_ports[j]; + strncpy(name, vpna->up.name, (size_t)IFNAMSIZ); + error = 0; + goto out; } - nmr->nr_arg1 = i; - nmr->nr_arg2 = j; - j = b->bdg_port_index[j]; - vpna = b->bdg_ports[j]; - strncpy(name, vpna->up.name, (size_t)IFNAMSIZ); - error = 0; - break; + j = 0; /* following bridges scan from 0 */ } + out: + nmr->nr_arg1 = i; + nmr->nr_arg2 = j; NMG_UNLOCK(); } break; @@ -1238,7 +1316,7 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) break; } NMG_LOCK(); - error = netmap_get_bdg_na(nmr, &na, 0); + error = netmap_get_bdg_na(nmr, &na, NULL, 0); if (na && !error) { vpna = (struct netmap_vp_adapter *)na; na->virt_hdr_len = nmr->nr_arg1; @@ -1256,7 +1334,7 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) case NETMAP_BDG_POLLING_ON: case NETMAP_BDG_POLLING_OFF: NMG_LOCK(); - error = netmap_get_bdg_na(nmr, &na, 0); + error = netmap_get_bdg_na(nmr, &na, NULL, 0); if (na && !error) { if (!nm_is_bwrap(na)) { error = EOPNOTSUPP; @@ -1384,7 +1462,7 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end) if (na->up.na_flags & NAF_BDG_MAYSLEEP) BDG_RLOCK(b); else if (!BDG_RTRYLOCK(b)) - return 0; + return j; ND(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j); ft = kring->nkr_ft; @@ -1802,8 +1880,10 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, needed = d->bq_len + brddst->bq_len; if (unlikely(dst_na->up.virt_hdr_len != na->up.virt_hdr_len)) { - RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len, - dst_na->up.virt_hdr_len); + if (netmap_verbose) { + RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len, + dst_na->up.virt_hdr_len); + } /* There is a virtio-net header/offloadings mismatch between * source and destination. The slower mismatch datapath will * be used to cope with all the mismatches. @@ -2125,14 +2205,16 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na) * Only persistent VALE ports have a non-null ifp. */ static int -netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp, struct netmap_vp_adapter **ret) +netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp, + struct netmap_mem_d *nmd, + struct netmap_vp_adapter **ret) { struct netmap_vp_adapter *vpna; struct netmap_adapter *na; - int error; + int error = 0; u_int npipes = 0; - vpna = malloc(sizeof(*vpna), M_DEVBUF, M_NOWAIT | M_ZERO); + vpna = nm_os_malloc(sizeof(*vpna)); if (vpna == NULL) return ENOMEM; @@ -2183,7 +2265,10 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp, struct netmap_vp_adapter na->nm_krings_create = netmap_vp_krings_create; na->nm_krings_delete = netmap_vp_krings_delete; na->nm_dtor = netmap_vp_dtor; - na->nm_mem = netmap_mem_private_new(na->name, + D("nr_arg2 %d", nmr->nr_arg2); + na->nm_mem = nmd ? + netmap_mem_get(nmd): + netmap_mem_private_new( na->num_tx_rings, na->num_tx_desc, na->num_rx_rings, na->num_rx_desc, nmr->nr_arg3, npipes, &error); @@ -2199,8 +2284,8 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp, struct netmap_vp_adapter err: if (na->nm_mem != NULL) - netmap_mem_delete(na->nm_mem); - free(vpna, M_DEVBUF); + netmap_mem_put(na->nm_mem); + nm_os_free(vpna); return error; } @@ -2243,6 +2328,8 @@ netmap_bwrap_dtor(struct netmap_adapter *na) struct nm_bridge *b = bna->up.na_bdg, *bh = bna->host.na_bdg; + netmap_mem_put(bna->host.up.nm_mem); + if (b) { netmap_bdg_detach_common(b, bna->up.bdg_port, (bh ? bna->host.bdg_port : -1)); @@ -2644,7 +2731,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) return EBUSY; } - bna = malloc(sizeof(*bna), M_DEVBUF, M_NOWAIT | M_ZERO); + bna = nm_os_malloc(sizeof(*bna)); if (bna == NULL) { return ENOMEM; } @@ -2652,6 +2739,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) na = &bna->up.up; /* make bwrap ifp point to the real ifp */ na->ifp = hwna->ifp; + if_ref(na->ifp); na->na_private = bna; strncpy(na->name, nr_name, sizeof(na->name)); /* fill the ring data for the bwrap adapter with rx/tx meanings @@ -2673,7 +2761,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) na->nm_notify = netmap_bwrap_notify; na->nm_bdg_ctl = netmap_bwrap_bdg_ctl; na->pdev = hwna->pdev; - na->nm_mem = hwna->nm_mem; + na->nm_mem = netmap_mem_get(hwna->nm_mem); na->virt_hdr_len = hwna->virt_hdr_len; bna->up.retry = 1; /* XXX maybe this should depend on the hwna */ @@ -2697,7 +2785,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) // hostna->nm_txsync = netmap_bwrap_host_txsync; // hostna->nm_rxsync = netmap_bwrap_host_rxsync; hostna->nm_notify = netmap_bwrap_notify; - hostna->nm_mem = na->nm_mem; + hostna->nm_mem = netmap_mem_get(na->nm_mem); hostna->na_private = bna; hostna->na_vp = &bna->up; na->na_hostvp = hwna->na_hostvp = @@ -2720,7 +2808,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) err_free: hwna->na_vp = hwna->na_hostvp = NULL; netmap_adapter_put(hwna); - free(bna, M_DEVBUF); + nm_os_free(bna); return error; } @@ -2731,8 +2819,7 @@ netmap_init_bridges2(u_int n) int i; struct nm_bridge *b; - b = malloc(sizeof(struct nm_bridge) * n, M_DEVBUF, - M_NOWAIT | M_ZERO); + b = nm_os_malloc(sizeof(struct nm_bridge) * n); if (b == NULL) return NULL; for (i = 0; i < n; i++) @@ -2750,7 +2837,7 @@ netmap_uninit_bridges2(struct nm_bridge *b, u_int n) for (i = 0; i < n; i++) BDG_RWDESTROY(&b[i]); - free(b, M_DEVBUF); + nm_os_free(b); } int |
