struct l2t_data { unsignedint l2t_start; /* start index of our piece of the L2T */ unsignedint l2t_size; /* number of entries in l2tab */
rwlock_t lock;
atomic_t nfree; /* number of free entries */ struct l2t_entry *rover; /* starting point for next allocation */ struct l2t_entry l2tab[] __counted_by(l2t_size); /* MUST BE LAST */
};
for (e = &d->l2tab[0], end = &d->l2tab[d->l2t_size]; e != end; ++e) { if (atomic_read(&e->refcnt) == 0) { if (!first_free)
first_free = e;
} else { if (e->state == L2T_STATE_SWITCHING) { if (ether_addr_equal(e->dmac, dmac) &&
(e->vlan == vlan) && (e->lport == port)) goto exists;
}
}
}
if (first_free) {
e = first_free; goto found;
}
return NULL;
found: /* The entry we found may be an inactive entry that is *presentlyinthehashtable.Weneedtoremoveit.
*/ if (e->state < L2T_STATE_SWITCHING) for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) if (*p == e) {
*p = e->next;
e->next = NULL; break;
}
e->state = L2T_STATE_UNUSED;
exists: return e;
}
/* Called when an L2T entry has no more users. The entry is left in the hash *tablesinceitislikelytobereusedbutwealsobumpnfreetoindicate *thattheentrycanbereallocatedforadifferentneighbor.Wealsodrop *theexistingneighborreferenceincasetheneighborisgoingawayandis *waitingonourreference. * *Becauseentriescanbereallocatedtootherneighborsoncetheirrefcount *dropsto0weneedtotaketheentry'slocktoavoidraceswithanew *incarnation.
*/ staticvoid _t4_l2e_free(struct l2t_entry *e)
{ struct l2t_data *d;
if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ if (e->neigh) {
neigh_release(e->neigh);
e->neigh = NULL;
}
__skb_queue_purge(&e->arpq);
}
d = container_of(e, struct l2t_data, l2tab[e->idx]);
atomic_inc(&d->nfree);
}
/* Locked version of _t4_l2e_free */ staticvoid t4_l2e_free(struct l2t_entry *e)
{ struct l2t_data *d;
spin_lock_bh(&e->lock); if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ if (e->neigh) {
neigh_release(e->neigh);
e->neigh = NULL;
}
__skb_queue_purge(&e->arpq);
}
spin_unlock_bh(&e->lock);
d = container_of(e, struct l2t_data, l2tab[e->idx]);
atomic_inc(&d->nfree);
}
void cxgb4_l2t_release(struct l2t_entry *e)
{ if (atomic_dec_and_test(&e->refcnt))
t4_l2e_free(e);
}
EXPORT_SYMBOL(cxgb4_l2t_release);
/* Initialize each of the fields which we care about which are present *intheCompressedFilterTuple.
*/ if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE)
ntuple |= (u64)(FT_VLAN_VLD_F | l2t->vlan) << tp->vlan_shift;
if (tp->port_shift >= 0)
ntuple |= (u64)l2t->lport << tp->port_shift;
if (tp->protocol_shift >= 0)
ntuple |= (u64)IPPROTO_TCP << tp->protocol_shift;
hash = addr_hash(d, addr, addr_len, ifidx);
read_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) if (!addreq(e, addr) && e->ifindex == ifidx) {
spin_lock(&e->lock); if (atomic_read(&e->refcnt)) goto found;
spin_unlock(&e->lock); break;
}
read_unlock_bh(&d->lock); return;
found:
read_unlock(&d->lock);
if (neigh != e->neigh)
neigh_replace(e, neigh);
if (e->state == L2T_STATE_RESOLVING) { if (neigh->nud_state & NUD_FAILED) {
arpq = &e->arpq;
} elseif ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) &&
!skb_queue_empty(&e->arpq)) {
write_l2e(adap, e, 1);
}
} else {
e->state = neigh->nud_state & NUD_CONNECTED ?
L2T_STATE_VALID : L2T_STATE_STALE; if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)))
write_l2e(adap, e, 0);
}
if (arpq) { struct sk_buff *skb;
/* Called when address resolution fails for an L2T *entrytohandlepacketsonthearpqhead.Ifa *packetspecifiesafailurehandleritisinvoked, *otherwisethepacketissenttothedevice.
*/ while ((skb = __skb_dequeue(&e->arpq)) != NULL) { conststruct l2t_skb_cb *cb = L2T_SKB_CB(skb);
/* Allocate an L2T entry for use by a switching rule. Such need to be *explicitlyfreedandwhilebusytheyarenotonanyhashchain,sonormal *addressresolutionupdatesdonotseethem.
*/ struct l2t_entry *t4_l2t_alloc_switching(struct adapter *adap, u16 vlan,
u8 port, u8 *eth_addr)
{ struct l2t_data *d = adap->l2t; struct l2t_entry *e; int ret;
write_lock_bh(&d->lock);
e = find_or_alloc_l2e(d, vlan, port, eth_addr); if (e) {
spin_lock(&e->lock); /* avoid race with t4_l2t_free */ if (!atomic_read(&e->refcnt)) {
e->state = L2T_STATE_SWITCHING;
e->vlan = vlan;
e->lport = port;
ether_addr_copy(e->dmac, eth_addr);
atomic_set(&e->refcnt, 1);
ret = write_l2e(adap, e, 0); if (ret < 0) {
_t4_l2e_free(e);
spin_unlock(&e->lock);
write_unlock_bh(&d->lock); return NULL;
}
} else {
atomic_inc(&e->refcnt);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.