Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/netmap/netmap_monitor.c
Context not available. | |||||
static int | static int | ||||
netmap_monitor_rxsync(struct netmap_kring *kring, int flags) | netmap_monitor_rxsync(struct netmap_kring *kring, int flags) | ||||
{ | { | ||||
struct netmap_monitor_adapter *mna = | |||||
(struct netmap_monitor_adapter *)kring->na; | |||||
if (unlikely(mna->priv.np_na == NULL)) { | |||||
/* parent left netmap mode */ | |||||
return EIO; | |||||
} | |||||
ND("%s %x", kring->name, flags); | ND("%s %x", kring->name, flags); | ||||
kring->nr_hwcur = kring->rhead; | kring->nr_hwcur = kring->rhead; | ||||
mb(); | mb(); | ||||
Context not available. | |||||
netmap_monitor_krings_create(struct netmap_adapter *na) | netmap_monitor_krings_create(struct netmap_adapter *na) | ||||
{ | { | ||||
int error = netmap_krings_create(na, 0); | int error = netmap_krings_create(na, 0); | ||||
enum txrx t; | |||||
if (error) | if (error) | ||||
return error; | return error; | ||||
/* override the host rings callbacks */ | /* override the host rings callbacks */ | ||||
na->tx_rings[na->num_tx_rings]->nm_sync = netmap_monitor_txsync; | for_rx_tx(t) { | ||||
na->rx_rings[na->num_rx_rings]->nm_sync = netmap_monitor_rxsync; | int i; | ||||
u_int first = nma_get_nrings(na, t); | |||||
for (i = 0; i < nma_get_host_nrings(na, t); i++) { | |||||
struct netmap_kring *kring = NMR(na, t)[first + i]; | |||||
kring->nm_sync = t == NR_TX ? netmap_monitor_txsync : | |||||
netmap_monitor_rxsync; | |||||
} | |||||
} | |||||
return 0; | return 0; | ||||
} | } | ||||
Context not available. | |||||
static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); | static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); | ||||
static int netmap_monitor_parent_notify(struct netmap_kring *, int); | static int netmap_monitor_parent_notify(struct netmap_kring *, int); | ||||
static void | |||||
nm_monitor_intercept_callbacks(struct netmap_kring *kring) | |||||
{ | |||||
ND("intercept callbacks on %s", kring->name); | |||||
kring->mon_sync = kring->nm_sync; | |||||
kring->mon_notify = kring->nm_notify; | |||||
if (kring->tx == NR_TX) { | |||||
kring->nm_sync = netmap_monitor_parent_txsync; | |||||
} else { | |||||
kring->nm_sync = netmap_monitor_parent_rxsync; | |||||
kring->nm_notify = netmap_monitor_parent_notify; | |||||
kring->mon_tail = kring->nr_hwtail; | |||||
} | |||||
} | |||||
static void | |||||
nm_monitor_restore_callbacks(struct netmap_kring *kring) | |||||
{ | |||||
ND("restoring callbacks on %s", kring->name); | |||||
kring->nm_sync = kring->mon_sync; | |||||
kring->mon_sync = NULL; | |||||
if (kring->tx == NR_RX) { | |||||
kring->nm_notify = kring->mon_notify; | |||||
} | |||||
kring->mon_notify = NULL; | |||||
} | |||||
static struct netmap_kring * | |||||
nm_zmon_list_head(struct netmap_kring *mkring, enum txrx t) | |||||
{ | |||||
struct netmap_adapter *na = mkring->na; | |||||
struct netmap_kring *kring = mkring; | |||||
struct netmap_zmon_list *z = &kring->zmon_list[t]; | |||||
/* reach the head of the list */ | |||||
while (nm_is_zmon(na) && z->prev != NULL) { | |||||
kring = z->prev; | |||||
na = kring->na; | |||||
z = &kring->zmon_list[t]; | |||||
} | |||||
return nm_is_zmon(na) ? NULL : kring; | |||||
} | |||||
/* add the monitor mkring to the list of monitors of kring. | /* add the monitor mkring to the list of monitors of kring. | ||||
* If this is the first monitor, intercept the callbacks | * If this is the first monitor, intercept the callbacks | ||||
*/ | */ | ||||
Context not available. | |||||
enum txrx t = kring->tx; | enum txrx t = kring->tx; | ||||
struct netmap_zmon_list *z = &kring->zmon_list[t]; | struct netmap_zmon_list *z = &kring->zmon_list[t]; | ||||
struct netmap_zmon_list *mz = &mkring->zmon_list[t]; | struct netmap_zmon_list *mz = &mkring->zmon_list[t]; | ||||
struct netmap_kring *ikring = kring; | |||||
/* a zero-copy monitor which is not the first in the list | /* a zero-copy monitor which is not the first in the list | ||||
* must monitor the previous monitor | * must monitor the previous monitor | ||||
*/ | */ | ||||
if (zmon && z->prev != NULL) | if (zmon && z->prev != NULL) | ||||
kring = z->prev; | ikring = z->prev; /* tail of the list */ | ||||
/* synchronize with concurrently running nm_sync()s */ | /* synchronize with concurrently running nm_sync()s */ | ||||
nm_kr_stop(kring, NM_KR_LOCKED); | nm_kr_stop(kring, NM_KR_LOCKED); | ||||
if (nm_monitor_none(kring)) { | if (nm_monitor_none(ikring)) { | ||||
/* this is the first monitor, intercept callbacks */ | /* this is the first monitor, intercept the callbacks */ | ||||
ND("intercept callbacks on %s", kring->name); | ND("%s: intercept callbacks on %s", mkring->name, ikring->name); | ||||
kring->mon_sync = kring->nm_sync; | nm_monitor_intercept_callbacks(ikring); | ||||
kring->mon_notify = kring->nm_notify; | |||||
if (kring->tx == NR_TX) { | |||||
kring->nm_sync = netmap_monitor_parent_txsync; | |||||
} else { | |||||
kring->nm_sync = netmap_monitor_parent_rxsync; | |||||
kring->nm_notify = netmap_monitor_parent_notify; | |||||
kring->mon_tail = kring->nr_hwtail; | |||||
} | |||||
} | } | ||||
if (zmon) { | if (zmon) { | ||||
/* append the zmon to the list */ | /* append the zmon to the list */ | ||||
struct netmap_monitor_adapter *mna = | ikring->zmon_list[t].next = mkring; | ||||
(struct netmap_monitor_adapter *)mkring->na; | z->prev = mkring; /* new tail */ | ||||
struct netmap_adapter *pna; | mz->prev = ikring; | ||||
mz->next = NULL; | |||||
if (z->prev != NULL) | /* grab a reference to the previous netmap adapter | ||||
z->prev->zmon_list[t].next = mkring; | |||||
mz->prev = z->prev; | |||||
z->prev = mkring; | |||||
if (z->next == NULL) | |||||
z->next = mkring; | |||||
/* grap a reference to the previous netmap adapter | |||||
* in the chain (this may be the monitored port | * in the chain (this may be the monitored port | ||||
* or another zero-copy monitor) | * or another zero-copy monitor) | ||||
*/ | */ | ||||
pna = kring->na; | netmap_adapter_get(ikring->na); | ||||
netmap_adapter_get(pna); | |||||
netmap_adapter_put(mna->priv.np_na); | |||||
mna->priv.np_na = pna; | |||||
} else { | } else { | ||||
/* make sure the monitor array exists and is big enough */ | /* make sure the monitor array exists and is big enough */ | ||||
error = nm_monitor_alloc(kring, kring->n_monitors + 1); | error = nm_monitor_alloc(kring, kring->n_monitors + 1); | ||||
Context not available. | |||||
* If this is the last monitor, restore the original callbacks | * If this is the last monitor, restore the original callbacks | ||||
*/ | */ | ||||
static void | static void | ||||
netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) | netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum txrx t) | ||||
{ | { | ||||
struct netmap_zmon_list *mz = &mkring->zmon_list[kring->tx]; | |||||
int zmon = nm_is_zmon(mkring->na); | int zmon = nm_is_zmon(mkring->na); | ||||
struct netmap_zmon_list *mz = &mkring->zmon_list[t]; | |||||
struct netmap_kring *ikring = kring; | |||||
if (zmon && mz->prev != NULL) | if (zmon) { | ||||
kring = mz->prev; | /* get to the head of the list */ | ||||
kring = nm_zmon_list_head(mkring, t); | |||||
ikring = mz->prev; | |||||
} | |||||
/* synchronize with concurrently running nm_sync()s */ | /* synchronize with concurrently running nm_sync()s | ||||
nm_kr_stop(kring, NM_KR_LOCKED); | * if kring is NULL (orphaned list) the monitored port | ||||
* has exited netmap mode, so there is nothing to stop | |||||
*/ | |||||
if (kring != NULL) | |||||
nm_kr_stop(kring, NM_KR_LOCKED); | |||||
if (zmon) { | if (zmon) { | ||||
/* remove the monitor from the list */ | /* remove the monitor from the list */ | ||||
if (mz->prev != NULL) | |||||
mz->prev->zmon_list[kring->tx].next = mz->next; | |||||
else | |||||
kring->zmon_list[kring->tx].next = mz->next; | |||||
if (mz->next != NULL) { | if (mz->next != NULL) { | ||||
mz->next->zmon_list[kring->tx].prev = mz->prev; | mz->next->zmon_list[t].prev = mz->prev; | ||||
} else { | /* we also need to let the next monitor drop the | ||||
kring->zmon_list[kring->tx].prev = mz->prev; | * reference to us and grab the reference to the | ||||
* previous ring owner, instead | |||||
*/ | |||||
if (mz->prev != NULL) | |||||
netmap_adapter_get(mz->prev->na); | |||||
netmap_adapter_put(mkring->na); | |||||
} else if (kring != NULL) { | |||||
/* in the monitored kring, prev is actually the | |||||
* pointer to the tail of the list | |||||
*/ | |||||
kring->zmon_list[t].prev = | |||||
(mz->prev != kring ? mz->prev : NULL); | |||||
} | } | ||||
if (mz->prev != NULL) { | |||||
netmap_adapter_put(mz->prev->na); | |||||
mz->prev->zmon_list[t].next = mz->next; | |||||
} | |||||
mz->prev = NULL; | |||||
mz->next = NULL; | |||||
} else { | } else { | ||||
/* this is a copy monitor */ | /* this is a copy monitor */ | ||||
uint32_t mon_pos = mkring->mon_pos[kring->tx]; | uint32_t mon_pos = mkring->mon_pos[kring->tx]; | ||||
Context not available. | |||||
} | } | ||||
} | } | ||||
if (nm_monitor_none(kring)) { | if (ikring != NULL && nm_monitor_none(ikring)) { | ||||
/* this was the last monitor, restore the callbacks */ | /* this was the last monitor, restore the callbacks */ | ||||
ND("%s: restoring sync on %s: %p", mkring->name, kring->name, | nm_monitor_restore_callbacks(ikring); | ||||
kring->mon_sync); | |||||
kring->nm_sync = kring->mon_sync; | |||||
kring->mon_sync = NULL; | |||||
if (kring->tx == NR_RX) { | |||||
ND("%s: restoring notify on %s: %p", | |||||
mkring->name, kring->name, kring->mon_notify); | |||||
kring->nm_notify = kring->mon_notify; | |||||
kring->mon_notify = NULL; | |||||
} | |||||
} | } | ||||
nm_kr_start(kring); | if (kring != NULL) | ||||
nm_kr_start(kring); | |||||
} | } | ||||
Context not available. | |||||
for_rx_tx(t) { | for_rx_tx(t) { | ||||
u_int i; | u_int i; | ||||
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { | for (i = 0; i < netmap_all_rings(na, t); i++) { | ||||
struct netmap_kring *kring = NMR(na, t)[i]; | struct netmap_kring *kring = NMR(na, t)[i]; | ||||
struct netmap_kring *zkring; | struct netmap_zmon_list *z = &kring->zmon_list[t]; | ||||
u_int j; | u_int j; | ||||
for (j = 0; j < kring->n_monitors; j++) { | for (j = 0; j < kring->n_monitors; j++) { | ||||
Context not available. | |||||
netmap_adapter_put(mna->priv.np_na); | netmap_adapter_put(mna->priv.np_na); | ||||
mna->priv.np_na = NULL; | mna->priv.np_na = NULL; | ||||
} | } | ||||
kring->monitors[j] = NULL; | |||||
} | } | ||||
zkring = kring->zmon_list[kring->tx].next; | if (!nm_is_zmon(na)) { | ||||
if (zkring != NULL) { | /* we are the head of at most one list */ | ||||
struct netmap_monitor_adapter *next = | struct netmap_kring *zkring; | ||||
(struct netmap_monitor_adapter *)zkring->na; | for (zkring = z->next; zkring != NULL; | ||||
struct netmap_monitor_adapter *this = | zkring = zkring->zmon_list[t].next) | ||||
(struct netmap_monitor_adapter *)na; | { | ||||
struct netmap_adapter *pna = this->priv.np_na; | struct netmap_monitor_adapter *next = | ||||
/* let the next monitor forget about us */ | (struct netmap_monitor_adapter *)zkring->na; | ||||
if (next->priv.np_na != NULL) { | /* let the monitor forget about us */ | ||||
netmap_adapter_put(next->priv.np_na); | netmap_adapter_put(next->priv.np_na); /* nop if null */ | ||||
next->priv.np_na = NULL; | |||||
} | } | ||||
if (pna != NULL && nm_is_zmon(na)) { | /* orhpan the zmon list */ | ||||
/* we are a monitor ourselves and we may | if (z->next != NULL) | ||||
* need to pass down the reference to | z->next->zmon_list[t].prev = NULL; | ||||
* the previous adapter in the chain | z->next = NULL; | ||||
*/ | z->prev = NULL; | ||||
netmap_adapter_get(pna); | |||||
next->priv.np_na = pna; | |||||
continue; | |||||
} | |||||
next->priv.np_na = NULL; | |||||
} | } | ||||
if (!nm_monitor_none(kring)) { | |||||
kring->n_monitors = 0; | |||||
nm_monitor_dealloc(kring); | |||||
nm_monitor_restore_callbacks(kring); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
return ENXIO; | return ENXIO; | ||||
} | } | ||||
for_rx_tx(t) { | for_rx_tx(t) { | ||||
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { | for (i = 0; i < netmap_all_rings(na, t); i++) { | ||||
mkring = NMR(na, t)[i]; | mkring = NMR(na, t)[i]; | ||||
if (!nm_kring_pending_on(mkring)) | if (!nm_kring_pending_on(mkring)) | ||||
continue; | continue; | ||||
Context not available. | |||||
if (na->active_fds == 0) | if (na->active_fds == 0) | ||||
na->na_flags &= ~NAF_NETMAP_ON; | na->na_flags &= ~NAF_NETMAP_ON; | ||||
for_rx_tx(t) { | for_rx_tx(t) { | ||||
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { | for (i = 0; i < netmap_all_rings(na, t); i++) { | ||||
mkring = NMR(na, t)[i]; | mkring = NMR(na, t)[i]; | ||||
if (!nm_kring_pending_off(mkring)) | if (!nm_kring_pending_off(mkring)) | ||||
continue; | continue; | ||||
Context not available. | |||||
continue; | continue; | ||||
if (mna->flags & nm_txrx2flag(s)) { | if (mna->flags & nm_txrx2flag(s)) { | ||||
kring = NMR(pna, s)[i]; | kring = NMR(pna, s)[i]; | ||||
netmap_monitor_del(mkring, kring); | netmap_monitor_del(mkring, kring, s); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
ms->len = s->len; | ms->len = s->len; | ||||
s->len = tmp; | s->len = tmp; | ||||
ms->flags = s->flags; | |||||
s->flags |= NS_BUF_CHANGED; | s->flags |= NS_BUF_CHANGED; | ||||
beg = nm_next(beg, lim); | beg = nm_next(beg, lim); | ||||
Context not available. | |||||
memcpy(dst, src, copy_len); | memcpy(dst, src, copy_len); | ||||
ms->len = copy_len; | ms->len = copy_len; | ||||
ms->flags = s->flags; | |||||
sent++; | sent++; | ||||
beg = nm_next(beg, lim); | beg = nm_next(beg, lim); | ||||
Context not available. | |||||
struct ifnet *ifp = NULL; | struct ifnet *ifp = NULL; | ||||
int error; | int error; | ||||
int zcopy = (req->nr_flags & NR_ZCOPY_MON); | int zcopy = (req->nr_flags & NR_ZCOPY_MON); | ||||
char monsuff[10] = ""; | |||||
if (zcopy) { | if (zcopy) { | ||||
req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); | req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); | ||||
Context not available. | |||||
D("ringid error"); | D("ringid error"); | ||||
goto free_out; | goto free_out; | ||||
} | } | ||||
if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) { | snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name, | ||||
snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]); | |||||
} | |||||
snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name, | |||||
monsuff, | |||||
zcopy ? "z" : "", | zcopy ? "z" : "", | ||||
(req->nr_flags & NR_MONITOR_RX) ? "r" : "", | (req->nr_flags & NR_MONITOR_RX) ? "r" : "", | ||||
(req->nr_flags & NR_MONITOR_TX) ? "t" : ""); | (req->nr_flags & NR_MONITOR_TX) ? "t" : "", | ||||
pna->monitor_id++); | |||||
/* the monitor supports the host rings iff the parent does */ | /* the monitor supports the host rings iff the parent does */ | ||||
mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS); | mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS); | ||||
Context not available. |