PERFORCE change 118648 for review
Kip Macy
kmacy at FreeBSD.org
Mon Apr 23 08:41:22 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=118648
Change 118648 by kmacy at kmacy_vt-x:opentoe_init on 2007/04/23 08:40:40
bring l2t closer to being a working implementation by replacing "neighbour" with rtentry
re-declare llinfo_arp outside of if_ether.c for the moment until accessor functions can be added
disable VLAN support until the vlan tag for a route can be queried
don't support custom resolution failure routines
Affected files ...
.. //depot/projects/opentoe/sys/dev/cxgb/cxgb_l2t.c#4 edit
.. //depot/projects/opentoe/sys/dev/cxgb/cxgb_l2t.h#4 edit
Differences ...
==== //depot/projects/opentoe/sys/dev/cxgb/cxgb_l2t.c#4 (text+ko) ====
@@ -44,6 +44,15 @@
#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
#include <dev/cxgb/common/cxgb_common.h>
@@ -54,12 +63,19 @@
#include <dev/cxgb/common/jhash.h>
#include <dev/cxgb/cxgb_offload.h>
-#include <net/if_vlan_var.h>
+#define VLAN_NONE 0xfff
+#define SDL(s) ((struct sockaddr_dl *)s)
+#define RT_ENADDR(rt) ((char *)LLADDR(SDL((rt))))
+#define rt_expire rt_rmx.rmx_expire
-#define neigh_release(...)
+struct llinfo_arp {
+ struct callout la_timer;
+ struct rtentry *la_rt;
+ struct mbuf *la_hold; /* last packet until resolved/timeout */
+ u_short la_preempt; /* countdown for pre-expiry arps */
+ u_short la_asked; /* # requests sent */
+};
-#define VLAN_NONE 0xfff
-
/*
* Module locking notes: There is a RW lock protecting the L2 table as a
* whole plus a spinlock per L2T entry. Entry lookups and allocations happen
@@ -87,16 +103,20 @@
}
static inline void
-neigh_replace(struct l2t_entry *e, struct ifnet *n)
+neigh_replace(struct l2t_entry *e, struct rtentry *rt)
{
-#if 0
- neigh_hold(n);
- if (e->neigh)
- neigh_release(e->neigh);
- e->neigh = n;
-#endif
+ RT_LOCK(rt);
+ RT_ADDREF(rt);
+ RT_UNLOCK(rt);
+
+ if (e->neigh) {
+ RT_LOCK(e->neigh);
+ RT_REMREF(e->neigh);
+ RT_UNLOCK(e->neigh);
+ }
+ e->neigh = rt;
}
-#if 0
+
/*
* Set up an L2T entry and send any packets waiting in the arp queue. The
* supplied mbuf is used for the CPL_L2T_WRITE_REQ. Must be called with the
@@ -121,9 +141,8 @@
req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
V_L2T_W_VLAN(e->vlan & EVL_VLID_MASK) |
V_L2T_W_PRIO(vlan_prio(e)));
-#if 0
- memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
-#endif
+
+ memcpy(e->dmac, RT_ENADDR(e->neigh), sizeof(e->dmac));
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
m->m_priority = CPL_PRIORITY_CONTROL;
cxgb_ofld_send(dev, m);
@@ -138,7 +157,7 @@
return 0;
}
-#endif
+
/*
* Add a packet to the an L2T entry's queue of packets awaiting resolution.
* Must be called with the entry's lock held.
@@ -158,12 +177,18 @@
t3_l2t_send_slow(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e)
{
+ struct rtentry *rt;
+ struct mbuf *m0;
+
+ if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
+ return (ENOMEM);
+
+ rt = e->neigh;
+
again:
switch (e->state) {
case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
-#if 0
- neigh_event_send(e->neigh, NULL);
-#endif
+ arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
mtx_lock(&e->lock);
if (e->state == L2T_STATE_STALE)
e->state = L2T_STATE_VALID;
@@ -179,6 +204,8 @@
arpq_enqueue(e, m);
mtx_unlock(&e->lock);
+ if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
+ return (ENOMEM);
/*
* Only the first packet added to the arpq should kick off
* resolution. However, because the m_gethdr below can fail,
@@ -187,19 +214,15 @@
* A better way would be to use a work request to retry L2T
* entries when there's no memory.
*/
-#if 0
- if (!neigh_event_send(e->neigh, NULL)) {
- if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
- break;
+ if (arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt)) == 0) {
mtx_lock(&e->lock);
- if (e->arpq_head)
+ if (e->arpq_head)
setup_l2e_send_pending(dev, m, e);
- else /* we lost the race */
- m_free(m);
+ else
+ m_freem(m);
mtx_unlock(&e->lock);
}
-#endif
}
return 0;
}
@@ -207,12 +230,17 @@
void
t3_l2t_send_event(struct toedev *dev, struct l2t_entry *e)
{
+ struct rtentry *rt;
+ struct mbuf *m0;
+
+ if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
+ return;
+
+ rt = e->neigh;
again:
switch (e->state) {
case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
-#if 0
- neigh_event_send(e->neigh, NULL);
-#endif
+ arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
mtx_lock(&e->lock);
if (e->state == L2T_STATE_STALE) {
e->state = L2T_STATE_VALID;
@@ -228,7 +256,9 @@
goto again;
}
mtx_unlock(&e->lock);
-
+
+ if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
+ return;
/*
* Only the first packet added to the arpq should kick off
* resolution. However, because the alloc_skb below can fail,
@@ -237,13 +267,11 @@
* A better way would be to use a work request to retry L2T
* entries when there's no memory.
*/
-#if 0
- neigh_event_send(e->neigh, NULL);
-#endif
+ arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
+
}
return;
}
-#if 0
/*
* Allocate a free L2T entry. Must be called with l2t_data.lock held.
*/
@@ -281,7 +309,7 @@
}
return e;
}
-#endif
+
/*
* Called when an L2T entry has no more users. The entry is left in the hash
* table since it is likely to be reused but we also bump nfree to indicate
@@ -299,7 +327,9 @@
mtx_lock(&e->lock);
if (atomic_load_acq_int(&e->refcnt) == 0) { /* hasn't been recycled */
if (e->neigh) {
- neigh_release(e->neigh);
+ RT_LOCK(e->neigh);
+ RT_REMREF(e->neigh);
+ RT_UNLOCK(e->neigh);
e->neigh = NULL;
}
}
@@ -312,36 +342,34 @@
* Must be called with softirqs disabled.
*/
static inline void
-reuse_entry(struct l2t_entry *e, struct ifnet *neigh)
+reuse_entry(struct l2t_entry *e, struct rtentry *neigh)
{
-#ifdef notyet
- unsigned int nud_state;
+ struct llinfo_arp *la;
+
+ la = (struct llinfo_arp *)neigh->rt_llinfo;
mtx_lock(&e->lock); /* avoid race with t3_l2t_free */
-
if (neigh != e->neigh)
neigh_replace(e, neigh);
- nud_state = neigh->nud_state;
- if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
- !(nud_state & NUD_VALID))
+
+ if (memcmp(e->dmac, RT_ENADDR(neigh), sizeof(e->dmac)) ||
+ (neigh->rt_expire > time_uptime))
e->state = L2T_STATE_RESOLVING;
- else if (nud_state & NUD_CONNECTED)
+ else if (la->la_hold == NULL)
e->state = L2T_STATE_VALID;
else
e->state = L2T_STATE_STALE;
mtx_unlock(&e->lock);
-#endif
}
struct l2t_entry *
-t3_l2t_get(struct toedev *dev, struct ifnet *neigh,
+t3_l2t_get(struct toedev *dev, struct rtentry *neigh,
unsigned int smt_idx)
{
-#if 0
struct l2t_entry *e;
struct l2t_data *d = L2DATA(dev);
- u32 addr = *(u32 *) neigh->primary_key;
- int ifidx = neigh->if_index;
+ u32 addr = *(u32 *) rt_key(neigh);
+ int ifidx = neigh->rt_ifp->if_index;
int hash = arp_hash(addr, ifidx, d);
rw_wlock(&d->lock);
@@ -366,17 +394,20 @@
e->smt_idx = smt_idx;
atomic_store_rel_int(&e->refcnt, 1);
neigh_replace(e, neigh);
- if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+#ifdef notyet
+ /*
+ * XXX need to add accessor function for vlan tag
+ */
+ if (neigh->rt_ifp->if_vlantrunk)
e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
else
+#endif
e->vlan = VLAN_NONE;
mtx_unlock(&e->lock);
}
done:
rw_wunlock(&d->lock);
return e;
-#endif
- return (NULL);
}
/*
@@ -387,41 +418,43 @@
* XXX: maybe we should abandon the latter behavior and just require a failure
* handler.
*/
-#if 0
static void
handle_failed_resolution(struct toedev *dev, struct mbuf *arpq)
{
while (arpq) {
struct mbuf *m = arpq;
+#ifdef notyet
struct l2t_mbuf_cb *cb = L2T_MBUF_CB(m);
-
+#endif
arpq = m->m_next;
m->m_next = NULL;
+#ifdef notyet
if (cb->arp_failure_handler)
cb->arp_failure_handler(dev, m);
else
+#endif
cxgb_ofld_send(dev, m);
}
}
-#endif
+
#if defined(NETEVENT) || !defined(CONFIG_CHELSIO_T3_MODULE)
/*
* Called when the host's ARP layer makes a change to some entry that is
* loaded into the HW L2 table.
*/
void
-t3_l2t_update(struct toedev *dev, struct ifnet *neigh)
+t3_l2t_update(struct toedev *dev, struct rtentry *neigh)
{
-#if 0
struct l2t_entry *e;
struct mbuf *arpq = NULL;
struct l2t_data *d = L2DATA(dev);
- u32 addr = *(u32 *) neigh->primary_key;
- int ifidx = neigh->dev->ifindex;
+ u32 addr = *(u32 *) rt_key(neigh);
+ int ifidx = neigh->rt_ifp->if_index;
int hash = arp_hash(addr, ifidx, d);
-
+ struct llinfo_arp *la;
+
rw_rlock(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx) {
@@ -436,17 +469,19 @@
if (atomic_load_acq_int(&e->refcnt)) {
if (neigh != e->neigh)
neigh_replace(e, neigh);
-
+
+ la = (struct llinfo_arp *)neigh->rt_llinfo;
if (e->state == L2T_STATE_RESOLVING) {
- if (neigh->nud_state & NUD_FAILED) {
+
+ if (la->la_asked >= 5 /* arp_maxtries */) {
arpq = e->arpq_head;
e->arpq_head = e->arpq_tail = NULL;
- } else if (neigh_is_connected(neigh))
+ } else if (la->la_hold == NULL)
setup_l2e_send_pending(dev, NULL, e);
} else {
- e->state = neigh_is_connected(neigh) ?
+ e->state = (la->la_hold == NULL) ?
L2T_STATE_VALID : L2T_STATE_STALE;
- if (memcmp(e->dmac, neigh->ha, 6))
+ if (memcmp(e->dmac, RT_ENADDR(neigh), 6))
setup_l2e_send_pending(dev, NULL, e);
}
}
@@ -454,18 +489,17 @@
if (arpq)
handle_failed_resolution(dev, arpq);
-#endif
}
#else
/*
* Called from a kprobe, interrupts are off.
*/
void
-t3_l2t_update(struct toedev *dev, struct ifnet *neigh)
+t3_l2t_update(struct toedev *dev, struct rtentry *neigh)
{
struct l2t_entry *e;
struct l2t_data *d = L2DATA(dev);
- u32 addr = *(u32 *) neigh->primary_key;
+ u32 addr = *(u32 *) rt_key(neigh);
int ifidx = neigh->dev->ifindex;
int hash = arp_hash(addr, ifidx, d);
@@ -490,7 +524,7 @@
{
struct mbuf *arpq = NULL;
struct l2t_entry *e = (struct l2t_entry *)data;
- struct ifnet *neigh = e->neigh;
+ struct rtentry *neigh = e->neigh;
struct toedev *dev = e->tdev;
barrier();
@@ -510,7 +544,7 @@
} else {
e->state = neigh_is_connected(neigh) ?
L2T_STATE_VALID : L2T_STATE_STALE;
- if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)))
+ if (memcmp(e->dmac, RT_ENADDR(neigh), sizeof(e->dmac)))
setup_l2e_send_pending(dev, NULL, e);
}
}
==== //depot/projects/opentoe/sys/dev/cxgb/cxgb_l2t.h#4 (text+ko) ====
@@ -20,20 +20,20 @@
* first element in its chain through its first pointer.
*/
struct l2t_entry {
- uint16_t state; /* entry state */
- uint16_t idx; /* entry index */
- uint32_t addr; /* dest IP address */
- int ifindex; /* neighbor's net_device's ifindex */
- uint16_t smt_idx; /* SMT index */
- uint16_t vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
- struct ifnet *neigh; /* associated neighbour */
- struct l2t_entry *first; /* start of hash chain */
- struct l2t_entry *next; /* next l2t_entry on chain */
- struct mbuf *arpq_head; /* queue of packets awaiting resolution */
+ uint16_t state; /* entry state */
+ uint16_t idx; /* entry index */
+ uint32_t addr; /* dest IP address */
+ int ifindex; /* neighbor's net_device's ifindex */
+ uint16_t smt_idx; /* SMT index */
+ uint16_t vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
+ struct rtentry *neigh; /* associated neighbour */
+ struct l2t_entry *first; /* start of hash chain */
+ struct l2t_entry *next; /* next l2t_entry on chain */
+ struct mbuf *arpq_head; /* queue of packets awaiting resolution */
struct mbuf *arpq_tail;
struct mtx lock;
- volatile uint32_t refcnt; /* entry reference count */
- uint8_t dmac[6]; /* neighbour's MAC address */
+ volatile uint32_t refcnt; /* entry reference count */
+ uint8_t dmac[6]; /* neighbour's MAC address */
#ifndef NETEVENT
#ifdef CONFIG_CHELSIO_T3_MODULE
struct timer_list update_timer;
@@ -45,7 +45,7 @@
struct l2t_data {
unsigned int nentries; /* number of entries */
struct l2t_entry *rover; /* starting point for next allocation */
- volatile uint32_t nfree; /* number of free entries */
+ volatile uint32_t nfree; /* number of free entries */
struct rwlock lock;
struct l2t_entry l2tab[0];
};
@@ -65,21 +65,24 @@
*/
#define L2T_MBUF_CB(skb) ((struct l2t_mbuf_cb *)(skb)->cb)
-#ifdef notyet
-static inline void set_arp_failure_handler(struct mbuf *m,
+
+static __inline void set_arp_failure_handler(struct mbuf *m,
arp_failure_handler_func hnd)
{
+#if 0
L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+#endif
+ panic("implement me");
}
-#endif
+
/*
* Getting to the L2 data from an offload device.
*/
#define L2DATA(dev) ((dev)->l2opt)
void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
-void t3_l2t_update(struct toedev *dev, struct ifnet *ifp);
-struct l2t_entry *t3_l2t_get(struct toedev *dev, struct ifnet *neigh,
+void t3_l2t_update(struct toedev *dev, struct rtentry *ifp);
+struct l2t_entry *t3_l2t_get(struct toedev *dev, struct rtentry *neigh,
unsigned int smt_idx);
int t3_l2t_send_slow(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e);
More information about the p4-projects
mailing list