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