xref: /freebsd/sys/netpfil/ipfw/ip_dn_glue.c (revision 31cf66d7)
13b3a8eb9SGleb Smirnoff /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
43b3a8eb9SGleb Smirnoff  * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
53b3a8eb9SGleb Smirnoff  * All rights reserved
63b3a8eb9SGleb Smirnoff  *
73b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
83b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
93b3a8eb9SGleb Smirnoff  * are met:
103b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
113b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
123b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
133b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
143b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
153b3a8eb9SGleb Smirnoff  *
163b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b3a8eb9SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b3a8eb9SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b3a8eb9SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b3a8eb9SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b3a8eb9SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b3a8eb9SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b3a8eb9SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b3a8eb9SGleb Smirnoff  * SUCH DAMAGE.
273b3a8eb9SGleb Smirnoff  */
283b3a8eb9SGleb Smirnoff 
293b3a8eb9SGleb Smirnoff /*
303b3a8eb9SGleb Smirnoff  *
313b3a8eb9SGleb Smirnoff  * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8
323b3a8eb9SGleb Smirnoff  */
333b3a8eb9SGleb Smirnoff 
343b3a8eb9SGleb Smirnoff #include "opt_inet6.h"
353b3a8eb9SGleb Smirnoff 
363b3a8eb9SGleb Smirnoff #include <sys/param.h>
373b3a8eb9SGleb Smirnoff #include <sys/systm.h>
383b3a8eb9SGleb Smirnoff #include <sys/malloc.h>
393b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
403b3a8eb9SGleb Smirnoff #include <sys/kernel.h>
413b3a8eb9SGleb Smirnoff #include <sys/lock.h>
423b3a8eb9SGleb Smirnoff #include <sys/module.h>
433b3a8eb9SGleb Smirnoff #include <sys/priv.h>
443b3a8eb9SGleb Smirnoff #include <sys/proc.h>
453b3a8eb9SGleb Smirnoff #include <sys/rwlock.h>
463b3a8eb9SGleb Smirnoff #include <sys/socket.h>
473b3a8eb9SGleb Smirnoff #include <sys/socketvar.h>
483b3a8eb9SGleb Smirnoff #include <sys/time.h>
493b3a8eb9SGleb Smirnoff #include <sys/taskqueue.h>
503b3a8eb9SGleb Smirnoff #include <net/if.h>	/* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
513b3a8eb9SGleb Smirnoff #include <netinet/in.h>
523b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h>	/* ip_output(), IP_FORWARDING */
533b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h>
543b3a8eb9SGleb Smirnoff #include <netinet/ip_dummynet.h>
553b3a8eb9SGleb Smirnoff 
563b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h>
573b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/dn_heap.h>
583b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_dn_private.h>
5991336b40SDon Lewis #ifdef NEW_AQM
6091336b40SDon Lewis #include <netpfil/ipfw/dn_aqm.h>
6191336b40SDon Lewis #endif
623b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/dn_sched.h>
633b3a8eb9SGleb Smirnoff 
643b3a8eb9SGleb Smirnoff /* FREEBSD7.2 ip_dummynet.h r191715*/
653b3a8eb9SGleb Smirnoff 
663b3a8eb9SGleb Smirnoff struct dn_heap_entry7 {
673b3a8eb9SGleb Smirnoff 	int64_t key;        /* sorting key. Topmost element is smallest one */
683b3a8eb9SGleb Smirnoff 	void *object;      /* object pointer */
693b3a8eb9SGleb Smirnoff };
703b3a8eb9SGleb Smirnoff 
713b3a8eb9SGleb Smirnoff struct dn_heap7 {
723b3a8eb9SGleb Smirnoff 	int size;
733b3a8eb9SGleb Smirnoff 	int elements;
743b3a8eb9SGleb Smirnoff 	int offset; /* XXX if > 0 this is the offset of direct ptr to obj */
753b3a8eb9SGleb Smirnoff 	struct dn_heap_entry7 *p;   /* really an array of "size" entries */
763b3a8eb9SGleb Smirnoff };
773b3a8eb9SGleb Smirnoff 
783b3a8eb9SGleb Smirnoff /* Common to 7.2 and 8 */
793b3a8eb9SGleb Smirnoff struct dn_flow_set {
803b3a8eb9SGleb Smirnoff 	SLIST_ENTRY(dn_flow_set) next;	/* linked list in a hash slot */
813b3a8eb9SGleb Smirnoff 
823b3a8eb9SGleb Smirnoff 	u_short fs_nr ;			/* flow_set number       */
833b3a8eb9SGleb Smirnoff 	u_short flags_fs;
843b3a8eb9SGleb Smirnoff #define DNOLD_HAVE_FLOW_MASK   0x0001
853b3a8eb9SGleb Smirnoff #define DNOLD_IS_RED           0x0002
863b3a8eb9SGleb Smirnoff #define DNOLD_IS_GENTLE_RED    0x0004
873b3a8eb9SGleb Smirnoff #define DNOLD_QSIZE_IS_BYTES   0x0008	/* queue size is measured in bytes */
883b3a8eb9SGleb Smirnoff #define DNOLD_NOERROR          0x0010	/* do not report ENOBUFS on drops  */
893b3a8eb9SGleb Smirnoff #define DNOLD_HAS_PROFILE      0x0020	/* the pipe has a delay profile. */
903b3a8eb9SGleb Smirnoff #define DNOLD_IS_PIPE          0x4000
913b3a8eb9SGleb Smirnoff #define DNOLD_IS_QUEUE         0x8000
923b3a8eb9SGleb Smirnoff 
933b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *pipe ;		/* pointer to parent pipe */
943b3a8eb9SGleb Smirnoff 	u_short parent_nr ;		/* parent pipe#, 0 if local to a pipe */
953b3a8eb9SGleb Smirnoff 
963b3a8eb9SGleb Smirnoff 	int weight ;			/* WFQ queue weight */
973b3a8eb9SGleb Smirnoff 	int qsize ;			/* queue size in slots or bytes */
9831cf66d7SRichard Scheffenegger 	int plr[4] ;			/* pkt loss rate (2^31-1 means 100%) */
993b3a8eb9SGleb Smirnoff 
1003b3a8eb9SGleb Smirnoff 	struct ipfw_flow_id flow_mask ;
1013b3a8eb9SGleb Smirnoff 
1023b3a8eb9SGleb Smirnoff 	/* hash table of queues onto this flow_set */
1033b3a8eb9SGleb Smirnoff 	int rq_size ;			/* number of slots */
1043b3a8eb9SGleb Smirnoff 	int rq_elements ;		/* active elements */
1053b3a8eb9SGleb Smirnoff 	struct dn_flow_queue7 **rq ;	/* array of rq_size entries */
1063b3a8eb9SGleb Smirnoff 
1073b3a8eb9SGleb Smirnoff 	u_int32_t last_expired ;	/* do not expire too frequently */
1083b3a8eb9SGleb Smirnoff 	int backlogged ;		/* #active queues for this flowset */
1093b3a8eb9SGleb Smirnoff 
1103b3a8eb9SGleb Smirnoff         /* RED parameters */
1113b3a8eb9SGleb Smirnoff #define SCALE_RED               16
1123b3a8eb9SGleb Smirnoff #define SCALE(x)                ( (x) << SCALE_RED )
1133b3a8eb9SGleb Smirnoff #define SCALE_VAL(x)            ( (x) >> SCALE_RED )
1143b3a8eb9SGleb Smirnoff #define SCALE_MUL(x,y)          ( ( (x) * (y) ) >> SCALE_RED )
1153b3a8eb9SGleb Smirnoff 	int w_q ;           /* queue weight (scaled) */
1163b3a8eb9SGleb Smirnoff 	int max_th ;        /* maximum threshold for queue (scaled) */
1173b3a8eb9SGleb Smirnoff 	int min_th ;        /* minimum threshold for queue (scaled) */
1183b3a8eb9SGleb Smirnoff 	int max_p ;         /* maximum value for p_b (scaled) */
1193b3a8eb9SGleb Smirnoff 	u_int c_1 ;         /* max_p/(max_th-min_th) (scaled) */
1203b3a8eb9SGleb Smirnoff 	u_int c_2 ;         /* max_p*min_th/(max_th-min_th) (scaled) */
1213b3a8eb9SGleb Smirnoff 	u_int c_3 ;         /* for GRED, (1-max_p)/max_th (scaled) */
1223b3a8eb9SGleb Smirnoff 	u_int c_4 ;         /* for GRED, 1 - 2*max_p (scaled) */
1233b3a8eb9SGleb Smirnoff 	u_int * w_q_lookup ;    /* lookup table for computing (1-w_q)^t */
1243b3a8eb9SGleb Smirnoff 	u_int lookup_depth ;    /* depth of lookup table */
1253b3a8eb9SGleb Smirnoff 	int lookup_step ;       /* granularity inside the lookup table */
1263b3a8eb9SGleb Smirnoff 	int lookup_weight ;     /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
1273b3a8eb9SGleb Smirnoff 	int avg_pkt_size ;      /* medium packet size */
1283b3a8eb9SGleb Smirnoff 	int max_pkt_size ;      /* max packet size */
1293b3a8eb9SGleb Smirnoff };
1303b3a8eb9SGleb Smirnoff SLIST_HEAD(dn_flow_set_head, dn_flow_set);
1313b3a8eb9SGleb Smirnoff 
1323b3a8eb9SGleb Smirnoff #define DN_IS_PIPE		0x4000
1333b3a8eb9SGleb Smirnoff #define DN_IS_QUEUE		0x8000
1343b3a8eb9SGleb Smirnoff struct dn_flow_queue7 {
1353b3a8eb9SGleb Smirnoff 	struct dn_flow_queue7 *next ;
1363b3a8eb9SGleb Smirnoff 	struct ipfw_flow_id id ;
1373b3a8eb9SGleb Smirnoff 
1383b3a8eb9SGleb Smirnoff 	struct mbuf *head, *tail ;  /* queue of packets */
1393b3a8eb9SGleb Smirnoff 	u_int len ;
1403b3a8eb9SGleb Smirnoff 	u_int len_bytes ;
1413b3a8eb9SGleb Smirnoff 
1423b3a8eb9SGleb Smirnoff 	u_long numbytes;
1433b3a8eb9SGleb Smirnoff 
1443b3a8eb9SGleb Smirnoff 	u_int64_t tot_pkts ;    /* statistics counters  */
1453b3a8eb9SGleb Smirnoff 	u_int64_t tot_bytes ;
1463b3a8eb9SGleb Smirnoff 	u_int32_t drops ;
1473b3a8eb9SGleb Smirnoff 
1483b3a8eb9SGleb Smirnoff 	int hash_slot ;     /* debugging/diagnostic */
1493b3a8eb9SGleb Smirnoff 
1503b3a8eb9SGleb Smirnoff 	/* RED parameters */
1513b3a8eb9SGleb Smirnoff 	int avg ;                   /* average queue length est. (scaled) */
1523b3a8eb9SGleb Smirnoff 	int count ;                 /* arrivals since last RED drop */
1533b3a8eb9SGleb Smirnoff 	int random ;                /* random value (scaled) */
1543b3a8eb9SGleb Smirnoff 	u_int32_t q_time;      /* start of queue idle time */
1553b3a8eb9SGleb Smirnoff 
1563b3a8eb9SGleb Smirnoff 	/* WF2Q+ support */
1573b3a8eb9SGleb Smirnoff 	struct dn_flow_set *fs ;    /* parent flow set */
1583b3a8eb9SGleb Smirnoff 	int heap_pos ;      /* position (index) of struct in heap */
1593b3a8eb9SGleb Smirnoff 	int64_t sched_time ;     /* current time when queue enters ready_heap */
1603b3a8eb9SGleb Smirnoff 
1613b3a8eb9SGleb Smirnoff 	int64_t S,F ;        /* start time, finish time */
1623b3a8eb9SGleb Smirnoff };
1633b3a8eb9SGleb Smirnoff 
1643b3a8eb9SGleb Smirnoff struct dn_pipe7 {        /* a pipe */
1653b3a8eb9SGleb Smirnoff 	SLIST_ENTRY(dn_pipe7)    next;   /* linked list in a hash slot */
1663b3a8eb9SGleb Smirnoff 
1673b3a8eb9SGleb Smirnoff 	int pipe_nr ;       /* number   */
16820ffd88eSLuiz Otavio O Souza 	uint32_t bandwidth;      /* really, bytes/tick.  */
1693b3a8eb9SGleb Smirnoff 	int delay ;         /* really, ticks    */
1703b3a8eb9SGleb Smirnoff 
1713b3a8eb9SGleb Smirnoff 	struct  mbuf *head, *tail ; /* packets in delay line */
1723b3a8eb9SGleb Smirnoff 
1733b3a8eb9SGleb Smirnoff 	/* WF2Q+ */
1743b3a8eb9SGleb Smirnoff 	struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
1753b3a8eb9SGleb Smirnoff 	struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
1763b3a8eb9SGleb Smirnoff 	struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
1773b3a8eb9SGleb Smirnoff 
1783b3a8eb9SGleb Smirnoff 	int64_t V ;          /* virtual time */
1793b3a8eb9SGleb Smirnoff 	int sum;            /* sum of weights of all active sessions */
1803b3a8eb9SGleb Smirnoff 
1813b3a8eb9SGleb Smirnoff 	int numbytes;
1823b3a8eb9SGleb Smirnoff 
1833b3a8eb9SGleb Smirnoff 	int64_t sched_time ;     /* time pipe was scheduled in ready_heap */
1843b3a8eb9SGleb Smirnoff 
1853b3a8eb9SGleb Smirnoff 	/*
1863b3a8eb9SGleb Smirnoff 	* When the tx clock come from an interface (if_name[0] != '\0'), its name
1873b3a8eb9SGleb Smirnoff 	* is stored below, whereas the ifp is filled when the rule is configured.
1883b3a8eb9SGleb Smirnoff 	*/
1893b3a8eb9SGleb Smirnoff 	char if_name[IFNAMSIZ];
1903b3a8eb9SGleb Smirnoff 	struct ifnet *ifp ;
1913b3a8eb9SGleb Smirnoff 	int ready ; /* set if ifp != NULL and we got a signal from it */
1923b3a8eb9SGleb Smirnoff 
1933b3a8eb9SGleb Smirnoff 	struct dn_flow_set fs ; /* used with fixed-rate flows */
1943b3a8eb9SGleb Smirnoff };
1953b3a8eb9SGleb Smirnoff SLIST_HEAD(dn_pipe_head7, dn_pipe7);
1963b3a8eb9SGleb Smirnoff 
1973b3a8eb9SGleb Smirnoff /* FREEBSD8 ip_dummynet.h r196045 */
1983b3a8eb9SGleb Smirnoff struct dn_flow_queue8 {
1993b3a8eb9SGleb Smirnoff 	struct dn_flow_queue8 *next ;
2003b3a8eb9SGleb Smirnoff 	struct ipfw_flow_id id ;
2013b3a8eb9SGleb Smirnoff 
2023b3a8eb9SGleb Smirnoff 	struct mbuf *head, *tail ;  /* queue of packets */
2033b3a8eb9SGleb Smirnoff 	u_int len ;
2043b3a8eb9SGleb Smirnoff 	u_int len_bytes ;
2053b3a8eb9SGleb Smirnoff 
2063b3a8eb9SGleb Smirnoff 	uint64_t numbytes ;     /* credit for transmission (dynamic queues) */
2073b3a8eb9SGleb Smirnoff 	int64_t extra_bits;     /* extra bits simulating unavailable channel */
2083b3a8eb9SGleb Smirnoff 
2093b3a8eb9SGleb Smirnoff 	u_int64_t tot_pkts ;    /* statistics counters  */
2103b3a8eb9SGleb Smirnoff 	u_int64_t tot_bytes ;
2113b3a8eb9SGleb Smirnoff 	u_int32_t drops ;
2123b3a8eb9SGleb Smirnoff 
2133b3a8eb9SGleb Smirnoff 	int hash_slot ;     /* debugging/diagnostic */
2143b3a8eb9SGleb Smirnoff 
2153b3a8eb9SGleb Smirnoff 	/* RED parameters */
2163b3a8eb9SGleb Smirnoff 	int avg ;                   /* average queue length est. (scaled) */
2173b3a8eb9SGleb Smirnoff 	int count ;                 /* arrivals since last RED drop */
2183b3a8eb9SGleb Smirnoff 	int random ;                /* random value (scaled) */
2193b3a8eb9SGleb Smirnoff 	int64_t idle_time;       /* start of queue idle time */
2203b3a8eb9SGleb Smirnoff 
2213b3a8eb9SGleb Smirnoff 	/* WF2Q+ support */
2223b3a8eb9SGleb Smirnoff 	struct dn_flow_set *fs ;    /* parent flow set */
2233b3a8eb9SGleb Smirnoff 	int heap_pos ;      /* position (index) of struct in heap */
2243b3a8eb9SGleb Smirnoff 	int64_t sched_time ;     /* current time when queue enters ready_heap */
2253b3a8eb9SGleb Smirnoff 
2263b3a8eb9SGleb Smirnoff 	int64_t S,F ;        /* start time, finish time */
2273b3a8eb9SGleb Smirnoff };
2283b3a8eb9SGleb Smirnoff 
2293b3a8eb9SGleb Smirnoff struct dn_pipe8 {        /* a pipe */
2303b3a8eb9SGleb Smirnoff 	SLIST_ENTRY(dn_pipe8)    next;   /* linked list in a hash slot */
2313b3a8eb9SGleb Smirnoff 
2323b3a8eb9SGleb Smirnoff 	int pipe_nr ;       /* number   */
23320ffd88eSLuiz Otavio O Souza 	uint32_t bandwidth;      /* really, bytes/tick.  */
2343b3a8eb9SGleb Smirnoff 	int delay ;         /* really, ticks    */
2353b3a8eb9SGleb Smirnoff 
2363b3a8eb9SGleb Smirnoff 	struct  mbuf *head, *tail ; /* packets in delay line */
2373b3a8eb9SGleb Smirnoff 
2383b3a8eb9SGleb Smirnoff 	/* WF2Q+ */
2393b3a8eb9SGleb Smirnoff 	struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
2403b3a8eb9SGleb Smirnoff 	struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
2413b3a8eb9SGleb Smirnoff 	struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
2423b3a8eb9SGleb Smirnoff 
2433b3a8eb9SGleb Smirnoff 	int64_t V ;          /* virtual time */
2443b3a8eb9SGleb Smirnoff 	int sum;            /* sum of weights of all active sessions */
2453b3a8eb9SGleb Smirnoff 
2463b3a8eb9SGleb Smirnoff 	/* Same as in dn_flow_queue, numbytes can become large */
2473b3a8eb9SGleb Smirnoff 	int64_t numbytes;       /* bits I can transmit (more or less). */
2483b3a8eb9SGleb Smirnoff 	uint64_t burst;     /* burst size, scaled: bits * hz */
2493b3a8eb9SGleb Smirnoff 
2503b3a8eb9SGleb Smirnoff 	int64_t sched_time ;     /* time pipe was scheduled in ready_heap */
2513b3a8eb9SGleb Smirnoff 	int64_t idle_time;       /* start of pipe idle time */
2523b3a8eb9SGleb Smirnoff 
2533b3a8eb9SGleb Smirnoff 	char if_name[IFNAMSIZ];
2543b3a8eb9SGleb Smirnoff 	struct ifnet *ifp ;
2553b3a8eb9SGleb Smirnoff 	int ready ; /* set if ifp != NULL and we got a signal from it */
2563b3a8eb9SGleb Smirnoff 
2573b3a8eb9SGleb Smirnoff 	struct dn_flow_set fs ; /* used with fixed-rate flows */
2583b3a8eb9SGleb Smirnoff 
2593b3a8eb9SGleb Smirnoff     /* fields to simulate a delay profile */
2603b3a8eb9SGleb Smirnoff #define ED_MAX_NAME_LEN     32
2613b3a8eb9SGleb Smirnoff 	char name[ED_MAX_NAME_LEN];
2623b3a8eb9SGleb Smirnoff 	int loss_level;
2633b3a8eb9SGleb Smirnoff 	int samples_no;
2643b3a8eb9SGleb Smirnoff 	int *samples;
2653b3a8eb9SGleb Smirnoff };
2663b3a8eb9SGleb Smirnoff 
2673b3a8eb9SGleb Smirnoff #define ED_MAX_SAMPLES_NO   1024
2683b3a8eb9SGleb Smirnoff struct dn_pipe_max8 {
2693b3a8eb9SGleb Smirnoff 	struct dn_pipe8 pipe;
2703b3a8eb9SGleb Smirnoff 	int samples[ED_MAX_SAMPLES_NO];
2713b3a8eb9SGleb Smirnoff };
2723b3a8eb9SGleb Smirnoff SLIST_HEAD(dn_pipe_head8, dn_pipe8);
2733b3a8eb9SGleb Smirnoff 
2743b3a8eb9SGleb Smirnoff /*
2753b3a8eb9SGleb Smirnoff  * Changes from 7.2 to 8:
2763b3a8eb9SGleb Smirnoff  * dn_pipe:
2773b3a8eb9SGleb Smirnoff  *      numbytes from int to int64_t
2783b3a8eb9SGleb Smirnoff  *      add burst (int64_t)
2793b3a8eb9SGleb Smirnoff  *      add idle_time (int64_t)
2803b3a8eb9SGleb Smirnoff  *      add profile
2813b3a8eb9SGleb Smirnoff  *      add struct dn_pipe_max
2823b3a8eb9SGleb Smirnoff  *      add flag DN_HAS_PROFILE
2833b3a8eb9SGleb Smirnoff  *
2843b3a8eb9SGleb Smirnoff  * dn_flow_queue
2853b3a8eb9SGleb Smirnoff  *      numbytes from u_long to int64_t
2863b3a8eb9SGleb Smirnoff  *      add extra_bits (int64_t)
2873b3a8eb9SGleb Smirnoff  *      q_time from u_int32_t to int64_t and name idle_time
2883b3a8eb9SGleb Smirnoff  *
2893b3a8eb9SGleb Smirnoff  * dn_flow_set unchanged
2903b3a8eb9SGleb Smirnoff  *
2913b3a8eb9SGleb Smirnoff  */
2923b3a8eb9SGleb Smirnoff 
2933b3a8eb9SGleb Smirnoff /* NOTE:XXX copied from dummynet.c */
2943b3a8eb9SGleb Smirnoff #define O_NEXT(p, len) ((void *)((char *)p + len))
2953b3a8eb9SGleb Smirnoff static void
oid_fill(struct dn_id * oid,int len,int type,uintptr_t id)2963b3a8eb9SGleb Smirnoff oid_fill(struct dn_id *oid, int len, int type, uintptr_t id)
2973b3a8eb9SGleb Smirnoff {
2983b3a8eb9SGleb Smirnoff 	oid->len = len;
2993b3a8eb9SGleb Smirnoff 	oid->type = type;
3003b3a8eb9SGleb Smirnoff 	oid->subtype = 0;
3013b3a8eb9SGleb Smirnoff 	oid->id = id;
3023b3a8eb9SGleb Smirnoff }
3033b3a8eb9SGleb Smirnoff /* make room in the buffer and move the pointer forward */
3043b3a8eb9SGleb Smirnoff static void *
o_next(struct dn_id ** o,int len,int type)3053b3a8eb9SGleb Smirnoff o_next(struct dn_id **o, int len, int type)
3063b3a8eb9SGleb Smirnoff {
3073b3a8eb9SGleb Smirnoff 	struct dn_id *ret = *o;
3083b3a8eb9SGleb Smirnoff 	oid_fill(ret, len, type, 0);
3093b3a8eb9SGleb Smirnoff 	*o = O_NEXT(*o, len);
3103b3a8eb9SGleb Smirnoff 	return ret;
3113b3a8eb9SGleb Smirnoff }
3123b3a8eb9SGleb Smirnoff 
3133b3a8eb9SGleb Smirnoff static size_t pipesize7 = sizeof(struct dn_pipe7);
3143b3a8eb9SGleb Smirnoff static size_t pipesize8 = sizeof(struct dn_pipe8);
3153b3a8eb9SGleb Smirnoff static size_t pipesizemax8 = sizeof(struct dn_pipe_max8);
3163b3a8eb9SGleb Smirnoff 
3173b3a8eb9SGleb Smirnoff /* Indicate 'ipfw' version
3183b3a8eb9SGleb Smirnoff  * 1: from FreeBSD 7.2
3193b3a8eb9SGleb Smirnoff  * 0: from FreeBSD 8
32010d66948SKevin Lo  * -1: unknown (for now is unused)
3213b3a8eb9SGleb Smirnoff  *
3223b3a8eb9SGleb Smirnoff  * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives
32310d66948SKevin Lo  * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknown,
3243b3a8eb9SGleb Smirnoff  *       it is suppose to be the FreeBSD 8 version.
3253b3a8eb9SGleb Smirnoff  */
3263b3a8eb9SGleb Smirnoff static int is7 = 0;
3273b3a8eb9SGleb Smirnoff 
3283b3a8eb9SGleb Smirnoff static int
convertflags2new(int src)3293b3a8eb9SGleb Smirnoff convertflags2new(int src)
3303b3a8eb9SGleb Smirnoff {
3313b3a8eb9SGleb Smirnoff 	int dst = 0;
3323b3a8eb9SGleb Smirnoff 
3333b3a8eb9SGleb Smirnoff 	if (src & DNOLD_HAVE_FLOW_MASK)
3343b3a8eb9SGleb Smirnoff 		dst |= DN_HAVE_MASK;
3353b3a8eb9SGleb Smirnoff 	if (src & DNOLD_QSIZE_IS_BYTES)
3363b3a8eb9SGleb Smirnoff 		dst |= DN_QSIZE_BYTES;
3373b3a8eb9SGleb Smirnoff 	if (src & DNOLD_NOERROR)
3383b3a8eb9SGleb Smirnoff 		dst |= DN_NOERROR;
3393b3a8eb9SGleb Smirnoff 	if (src & DNOLD_IS_RED)
3403b3a8eb9SGleb Smirnoff 		dst |= DN_IS_RED;
3413b3a8eb9SGleb Smirnoff 	if (src & DNOLD_IS_GENTLE_RED)
3423b3a8eb9SGleb Smirnoff 		dst |= DN_IS_GENTLE_RED;
3433b3a8eb9SGleb Smirnoff 	if (src & DNOLD_HAS_PROFILE)
3443b3a8eb9SGleb Smirnoff 		dst |= DN_HAS_PROFILE;
3453b3a8eb9SGleb Smirnoff 
3463b3a8eb9SGleb Smirnoff 	return dst;
3473b3a8eb9SGleb Smirnoff }
3483b3a8eb9SGleb Smirnoff 
3493b3a8eb9SGleb Smirnoff static int
convertflags2old(int src)3503b3a8eb9SGleb Smirnoff convertflags2old(int src)
3513b3a8eb9SGleb Smirnoff {
3523b3a8eb9SGleb Smirnoff 	int dst = 0;
3533b3a8eb9SGleb Smirnoff 
3543b3a8eb9SGleb Smirnoff 	if (src & DN_HAVE_MASK)
3553b3a8eb9SGleb Smirnoff 		dst |= DNOLD_HAVE_FLOW_MASK;
3563b3a8eb9SGleb Smirnoff 	if (src & DN_IS_RED)
3573b3a8eb9SGleb Smirnoff 		dst |= DNOLD_IS_RED;
3583b3a8eb9SGleb Smirnoff 	if (src & DN_IS_GENTLE_RED)
3593b3a8eb9SGleb Smirnoff 		dst |= DNOLD_IS_GENTLE_RED;
3603b3a8eb9SGleb Smirnoff 	if (src & DN_NOERROR)
3613b3a8eb9SGleb Smirnoff 		dst |= DNOLD_NOERROR;
3623b3a8eb9SGleb Smirnoff 	if (src & DN_HAS_PROFILE)
3633b3a8eb9SGleb Smirnoff 		dst |= DNOLD_HAS_PROFILE;
3643b3a8eb9SGleb Smirnoff 	if (src & DN_QSIZE_BYTES)
3653b3a8eb9SGleb Smirnoff 		dst |= DNOLD_QSIZE_IS_BYTES;
3663b3a8eb9SGleb Smirnoff 
3673b3a8eb9SGleb Smirnoff 	return dst;
3683b3a8eb9SGleb Smirnoff }
3693b3a8eb9SGleb Smirnoff 
3703b3a8eb9SGleb Smirnoff static int
dn_compat_del(void * v)3713b3a8eb9SGleb Smirnoff dn_compat_del(void *v)
3723b3a8eb9SGleb Smirnoff {
3733b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *p = (struct dn_pipe7 *) v;
3743b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *p8 = (struct dn_pipe8 *) v;
3753b3a8eb9SGleb Smirnoff 	struct {
3763b3a8eb9SGleb Smirnoff 		struct dn_id oid;
3773b3a8eb9SGleb Smirnoff 		uintptr_t a[1];	/* add more if we want a list */
3783b3a8eb9SGleb Smirnoff 	} cmd;
3793b3a8eb9SGleb Smirnoff 
3803b3a8eb9SGleb Smirnoff 	/* XXX DN_API_VERSION ??? */
3813b3a8eb9SGleb Smirnoff 	oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);
3823b3a8eb9SGleb Smirnoff 
3833b3a8eb9SGleb Smirnoff 	if (is7) {
3843b3a8eb9SGleb Smirnoff 		if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
3853b3a8eb9SGleb Smirnoff 			return EINVAL;
3863b3a8eb9SGleb Smirnoff 		if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
3873b3a8eb9SGleb Smirnoff 			return EINVAL;
3883b3a8eb9SGleb Smirnoff 	} else {
3893b3a8eb9SGleb Smirnoff 		if (p8->pipe_nr == 0 && p8->fs.fs_nr == 0)
3903b3a8eb9SGleb Smirnoff 			return EINVAL;
3913b3a8eb9SGleb Smirnoff 		if (p8->pipe_nr != 0 && p8->fs.fs_nr != 0)
3923b3a8eb9SGleb Smirnoff 			return EINVAL;
3933b3a8eb9SGleb Smirnoff 	}
3943b3a8eb9SGleb Smirnoff 
3953b3a8eb9SGleb Smirnoff 	if (p->pipe_nr != 0) { /* pipe x delete */
3963b3a8eb9SGleb Smirnoff 		cmd.a[0] = p->pipe_nr;
3973b3a8eb9SGleb Smirnoff 		cmd.oid.subtype = DN_LINK;
3983b3a8eb9SGleb Smirnoff 	} else { /* queue x delete */
3993b3a8eb9SGleb Smirnoff 		cmd.oid.subtype = DN_FS;
4003b3a8eb9SGleb Smirnoff 		cmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr;
4013b3a8eb9SGleb Smirnoff 	}
4023b3a8eb9SGleb Smirnoff 
4033b3a8eb9SGleb Smirnoff 	return do_config(&cmd, cmd.oid.len);
4043b3a8eb9SGleb Smirnoff }
4053b3a8eb9SGleb Smirnoff 
4063b3a8eb9SGleb Smirnoff static int
dn_compat_config_queue(struct dn_fs * fs,void * v)4073b3a8eb9SGleb Smirnoff dn_compat_config_queue(struct dn_fs *fs, void* v)
4083b3a8eb9SGleb Smirnoff {
4093b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
4103b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
4113b3a8eb9SGleb Smirnoff 	struct dn_flow_set *f;
4123b3a8eb9SGleb Smirnoff 
4133b3a8eb9SGleb Smirnoff 	if (is7)
4143b3a8eb9SGleb Smirnoff 		f = &p7->fs;
4153b3a8eb9SGleb Smirnoff 	else
4163b3a8eb9SGleb Smirnoff 		f = &p8->fs;
4173b3a8eb9SGleb Smirnoff 
4183b3a8eb9SGleb Smirnoff 	fs->fs_nr = f->fs_nr;
4193b3a8eb9SGleb Smirnoff 	fs->sched_nr = f->parent_nr;
4203b3a8eb9SGleb Smirnoff 	fs->flow_mask = f->flow_mask;
4213b3a8eb9SGleb Smirnoff 	fs->buckets = f->rq_size;
4223b3a8eb9SGleb Smirnoff 	fs->qsize = f->qsize;
42331cf66d7SRichard Scheffenegger 	fs->plr[0] = f->plr[0];
42431cf66d7SRichard Scheffenegger 	fs->plr[1] = f->plr[1];
42531cf66d7SRichard Scheffenegger 	fs->plr[2] = f->plr[2];
42631cf66d7SRichard Scheffenegger 	fs->plr[3] = f->plr[3];
4273b3a8eb9SGleb Smirnoff 	fs->par[0] = f->weight;
4283b3a8eb9SGleb Smirnoff 	fs->flags = convertflags2new(f->flags_fs);
4293b3a8eb9SGleb Smirnoff 	if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {
4303b3a8eb9SGleb Smirnoff 		fs->w_q = f->w_q;
4313b3a8eb9SGleb Smirnoff 		fs->max_th = f->max_th;
4323b3a8eb9SGleb Smirnoff 		fs->min_th = f->min_th;
4333b3a8eb9SGleb Smirnoff 		fs->max_p = f->max_p;
4343b3a8eb9SGleb Smirnoff 	}
4353b3a8eb9SGleb Smirnoff 
4363b3a8eb9SGleb Smirnoff 	return 0;
4373b3a8eb9SGleb Smirnoff }
4383b3a8eb9SGleb Smirnoff 
4393b3a8eb9SGleb Smirnoff static int
dn_compat_config_pipe(struct dn_sch * sch,struct dn_link * p,struct dn_fs * fs,void * v)4403b3a8eb9SGleb Smirnoff dn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p,
4413b3a8eb9SGleb Smirnoff 		      struct dn_fs *fs, void* v)
4423b3a8eb9SGleb Smirnoff {
4433b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
4443b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
4453b3a8eb9SGleb Smirnoff 	int i = p7->pipe_nr;
4463b3a8eb9SGleb Smirnoff 
4473b3a8eb9SGleb Smirnoff 	sch->sched_nr = i;
4483b3a8eb9SGleb Smirnoff 	sch->oid.subtype = 0;
4493b3a8eb9SGleb Smirnoff 	p->link_nr = i;
4503b3a8eb9SGleb Smirnoff 	fs->fs_nr = i + 2*DN_MAX_ID;
4513b3a8eb9SGleb Smirnoff 	fs->sched_nr = i + DN_MAX_ID;
4523b3a8eb9SGleb Smirnoff 
4533b3a8eb9SGleb Smirnoff 	/* Common to 7 and 8 */
4543b3a8eb9SGleb Smirnoff 	p->bandwidth = p7->bandwidth;
4553b3a8eb9SGleb Smirnoff 	p->delay = p7->delay;
4563b3a8eb9SGleb Smirnoff 	if (!is7) {
4573b3a8eb9SGleb Smirnoff 		/* FreeBSD 8 has burst  */
4583b3a8eb9SGleb Smirnoff 		p->burst = p8->burst;
4593b3a8eb9SGleb Smirnoff 	}
4603b3a8eb9SGleb Smirnoff 
4613b3a8eb9SGleb Smirnoff 	/* fill the fifo flowset */
4623b3a8eb9SGleb Smirnoff 	dn_compat_config_queue(fs, v);
4633b3a8eb9SGleb Smirnoff 	fs->fs_nr = i + 2*DN_MAX_ID;
4643b3a8eb9SGleb Smirnoff 	fs->sched_nr = i + DN_MAX_ID;
4653b3a8eb9SGleb Smirnoff 
4663b3a8eb9SGleb Smirnoff 	/* Move scheduler related parameter from fs to sch */
4673b3a8eb9SGleb Smirnoff 	sch->buckets = fs->buckets; /*XXX*/
4683b3a8eb9SGleb Smirnoff 	fs->buckets = 0;
4693b3a8eb9SGleb Smirnoff 	if (fs->flags & DN_HAVE_MASK) {
4703b3a8eb9SGleb Smirnoff 		sch->flags |= DN_HAVE_MASK;
4713b3a8eb9SGleb Smirnoff 		fs->flags &= ~DN_HAVE_MASK;
4723b3a8eb9SGleb Smirnoff 		sch->sched_mask = fs->flow_mask;
4733b3a8eb9SGleb Smirnoff 		bzero(&fs->flow_mask, sizeof(struct ipfw_flow_id));
4743b3a8eb9SGleb Smirnoff 	}
4753b3a8eb9SGleb Smirnoff 
4763b3a8eb9SGleb Smirnoff 	return 0;
4773b3a8eb9SGleb Smirnoff }
4783b3a8eb9SGleb Smirnoff 
4793b3a8eb9SGleb Smirnoff static int
dn_compat_config_profile(struct dn_profile * pf,struct dn_link * p,void * v)4803b3a8eb9SGleb Smirnoff dn_compat_config_profile(struct dn_profile *pf, struct dn_link *p,
4813b3a8eb9SGleb Smirnoff 			 void *v)
4823b3a8eb9SGleb Smirnoff {
4833b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
4843b3a8eb9SGleb Smirnoff 
4853b3a8eb9SGleb Smirnoff 	p8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]);
4863b3a8eb9SGleb Smirnoff 
4873b3a8eb9SGleb Smirnoff 	pf->link_nr = p->link_nr;
4883b3a8eb9SGleb Smirnoff 	pf->loss_level = p8->loss_level;
4893b3a8eb9SGleb Smirnoff // 	pf->bandwidth = p->bandwidth; //XXX bandwidth redundant?
4903b3a8eb9SGleb Smirnoff 	pf->samples_no = p8->samples_no;
4913b3a8eb9SGleb Smirnoff 	strncpy(pf->name, p8->name,sizeof(pf->name));
4923b3a8eb9SGleb Smirnoff 	bcopy(p8->samples, pf->samples, sizeof(pf->samples));
4933b3a8eb9SGleb Smirnoff 
4943b3a8eb9SGleb Smirnoff 	return 0;
4953b3a8eb9SGleb Smirnoff }
4963b3a8eb9SGleb Smirnoff 
4973b3a8eb9SGleb Smirnoff /*
4983b3a8eb9SGleb Smirnoff  * If p->pipe_nr != 0 the command is 'pipe x config', so need to create
4993b3a8eb9SGleb Smirnoff  * the three main struct, else only a flowset is created
5003b3a8eb9SGleb Smirnoff  */
5013b3a8eb9SGleb Smirnoff static int
dn_compat_configure(void * v)5023b3a8eb9SGleb Smirnoff dn_compat_configure(void *v)
5033b3a8eb9SGleb Smirnoff {
5043b3a8eb9SGleb Smirnoff 	struct dn_id *buf = NULL, *base;
5053b3a8eb9SGleb Smirnoff 	struct dn_sch *sch = NULL;
5063b3a8eb9SGleb Smirnoff 	struct dn_link *p = NULL;
5073b3a8eb9SGleb Smirnoff 	struct dn_fs *fs = NULL;
5083b3a8eb9SGleb Smirnoff 	struct dn_profile *pf = NULL;
5093b3a8eb9SGleb Smirnoff 	int lmax;
5103b3a8eb9SGleb Smirnoff 	int error;
5113b3a8eb9SGleb Smirnoff 
5123b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
5133b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
5143b3a8eb9SGleb Smirnoff 
5153b3a8eb9SGleb Smirnoff 	int i; /* number of object to configure */
5163b3a8eb9SGleb Smirnoff 
5173b3a8eb9SGleb Smirnoff 	lmax = sizeof(struct dn_id);	/* command header */
5183b3a8eb9SGleb Smirnoff 	lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
5193b3a8eb9SGleb Smirnoff 		sizeof(struct dn_fs) + sizeof(struct dn_profile);
5203b3a8eb9SGleb Smirnoff 
521eb1b1807SGleb Smirnoff 	base = buf = malloc(lmax, M_DUMMYNET, M_WAITOK|M_ZERO);
5223b3a8eb9SGleb Smirnoff 	o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
5233b3a8eb9SGleb Smirnoff 	base->id = DN_API_VERSION;
5243b3a8eb9SGleb Smirnoff 
5253b3a8eb9SGleb Smirnoff 	/* pipe_nr is the same in p7 and p8 */
5263b3a8eb9SGleb Smirnoff 	i = p7->pipe_nr;
5273b3a8eb9SGleb Smirnoff 	if (i != 0) { /* pipe config */
5283b3a8eb9SGleb Smirnoff 		sch = o_next(&buf, sizeof(*sch), DN_SCH);
5293b3a8eb9SGleb Smirnoff 		p = o_next(&buf, sizeof(*p), DN_LINK);
5303b3a8eb9SGleb Smirnoff 		fs = o_next(&buf, sizeof(*fs), DN_FS);
5313b3a8eb9SGleb Smirnoff 
5323b3a8eb9SGleb Smirnoff 		error = dn_compat_config_pipe(sch, p, fs, v);
5333b3a8eb9SGleb Smirnoff 		if (error) {
5343b3a8eb9SGleb Smirnoff 			free(buf, M_DUMMYNET);
5353b3a8eb9SGleb Smirnoff 			return error;
5363b3a8eb9SGleb Smirnoff 		}
5373b3a8eb9SGleb Smirnoff 		if (!is7 && p8->samples_no > 0) {
5383b3a8eb9SGleb Smirnoff 			/* Add profiles*/
5393b3a8eb9SGleb Smirnoff 			pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
5403b3a8eb9SGleb Smirnoff 			error = dn_compat_config_profile(pf, p, v);
5413b3a8eb9SGleb Smirnoff 			if (error) {
5423b3a8eb9SGleb Smirnoff 				free(buf, M_DUMMYNET);
5433b3a8eb9SGleb Smirnoff 				return error;
5443b3a8eb9SGleb Smirnoff 			}
5453b3a8eb9SGleb Smirnoff 		}
5463b3a8eb9SGleb Smirnoff 	} else { /* queue config */
5473b3a8eb9SGleb Smirnoff 		fs = o_next(&buf, sizeof(*fs), DN_FS);
5483b3a8eb9SGleb Smirnoff 		error = dn_compat_config_queue(fs, v);
5493b3a8eb9SGleb Smirnoff 		if (error) {
5503b3a8eb9SGleb Smirnoff 			free(buf, M_DUMMYNET);
5513b3a8eb9SGleb Smirnoff 			return error;
5523b3a8eb9SGleb Smirnoff 		}
5533b3a8eb9SGleb Smirnoff 	}
5543b3a8eb9SGleb Smirnoff 	error = do_config(base, (char *)buf - (char *)base);
5553b3a8eb9SGleb Smirnoff 
5563b3a8eb9SGleb Smirnoff 	if (buf)
5573b3a8eb9SGleb Smirnoff 		free(buf, M_DUMMYNET);
5583b3a8eb9SGleb Smirnoff 	return error;
5593b3a8eb9SGleb Smirnoff }
5603b3a8eb9SGleb Smirnoff 
5613b3a8eb9SGleb Smirnoff int
dn_compat_calc_size(void)5623b3a8eb9SGleb Smirnoff dn_compat_calc_size(void)
5633b3a8eb9SGleb Smirnoff {
5643b3a8eb9SGleb Smirnoff 	int need = 0;
5653b3a8eb9SGleb Smirnoff 	/* XXX use FreeBSD 8 struct size */
5663b3a8eb9SGleb Smirnoff 	/* NOTE:
5673b3a8eb9SGleb Smirnoff 	 * - half scheduler: 		schk_count/2
5683b3a8eb9SGleb Smirnoff 	 * - all flowset:		fsk_count
5693b3a8eb9SGleb Smirnoff 	 * - all flowset queues:	queue_count
5703b3a8eb9SGleb Smirnoff 	 * - all pipe queue:		si_count
5713b3a8eb9SGleb Smirnoff 	 */
572fe3bcfbdSTom Jones 	need += V_dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2;
573fe3bcfbdSTom Jones 	need += V_dn_cfg.fsk_count * sizeof(struct dn_flow_set);
574fe3bcfbdSTom Jones 	need += V_dn_cfg.si_count * sizeof(struct dn_flow_queue8);
575fe3bcfbdSTom Jones 	need += V_dn_cfg.queue_count * sizeof(struct dn_flow_queue8);
5763b3a8eb9SGleb Smirnoff 
5773b3a8eb9SGleb Smirnoff 	return need;
5783b3a8eb9SGleb Smirnoff }
5793b3a8eb9SGleb Smirnoff 
5803b3a8eb9SGleb Smirnoff int
dn_c_copy_q(void * _ni,void * arg)5813b3a8eb9SGleb Smirnoff dn_c_copy_q (void *_ni, void *arg)
5823b3a8eb9SGleb Smirnoff {
5833b3a8eb9SGleb Smirnoff 	struct copy_args *a = arg;
5843b3a8eb9SGleb Smirnoff 	struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start;
5853b3a8eb9SGleb Smirnoff 	struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start;
5863b3a8eb9SGleb Smirnoff 	struct dn_flow *ni = (struct dn_flow *)_ni;
5873b3a8eb9SGleb Smirnoff 	int size = 0;
5883b3a8eb9SGleb Smirnoff 
5893b3a8eb9SGleb Smirnoff 	/* XXX hash slot not set */
5903b3a8eb9SGleb Smirnoff 	/* No difference between 7.2/8 */
5913b3a8eb9SGleb Smirnoff 	fq7->len = ni->length;
5923b3a8eb9SGleb Smirnoff 	fq7->len_bytes = ni->len_bytes;
5933b3a8eb9SGleb Smirnoff 	fq7->id = ni->fid;
5943b3a8eb9SGleb Smirnoff 
5953b3a8eb9SGleb Smirnoff 	if (is7) {
5963b3a8eb9SGleb Smirnoff 		size = sizeof(struct dn_flow_queue7);
5973b3a8eb9SGleb Smirnoff 		fq7->tot_pkts = ni->tot_pkts;
5983b3a8eb9SGleb Smirnoff 		fq7->tot_bytes = ni->tot_bytes;
5993b3a8eb9SGleb Smirnoff 		fq7->drops = ni->drops;
6003b3a8eb9SGleb Smirnoff 	} else {
6013b3a8eb9SGleb Smirnoff 		size = sizeof(struct dn_flow_queue8);
6023b3a8eb9SGleb Smirnoff 		fq8->tot_pkts = ni->tot_pkts;
6033b3a8eb9SGleb Smirnoff 		fq8->tot_bytes = ni->tot_bytes;
6043b3a8eb9SGleb Smirnoff 		fq8->drops = ni->drops;
6053b3a8eb9SGleb Smirnoff 	}
6063b3a8eb9SGleb Smirnoff 
6073b3a8eb9SGleb Smirnoff 	*a->start += size;
6083b3a8eb9SGleb Smirnoff 	return 0;
6093b3a8eb9SGleb Smirnoff }
6103b3a8eb9SGleb Smirnoff 
6113b3a8eb9SGleb Smirnoff int
dn_c_copy_pipe(struct dn_schk * s,struct copy_args * a,int nq)6123b3a8eb9SGleb Smirnoff dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq)
6133b3a8eb9SGleb Smirnoff {
6143b3a8eb9SGleb Smirnoff 	struct dn_link *l = &s->link;
6153b3a8eb9SGleb Smirnoff 	struct dn_fsk *f = s->fs;
6163b3a8eb9SGleb Smirnoff 
6173b3a8eb9SGleb Smirnoff 	struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start;
6183b3a8eb9SGleb Smirnoff 	struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start;
6193b3a8eb9SGleb Smirnoff 	struct dn_flow_set *fs;
6203b3a8eb9SGleb Smirnoff 	int size = 0;
6213b3a8eb9SGleb Smirnoff 
6223b3a8eb9SGleb Smirnoff 	if (is7) {
6233b3a8eb9SGleb Smirnoff 		fs = &pipe7->fs;
6243b3a8eb9SGleb Smirnoff 		size = sizeof(struct dn_pipe7);
6253b3a8eb9SGleb Smirnoff 	} else {
6263b3a8eb9SGleb Smirnoff 		fs = &pipe8->fs;
6273b3a8eb9SGleb Smirnoff 		size = sizeof(struct dn_pipe8);
6283b3a8eb9SGleb Smirnoff 	}
6293b3a8eb9SGleb Smirnoff 
6303b3a8eb9SGleb Smirnoff 	/* These 4 field are the same in pipe7 and pipe8 */
6313b3a8eb9SGleb Smirnoff 	pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE;
6323b3a8eb9SGleb Smirnoff 	pipe7->bandwidth = l->bandwidth;
6333b3a8eb9SGleb Smirnoff 	pipe7->delay = l->delay * 1000 / hz;
6343b3a8eb9SGleb Smirnoff 	pipe7->pipe_nr = l->link_nr - DN_MAX_ID;
6353b3a8eb9SGleb Smirnoff 
6363b3a8eb9SGleb Smirnoff 	if (!is7) {
6373b3a8eb9SGleb Smirnoff 		if (s->profile) {
6383b3a8eb9SGleb Smirnoff 			struct dn_profile *pf = s->profile;
6393b3a8eb9SGleb Smirnoff 			strncpy(pipe8->name, pf->name, sizeof(pf->name));
6403b3a8eb9SGleb Smirnoff 			pipe8->loss_level = pf->loss_level;
6413b3a8eb9SGleb Smirnoff 			pipe8->samples_no = pf->samples_no;
6423b3a8eb9SGleb Smirnoff 		}
6433b3a8eb9SGleb Smirnoff 		pipe8->burst = div64(l->burst , 8 * hz);
6443b3a8eb9SGleb Smirnoff 	}
6453b3a8eb9SGleb Smirnoff 
6463b3a8eb9SGleb Smirnoff 	fs->flow_mask = s->sch.sched_mask;
6473b3a8eb9SGleb Smirnoff 	fs->rq_size = s->sch.buckets ? s->sch.buckets : 1;
6483b3a8eb9SGleb Smirnoff 
6493b3a8eb9SGleb Smirnoff 	fs->parent_nr = l->link_nr - DN_MAX_ID;
6503b3a8eb9SGleb Smirnoff 	fs->qsize = f->fs.qsize;
65131cf66d7SRichard Scheffenegger 	fs->plr[0] = f->fs.plr[0];
65231cf66d7SRichard Scheffenegger 	fs->plr[1] = f->fs.plr[1];
65331cf66d7SRichard Scheffenegger 	fs->plr[2] = f->fs.plr[2];
65431cf66d7SRichard Scheffenegger 	fs->plr[3] = f->fs.plr[3];
6553b3a8eb9SGleb Smirnoff 	fs->w_q = f->fs.w_q;
6563b3a8eb9SGleb Smirnoff 	fs->max_th = f->max_th;
6573b3a8eb9SGleb Smirnoff 	fs->min_th = f->min_th;
6583b3a8eb9SGleb Smirnoff 	fs->max_p = f->fs.max_p;
6593b3a8eb9SGleb Smirnoff 	fs->rq_elements = nq;
6603b3a8eb9SGleb Smirnoff 
6613b3a8eb9SGleb Smirnoff 	fs->flags_fs = convertflags2old(f->fs.flags);
6623b3a8eb9SGleb Smirnoff 
6633b3a8eb9SGleb Smirnoff 	*a->start += size;
6643b3a8eb9SGleb Smirnoff 	return 0;
6653b3a8eb9SGleb Smirnoff }
6663b3a8eb9SGleb Smirnoff 
6673b3a8eb9SGleb Smirnoff int
dn_compat_copy_pipe(struct copy_args * a,void * _o)6683b3a8eb9SGleb Smirnoff dn_compat_copy_pipe(struct copy_args *a, void *_o)
6693b3a8eb9SGleb Smirnoff {
6703b3a8eb9SGleb Smirnoff 	int have = a->end - *a->start;
6713b3a8eb9SGleb Smirnoff 	int need = 0;
6723b3a8eb9SGleb Smirnoff 	int pipe_size = sizeof(struct dn_pipe8);
6733b3a8eb9SGleb Smirnoff 	int queue_size = sizeof(struct dn_flow_queue8);
6743b3a8eb9SGleb Smirnoff 	int n_queue = 0; /* number of queues */
6753b3a8eb9SGleb Smirnoff 
6763b3a8eb9SGleb Smirnoff 	struct dn_schk *s = (struct dn_schk *)_o;
6773b3a8eb9SGleb Smirnoff 	/* calculate needed space:
6783b3a8eb9SGleb Smirnoff 	 * - struct dn_pipe
6793b3a8eb9SGleb Smirnoff 	 * - if there are instances, dn_queue * n_instances
6803b3a8eb9SGleb Smirnoff 	 */
6813b3a8eb9SGleb Smirnoff 	n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) :
6823b3a8eb9SGleb Smirnoff 						(s->siht ? 1 : 0));
6833b3a8eb9SGleb Smirnoff 	need = pipe_size + queue_size * n_queue;
6843b3a8eb9SGleb Smirnoff 	if (have < need) {
6853b3a8eb9SGleb Smirnoff 		D("have %d < need %d", have, need);
6863b3a8eb9SGleb Smirnoff 		return 1;
6873b3a8eb9SGleb Smirnoff 	}
6883b3a8eb9SGleb Smirnoff 	/* copy pipe */
6893b3a8eb9SGleb Smirnoff 	dn_c_copy_pipe(s, a, n_queue);
6903b3a8eb9SGleb Smirnoff 
6913b3a8eb9SGleb Smirnoff 	/* copy queues */
6923b3a8eb9SGleb Smirnoff 	if (s->sch.flags & DN_HAVE_MASK)
6933b3a8eb9SGleb Smirnoff 		dn_ht_scan(s->siht, dn_c_copy_q, a);
6943b3a8eb9SGleb Smirnoff 	else if (s->siht)
6953b3a8eb9SGleb Smirnoff 		dn_c_copy_q(s->siht, a);
6963b3a8eb9SGleb Smirnoff 	return 0;
6973b3a8eb9SGleb Smirnoff }
6983b3a8eb9SGleb Smirnoff 
6993b3a8eb9SGleb Smirnoff int
dn_c_copy_fs(struct dn_fsk * f,struct copy_args * a,int nq)7003b3a8eb9SGleb Smirnoff dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq)
7013b3a8eb9SGleb Smirnoff {
7023b3a8eb9SGleb Smirnoff 	struct dn_flow_set *fs = (struct dn_flow_set *)*a->start;
7033b3a8eb9SGleb Smirnoff 
7043b3a8eb9SGleb Smirnoff 	fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
7053b3a8eb9SGleb Smirnoff 	fs->fs_nr = f->fs.fs_nr;
7063b3a8eb9SGleb Smirnoff 	fs->qsize = f->fs.qsize;
70731cf66d7SRichard Scheffenegger 	fs->plr[0] = f->fs.plr[0];
70831cf66d7SRichard Scheffenegger 	fs->plr[1] = f->fs.plr[1];
70931cf66d7SRichard Scheffenegger 	fs->plr[2] = f->fs.plr[2];
71031cf66d7SRichard Scheffenegger 	fs->plr[3] = f->fs.plr[3];
7113b3a8eb9SGleb Smirnoff 	fs->w_q = f->fs.w_q;
7123b3a8eb9SGleb Smirnoff 	fs->max_th = f->max_th;
7133b3a8eb9SGleb Smirnoff 	fs->min_th = f->min_th;
7143b3a8eb9SGleb Smirnoff 	fs->max_p = f->fs.max_p;
7153b3a8eb9SGleb Smirnoff 	fs->flow_mask = f->fs.flow_mask;
7163b3a8eb9SGleb Smirnoff 	fs->rq_elements = nq;
7173b3a8eb9SGleb Smirnoff 	fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1);
7183b3a8eb9SGleb Smirnoff 	fs->parent_nr = f->fs.sched_nr;
7193b3a8eb9SGleb Smirnoff 	fs->weight = f->fs.par[0];
7203b3a8eb9SGleb Smirnoff 
7213b3a8eb9SGleb Smirnoff 	fs->flags_fs = convertflags2old(f->fs.flags);
7223b3a8eb9SGleb Smirnoff 	*a->start += sizeof(struct dn_flow_set);
7233b3a8eb9SGleb Smirnoff 	return 0;
7243b3a8eb9SGleb Smirnoff }
7253b3a8eb9SGleb Smirnoff 
7263b3a8eb9SGleb Smirnoff int
dn_compat_copy_queue(struct copy_args * a,void * _o)7273b3a8eb9SGleb Smirnoff dn_compat_copy_queue(struct copy_args *a, void *_o)
7283b3a8eb9SGleb Smirnoff {
7293b3a8eb9SGleb Smirnoff 	int have = a->end - *a->start;
7303b3a8eb9SGleb Smirnoff 	int need = 0;
7313b3a8eb9SGleb Smirnoff 	int fs_size = sizeof(struct dn_flow_set);
7323b3a8eb9SGleb Smirnoff 	int queue_size = sizeof(struct dn_flow_queue8);
7333b3a8eb9SGleb Smirnoff 
7343b3a8eb9SGleb Smirnoff 	struct dn_fsk *fs = (struct dn_fsk *)_o;
7353b3a8eb9SGleb Smirnoff 	int n_queue = 0; /* number of queues */
7363b3a8eb9SGleb Smirnoff 
7373b3a8eb9SGleb Smirnoff 	n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) :
7383b3a8eb9SGleb Smirnoff 						(fs->qht ? 1 : 0));
7393b3a8eb9SGleb Smirnoff 
7403b3a8eb9SGleb Smirnoff 	need = fs_size + queue_size * n_queue;
7413b3a8eb9SGleb Smirnoff 	if (have < need) {
7423b3a8eb9SGleb Smirnoff 		D("have < need");
7433b3a8eb9SGleb Smirnoff 		return 1;
7443b3a8eb9SGleb Smirnoff 	}
7453b3a8eb9SGleb Smirnoff 
7463b3a8eb9SGleb Smirnoff 	/* copy flowset */
7473b3a8eb9SGleb Smirnoff 	dn_c_copy_fs(fs, a, n_queue);
7483b3a8eb9SGleb Smirnoff 
7493b3a8eb9SGleb Smirnoff 	/* copy queues */
7503b3a8eb9SGleb Smirnoff 	if (fs->fs.flags & DN_HAVE_MASK)
7513b3a8eb9SGleb Smirnoff 		dn_ht_scan(fs->qht, dn_c_copy_q, a);
7523b3a8eb9SGleb Smirnoff 	else if (fs->qht)
7533b3a8eb9SGleb Smirnoff 		dn_c_copy_q(fs->qht, a);
7543b3a8eb9SGleb Smirnoff 
7553b3a8eb9SGleb Smirnoff 	return 0;
7563b3a8eb9SGleb Smirnoff }
7573b3a8eb9SGleb Smirnoff 
7583b3a8eb9SGleb Smirnoff int
copy_data_helper_compat(void * _o,void * _arg)7593b3a8eb9SGleb Smirnoff copy_data_helper_compat(void *_o, void *_arg)
7603b3a8eb9SGleb Smirnoff {
7613b3a8eb9SGleb Smirnoff 	struct copy_args *a = _arg;
7623b3a8eb9SGleb Smirnoff 
7633b3a8eb9SGleb Smirnoff 	if (a->type == DN_COMPAT_PIPE) {
7643b3a8eb9SGleb Smirnoff 		struct dn_schk *s = _o;
7653b3a8eb9SGleb Smirnoff 		if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) {
7663b3a8eb9SGleb Smirnoff 			return 0;	/* not old type */
7673b3a8eb9SGleb Smirnoff 		}
7683b3a8eb9SGleb Smirnoff 		/* copy pipe parameters, and if instance exists, copy
7693b3a8eb9SGleb Smirnoff 		 * other parameters and eventually queues.
7703b3a8eb9SGleb Smirnoff 		 */
7713b3a8eb9SGleb Smirnoff 		if(dn_compat_copy_pipe(a, _o))
7723b3a8eb9SGleb Smirnoff 			return DNHT_SCAN_END;
7733b3a8eb9SGleb Smirnoff 	} else if (a->type == DN_COMPAT_QUEUE) {
7743b3a8eb9SGleb Smirnoff 		struct dn_fsk *fs = _o;
7753b3a8eb9SGleb Smirnoff 		if (fs->fs.fs_nr >= DN_MAX_ID)
7763b3a8eb9SGleb Smirnoff 			return 0;
7773b3a8eb9SGleb Smirnoff 		if (dn_compat_copy_queue(a, _o))
7783b3a8eb9SGleb Smirnoff 			return DNHT_SCAN_END;
7793b3a8eb9SGleb Smirnoff 	}
7803b3a8eb9SGleb Smirnoff 	return 0;
7813b3a8eb9SGleb Smirnoff }
7823b3a8eb9SGleb Smirnoff 
7833b3a8eb9SGleb Smirnoff /* Main function to manage old requests */
7843b3a8eb9SGleb Smirnoff int
ip_dummynet_compat(struct sockopt * sopt)7853b3a8eb9SGleb Smirnoff ip_dummynet_compat(struct sockopt *sopt)
7863b3a8eb9SGleb Smirnoff {
7873b3a8eb9SGleb Smirnoff 	int error=0;
7883b3a8eb9SGleb Smirnoff 	void *v = NULL;
7893b3a8eb9SGleb Smirnoff 	struct dn_id oid;
7903b3a8eb9SGleb Smirnoff 
791a4641f4eSPedro F. Giffuni 	/* Length of data, used to found ipfw version... */
7923b3a8eb9SGleb Smirnoff 	int len = sopt->sopt_valsize;
7933b3a8eb9SGleb Smirnoff 
7943b3a8eb9SGleb Smirnoff 	/* len can be 0 if command was dummynet_flush */
7953b3a8eb9SGleb Smirnoff 	if (len == pipesize7) {
7963b3a8eb9SGleb Smirnoff 		D("setting compatibility with FreeBSD 7.2");
7973b3a8eb9SGleb Smirnoff 		is7 = 1;
7983b3a8eb9SGleb Smirnoff 	}
7993b3a8eb9SGleb Smirnoff 	else if (len == pipesize8 || len == pipesizemax8) {
8003b3a8eb9SGleb Smirnoff 		D("setting compatibility with FreeBSD 8");
8013b3a8eb9SGleb Smirnoff 		is7 = 0;
8023b3a8eb9SGleb Smirnoff 	}
8033b3a8eb9SGleb Smirnoff 
8043b3a8eb9SGleb Smirnoff 	switch (sopt->sopt_name) {
8053b3a8eb9SGleb Smirnoff 	default:
8063b3a8eb9SGleb Smirnoff 		printf("dummynet: -- unknown option %d", sopt->sopt_name);
8073b3a8eb9SGleb Smirnoff 		error = EINVAL;
8083b3a8eb9SGleb Smirnoff 		break;
8093b3a8eb9SGleb Smirnoff 
8103b3a8eb9SGleb Smirnoff 	case IP_DUMMYNET_FLUSH:
8113b3a8eb9SGleb Smirnoff 		oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);
8123b3a8eb9SGleb Smirnoff 		do_config(&oid, oid.len);
8133b3a8eb9SGleb Smirnoff 		break;
8143b3a8eb9SGleb Smirnoff 
8153b3a8eb9SGleb Smirnoff 	case IP_DUMMYNET_DEL:
8163b3a8eb9SGleb Smirnoff 		v = malloc(len, M_TEMP, M_WAITOK);
8173b3a8eb9SGleb Smirnoff 		error = sooptcopyin(sopt, v, len, len);
8183b3a8eb9SGleb Smirnoff 		if (error)
8193b3a8eb9SGleb Smirnoff 			break;
8203b3a8eb9SGleb Smirnoff 		error = dn_compat_del(v);
8213b3a8eb9SGleb Smirnoff 		free(v, M_TEMP);
8223b3a8eb9SGleb Smirnoff 		break;
8233b3a8eb9SGleb Smirnoff 
8243b3a8eb9SGleb Smirnoff 	case IP_DUMMYNET_CONFIGURE:
82551d73df1SKristof Provost 		v = malloc(len, M_TEMP, M_NOWAIT);
82651d73df1SKristof Provost 		if (v == NULL) {
82751d73df1SKristof Provost 			error = ENOMEM;
82851d73df1SKristof Provost 			break;
82951d73df1SKristof Provost 		}
8303b3a8eb9SGleb Smirnoff 		error = sooptcopyin(sopt, v, len, len);
8313b3a8eb9SGleb Smirnoff 		if (error)
8323b3a8eb9SGleb Smirnoff 			break;
8333b3a8eb9SGleb Smirnoff 		error = dn_compat_configure(v);
8343b3a8eb9SGleb Smirnoff 		free(v, M_TEMP);
8353b3a8eb9SGleb Smirnoff 		break;
8363b3a8eb9SGleb Smirnoff 
8373b3a8eb9SGleb Smirnoff 	case IP_DUMMYNET_GET: {
8383b3a8eb9SGleb Smirnoff 		void *buf;
8393b3a8eb9SGleb Smirnoff 		int ret;
8403b3a8eb9SGleb Smirnoff 		int original_size = sopt->sopt_valsize;
8413b3a8eb9SGleb Smirnoff 		int size;
8423b3a8eb9SGleb Smirnoff 
8433b3a8eb9SGleb Smirnoff 		ret = dummynet_get(sopt, &buf);
8443b3a8eb9SGleb Smirnoff 		if (ret)
8453b3a8eb9SGleb Smirnoff 			return 0;//XXX ?
8463b3a8eb9SGleb Smirnoff 		size = sopt->sopt_valsize;
8473b3a8eb9SGleb Smirnoff 		sopt->sopt_valsize = original_size;
8483b3a8eb9SGleb Smirnoff 		D("size=%d, buf=%p", size, buf);
8493b3a8eb9SGleb Smirnoff 		ret = sooptcopyout(sopt, buf, size);
8503b3a8eb9SGleb Smirnoff 		if (ret)
8513b3a8eb9SGleb Smirnoff 			printf("  %s ERROR sooptcopyout\n", __FUNCTION__);
8523b3a8eb9SGleb Smirnoff 		if (buf)
8533b3a8eb9SGleb Smirnoff 			free(buf, M_DUMMYNET);
8543b3a8eb9SGleb Smirnoff 	    }
8553b3a8eb9SGleb Smirnoff 	}
8563b3a8eb9SGleb Smirnoff 
8573b3a8eb9SGleb Smirnoff 	return error;
8583b3a8eb9SGleb Smirnoff }
859