Hi. As promised. Feel free to comm{en,i}t. :-) Note that I've changed 'ifq->ifq_hfsc' to '&ifq->ifq_hfsc_data;' a lot of times; this is because some of the code is in the hot path and the reference is computed at compile time and not loaded from that useless pointer field (which will be gone after transition).
Compiles & is being tested on amd64. -- Martin Pelikan Index: altq/if_altq.h =================================================================== RCS file: /cvs/src/sys/altq/if_altq.h,v retrieving revision 1.16 diff -u -p -r1.16 if_altq.h --- altq/if_altq.h 12 Oct 2013 12:13:10 -0000 1.16 +++ altq/if_altq.h 19 Oct 2013 11:59:04 -0000 @@ -29,28 +29,21 @@ #ifndef _ALTQ_IF_ALTQ_H_ #define _ALTQ_IF_ALTQ_H_ -struct altq_pktattr; struct oldtb_regulator; struct hfsc_if; +struct altq_pktattr; struct oldtb_regulator; struct mbuf; #define ALTQ_IFQ_NQUEUES 8 /* - * Structure defining a queue for a network interface. + * Until we get rid of ALTQ, we'd better preserve binary compatibility + * between "ifaltq" and "ifqueue" in if.h. But ifaltq had all these + * appended to it, and we'd like to separate queue table from hfsc_if. + * Therefore, this ALTQ stuff will share space with hfsc_if during the + * transition and then will go away. */ -struct ifaltq { - /* fields compatible with struct ifqueue */ - struct { - struct mbuf *head; - struct mbuf *tail; - } ifq_q[ALTQ_IFQ_NQUEUES]; - int ifq_len; - int ifq_maxlen; - int ifq_drops; - struct hfsc_if *ifq_hfsc; - struct timeout *ifq_congestion; - +struct ifaltq; +struct altq_stuff { /* alternate queueing related fields */ int altq_type; /* discipline type */ - int altq_flags; /* flags (e.g. ready, in-use) */ void *altq_disc; /* for discipline-specific use */ struct ifnet *altq_ifp; /* back pointer to interface */ @@ -66,6 +59,48 @@ struct ifaltq { /* token bucket regulator */ struct oldtb_regulator *altq_tbr; }; + +/* + * Structure defining a queue for a network interface. + * XXX ALTQ_TRANSITION ifq_hfsc points to the union in the non-altq case. + */ +/* XXX hack, because we need the structure definition */ +#define ALTQ_IS_ENABLED 1 +#include <net/hfsc.h> +#undef ALTQ_IS_ENABLED +/* XXX hack */ + +struct ifaltq { + /* fields compatible with struct ifqueue */ + struct { + struct mbuf *head; + struct mbuf *tail; + } ifq_q[ALTQ_IFQ_NQUEUES]; + int ifq_len; + int ifq_maxlen; + int ifq_drops; + struct hfsc_if *ifq_hfsc; + struct timeout *ifq_congestion; + + union { + struct altq_stuff altq; + struct hfsc_if hfsc; + } transition; + + /* This can't be in the union, because it says if is ALTQ on. */ + int altq_flags; /* flags (e.g. ready, in-use) */ +}; +#define altq_type transition.altq.altq_type +#define altq_disc transition.altq.altq_disc +#define altq_ifp transition.altq.altq_ifp +#define altq_enqueue transition.altq.altq_enqueue +#define altq_dequeue transition.altq.altq_dequeue +#define altq_request transition.altq.altq_request +#define altq_clfier transition.altq.altq_clfier +#define altq_classify transition.altq.altq_classify +#define altq_tbr transition.altq.altq_tbr +#define ifq_hfsc_data transition.hfsc + #ifdef _KERNEL Index: net/hfsc.c =================================================================== RCS file: /cvs/src/sys/net/hfsc.c,v retrieving revision 1.1 diff -u -p -r1.1 hfsc.c --- net/hfsc.c 12 Oct 2013 11:39:17 -0000 1.1 +++ net/hfsc.c 19 Oct 2013 12:20:38 -0000 @@ -63,7 +63,7 @@ /* * function prototypes */ -struct hfsc_class *hfsc_class_create(struct hfsc_if *, +struct hfsc_class *hfsc_class_create(struct ifqueue *, struct hfsc_sc *, struct hfsc_sc *, struct hfsc_sc *, struct hfsc_class *, int, int, int); @@ -128,18 +128,49 @@ hfsc_microuptime(void) HFSC_CLK_SHIFT); } +/* + * The new table will be exactly one page larger, so in the most + * common case of 8B pointers and 4KB pages it's 512 more classes. + * Returns the amount of classes, so all new pages are 100% utilized. + */ +static inline u_int +hfsc_new_amount(u_int old) +{ + u_int was_pages = old * sizeof(void *) / PAGE_SIZE; + u_int n = ((was_pages + 1) * PAGE_SIZE) / sizeof(void *); + + return (n); +} + +static void +hfsc_grow(struct hfsc_if *hif) +{ + struct hfsc_class **newtbl, **old = hif->hif_class_tbl; + const u_int slots = hfsc_new_amount(hif->hif_allocated); + + newtbl = malloc(slots * sizeof(void *), M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(newtbl, old, hif->hif_allocated * sizeof(void *)); + + hif->hif_allocated = slots; + hif->hif_class_tbl = newtbl; + + free(old, M_DEVBUF); +} + int hfsc_attach(struct ifnet *ifp) { - struct hfsc_if *hif; + const u_int slots = hfsc_new_amount(0); + const size_t sz = slots * sizeof(void *); + struct hfsc_if *hif = &ifp->if_snd.ifq_hfsc_data; - if (ifp->if_snd.ifq_hfsc != NULL) - return (0); + /* XXX ALTQ_TRANSITION ifaltq ~ ifqueue binary compatibility */ + ifp->if_snd.ifq_hfsc = hif; - hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_WAITOK|M_ZERO); + hif->hif_allocated = slots; + hif->hif_classes = 0; + hif->hif_class_tbl = malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO); hif->hif_eligible = hfsc_ellist_alloc(); - hif->hif_ifq = (struct ifqueue *)&ifp->if_snd; /* XXX cast temp */ - ifp->if_snd.ifq_hfsc = hif; return (0); } @@ -147,8 +178,10 @@ hfsc_attach(struct ifnet *ifp) int hfsc_detach(struct ifnet *ifp) { - free(ifp->if_snd.ifq_hfsc, M_DEVBUF); - ifp->if_snd.ifq_hfsc = NULL; + struct hfsc_if *hif = &ifp->if_snd.ifq_hfsc_data; + + free(hif->hif_class_tbl, M_DEVBUF); + hif->hif_allocated = hif->hif_classes = 0; return (0); } @@ -156,11 +189,15 @@ hfsc_detach(struct ifnet *ifp) int hfsc_addqueue(struct pf_queuespec *q) { - struct hfsc_if *hif; + union { + struct ifqueue *ifq; + struct ifaltq *ifaq; + } ifq = { .ifaq = &q->kif->pfik_ifp->if_snd }; + struct hfsc_if *hif = &ifq.ifq->ifq_hfsc_data; struct hfsc_class *cl, *parent; struct hfsc_sc rtsc, lssc, ulsc; - if ((hif = q->kif->pfik_ifp->if_snd.ifq_hfsc) == NULL) + if (hif->hif_allocated == 0) return (EINVAL); if (q->parent_qid == HFSC_NULLCLASS_HANDLE && @@ -185,7 +222,7 @@ hfsc_addqueue(struct pf_queuespec *q) ulsc.d = q->upperlimit.d; ulsc.m2 = q->upperlimit.m2.absolute; - cl = hfsc_class_create(hif, &rtsc, &lssc, &ulsc, + cl = hfsc_class_create(ifq.ifq, &rtsc, &lssc, &ulsc, parent, q->qlimit, q->flags, q->qid); if (cl == NULL) return (ENOMEM); @@ -199,7 +236,7 @@ hfsc_delqueue(struct pf_queuespec *q) struct hfsc_if *hif; struct hfsc_class *cl; - if ((hif = q->kif->pfik_ifp->if_snd.ifq_hfsc) == NULL) + if ((hif = &q->kif->pfik_ifp->if_snd.ifq_hfsc_data) == NULL) return (EINVAL); if ((cl = hfsc_clh2cph(hif, q->qid)) == NULL) @@ -216,7 +253,7 @@ hfsc_qstats(struct pf_queuespec *q, void struct hfsc_class_stats stats; int error = 0; - if ((hif = q->kif->pfik_ifp->if_snd.ifq_hfsc) == NULL) + if ((hif = &q->kif->pfik_ifp->if_snd.ifq_hfsc_data) == NULL) return (EBADF); if ((cl = hfsc_clh2cph(hif, q->qid)) == NULL) @@ -236,25 +273,26 @@ hfsc_qstats(struct pf_queuespec *q, void void hfsc_purge(struct ifqueue *ifq) { - struct hfsc_if *hif = ifq->ifq_hfsc; + struct hfsc_if *hif = &ifq->ifq_hfsc_data; struct hfsc_class *cl; for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl)) if (cl->cl_q->qlen > 0) hfsc_purgeq(cl); - hif->hif_ifq->ifq_len = 0; + ifq->ifq_len = 0; } struct hfsc_class * -hfsc_class_create(struct hfsc_if *hif, struct hfsc_sc *rsc, +hfsc_class_create(struct ifqueue *ifq, struct hfsc_sc *rsc, struct hfsc_sc *fsc, struct hfsc_sc *usc, struct hfsc_class *parent, int qlimit, int flags, int qid) { + struct hfsc_if *hif = &ifq->ifq_hfsc_data; struct hfsc_class *cl, *p; int i, s; - if (hif->hif_classes >= HFSC_MAX_CLASSES) - return (NULL); + if (hif->hif_classes >= hif->hif_allocated) + hfsc_grow(hif); cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_WAITOK|M_ZERO); cl->cl_q = malloc(sizeof(struct hfsc_classq), M_DEVBUF, @@ -285,7 +323,7 @@ hfsc_class_create(struct hfsc_if *hif, s if (m2 < 8) red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ else - red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu + red_pkttime = (int64_t)ifq->altq_ifp->if_mtu * 1000 * 1000 * 1000 / (m2 / 8); if (flags & HFSC_RED) { cl->cl_red = red_alloc(0, 0, @@ -319,7 +357,7 @@ hfsc_class_create(struct hfsc_if *hif, s cl->cl_id = hif->hif_classid++; cl->cl_handle = qid; - cl->cl_hif = hif; + cl->cl_ifq = ifq; cl->cl_parent = parent; s = splnet(); @@ -330,16 +368,16 @@ hfsc_class_create(struct hfsc_if *hif, s * the lower bits of qid is free, use this slot. otherwise, * use the first free slot. */ - i = qid % HFSC_MAX_CLASSES; + i = qid % hif->hif_allocated; if (hif->hif_class_tbl[i] == NULL) hif->hif_class_tbl[i] = cl; else { - for (i = 0; i < HFSC_MAX_CLASSES; i++) + for (i = 0; i < hif->hif_allocated; i++) if (hif->hif_class_tbl[i] == NULL) { hif->hif_class_tbl[i] = cl; break; } - if (i == HFSC_MAX_CLASSES) { + if (i == hif->hif_allocated) { splx(s); goto err_ret; } @@ -389,6 +427,7 @@ int hfsc_class_destroy(struct hfsc_class *cl) { int i, s; + u_int lim = cl->cl_ifq->ifq_hfsc_data.hif_allocated; if (cl == NULL) return (0); @@ -414,13 +453,13 @@ hfsc_class_destroy(struct hfsc_class *cl } while ((p = p->cl_siblings) != NULL); } - for (i = 0; i < HFSC_MAX_CLASSES; i++) - if (cl->cl_hif->hif_class_tbl[i] == cl) { - cl->cl_hif->hif_class_tbl[i] = NULL; + for (i = 0; i < lim; i++) + if (cl->cl_ifq->ifq_hfsc_data.hif_class_tbl[i] == cl) { + cl->cl_ifq->ifq_hfsc_data.hif_class_tbl[i] = NULL; break; } - cl->cl_hif->hif_classes--; + cl->cl_ifq->ifq_hfsc_data.hif_classes--; splx(s); hfsc_actlist_destroy(cl->cl_actc); @@ -432,10 +471,10 @@ hfsc_class_destroy(struct hfsc_class *cl } #endif - if (cl == cl->cl_hif->hif_rootclass) - cl->cl_hif->hif_rootclass = NULL; - if (cl == cl->cl_hif->hif_defaultclass) - cl->cl_hif->hif_defaultclass = NULL; + if (cl == cl->cl_ifq->ifq_hfsc_data.hif_rootclass) + cl->cl_ifq->ifq_hfsc_data.hif_rootclass = NULL; + if (cl == cl->cl_ifq->ifq_hfsc_data.hif_defaultclass) + cl->cl_ifq->ifq_hfsc_data.hif_defaultclass = NULL; if (cl->cl_usc != NULL) free(cl->cl_usc, M_DEVBUF); @@ -476,7 +515,7 @@ hfsc_nextclass(struct hfsc_class *cl) int hfsc_enqueue(struct ifqueue *ifq, struct mbuf *m) { - struct hfsc_if *hif = ifq->ifq_hfsc; + struct hfsc_if *hif = &ifq->ifq_hfsc_data; struct hfsc_class *cl; if ((cl = hfsc_clh2cph(hif, m->m_pkthdr.pf.qid)) == NULL || @@ -496,7 +535,7 @@ hfsc_enqueue(struct ifqueue *ifq, struct return (ENOBUFS); } IFQ_INC_LEN(ifq); - cl->cl_hif->hif_packets++; + cl->cl_ifq->ifq_hfsc_data.hif_packets++; m->m_pkthdr.pf.prio = IFQ_MAXPRIO; /* successfully queued. */ @@ -509,7 +548,7 @@ hfsc_enqueue(struct ifqueue *ifq, struct struct mbuf * hfsc_dequeue(struct ifqueue *ifq, int remove) { - struct hfsc_if *hif = ifq->ifq_hfsc; + struct hfsc_if *hif = &ifq->ifq_hfsc_data; struct hfsc_class *cl, *tcl; struct mbuf *m; int next_len, realtime = 0; @@ -577,7 +616,7 @@ hfsc_dequeue(struct ifqueue *ifq, int re if (m == NULL) panic("hfsc_dequeue"); - cl->cl_hif->hif_packets--; + cl->cl_ifq->ifq_hfsc_data.hif_packets--; IFQ_DEC_LEN(ifq); PKTCNTR_INC(&cl->cl_stats.xmit_cnt, m->m_pkthdr.len); @@ -661,8 +700,8 @@ hfsc_purgeq(struct hfsc_class *cl) while ((m = hfsc_getq(cl)) != NULL) { PKTCNTR_INC(&cl->cl_stats.drop_cnt, m->m_pkthdr.len); m_freem(m); - cl->cl_hif->hif_packets--; - IFQ_DEC_LEN(cl->cl_hif->hif_ifq); + cl->cl_ifq->ifq_hfsc_data.hif_packets--; + IFQ_DEC_LEN(cl->cl_ifq); } hfsc_update_vf(cl, 0, 0); /* remove cl from the actlist */ @@ -674,6 +713,7 @@ hfsc_set_active(struct hfsc_class *cl, i { if (cl->cl_rsc != NULL) hfsc_init_ed(cl, len); + if (cl->cl_fsc != NULL) hfsc_init_vf(cl, len); @@ -955,7 +995,7 @@ hfsc_ellist_destroy(hfsc_ellist_t *head) void hfsc_ellist_insert(struct hfsc_class *cl) { - struct hfsc_if *hif = cl->cl_hif; + struct hfsc_if *hif = &cl->cl_ifq->ifq_hfsc_data; struct hfsc_class *p; /* check the last entry first */ @@ -976,7 +1016,7 @@ hfsc_ellist_insert(struct hfsc_class *cl void hfsc_ellist_remove(struct hfsc_class *cl) { - struct hfsc_if *hif = cl->cl_hif; + struct hfsc_if *hif = &cl->cl_ifq->ifq_hfsc_data; TAILQ_REMOVE(hif->hif_eligible, cl, cl_ellist); } @@ -984,7 +1024,7 @@ hfsc_ellist_remove(struct hfsc_class *cl void hfsc_ellist_update(struct hfsc_class *cl) { - struct hfsc_if *hif = cl->cl_hif; + struct hfsc_if *hif = &cl->cl_ifq->ifq_hfsc_data; struct hfsc_class *p, *last; /* @@ -1454,10 +1494,10 @@ hfsc_clh2cph(struct hfsc_if *hif, u_int3 * first, try the slot corresponding to the lower bits of the handle. * if it does not match, do the linear table search. */ - i = chandle % HFSC_MAX_CLASSES; + i = chandle % hif->hif_allocated; if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle) return (cl); - for (i = 0; i < HFSC_MAX_CLASSES; i++) + for (i = 0; i < hif->hif_allocated; i++) if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle) return (cl); Index: net/hfsc.h =================================================================== RCS file: /cvs/src/sys/net/hfsc.h,v retrieving revision 1.1 diff -u -p -r1.1 hfsc.h --- net/hfsc.h 12 Oct 2013 11:39:17 -0000 1.1 +++ net/hfsc.h 19 Oct 2013 11:59:04 -0000 @@ -55,7 +55,6 @@ struct hfsc_sc { /* special class handles */ #define HFSC_NULLCLASS_HANDLE 0 -#define HFSC_MAX_CLASSES 64 /* service curve types */ #define HFSC_REALTIMESC 1 @@ -168,7 +167,7 @@ typedef TAILQ_ENTRY(hfsc_class) hfsc_act struct hfsc_class { u_int cl_id; /* class id (just for debug) */ u_int32_t cl_handle; /* class handle */ - struct hfsc_if *cl_hif; /* back pointer to struct hfsc_if */ + struct ifqueue *cl_ifq; /* back pointer to our parent ifqueue */ int cl_flags; /* misc flags */ struct hfsc_class *cl_parent; /* parent class */ @@ -230,18 +229,17 @@ struct hfsc_class { * hfsc interface state */ struct hfsc_if { - struct hfsc_if *hif_next; /* interface state list */ - struct ifqueue *hif_ifq; /* backpointer to ifq */ + struct hfsc_class **hif_class_tbl; /* visited per-packet */ struct hfsc_class *hif_rootclass; /* root class */ struct hfsc_class *hif_defaultclass; /* default class */ - struct hfsc_class *hif_class_tbl[HFSC_MAX_CLASSES]; struct hfsc_class *hif_pollcache; /* cache for poll operation */ + u_int hif_allocated; /* how many slots above */ u_int hif_classes; /* # of classes in the tree */ u_int hif_packets; /* # of packets in the tree */ u_int hif_classid; /* class id sequence number */ - hfsc_ellist_t *hif_eligible; /* eligible list */ + hfsc_ellist_t *hif_eligible; /* eligible list */ }; #define HFSC_CLK_SHIFT 8 Index: net/if.h =================================================================== RCS file: /cvs/src/sys/net/if.h,v retrieving revision 1.148 diff -u -p -r1.148 if.h --- net/if.h 13 Oct 2013 10:10:02 -0000 1.148 +++ net/if.h 19 Oct 2013 12:29:19 -0000 @@ -175,7 +175,9 @@ struct if_data { /* * Structure defining a queue for a network interface. - * XXX keep in sync with struct ifaltq. + * XXX ALTQ_TRANSITION keep in sync with struct ifaltq. + * XXX This is why ifq_hfsc points just a couple of bytes in front. + * XXX There is altq_flags down in ifaltq, so don't embed this one yet. */ struct ifqueue { struct { @@ -187,6 +189,9 @@ struct ifqueue { int ifq_drops; struct hfsc_if *ifq_hfsc; struct timeout *ifq_congestion; + union { + struct hfsc_if hfsc; + } transition; }; /*