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