Index: share/man/man9/Makefile =================================================================== --- share/man/man9/Makefile +++ share/man/man9/Makefile @@ -1558,6 +1558,7 @@ timeout.9 callout_active.9 \ timeout.9 callout_deactivate.9 \ timeout.9 callout_drain.9 \ + timeout.9 callout_drain_async.9 \ timeout.9 callout_handle_init.9 \ timeout.9 callout_init.9 \ timeout.9 callout_init_mtx.9 \ Index: share/man/man9/timeout.9 =================================================================== --- share/man/man9/timeout.9 +++ share/man/man9/timeout.9 @@ -29,13 +29,14 @@ .\" .\" $FreeBSD$ .\" -.Dd October 8, 2014 +.Dd January 24, 2015 .Dt TIMEOUT 9 .Os .Sh NAME .Nm callout_active , .Nm callout_deactivate , .Nm callout_drain , +.Nm callout_drain_async , .Nm callout_handle_init , .Nm callout_init , .Nm callout_init_mtx , @@ -63,256 +64,234 @@ .In sys/systm.h .Bd -literal typedef void timeout_t (void *); +typedef void callout_func_t (void *); .Ed -.Ft int -.Fn callout_active "struct callout *c" -.Ft void -.Fn callout_deactivate "struct callout *c" -.Ft int -.Fn callout_drain "struct callout *c" -.Ft void -.Fn callout_handle_init "struct callout_handle *handle" -.Bd -literal -struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle); -.Ed -.Ft void -.Fn callout_init "struct callout *c" "int mpsafe" -.Ft void -.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags" -.Ft void -.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags" -.Ft void -.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags" -.Ft int -.Fn callout_pending "struct callout *c" -.Ft int -.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg" -.Ft int -.Fn callout_reset_curcpu "struct callout *c" "int ticks" "timeout_t *func" \ -"void *arg" -.Ft int -.Fn callout_reset_on "struct callout *c" "int ticks" "timeout_t *func" \ -"void *arg" "int cpu" -.Ft int -.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "timeout_t *func" "void *arg" "int flags" -.Ft int -.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "timeout_t *func" "void *arg" "int flags" -.Ft int -.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "timeout_t *func" "void *arg" "int cpu" "int flags" -.Ft int -.Fn callout_schedule "struct callout *c" "int ticks" -.Ft int -.Fn callout_schedule_curcpu "struct callout *c" "int ticks" -.Ft int -.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu" -.Ft int -.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int flags" -.Ft int -.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int flags" -.Ft int -.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \ -"sbintime_t pr" "int cpu" "int flags" -.Ft int -.Fn callout_stop "struct callout *c" -.Ft struct callout_handle -.Fn timeout "timeout_t *func" "void *arg" "int ticks" -.Ft void -.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" .Sh DESCRIPTION The .Nm callout -API is used to schedule a call to an arbitrary function at a specific -time in the future. -Consumers of this API are required to allocate a callout structure -.Pq struct callout +API is used to schedule a one-time call to an arbitrary function at a +specific time in the future. +Consumers of this API are required to allocate a +.Ft struct callout for each pending function invocation. -This structure stores state about the pending function invocation including -the function to be called and the time at which the function should be invoked. -Pending function calls can be cancelled or rescheduled to a different time. -In addition, -a callout structure may be reused to schedule a new function call after a -scheduled call is completed. -.Pp -Callouts only provide a single-shot mode. -If a consumer requires a periodic timer, -it must explicitly reschedule each function call. -This is normally done by rescheduling the subsequent call within the called -function. -.Pp -Callout functions must not sleep. -They may not acquire sleepable locks, -wait on condition variables, -perform blocking allocation requests, -or invoke any other action that might sleep. -.Pp -Each callout structure must be initialized by -.Fn callout_init , -.Fn callout_init_mtx , -.Fn callout_init_rm , -or -.Fn callout_init_rw -before it is passed to any of the other callout functions. The +.Ft struct callout +stores the full state about any pending function call and +must be drained by a call to +.Fn callout_drain +or +.Fn callout_drain_async +before freeing. +.Sh INITIALIZATION +.Ft void +.Fn callout_handle_init "struct callout_handle *handle" +This function is deprecated. +Please use .Fn callout_init -function initializes a callout structure in -.Fa c -that is not associated with a specific lock. +instead. +This function is used to prepare a +.Ft struct callout_handle +before it can be used the first time. +If this function is called on a pending timeout, the pending timeout +cannot be cancelled and the +.Fn untimeout +function will return as if no timeout was pending. +.Pp +.Fn CALLOUT_HANDLE_INITIALIZER "&handle" +This macro is deprecated. +This macro is used to statically initialize a +.Ft struct callout_handle . +Please use +.Fn callout_init +instead. +.Pp +.Ft void +.Fn callout_init "struct callout *c" "int mpsafe" +This function prepares a +.Ft struct callout +before it can be used. +This function should not be used when the callout is pending a timeout. If the .Fa mpsafe -argument is zero, -the callout structure is not considered to be -.Dq multi-processor safe ; -and the Giant lock will be acquired before calling the callout function -and released when the callout function returns. -.Pp -The -.Fn callout_init_mtx , -.Fn callout_init_rm , -and -.Fn callout_init_rw -functions initialize a callout structure in -.Fa c -that is associated with a specific lock. -The lock is specified by the -.Fa mtx , -.Fa rm , -or -.Fa rw -parameter. -The associated lock must be held while stopping or rescheduling the -callout. -The callout subsystem acquires the associated lock before calling the -callout function and releases it after the function returns. -If the callout was cancelled while the callout subsystem waited for the -associated lock, -the callout function is not called, -and the associated lock is released. -This ensures that stopping or rescheduling the callout will abort any -previously scheduled invocation. -.Pp -Only regular mutexes may be used with -.Fn callout_init_mtx ; -spin mutexes are not supported. -A sleepable read-mostly lock -.Po -one initialized with the -.Dv RM_SLEEPABLE -flag -.Pc -may not be used with -.Fn callout_init_rm . -Similarly, other sleepable lock types such as -.Xr sx 9 -and -.Xr lockmgr 9 -cannot be used with callouts because sleeping is not permitted in -the callout subsystem. +argument is non-zero, the callback function will be running unlocked +and the callback is so-called "mpsafe". +.Bf Sy +It is the application's entire responsibility to not call any +.Fn callout_xxx +functions, including the +.Fn callout_drain +function, simultaneously on the same callout when the +.Fa mpsafe +argument is non-zero. +Otherwise, undefined behavior can happen. +Avoid simultaneous calls by obtaining an exclusive lock before calling +any +.Fn callout_xxx +functions other than the +.Fn callout_drain +function. +.Ef +If the +.Fa mpsafe +argument is zero, the Giant mutex will be locked before the callback +function is called. +If the +.Fa mpsafe +argument is zero, the Giant mutex is expected to be locked when calling +any +.Fn callout_xxx +functions which start and stop a callout other than the +.Fn callout_drain +function. .Pp -These +.Ft void +.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags" +This function prepares a +.Ft struct callout +before it can be used. +This function should not be used when the callout is pending a timeout. +The +.Fa mtx +argument is a pointer to a valid spinlock type of mutex or a valid +regular non-sleepable mutex which the callback subsystem will lock +before calling the callback function. +The specified mutex is expected to be locked when calling any +.Fn callout_xxx +functions which start and stop a callout other than the +.Fn callout_drain +function. +Valid .Fa flags -may be specified for -.Fn callout_init_mtx , -.Fn callout_init_rm , -or -.Fn callout_init_rw : +are: .Bl -tag -width ".Dv CALLOUT_RETURNUNLOCKED" .It Dv CALLOUT_RETURNUNLOCKED -The callout function will release the associated lock itself, -so the callout subsystem should not attempt to unlock it -after the callout function returns. -.It Dv CALLOUT_SHAREDLOCK -The lock is only acquired in read mode when running the callout handler. -This flag is ignored by -.Fn callout_init_mtx . +The callout function is assumed to have released the specified mutex +before returning. +.It Dv 0 +The callout subsystem will release the specified mutex after the +callout function has returned. .El .Pp -The function -.Fn callout_stop -cancels a callout -.Fa c -if it is currently pending. -If the callout is pending, then -.Fn callout_stop -returns a non-zero value. -If the callout is not set, -has already been serviced, -or is currently being serviced, -then zero will be returned. -If the callout has an associated lock, -then that lock must be held when this function is called. -.Pp -The function -.Fn callout_drain -is identical to -.Fn callout_stop -except that it will wait for the callout -.Fa c -to complete if it is already in progress. -This function MUST NOT be called while holding any -locks on which the callout might block, or deadlock will result. -Note that if the callout subsystem has already begun processing this -callout, then the callout function may be invoked before -.Fn callout_drain -returns. -However, the callout subsystem does guarantee that the callout will be -fully stopped before -.Fn callout_drain -returns. +.Ft void +.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags" +This function is similar to +.Fn callout_init_mtx , +but it accepts a read-mostly type of lock. +The read-mostly lock must not be initialized with the +.Dv RM_SLEEPABLE +flag. .Pp -The +.Ft void +.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags" +This function is similar to +.Fn callout_init_mtx , +but it accepts a read/write type of lock. +.Sh SCHEDULING CALLOUTS +.Ft struct callout_handle +.Fn timeout "timeout_t *func" "void *arg" "int ticks" +This function is deprecated. +Please use .Fn callout_reset -and -.Fn callout_schedule -function families schedule a future function invocation for callout -.Fa c . -If -.Fa c -already has a pending callout, -it is cancelled before the new invocation is scheduled. -These functions return a non-zero value if a pending callout was cancelled -and zero if there was no pending callout. -If the callout has an associated lock, -then that lock must be held when any of these functions are called. -.Pp -The time at which the callout function will be invoked is determined by -either the -.Fa ticks -argument or the -.Fa sbt , -.Fa pr , -and -.Fa flags -arguments. -When -.Fa ticks -is used, -the callout is scheduled to execute after +instead. +This function schedules a call to +.Fa func +to take place after .Fa ticks Ns No /hz seconds. Non-positive values of .Fa ticks are silently converted to the value .Sq 1 . -.Pp The -.Fa sbt , -.Fa pr , -and -.Fa flags -arguments provide more control over the scheduled time including -support for higher resolution times, -specifying the precision of the scheduled time, -and setting an absolute deadline instead of a relative timeout. -The callout is scheduled to execute in a time window which begins at -the time specified in +.Fa func +argument is a valid pointer to a function that takes a single +.Fa void * +argument. +Upon invocation, the +.Fa func +function will receive +.Fa arg +as its only argument. +The Giant lock is locked when the +.Fa arg +function is invoked and should not be unlocked by this function. +The returned value from +.Fn timeout +is a +.Ft struct callout_handle +structure which can be used in conjunction with the +.Fn untimeout +function to request that a scheduled timeout be cancelled. +As handles are recycled by the system, it is possible, although unlikely, +that a handle from one invocation of +.Fn timeout +may match the handle of another invocation of +.Fn timeout +if both calls used the same function pointer and argument, and the first +timeout is expired or cancelled before the second call. +Please ensure that the function and argument pointers are unique when using this function. +.Pp +.Ft int +.Fn callout_reset "struct callout *c" "int ticks" "callout_func_t *func" "void *arg" +This function is used to schedule or re-schedule a callout. +This function at first stops the callout given by the +.Fa c +argument, if any. +Then it will start the callout given by the +.Fa c +argument. +The relative time until the timeout callback happens is given by the +.Fa ticks +argument. +The number of ticks in a second is defined by +.Dv hz +and can vary from system to system. +This function returns a non-zero value if the given callout was pending and +the callback function was prevented from being called. +Otherwise, a value of zero is returned. +If a lock is associated with the callout given by the +.Fa c +argument and it is exclusivly locked when this function is called, this +function will always ensure that previous callback function, if any, +is never reached. +In other words, the callout will be atomically restarted. +Otherwise, there is no such guarantee. +The callback function is given by +.Fa func +and its function argument is given by +.Fa arg . +.Pp +.Ft int +.Fn callout_reset_curcpu "struct callout *c" "int ticks" "callout_func_t *func" \ +"void *arg" +This function works the same like the +.Fn callout_reset +function except the callback function given by the +.Fa func +argument will be executed on the same CPU which called this function. +.Pp +.Ft int +.Fn callout_reset_on "struct callout *c" "int ticks" "callout_func_t *func" \ +"void *arg" "int cpu" +This function works the same like the +.Fn callout_reset +function except the callback function given by the +.Fa func +argument will be executed on the CPU given by the +.Fa cpu +argument. +.Pp +.Ft int +.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags" +This function works the same like the +.Fn callout_reset +function except the relative or absolute time after which the timeout +callback should happen is given by the .Fa sbt -and extends for the amount of time specified in +argument and extends for the amount of time specified in .Fa pr . +This function is used when high precision timeouts are needed. If .Fa sbt specifies a time in the past, @@ -322,12 +301,13 @@ allows the callout subsystem to coalesce callouts scheduled close to each other into fewer timer interrupts, reducing processing overhead and power consumption. -These +The .Fa flags -may be specified to adjust the interpretation of +argument may be non-zero to adjust the interpretation of the .Fa sbt and -.Fa pr : +.Fa pr +arguments: .Bl -tag -width ".Dv C_DIRECT_EXEC" .It Dv C_ABSOLUTE Handle the @@ -347,7 +327,7 @@ and should be as small as possible because they run with absolute priority. .It Fn C_PREL Specifies relative event time precision as binary logarithm of time interval -divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, etc. +divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, and so on. Note that the larger of .Fa pr or this value is used as the length of the time window. @@ -360,65 +340,207 @@ calls if possible. .El .Pp -The -.Fn callout_reset -functions accept a +.Ft int +.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags" +This function works like +.Fn callout_reset_sbt , +except the callback function given by the .Fa func -argument which identifies the function to be called when the time expires. -It must be a pointer to a function that takes a single -.Fa void * -argument. -Upon invocation, +argument will be executed on the CPU which called this function. +.Pp +.Ft int +.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "callout_func_t *func" "void *arg" "int cpu" "int flags" +This function works like +.Fn callout_reset_sbt , +except the callback function given by .Fa func -will receive -.Fa arg -as its only argument. -The -.Fn callout_schedule -functions reuse the +will be executed on the CPU given by +.Fa cpu . +.Pp +.Ft int +.Fn callout_schedule "struct callout *c" "int ticks" +This function works the same like the +.Fn callout_reset +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Pp +.Ft int +.Fn callout_schedule_curcpu "struct callout *c" "int ticks" +This function works the same like the +.Fn callout_reset_curcpu +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Pp +.Ft int +.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu" +This function works the same like the +.Fn callout_reset_on +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Pp +.Ft int +.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int flags" +This function works the same like the +.Fn callout_reset_sbt +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Pp +.Ft int +.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int flags" +This function works the same like the +.Fn callout_reset_sbt_curcpu +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Pp +.Ft int +.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \ +"sbintime_t pr" "int cpu" "int flags" +This function works the same like the +.Fn callout_reset_sbt_on +function except it re-uses the callback function and the callback argument +already stored in the +.Pq struct callout +structure. +.Sh CHECKING THE STATE OF CALLOUTS +.Ft int +.Fn callout_pending "struct callout *c" +This function returns non-zero if the callout pointed to by the +.Fa c +argument is pending for callback. +Else this function returns zero. +This function returns zero when inside the callout function if the +callout is not re-scheduled. +.Pp +.Ft int +.Fn callout_active "struct callout *c" +This function is deprecated and returns non-zero if the callout +pointed to by the +.Fa c +argument was scheduled in the past. +Else this function returns zero. +This function also returns zero after the +.Fn callout_deactivate +or the +.Fn callout_stop +or the +.Fn callout_drain +or the +.Fn callout_drain_async +function is called on the same callout as given by the +.Fa c +argument. +.Pp +.Ft void +.Fn callout_deactivate "struct callout *c" +This function is deprecated and ensures that subsequent calls to the +.Fn callout_activate +function returns zero until the callout is scheduled again. +.Sh STOPPING CALLOUTS +.Ft void +.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" +This function is deprecated and cancels the timeout associated with the +.Fa handle +argument using the function pointed to by the .Fa func -and +argument and having the .Fa arg -arguments from the previous callout. -Note that one of the -.Fn callout_reset -functions must always be called to initialize +arguments to validate the handle. +If the handle does not correspond to a timeout with +the function .Fa func -and +taking the argument .Fa arg -before one of the -.Fn callout_schedule -functions can be used. +no action is taken. The +.Fa handle +must be initialized by a previous call to +.Fn timeout , +.Fn callout_handle_init +or assigned the value of +.Fn CALLOUT_HANDLE_INITIALIZER "&handle" +before being passed to +.Fn untimeout . +The behavior of calling +.Fn untimeout +with an uninitialized handle +is undefined. .Pp -The callout subsystem provides a softclock thread for each CPU in the system. -Callouts are assigned to a single CPU and are executed by the softclock thread -for that CPU. -Initially, -callouts are assigned to CPU 0. -The -.Fn callout_reset_on , -.Fn callout_reset_sbt_on , -.Fn callout_schedule_on -and -.Fn callout_schedule_sbt_on -functions assign the callout to CPU -.Fa cpu . -The -.Fn callout_reset_curcpu , -.Fn callout_reset_sbt_curpu , -.Fn callout_schedule_curcpu -and -.Fn callout_schedule_sbt_curcpu -functions assign the callout to the current CPU. -The -.Fn callout_reset , -.Fn callout_reset_sbt , -.Fn callout_schedule -and -.Fn callout_schedule_sbt -functions schedule the callout to execute in the softclock thread of the CPU -to which it is currently assigned. +.Ft int +.Fn callout_stop "struct callout *c" +This function is used to stop a timeout function invocation associated with the callout pointed to by the +.Fa c +argument, in a non-blocking fashion. +This function can be called multiple times in a row with no side effects, even if the callout is already stopped. This function however should not be called before the callout has been initialized. +This function returns a non-zero value if the given callout was pending and +the callback function was prevented from being called. +Else a value of zero is returned. +If a lock is associated with the callout given by the +.Fa c +argument and it is exclusivly locked when this function is called, the +.Fn callout_stop +function will always ensure that the callback function is never reached. +In other words the callout will be atomically stopped. +Else there is no such guarantee. +.Sh DRAINING CALLOUTS +.Ft int +.Fn callout_drain "struct callout *c" +This function works the same like the +.Fn callout_stop +function except it ensures that all callback functions have returned and there are no more references to the callout pointed to by the +.Fa c +argument inside the callout subsystem before it returns. +Also this function ensures that the lock, if any, associated with the +callout is no longer being used. +When this function returns, it is safe to free the callout structure pointed to by the +.Fa c +argument. .Pp +.Ft int +.Fn callout_drain_async "struct callout *c" "callout_func_t *fn" "void *arg" +This function is non-blocking and works the same like the +.Fn callout_stop +function except if it returns non-zero it means the callback function pointed to by the +.Fa fn +argument will be called back with the +.Fa arg +argument when all references to the callout pointed to by the +.Fa c +argument are gone. +If this function returns non-zero it should not be called again until the callback function has been called. +If the +.Fn callout_drain +or +.Fn callout_drain_async +functions are called while an asynchronous drain is pending, +previously pending asynchronous drains might get cancelled. +If this function returns zero, it is safe to free the callout structure pointed to by the +.Fa c +argument right away. +.Sh CALLOUT FUNCTION RESTRICTIONS +Callout functions must not sleep. +They may not acquire sleepable locks, wait on condition variables, +perform blocking allocation requests, or invoke any other action that +might sleep. +.Sh CALLOUT SUBSYSTEM INTERNALS +The callout subsystem has its own set of spinlocks to protect its internal state. +The callout subsystem provides a softclock thread for each CPU in the +system. +Callouts are assigned to a single CPU and are executed by the +softclock thread for that CPU. +Initially, callouts are assigned to CPU 0. Softclock threads are not pinned to their respective CPUs by default. The softclock thread for CPU 0 can be pinned to CPU 0 by setting the .Va kern.pin_default_swi @@ -427,50 +549,7 @@ respective CPUs by setting the .Va kern.pin_pcpu_swi loader tunable to a non-zero value. -.Pp -The macros -.Fn callout_pending , -.Fn callout_active -and -.Fn callout_deactivate -provide access to the current state of the callout. -The -.Fn callout_pending -macro checks whether a callout is -.Em pending ; -a callout is considered -.Em pending -when a timeout has been set but the time has not yet arrived. -Note that once the timeout time arrives and the callout subsystem -starts to process this callout, -.Fn callout_pending -will return -.Dv FALSE -even though the callout function may not have finished -.Pq or even begun -executing. -The -.Fn callout_active -macro checks whether a callout is marked as -.Em active , -and the -.Fn callout_deactivate -macro clears the callout's -.Em active -flag. -The callout subsystem marks a callout as -.Em active -when a timeout is set and it clears the -.Em active -flag in -.Fn callout_stop -and -.Fn callout_drain , -but it -.Em does not -clear it when a callout expires normally via the execution of the -callout function. -.Ss "Avoiding Race Conditions" +.Sh "AVOIDING RACE CONDITIONS" The callout subsystem invokes callout functions from its own thread context. Without some kind of synchronization, @@ -531,9 +610,8 @@ .Pc indicates whether or not the callout was removed. If it is known that the callout was set and the callout function has -not yet executed, then a return value of -.Dv FALSE -indicates that the callout function is about to be called. +not yet executed, then a return value of zero indicates that the +callout function is about to be called. For example: .Bd -literal -offset indent if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) { @@ -589,16 +667,14 @@ .Em pending flag and return without action if .Fn callout_pending -returns -.Dv TRUE . +returns non-zero. This indicates that the callout was rescheduled using .Fn callout_reset just before the callout function was invoked. If .Fn callout_active -returns -.Dv FALSE -then the callout function should also return without action. +returns zero then the callout function should also return without +action. This indicates that the callout has been stopped. Finally, the callout function should call .Fn callout_deactivate @@ -668,129 +744,13 @@ or releasing the storage for the callout structure. .Sh LEGACY API .Bf Sy -The functions below are a legacy API that will be removed in a future release. -New code should not use these routines. -.Ef -.Pp -The function -.Fn timeout -schedules a call to the function given by the argument -.Fa func -to take place after -.Fa ticks Ns No /hz -seconds. -Non-positive values of -.Fa ticks -are silently converted to the value -.Sq 1 . -.Fa func -should be a pointer to a function that takes a -.Fa void * -argument. -Upon invocation, -.Fa func -will receive -.Fa arg -as its only argument. -The return value from +The .Fn timeout -is a -.Ft struct callout_handle -which can be used in conjunction with the -.Fn untimeout -function to request that a scheduled timeout be canceled. -.Pp -The function -.Fn callout_handle_init -can be used to initialize a handle to a state which will cause -any calls to -.Fn untimeout -with that handle to return with no side -effects. -.Pp -Assigning a callout handle the value of -.Fn CALLOUT_HANDLE_INITIALIZER -performs the same function as -.Fn callout_handle_init -and is provided for use on statically declared or global callout handles. -.Pp -The function -.Fn untimeout -cancels the timeout associated with -.Fa handle -using the -.Fa func and -.Fa arg -arguments to validate the handle. -If the handle does not correspond to a timeout with -the function -.Fa func -taking the argument -.Fa arg -no action is taken. -.Fa handle -must be initialized by a previous call to -.Fn timeout , -.Fn callout_handle_init , -or assigned the value of -.Fn CALLOUT_HANDLE_INITIALIZER "&handle" -before being passed to -.Fn untimeout . -The behavior of calling .Fn untimeout -with an uninitialized handle -is undefined. -.Pp -As handles are recycled by the system, it is possible (although unlikely) -that a handle from one invocation of -.Fn timeout -may match the handle of another invocation of -.Fn timeout -if both calls used the same function pointer and argument, and the first -timeout is expired or canceled before the second call. -The timeout facility offers O(1) running time for -.Fn timeout -and -.Fn untimeout . -Timeouts are executed from -.Fn softclock -with the -.Va Giant -lock held. -Thus they are protected from re-entrancy. -.Sh RETURN VALUES -The -.Fn callout_active -macro returns the state of a callout's -.Em active -flag. -.Pp -The -.Fn callout_pending -macro returns the state of a callout's -.Em pending -flag. -.Pp -The -.Fn callout_reset -and -.Fn callout_schedule -function families return non-zero if the callout was pending before the new -function invocation was scheduled. -.Pp -The -.Fn callout_stop -and -.Fn callout_drain -functions return non-zero if the callout was still pending when it was -called or zero otherwise. -The -.Fn timeout -function returns a -.Ft struct callout_handle -that can be passed to -.Fn untimeout . +functions are a legacy API that will be removed in a future release. +New code should not use these routines. +.Ef .Sh HISTORY The current timeout and untimeout routines are based on the work of .An Adam M. Costello @@ -815,4 +775,4 @@ .Bx linked list callout mechanism which offered O(n) insertion and removal running time -but did not generate or require handles for untimeout operations. +and did not generate or require handles for untimeout operations. Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3102,6 +3102,7 @@ kern/uipc_domain.c standard kern/uipc_mbuf.c standard kern/uipc_mbuf2.c standard +kern/uipc_mbufhash.c standard kern/uipc_mqueue.c optional p1003_1b_mqueue kern/uipc_sem.c optional p1003_1b_semaphores kern/uipc_shm.c standard Index: sys/kern/uipc_mbufhash.c =================================================================== --- sys/kern/uipc_mbufhash.c +++ sys/kern/uipc_mbufhash.c @@ -25,57 +25,32 @@ #include #include -#include #include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include -#include + +#include #if defined(INET) || defined(INET6) #include #endif + #ifdef INET -#include -#include #include #endif #ifdef INET6 #include -#include -#include #endif #include -#include "utils.h" - -/* XXX this code should be factored out */ -/* XXX copied from if_lagg.c */ - static const void * -mlx4_en_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) +m_ether_tcpip_hash_gethdr(const struct mbuf *m, const u_int off, + const u_int len, void *buf) { if (m->m_pkthdr.len < (off + len)) { return (NULL); @@ -87,7 +62,17 @@ } uint32_t -mlx4_en_hashmbuf(uint32_t flags, struct mbuf *m, uint32_t key) +m_ether_tcpip_hash_init(void) +{ + uint32_t seed; + + seed = arc4random(); + return (fnv_32_buf(&seed, sizeof(seed), FNV1_32_INIT)); +} + +uint32_t +m_ether_tcpip_hash(const uint32_t flags, const struct mbuf *m, + const uint32_t key) { uint16_t etype; uint32_t p = key; @@ -96,12 +81,9 @@ const struct ether_vlan_header *vlan; #ifdef INET const struct ip *ip; - const uint32_t *ports; - int iphlen; #endif #ifdef INET6 const struct ip6_hdr *ip6; - uint32_t flow; #endif union { #ifdef INET @@ -112,48 +94,47 @@ #endif struct ether_vlan_header vlan; uint32_t port; - } buf; + } buf; off = sizeof(*eh); if (m->m_len < off) - goto out; + goto done; eh = mtod(m, struct ether_header *); etype = ntohs(eh->ether_type); - if (flags & MLX4_F_HASHL2) { - p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); - p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); + if (flags & MBUF_HASHFLAG_L2) { + p = fnv_32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); + p = fnv_32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); } - /* Special handling for encapsulating VLAN frames */ - if ((m->m_flags & M_VLANTAG) && (flags & MLX4_F_HASHL2)) { - p = hash32_buf(&m->m_pkthdr.ether_vtag, + if ((m->m_flags & M_VLANTAG) && (flags & MBUF_HASHFLAG_L2)) { + p = fnv_32_buf(&m->m_pkthdr.ether_vtag, sizeof(m->m_pkthdr.ether_vtag), p); } else if (etype == ETHERTYPE_VLAN) { - vlan = mlx4_en_gethdr(m, off, sizeof(*vlan), &buf); + vlan = m_ether_tcpip_hash_gethdr(m, off, sizeof(*vlan), &buf); if (vlan == NULL) - goto out; + goto done; - if (flags & MLX4_F_HASHL2) - p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); + if (flags & MBUF_HASHFLAG_L2) + p = fnv_32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); etype = ntohs(vlan->evl_proto); off += sizeof(*vlan) - sizeof(*eh); } - switch (etype) { #ifdef INET case ETHERTYPE_IP: - ip = mlx4_en_gethdr(m, off, sizeof(*ip), &buf); + ip = m_ether_tcpip_hash_gethdr(m, off, sizeof(*ip), &buf); if (ip == NULL) - goto out; - - if (flags & MLX4_F_HASHL3) { - p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p); - p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p); - } - if (!(flags & MLX4_F_HASHL4)) break; - switch (ip->ip_p) { + if (flags & MBUF_HASHFLAG_L3) { + p = fnv_32_buf(&ip->ip_src, sizeof(struct in_addr), p); + p = fnv_32_buf(&ip->ip_dst, sizeof(struct in_addr), p); + } + if (flags & MBUF_HASHFLAG_L4) { + const uint32_t *ports; + int iphlen; + + switch (ip->ip_p) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_SCTP: @@ -161,29 +142,37 @@ if (iphlen < sizeof(*ip)) break; off += iphlen; - ports = mlx4_en_gethdr(m, off, sizeof(*ports), &buf); + ports = m_ether_tcpip_hash_gethdr(m, + off, sizeof(*ports), &buf); if (ports == NULL) break; - p = hash32_buf(ports, sizeof(*ports), p); + p = fnv_32_buf(ports, sizeof(*ports), p); break; + } } break; #endif #ifdef INET6 case ETHERTYPE_IPV6: - if (!(flags & MLX4_F_HASHL3)) - break; - ip6 = mlx4_en_gethdr(m, off, sizeof(*ip6), &buf); + ip6 = m_ether_tcpip_hash_gethdr(m, off, sizeof(*ip6), &buf); if (ip6 == NULL) - goto out; + break; + if (flags & MBUF_HASHFLAG_L3) { + p = fnv_32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); + p = fnv_32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); + } + if (flags & MBUF_HASHFLAG_L4) { + uint32_t flow; - p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); - p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); - flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; - p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ + /* IPv6 flow label */ + flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; + p = fnv_32_buf(&flow, sizeof(flow), p); + } break; #endif + default: + break; } -out: +done: return (p); } Index: sys/net/if_lagg.c =================================================================== --- sys/net/if_lagg.c +++ sys/net/if_lagg.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -131,7 +130,6 @@ static void lagg_media_status(struct ifnet *, struct ifmediareq *); static struct lagg_port *lagg_link_active(struct lagg_softc *, struct lagg_port *); -static const void *lagg_gethdr(struct mbuf *, u_int, u_int, void *); /* Simple round robin */ static void lagg_rr_attach(struct lagg_softc *); @@ -490,7 +488,7 @@ sc->flowid_shift = V_def_flowid_shift; /* Hash all layers by default */ - sc->sc_flags = LAGG_F_HASHL2|LAGG_F_HASHL3|LAGG_F_HASHL4; + sc->sc_flags = MBUF_HASHFLAG_L2|MBUF_HASHFLAG_L3|MBUF_HASHFLAG_L4; lagg_proto_attach(sc, LAGG_PROTO_DEFAULT); @@ -1349,7 +1347,13 @@ LAGG_WUNLOCK(sc); break; case SIOCGLAGGFLAGS: - rf->rf_flags = sc->sc_flags; + rf->rf_flags = 0; + if (sc->sc_flags & MBUF_HASHFLAG_L2) + rf->rf_flags |= LAGG_F_HASHL2; + if (sc->sc_flags & MBUF_HASHFLAG_L3) + rf->rf_flags |= LAGG_F_HASHL3; + if (sc->sc_flags & MBUF_HASHFLAG_L4) + rf->rf_flags |= LAGG_F_HASHL4; break; case SIOCSLAGGHASH: error = priv_check(td, PRIV_NET_LAGG); @@ -1360,8 +1364,13 @@ break; } LAGG_WLOCK(sc); - sc->sc_flags &= ~LAGG_F_HASHMASK; - sc->sc_flags |= rf->rf_flags & LAGG_F_HASHMASK; + sc->sc_flags &= ~MBUF_HASHFLAG_MASK; + if (rf->rf_flags & LAGG_F_HASHL2) + sc->sc_flags |= MBUF_HASHFLAG_L2; + if (rf->rf_flags & LAGG_F_HASHL3) + sc->sc_flags |= MBUF_HASHFLAG_L3; + if (rf->rf_flags & LAGG_F_HASHL4) + sc->sc_flags |= MBUF_HASHFLAG_L4; LAGG_WUNLOCK(sc); break; case SIOCGLAGGPORT: @@ -1806,120 +1815,6 @@ return (rval); } -static const void * -lagg_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) -{ - if (m->m_pkthdr.len < (off + len)) { - return (NULL); - } else if (m->m_len < (off + len)) { - m_copydata(m, off, len, buf); - return (buf); - } - return (mtod(m, char *) + off); -} - -uint32_t -lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key) -{ - uint16_t etype; - uint32_t p = key; - int off; - struct ether_header *eh; - const struct ether_vlan_header *vlan; -#ifdef INET - const struct ip *ip; - const uint32_t *ports; - int iphlen; -#endif -#ifdef INET6 - const struct ip6_hdr *ip6; - uint32_t flow; -#endif - union { -#ifdef INET - struct ip ip; -#endif -#ifdef INET6 - struct ip6_hdr ip6; -#endif - struct ether_vlan_header vlan; - uint32_t port; - } buf; - - - off = sizeof(*eh); - if (m->m_len < off) - goto out; - eh = mtod(m, struct ether_header *); - etype = ntohs(eh->ether_type); - if (sc->sc_flags & LAGG_F_HASHL2) { - p = fnv_32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); - p = fnv_32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); - } - - /* Special handling for encapsulating VLAN frames */ - if ((m->m_flags & M_VLANTAG) && (sc->sc_flags & LAGG_F_HASHL2)) { - p = fnv_32_buf(&m->m_pkthdr.ether_vtag, - sizeof(m->m_pkthdr.ether_vtag), p); - } else if (etype == ETHERTYPE_VLAN) { - vlan = lagg_gethdr(m, off, sizeof(*vlan), &buf); - if (vlan == NULL) - goto out; - - if (sc->sc_flags & LAGG_F_HASHL2) - p = fnv_32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); - etype = ntohs(vlan->evl_proto); - off += sizeof(*vlan) - sizeof(*eh); - } - - switch (etype) { -#ifdef INET - case ETHERTYPE_IP: - ip = lagg_gethdr(m, off, sizeof(*ip), &buf); - if (ip == NULL) - goto out; - - if (sc->sc_flags & LAGG_F_HASHL3) { - p = fnv_32_buf(&ip->ip_src, sizeof(struct in_addr), p); - p = fnv_32_buf(&ip->ip_dst, sizeof(struct in_addr), p); - } - if (!(sc->sc_flags & LAGG_F_HASHL4)) - break; - switch (ip->ip_p) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_SCTP: - iphlen = ip->ip_hl << 2; - if (iphlen < sizeof(*ip)) - break; - off += iphlen; - ports = lagg_gethdr(m, off, sizeof(*ports), &buf); - if (ports == NULL) - break; - p = fnv_32_buf(ports, sizeof(*ports), p); - break; - } - break; -#endif -#ifdef INET6 - case ETHERTYPE_IPV6: - if (!(sc->sc_flags & LAGG_F_HASHL3)) - break; - ip6 = lagg_gethdr(m, off, sizeof(*ip6), &buf); - if (ip6 == NULL) - goto out; - - p = fnv_32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); - p = fnv_32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); - flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; - p = fnv_32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ - break; -#endif - } -out: - return (p); -} - int lagg_enqueue(struct ifnet *ifp, struct mbuf *m) { @@ -2087,15 +1982,12 @@ { struct lagg_port *lp; struct lagg_lb *lb; - uint32_t seed; lb = malloc(sizeof(struct lagg_lb), M_DEVBUF, M_WAITOK | M_ZERO); sc->sc_capabilities = IFCAP_LAGG_FULLDUPLEX; - seed = arc4random(); - lb->lb_key = FNV1_32_INIT; - lb->lb_key = fnv_32_buf(&seed, sizeof(seed), lb->lb_key); + lb->lb_key = m_ether_tcpip_hash_init(); sc->sc_psc = lb; SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) @@ -2160,7 +2052,7 @@ M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) p = m->m_pkthdr.flowid >> sc->flowid_shift; else - p = lagg_hashmbuf(sc, m, lb->lb_key); + p = m_ether_tcpip_hash(sc->sc_flags, m, lb->lb_key); p %= sc->sc_count; lp = lb->lb_ports[p]; Index: sys/ofed/drivers/net/mlx4/en_tx.c =================================================================== --- sys/ofed/drivers/net/mlx4/en_tx.c +++ sys/ofed/drivers/net/mlx4/en_tx.c @@ -49,7 +49,6 @@ #include #include "mlx4_en.h" -#include "utils.h" enum { MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ @@ -699,10 +698,10 @@ tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; } -static unsigned long hashrandom; +static uint32_t hashrandom; static void hashrandom_init(void *arg) { - hashrandom = random(); + hashrandom = m_ether_tcpip_hash_init(); } SYSINIT(hashrandom_init, SI_SUB_KLD, SI_ORDER_SECOND, &hashrandom_init, NULL); @@ -724,7 +723,7 @@ if (M_HASHTYPE_GET(mb) != M_HASHTYPE_NONE) queue_index = mb->m_pkthdr.flowid; else - queue_index = mlx4_en_hashmbuf(MLX4_F_HASHL3 | MLX4_F_HASHL4, mb, hashrandom); + queue_index = m_ether_tcpip_hash(MBUF_HASHFLAG_L3 | MBUF_HASHFLAG_L4, mb, hashrandom); return ((queue_index % rings_p_up) + (up * rings_p_up)); } Index: sys/ofed/drivers/net/mlx4/utils.h =================================================================== --- sys/ofed/drivers/net/mlx4/utils.h +++ sys/ofed/drivers/net/mlx4/utils.h @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2014 Mellanox Technologies Ltd. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _MLX4_UTILS_H_ -#define _MLX4_UTILS_H_ - -/* Lagg flags */ -#define MLX4_F_HASHL2 0x00000001 /* hash layer 2 */ -#define MLX4_F_HASHL3 0x00000002 /* hash layer 3 */ -#define MLX4_F_HASHL4 0x00000004 /* hash layer 4 */ -#define MLX4_F_HASHMASK 0x00000007 - -uint32_t mlx4_en_hashmbuf(uint32_t flags, struct mbuf *m, uint32_t key); - -#endif /* _MLX4_UTILS_H_ */ Index: sys/ofed/drivers/net/mlx4/utils.c =================================================================== --- sys/ofed/drivers/net/mlx4/utils.c +++ sys/ofed/drivers/net/mlx4/utils.c @@ -1,189 +0,0 @@ -/* $OpenBSD: if_trunk.c,v 1.30 2007/01/31 06:20:19 reyk Exp $ */ - -/* - * Copyright (c) 2005, 2006 Reyk Floeter - * Copyright (c) 2007 Andrew Thompson - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(INET) || defined(INET6) -#include -#endif -#ifdef INET -#include -#include -#include -#endif - -#ifdef INET6 -#include -#include -#include -#endif - -#include - -#include "utils.h" - -/* XXX this code should be factored out */ -/* XXX copied from if_lagg.c */ - -static const void * -mlx4_en_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) -{ - if (m->m_pkthdr.len < (off + len)) { - return (NULL); - } else if (m->m_len < (off + len)) { - m_copydata(m, off, len, buf); - return (buf); - } - return (mtod(m, char *) + off); -} - -uint32_t -mlx4_en_hashmbuf(uint32_t flags, struct mbuf *m, uint32_t key) -{ - uint16_t etype; - uint32_t p = key; - int off; - struct ether_header *eh; - const struct ether_vlan_header *vlan; -#ifdef INET - const struct ip *ip; - const uint32_t *ports; - int iphlen; -#endif -#ifdef INET6 - const struct ip6_hdr *ip6; - uint32_t flow; -#endif - union { -#ifdef INET - struct ip ip; -#endif -#ifdef INET6 - struct ip6_hdr ip6; -#endif - struct ether_vlan_header vlan; - uint32_t port; - } buf; - - - off = sizeof(*eh); - if (m->m_len < off) - goto out; - eh = mtod(m, struct ether_header *); - etype = ntohs(eh->ether_type); - if (flags & MLX4_F_HASHL2) { - p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); - p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); - } - - /* Special handling for encapsulating VLAN frames */ - if ((m->m_flags & M_VLANTAG) && (flags & MLX4_F_HASHL2)) { - p = hash32_buf(&m->m_pkthdr.ether_vtag, - sizeof(m->m_pkthdr.ether_vtag), p); - } else if (etype == ETHERTYPE_VLAN) { - vlan = mlx4_en_gethdr(m, off, sizeof(*vlan), &buf); - if (vlan == NULL) - goto out; - - if (flags & MLX4_F_HASHL2) - p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); - etype = ntohs(vlan->evl_proto); - off += sizeof(*vlan) - sizeof(*eh); - } - - switch (etype) { -#ifdef INET - case ETHERTYPE_IP: - ip = mlx4_en_gethdr(m, off, sizeof(*ip), &buf); - if (ip == NULL) - goto out; - - if (flags & MLX4_F_HASHL3) { - p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p); - p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p); - } - if (!(flags & MLX4_F_HASHL4)) - break; - switch (ip->ip_p) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_SCTP: - iphlen = ip->ip_hl << 2; - if (iphlen < sizeof(*ip)) - break; - off += iphlen; - ports = mlx4_en_gethdr(m, off, sizeof(*ports), &buf); - if (ports == NULL) - break; - p = hash32_buf(ports, sizeof(*ports), p); - break; - } - break; -#endif -#ifdef INET6 - case ETHERTYPE_IPV6: - if (!(flags & MLX4_F_HASHL3)) - break; - ip6 = mlx4_en_gethdr(m, off, sizeof(*ip6), &buf); - if (ip6 == NULL) - goto out; - - p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); - p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); - flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; - p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ - break; -#endif - } -out: - return (p); -} Index: sys/sys/mbuf.h =================================================================== --- sys/sys/mbuf.h +++ sys/sys/mbuf.h @@ -1186,6 +1186,16 @@ ((_m)->m_pkthdr.fibnum) = (_fib); \ } while (0) +/* mbuf hash routines */ + +#define MBUF_HASHFLAG_L2 (1 << 2) +#define MBUF_HASHFLAG_L3 (1 << 3) +#define MBUF_HASHFLAG_L4 (1 << 4) +#define MBUF_HASHFLAG_MASK (MBUF_HASHFLAG_L2 | MBUF_HASHFLAG_L3 | MBUF_HASHFLAG_L4) + +uint32_t m_ether_tcpip_hash_init(void); +uint32_t m_ether_tcpip_hash(const uint32_t, const struct mbuf *, const uint32_t); + #endif /* _KERNEL */ #ifdef MBUF_PROFILING