Date: Thu, 30 Apr 2009 15:38:35 +0000 (UTC) From: Robert Watson <rwatson@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r191694 - projects/pnet/sys/net Message-ID: <200904301538.n3UFcZEH016169@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rwatson Date: Thu Apr 30 15:38:35 2009 New Revision: 191694 URL: http://svn.freebsd.org/changeset/base/191694 Log: Revise netisr2 interface some more: - Add public APIs to query available workstream counts and CPU IDs for them (netisr2_get_cpucount(), netisr2_get_cpuid()). - Provide default flow2cpu inmplementation as netisr2_default_flow2cpu, and install it if the protocol doesn't register one. - Add uintptr_t source argument to netisr2_queue() and netisr2_dispatch(), allowing to caller to provide additional information about a source that might be used to improve parallelism by constraining ordering. Should be set to 0 if none is identified (i.e., maximum ordering). - If the protocol doesn't provide a flow ID conversion function and there isn't one on the packet, use the source to order. Modified: projects/pnet/sys/net/netisr2.c projects/pnet/sys/net/netisr2.h Modified: projects/pnet/sys/net/netisr2.c ============================================================================== --- projects/pnet/sys/net/netisr2.c Thu Apr 30 14:31:52 2009 (r191693) +++ projects/pnet/sys/net/netisr2.c Thu Apr 30 15:38:35 2009 (r191694) @@ -250,6 +250,37 @@ static u_int nws_count; #define NWS_WAIT(s) cv_wait(&(s)->nws_cv, &(s)->nws_mtx) /* + * Utility routines for protocols that implement their own mapping of flows + * to CPUs. + */ +u_int +netisr2_get_cpucount(void) +{ + + return (nws_count); +} + +u_int +netisr2_get_cpuid(u_int cpunumber) +{ + + return (nws_array[cpunumber]); +} + +/* + * The default implementation of (source, flow ID) -> CPU ID mapping. + * Non-static so that protocols can use it to map their own work to specific + * CPUs in a manner consistent to netisr2 for affinity purposes. + */ +u_int +netisr2_default_flow2cpu(uintptr_t source, u_int flowid) +{ + + return (netisr2_get_cpuid((source ^ flowid) % + netisr2_get_cpucount())); +} + +/* * Register a new netisr handler, which requires initializing per-protocol * fields for each workstream. All netisr2 work is briefly suspended while * the protocol is installed. @@ -275,10 +306,6 @@ netisr2_register(u_int proto, const char KASSERT(name != NULL, ("netisr2_register: name NULL for %d", proto)); KASSERT(func != NULL, ("netisr2_register: func NULL for %s", name)); - KASSERT(m2flow != NULL, ("netisr2_register: m2flow NULL for %s", - name)); - KASSERT(flow2cpu != NULL, ("netisr2_registeR: flow2cpu NULL for %s", - name)); /* * Initialize global and per-workstream protocol state. @@ -286,7 +313,10 @@ netisr2_register(u_int proto, const char np[proto].np_name = name; np[proto].np_func = func; np[proto].np_m2flow = m2flow; - np[proto].np_flow2cpu = flow2cpu; + if (flow2cpu != NULL) + np[proto].np_flow2cpu = flow2cpu; + else + np[proto].np_flow2cpu = netisr2_default_flow2cpu; for (i = 0; i < MAXCPU; i++) { npwp = &nws[i].nws_work[proto]; bzero(npwp, sizeof(*npwp)); @@ -346,17 +376,6 @@ netisr2_deregister(u_int proto) } /* - * Provide a simple flow -> CPU mapping for protocols with strong ordering - * requirements but no built-in notion of affinity. - */ -u_int -netisr2_flowid2cpuid(u_int flowid) -{ - - return (nws_array[flowid % nws_count]); -} - -/* * Look up the correct stream for a requested flowid. There are two cases: * one in which the caller has requested execution on the current CPU (i.e., * source ordering is sufficient, perhaps because the underlying hardware has @@ -372,12 +391,13 @@ netisr2_flowid2cpuid(u_int flowid) * (i.e., out of mbufs and a rewrite is required). */ static struct mbuf * -netisr2_selectcpu(struct netisr_proto *npp, struct mbuf *m, u_int *cpuidp) +netisr2_selectcpu(struct netisr_proto *npp, uintptr_t source, struct mbuf *m, + u_int *cpuidp) { NETISR_LOCK_ASSERT(); - if (!(m->m_flags & M_FLOWID)) { + if (!(m->m_flags & M_FLOWID) && npp->np_m2flow != NULL) { m = npp->np_m2flow(m); if (m == NULL) return (NULL); @@ -385,7 +405,10 @@ netisr2_selectcpu(struct netisr_proto *n " %s failed to return flowid on mbuf", npp->np_name)); } - *cpuidp = npp->np_flow2cpu(m->m_pkthdr.flowid); + if (m->m_flags & M_FLOWID) + *cpuidp = npp->np_flow2cpu(source, m->m_pkthdr.flowid); + else + *cpuidp = npp->np_flow2cpu(source, 0); return (m); } @@ -554,7 +577,7 @@ netisr2_queue_internal(u_int proto, stru } int -netisr2_queue(u_int proto, struct mbuf *m) +netisr2_queue(u_int proto, uintptr_t source, struct mbuf *m) { u_int cpuid, error; @@ -565,7 +588,7 @@ netisr2_queue(u_int proto, struct mbuf * KASSERT(np[proto].np_func != NULL, ("netisr2_dispatch: invalid proto %d", proto)); - m = netisr2_selectcpu(&np[proto], m, &cpuid); + m = netisr2_selectcpu(&np[proto], source, m, &cpuid); if (m != NULL) error = netisr2_queue_internal(proto, m, cpuid); else @@ -575,13 +598,13 @@ netisr2_queue(u_int proto, struct mbuf * } int -netisr2_dispatch(u_int proto, struct mbuf *m) +netisr2_dispatch(u_int proto, uintptr_t source, struct mbuf *m) { struct netisr_workstream *nwsp; struct netisr_work *npwp; if (!netisr_direct) - return (netisr2_queue(proto, m)); + return (netisr2_queue(proto, source, m)); KASSERT(proto < NETISR_MAXPROT, ("netisr2_dispatch: invalid proto %d", proto)); Modified: projects/pnet/sys/net/netisr2.h ============================================================================== --- projects/pnet/sys/net/netisr2.h Thu Apr 30 14:31:52 2009 (r191693) +++ projects/pnet/sys/net/netisr2.h Thu Apr 30 15:38:35 2009 (r191694) @@ -43,14 +43,16 @@ * NULL should be returned. * * netisr_flow2cpu_t - Given a flowid, possibly generated by netisr_m2flow, - * select a CPU to execute the packet handler on. + * and an optional source identifier (possibly a tid, pcb, + * or kernel pointer), select a CPU to execute the packet + * handler on. If source isn't used, it will be 0/NULL. * * XXXRW: If we eventually support dynamic reconfiguration, there should be * protocol handlers to notify them of CPU configuration changes so that they * can rebalance work. */ typedef struct mbuf *netisr_m2flow_t(struct mbuf *m); -typedef u_int netisr_flow2cpu_t(u_int flowid); +typedef u_int netisr_flow2cpu_t(uintptr_t source, u_int flowid); /*- * Register a new netisr2 handler for a given protocol. No previous @@ -74,16 +76,20 @@ void netisr2_deregister(u_int proto); /* * Process a packet destined for a protocol, and attempt direct dispatch. */ -int netisr2_dispatch(u_int proto, struct mbuf *m); -int netisr2_queue(u_int proto, struct mbuf *m); +int netisr2_dispatch(u_int proto, uintptr_t source, struct mbuf *m); +int netisr2_queue(u_int proto, uintptr_t source, struct mbuf *m); /* - * Provide a default function to map flow IDs to CPU IDs, so that protocols - * needing a default flow->CPU model can use it. - * - * XXXRW: Should also provide a way to query available CPUs so that protocols - * can decide how to map work more usefully themselves. + * Provide a default implementation of "map a flow ID to a cpu ID". + */ +u_int netisr2_default_flow2cpu(uintptr_t source, u_int flowid); + +/* + * Utility routines to return the number of CPUs participting in netisr2, and + * to return a mapping from a number to a CPU ID that can be used with the + * scheduler. */ -u_int netisr2_flowid2cpuid(u_int flowid); +u_int netisr2_get_cpucount(void); +u_int netisr2_get_cpuid(u_int cpunumber); #endif /* !_NET_NETISR2_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200904301538.n3UFcZEH016169>