Date: Mon, 23 Apr 2007 08:41:21 GMT From: Kip Macy <kmacy@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 118648 for review Message-ID: <200704230841.l3N8fLJh076001@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=118648 Change 118648 by kmacy@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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200704230841.l3N8fLJh076001>