/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa4* All rights reserved5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728/*29* The API to write a packet scheduling algorithm for dummynet.30*/3132#ifndef _DN_SCHED_H33#define _DN_SCHED_H3435#include <sys/ck.h>3637#define DN_MULTIQUEUE 0x0138/*39* Descriptor for a scheduling algorithm.40* Contains all function pointers for a given scheduler41* This is typically created when a module is loaded, and stored42* in a global list of schedulers.43*/44struct dn_alg {45uint32_t type; /* the scheduler type */46const char *name; /* scheduler name */47uint32_t flags; /* DN_MULTIQUEUE if supports multiple queues */4849/*50* The following define the size of 3 optional data structures51* that may need to be allocated at runtime, and are appended52* to each of the base data structures: scheduler, sched.inst,53* and queue. We don't have a per-flowset structure.54*/55/* + parameters attached to the template, e.g.56* default queue sizes, weights, quantum size, and so on;57*/58size_t schk_datalen;5960/* + per-instance parameters, such as timestamps,61* containers for queues, etc;62*/63size_t si_datalen;6465size_t q_datalen; /* per-queue parameters (e.g. S,F) */6667/*68* Methods implemented by the scheduler:69* enqueue enqueue packet 'm' on scheduler 's', queue 'q'.70* q is NULL for !MULTIQUEUE.71* Return 0 on success, 1 on drop (packet consumed anyways).72* Note that q should be interpreted only as a hint73* on the flow that the mbuf belongs to: while a74* scheduler will normally enqueue m into q, it is ok75* to leave q alone and put the mbuf elsewhere.76* This function is called in two cases:77* - when a new packet arrives to the scheduler;78* - when a scheduler is reconfigured. In this case the79* call is issued by the new_queue callback, with a80* non empty queue (q) and m pointing to the first81* mbuf in the queue. For this reason, the function82* should internally check for (m != q->mq.head)83* before calling dn_enqueue().84*85* dequeue Called when scheduler instance 's' can86* dequeue a packet. Return NULL if none are available.87* XXX what about non work-conserving ?88*89* config called on 'sched X config ...', normally writes90* in the area of size sch_arg91*92* destroy called on 'sched delete', frees everything93* in sch_arg (other parts are handled by more specific94* functions)95*96* new_sched called when a new instance is created, e.g.97* to create the local queue for !MULTIQUEUE, set V or98* copy parameters for WFQ, and so on.99*100* free_sched called when deleting an instance, cleans101* extra data in the per-instance area.102*103* new_fsk called when a flowset is linked to a scheduler,104* e.g. to validate parameters such as weights etc.105* free_fsk when a flowset is unlinked from a scheduler.106* (probably unnecessary)107*108* new_queue called to set the per-queue parameters,109* e.g. S and F, adjust sum of weights in the parent, etc.110*111* The new_queue callback is normally called from when112* creating a new queue. In some cases (such as a113* scheduler change or reconfiguration) it can be called114* with a non empty queue. In this case, the queue115* In case of non empty queue, the new_queue callback could116* need to call the enqueue function. In this case,117* the callback should eventually call enqueue() passing118* as m the first element in the queue.119*120* free_queue actions related to a queue removal, e.g. undo121* all the above. If the queue has data in it, also remove122* from the scheduler. This can e.g. happen during a reconfigure.123*/124int (*enqueue)(struct dn_sch_inst *, struct dn_queue *,125struct mbuf *);126struct mbuf * (*dequeue)(struct dn_sch_inst *);127128int (*config)(struct dn_schk *);129int (*destroy)(struct dn_schk*);130int (*new_sched)(struct dn_sch_inst *);131int (*free_sched)(struct dn_sch_inst *);132int (*new_fsk)(struct dn_fsk *f);133int (*free_fsk)(struct dn_fsk *f);134int (*new_queue)(struct dn_queue *q);135int (*free_queue)(struct dn_queue *q);136#ifdef NEW_AQM137/* Getting scheduler extra parameters */138int (*getconfig)(struct dn_schk *, struct dn_extra_parms *);139#endif140141/* run-time fields */142int ref_count; /* XXX number of instances in the system */143CK_LIST_ENTRY(dn_alg) next; /* Next scheduler in the list */144};145146/* MSVC does not support initializers so we need this ugly macro */147#ifdef _WIN32148#define _SI(fld)149#else150#define _SI(fld) fld151#endif152153/*154* Additionally, dummynet exports some functions and macros155* to be used by schedulers:156*/157158void dn_free_pkts(struct mbuf *mnext);159int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);160/* bound a variable between min and max */161int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);162163/*164* Extract the head of a queue, update stats. Must be the very last165* thing done on a dequeue as the queue itself may go away.166*/167static __inline struct mbuf*168dn_dequeue(struct dn_queue *q)169{170struct mbuf *m;171172next:173m = q->mq.head;174if (m == NULL)175return NULL;176#ifdef NEW_AQM177/* Call AQM dequeue function */178if (q->fs->aqmfp && q->fs->aqmfp->dequeue )179return q->fs->aqmfp->dequeue(q);180#endif181q->mq.head = m->m_nextpkt;182q->mq.count--;183184/* Update stats for the queue */185q->ni.length--;186q->ni.len_bytes -= m->m_pkthdr.len;187if (q->_si) {188q->_si->ni.length--;189q->_si->ni.len_bytes -= m->m_pkthdr.len;190}191if (q->ni.length == 0) /* queue is now idle */192q->q_time = V_dn_cfg.curr_time;193if (m->m_pkthdr.rcvif != NULL &&194__predict_false(m_rcvif_restore(m) == NULL)) {195m_freem(m);196goto next;197}198return m;199}200201int dn_sched_modevent(module_t mod, int cmd, void *arg);202203#define DECLARE_DNSCHED_MODULE(name, dnsched) \204static moduledata_t name##_mod = { \205#name, dn_sched_modevent, dnsched \206}; \207DECLARE_MODULE(name, name##_mod, \208SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); \209MODULE_DEPEND(name, dummynet, 3, 3, 3)210#endif /* _DN_SCHED_H */211212213