altq_cdnr.c revision 184205
1130368Smlaier/* $FreeBSD: head/sys/contrib/altq/altq/altq_cdnr.c 184205 2008-10-23 15:53:51Z des $ */ 2130365Smlaier/* $KAME: altq_cdnr.c,v 1.14 2003/09/05 22:40:36 itojun Exp $ */ 3130365Smlaier 4130365Smlaier/* 5130365Smlaier * Copyright (C) 1999-2002 6130365Smlaier * Sony Computer Science Laboratories Inc. All rights reserved. 7130365Smlaier * 8130365Smlaier * Redistribution and use in source and binary forms, with or without 9130365Smlaier * modification, are permitted provided that the following conditions 10130365Smlaier * are met: 11130365Smlaier * 1. Redistributions of source code must retain the above copyright 12130365Smlaier * notice, this list of conditions and the following disclaimer. 13130365Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14130365Smlaier * notice, this list of conditions and the following disclaimer in the 15130365Smlaier * documentation and/or other materials provided with the distribution. 16130365Smlaier * 17130365Smlaier * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 18130365Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19130365Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20130365Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 21130365Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22130365Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23130365Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24130365Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25130365Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26130365Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27130365Smlaier * SUCH DAMAGE. 28130365Smlaier */ 29130365Smlaier 30130365Smlaier#if defined(__FreeBSD__) || defined(__NetBSD__) 31130365Smlaier#include "opt_altq.h" 32130365Smlaier#if (__FreeBSD__ != 2) 33130365Smlaier#include "opt_inet.h" 34130365Smlaier#ifdef __FreeBSD__ 35130365Smlaier#include "opt_inet6.h" 36130365Smlaier#endif 37130365Smlaier#endif 38130365Smlaier#endif /* __FreeBSD__ || __NetBSD__ */ 39130365Smlaier 40130365Smlaier#include <sys/param.h> 41130365Smlaier#include <sys/malloc.h> 42130365Smlaier#include <sys/mbuf.h> 43130365Smlaier#include <sys/socket.h> 44130365Smlaier#include <sys/sockio.h> 45130365Smlaier#include <sys/systm.h> 46130365Smlaier#include <sys/proc.h> 47130365Smlaier#include <sys/errno.h> 48130365Smlaier#include <sys/kernel.h> 49130365Smlaier#include <sys/queue.h> 50130365Smlaier 51130365Smlaier#include <net/if.h> 52130365Smlaier#include <net/if_types.h> 53130365Smlaier#include <netinet/in.h> 54130365Smlaier#include <netinet/in_systm.h> 55130365Smlaier#include <netinet/ip.h> 56130365Smlaier#ifdef INET6 57130365Smlaier#include <netinet/ip6.h> 58130365Smlaier#endif 59130365Smlaier 60130365Smlaier#include <altq/altq.h> 61130368Smlaier#ifdef ALTQ3_COMPAT 62130365Smlaier#include <altq/altq_conf.h> 63130368Smlaier#endif 64130365Smlaier#include <altq/altq_cdnr.h> 65130365Smlaier 66130365Smlaier#ifdef ALTQ3_COMPAT 67130365Smlaier/* 68130365Smlaier * diffserv traffic conditioning module 69130365Smlaier */ 70130365Smlaier 71130365Smlaierint altq_cdnr_enabled = 0; 72130365Smlaier 73130365Smlaier/* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */ 74130365Smlaier#ifdef ALTQ_CDNR 75130365Smlaier 76130365Smlaier/* cdnr_list keeps all cdnr's allocated. */ 77130365Smlaierstatic LIST_HEAD(, top_cdnr) tcb_list; 78130365Smlaier 79130365Smlaierstatic int altq_cdnr_input(struct mbuf *, int); 80130365Smlaierstatic struct top_cdnr *tcb_lookup(char *ifname); 81130365Smlaierstatic struct cdnr_block *cdnr_handle2cb(u_long); 82130365Smlaierstatic u_long cdnr_cb2handle(struct cdnr_block *); 83130365Smlaierstatic void *cdnr_cballoc(struct top_cdnr *, int, 84130365Smlaier struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *)); 85130365Smlaierstatic void cdnr_cbdestroy(void *); 86130365Smlaierstatic int tca_verify_action(struct tc_action *); 87130365Smlaierstatic void tca_import_action(struct tc_action *, struct tc_action *); 88130365Smlaierstatic void tca_invalidate_action(struct tc_action *); 89130365Smlaier 90130365Smlaierstatic int generic_element_destroy(struct cdnr_block *); 91130365Smlaierstatic struct top_cdnr *top_create(struct ifaltq *); 92130365Smlaierstatic int top_destroy(struct top_cdnr *); 93130365Smlaierstatic struct cdnr_block *element_create(struct top_cdnr *, struct tc_action *); 94130365Smlaierstatic int element_destroy(struct cdnr_block *); 95130365Smlaierstatic void tb_import_profile(struct tbe *, struct tb_profile *); 96130365Smlaierstatic struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *, 97130365Smlaier struct tc_action *, struct tc_action *); 98130365Smlaierstatic int tbm_destroy(struct tbmeter *); 99130365Smlaierstatic struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *); 100130365Smlaierstatic struct trtcm *trtcm_create(struct top_cdnr *, 101130365Smlaier struct tb_profile *, struct tb_profile *, 102130365Smlaier struct tc_action *, struct tc_action *, struct tc_action *, 103130365Smlaier int); 104130365Smlaierstatic int trtcm_destroy(struct trtcm *); 105130365Smlaierstatic struct tc_action *trtcm_input(struct cdnr_block *, struct cdnr_pktinfo *); 106130365Smlaierstatic struct tswtcm *tswtcm_create(struct top_cdnr *, 107130365Smlaier u_int32_t, u_int32_t, u_int32_t, 108130365Smlaier struct tc_action *, struct tc_action *, struct tc_action *); 109130365Smlaierstatic int tswtcm_destroy(struct tswtcm *); 110130365Smlaierstatic struct tc_action *tswtcm_input(struct cdnr_block *, struct cdnr_pktinfo *); 111130365Smlaier 112130365Smlaierstatic int cdnrcmd_if_attach(char *); 113130365Smlaierstatic int cdnrcmd_if_detach(char *); 114130365Smlaierstatic int cdnrcmd_add_element(struct cdnr_add_element *); 115130365Smlaierstatic int cdnrcmd_delete_element(struct cdnr_delete_element *); 116130365Smlaierstatic int cdnrcmd_add_filter(struct cdnr_add_filter *); 117130365Smlaierstatic int cdnrcmd_delete_filter(struct cdnr_delete_filter *); 118130365Smlaierstatic int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *); 119130365Smlaierstatic int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *); 120130365Smlaierstatic int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *); 121130365Smlaierstatic int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *); 122130365Smlaierstatic int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *); 123130365Smlaierstatic int cdnrcmd_tcm_stats(struct cdnr_tcm_stats *); 124130365Smlaierstatic int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *); 125130365Smlaierstatic int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *); 126130365Smlaierstatic int cdnrcmd_get_stats(struct cdnr_get_stats *); 127130365Smlaier 128130365Smlaieraltqdev_decl(cdnr); 129130365Smlaier 130130365Smlaier/* 131130365Smlaier * top level input function called from ip_input. 132130365Smlaier * should be called before converting header fields to host-byte-order. 133130365Smlaier */ 134130365Smlaierint 135130365Smlaieraltq_cdnr_input(m, af) 136130365Smlaier struct mbuf *m; 137130365Smlaier int af; /* address family */ 138130365Smlaier{ 139130365Smlaier struct ifnet *ifp; 140130365Smlaier struct ip *ip; 141130365Smlaier struct top_cdnr *top; 142130365Smlaier struct tc_action *tca; 143130365Smlaier struct cdnr_block *cb; 144130365Smlaier struct cdnr_pktinfo pktinfo; 145130365Smlaier 146130365Smlaier ifp = m->m_pkthdr.rcvif; 147130365Smlaier if (!ALTQ_IS_CNDTNING(&ifp->if_snd)) 148130365Smlaier /* traffic conditioner is not enabled on this interface */ 149130365Smlaier return (1); 150130365Smlaier 151130365Smlaier top = ifp->if_snd.altq_cdnr; 152130365Smlaier 153130365Smlaier ip = mtod(m, struct ip *); 154130365Smlaier#ifdef INET6 155130365Smlaier if (af == AF_INET6) { 156130365Smlaier u_int32_t flowlabel; 157130365Smlaier 158130365Smlaier flowlabel = ((struct ip6_hdr *)ip)->ip6_flow; 159130365Smlaier pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK; 160130365Smlaier } else 161130365Smlaier#endif 162130365Smlaier pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK; 163130365Smlaier pktinfo.pkt_len = m_pktlen(m); 164130365Smlaier 165130365Smlaier tca = NULL; 166130365Smlaier 167130365Smlaier cb = acc_classify(&top->tc_classifier, m, af); 168130365Smlaier if (cb != NULL) 169130365Smlaier tca = &cb->cb_action; 170130365Smlaier 171130365Smlaier if (tca == NULL) 172130365Smlaier tca = &top->tc_block.cb_action; 173130365Smlaier 174130365Smlaier while (1) { 175130365Smlaier PKTCNTR_ADD(&top->tc_cnts[tca->tca_code], pktinfo.pkt_len); 176130365Smlaier 177130365Smlaier switch (tca->tca_code) { 178130365Smlaier case TCACODE_PASS: 179130365Smlaier return (1); 180130365Smlaier case TCACODE_DROP: 181130365Smlaier m_freem(m); 182130365Smlaier return (0); 183130365Smlaier case TCACODE_RETURN: 184130365Smlaier return (0); 185130365Smlaier case TCACODE_MARK: 186130365Smlaier#ifdef INET6 187130365Smlaier if (af == AF_INET6) { 188130365Smlaier struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; 189130365Smlaier u_int32_t flowlabel; 190130365Smlaier 191130365Smlaier flowlabel = ntohl(ip6->ip6_flow); 192130365Smlaier flowlabel = (tca->tca_dscp << 20) | 193130365Smlaier (flowlabel & ~(DSCP_MASK << 20)); 194130365Smlaier ip6->ip6_flow = htonl(flowlabel); 195130365Smlaier } else 196130365Smlaier#endif 197130365Smlaier ip->ip_tos = tca->tca_dscp | 198130365Smlaier (ip->ip_tos & DSCP_CUMASK); 199130365Smlaier return (1); 200130365Smlaier case TCACODE_NEXT: 201130365Smlaier cb = tca->tca_next; 202130365Smlaier tca = (*cb->cb_input)(cb, &pktinfo); 203130365Smlaier break; 204130365Smlaier case TCACODE_NONE: 205130365Smlaier default: 206130365Smlaier return (1); 207130365Smlaier } 208130365Smlaier } 209130365Smlaier} 210130365Smlaier 211130365Smlaierstatic struct top_cdnr * 212130365Smlaiertcb_lookup(ifname) 213130365Smlaier char *ifname; 214130365Smlaier{ 215130365Smlaier struct top_cdnr *top; 216130365Smlaier struct ifnet *ifp; 217130365Smlaier 218130365Smlaier if ((ifp = ifunit(ifname)) != NULL) 219130365Smlaier LIST_FOREACH(top, &tcb_list, tc_next) 220130365Smlaier if (top->tc_ifq->altq_ifp == ifp) 221130365Smlaier return (top); 222130365Smlaier return (NULL); 223130365Smlaier} 224130365Smlaier 225130365Smlaierstatic struct cdnr_block * 226130365Smlaiercdnr_handle2cb(handle) 227130365Smlaier u_long handle; 228130365Smlaier{ 229130365Smlaier struct cdnr_block *cb; 230130365Smlaier 231130365Smlaier cb = (struct cdnr_block *)handle; 232130365Smlaier if (handle != ALIGN(cb)) 233130365Smlaier return (NULL); 234130365Smlaier 235130365Smlaier if (cb == NULL || cb->cb_handle != handle) 236130365Smlaier return (NULL); 237130365Smlaier return (cb); 238130365Smlaier} 239130365Smlaier 240130365Smlaierstatic u_long 241130365Smlaiercdnr_cb2handle(cb) 242130365Smlaier struct cdnr_block *cb; 243130365Smlaier{ 244130365Smlaier return (cb->cb_handle); 245130365Smlaier} 246130365Smlaier 247130365Smlaierstatic void * 248130365Smlaiercdnr_cballoc(top, type, input_func) 249130365Smlaier struct top_cdnr *top; 250130365Smlaier int type; 251130365Smlaier struct tc_action *(*input_func)(struct cdnr_block *, 252130365Smlaier struct cdnr_pktinfo *); 253130365Smlaier{ 254130365Smlaier struct cdnr_block *cb; 255130365Smlaier int size; 256130365Smlaier 257130365Smlaier switch (type) { 258130365Smlaier case TCETYPE_TOP: 259130365Smlaier size = sizeof(struct top_cdnr); 260130365Smlaier break; 261130365Smlaier case TCETYPE_ELEMENT: 262130365Smlaier size = sizeof(struct cdnr_block); 263130365Smlaier break; 264130365Smlaier case TCETYPE_TBMETER: 265130365Smlaier size = sizeof(struct tbmeter); 266130365Smlaier break; 267130365Smlaier case TCETYPE_TRTCM: 268130365Smlaier size = sizeof(struct trtcm); 269130365Smlaier break; 270130365Smlaier case TCETYPE_TSWTCM: 271130365Smlaier size = sizeof(struct tswtcm); 272130365Smlaier break; 273130365Smlaier default: 274130365Smlaier return (NULL); 275130365Smlaier } 276130365Smlaier 277184205Sdes cb = malloc(size, M_DEVBUF, M_WAITOK); 278130365Smlaier if (cb == NULL) 279130365Smlaier return (NULL); 280130365Smlaier bzero(cb, size); 281130365Smlaier 282130365Smlaier cb->cb_len = size; 283130365Smlaier cb->cb_type = type; 284130365Smlaier cb->cb_ref = 0; 285130365Smlaier cb->cb_handle = (u_long)cb; 286130365Smlaier if (top == NULL) 287130365Smlaier cb->cb_top = (struct top_cdnr *)cb; 288130365Smlaier else 289130365Smlaier cb->cb_top = top; 290130365Smlaier 291130365Smlaier if (input_func != NULL) { 292130365Smlaier /* 293130365Smlaier * if this cdnr has an action function, 294130365Smlaier * make tc_action to call itself. 295130365Smlaier */ 296130365Smlaier cb->cb_action.tca_code = TCACODE_NEXT; 297130365Smlaier cb->cb_action.tca_next = cb; 298130365Smlaier cb->cb_input = input_func; 299130365Smlaier } else 300130365Smlaier cb->cb_action.tca_code = TCACODE_NONE; 301130365Smlaier 302130365Smlaier /* if this isn't top, register the element to the top level cdnr */ 303130365Smlaier if (top != NULL) 304130365Smlaier LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next); 305130365Smlaier 306130365Smlaier return ((void *)cb); 307130365Smlaier} 308130365Smlaier 309130365Smlaierstatic void 310130365Smlaiercdnr_cbdestroy(cblock) 311130365Smlaier void *cblock; 312130365Smlaier{ 313130365Smlaier struct cdnr_block *cb = cblock; 314130365Smlaier 315130365Smlaier /* delete filters belonging to this cdnr */ 316130365Smlaier acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0); 317130365Smlaier 318130365Smlaier /* remove from the top level cdnr */ 319130365Smlaier if (cb->cb_top != cblock) 320130365Smlaier LIST_REMOVE(cb, cb_next); 321130365Smlaier 322184205Sdes free(cb, M_DEVBUF); 323130365Smlaier} 324130365Smlaier 325130365Smlaier/* 326130365Smlaier * conditioner common destroy routine 327130365Smlaier */ 328130365Smlaierstatic int 329130365Smlaiergeneric_element_destroy(cb) 330130365Smlaier struct cdnr_block *cb; 331130365Smlaier{ 332130365Smlaier int error = 0; 333130365Smlaier 334130365Smlaier switch (cb->cb_type) { 335130365Smlaier case TCETYPE_TOP: 336130365Smlaier error = top_destroy((struct top_cdnr *)cb); 337130365Smlaier break; 338130365Smlaier case TCETYPE_ELEMENT: 339130365Smlaier error = element_destroy(cb); 340130365Smlaier break; 341130365Smlaier case TCETYPE_TBMETER: 342130365Smlaier error = tbm_destroy((struct tbmeter *)cb); 343130365Smlaier break; 344130365Smlaier case TCETYPE_TRTCM: 345130365Smlaier error = trtcm_destroy((struct trtcm *)cb); 346130365Smlaier break; 347130365Smlaier case TCETYPE_TSWTCM: 348130365Smlaier error = tswtcm_destroy((struct tswtcm *)cb); 349130365Smlaier break; 350130365Smlaier default: 351130365Smlaier error = EINVAL; 352130365Smlaier } 353130365Smlaier return (error); 354130365Smlaier} 355130365Smlaier 356130365Smlaierstatic int 357130365Smlaiertca_verify_action(utca) 358130365Smlaier struct tc_action *utca; 359130365Smlaier{ 360130365Smlaier switch (utca->tca_code) { 361130365Smlaier case TCACODE_PASS: 362130365Smlaier case TCACODE_DROP: 363130365Smlaier case TCACODE_MARK: 364130365Smlaier /* these are ok */ 365130365Smlaier break; 366130365Smlaier 367130365Smlaier case TCACODE_HANDLE: 368130365Smlaier /* verify handle value */ 369130365Smlaier if (cdnr_handle2cb(utca->tca_handle) == NULL) 370130365Smlaier return (-1); 371130365Smlaier break; 372130365Smlaier 373130365Smlaier case TCACODE_NONE: 374130365Smlaier case TCACODE_RETURN: 375130365Smlaier case TCACODE_NEXT: 376130365Smlaier default: 377130365Smlaier /* should not be passed from a user */ 378130365Smlaier return (-1); 379130365Smlaier } 380130365Smlaier return (0); 381130365Smlaier} 382130365Smlaier 383130365Smlaierstatic void 384130365Smlaiertca_import_action(ktca, utca) 385130365Smlaier struct tc_action *ktca, *utca; 386130365Smlaier{ 387130365Smlaier struct cdnr_block *cb; 388130365Smlaier 389130365Smlaier *ktca = *utca; 390130365Smlaier if (ktca->tca_code == TCACODE_HANDLE) { 391130365Smlaier cb = cdnr_handle2cb(ktca->tca_handle); 392130365Smlaier if (cb == NULL) { 393130365Smlaier ktca->tca_code = TCACODE_NONE; 394130365Smlaier return; 395130365Smlaier } 396130365Smlaier ktca->tca_code = TCACODE_NEXT; 397130365Smlaier ktca->tca_next = cb; 398130365Smlaier cb->cb_ref++; 399130365Smlaier } else if (ktca->tca_code == TCACODE_MARK) { 400130365Smlaier ktca->tca_dscp &= DSCP_MASK; 401130365Smlaier } 402130365Smlaier return; 403130365Smlaier} 404130365Smlaier 405130365Smlaierstatic void 406130365Smlaiertca_invalidate_action(tca) 407130365Smlaier struct tc_action *tca; 408130365Smlaier{ 409130365Smlaier struct cdnr_block *cb; 410130365Smlaier 411130365Smlaier if (tca->tca_code == TCACODE_NEXT) { 412130365Smlaier cb = tca->tca_next; 413130365Smlaier if (cb == NULL) 414130365Smlaier return; 415130365Smlaier cb->cb_ref--; 416130365Smlaier } 417130365Smlaier tca->tca_code = TCACODE_NONE; 418130365Smlaier} 419130365Smlaier 420130365Smlaier/* 421130365Smlaier * top level traffic conditioner 422130365Smlaier */ 423130365Smlaierstatic struct top_cdnr * 424130365Smlaiertop_create(ifq) 425130365Smlaier struct ifaltq *ifq; 426130365Smlaier{ 427130365Smlaier struct top_cdnr *top; 428130365Smlaier 429130365Smlaier if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL) 430130365Smlaier return (NULL); 431130365Smlaier 432130365Smlaier top->tc_ifq = ifq; 433130365Smlaier /* set default action for the top level conditioner */ 434130365Smlaier top->tc_block.cb_action.tca_code = TCACODE_PASS; 435130365Smlaier 436130365Smlaier LIST_INSERT_HEAD(&tcb_list, top, tc_next); 437130365Smlaier 438130365Smlaier ifq->altq_cdnr = top; 439130365Smlaier 440130365Smlaier return (top); 441130365Smlaier} 442130365Smlaier 443130365Smlaierstatic int 444130365Smlaiertop_destroy(top) 445130365Smlaier struct top_cdnr *top; 446130365Smlaier{ 447130365Smlaier struct cdnr_block *cb; 448130365Smlaier 449130365Smlaier if (ALTQ_IS_CNDTNING(top->tc_ifq)) 450130365Smlaier ALTQ_CLEAR_CNDTNING(top->tc_ifq); 451130365Smlaier top->tc_ifq->altq_cdnr = NULL; 452130365Smlaier 453130365Smlaier /* 454130365Smlaier * destroy all the conditioner elements belonging to this interface 455130365Smlaier */ 456130365Smlaier while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) { 457130365Smlaier while (cb != NULL && cb->cb_ref > 0) 458130365Smlaier cb = LIST_NEXT(cb, cb_next); 459130365Smlaier if (cb != NULL) 460130365Smlaier generic_element_destroy(cb); 461130365Smlaier } 462130365Smlaier 463130365Smlaier LIST_REMOVE(top, tc_next); 464130365Smlaier 465130365Smlaier cdnr_cbdestroy(top); 466130365Smlaier 467130365Smlaier /* if there is no active conditioner, remove the input hook */ 468130365Smlaier if (altq_input != NULL) { 469130365Smlaier LIST_FOREACH(top, &tcb_list, tc_next) 470130365Smlaier if (ALTQ_IS_CNDTNING(top->tc_ifq)) 471130365Smlaier break; 472130365Smlaier if (top == NULL) 473130365Smlaier altq_input = NULL; 474130365Smlaier } 475130365Smlaier 476130365Smlaier return (0); 477130365Smlaier} 478130365Smlaier 479130365Smlaier/* 480130365Smlaier * simple tc elements without input function (e.g., dropper and makers). 481130365Smlaier */ 482130365Smlaierstatic struct cdnr_block * 483130365Smlaierelement_create(top, action) 484130365Smlaier struct top_cdnr *top; 485130365Smlaier struct tc_action *action; 486130365Smlaier{ 487130365Smlaier struct cdnr_block *cb; 488130365Smlaier 489130365Smlaier if (tca_verify_action(action) < 0) 490130365Smlaier return (NULL); 491130365Smlaier 492130365Smlaier if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL) 493130365Smlaier return (NULL); 494130365Smlaier 495130365Smlaier tca_import_action(&cb->cb_action, action); 496130365Smlaier 497130365Smlaier return (cb); 498130365Smlaier} 499130365Smlaier 500130365Smlaierstatic int 501130365Smlaierelement_destroy(cb) 502130365Smlaier struct cdnr_block *cb; 503130365Smlaier{ 504130365Smlaier if (cb->cb_ref > 0) 505130365Smlaier return (EBUSY); 506130365Smlaier 507130365Smlaier tca_invalidate_action(&cb->cb_action); 508130365Smlaier 509130365Smlaier cdnr_cbdestroy(cb); 510130365Smlaier return (0); 511130365Smlaier} 512130365Smlaier 513130365Smlaier/* 514130365Smlaier * internal representation of token bucket parameters 515130365Smlaier * rate: byte_per_unittime << 32 516130365Smlaier * (((bits_per_sec) / 8) << 32) / machclk_freq 517130365Smlaier * depth: byte << 32 518130365Smlaier * 519130365Smlaier */ 520130365Smlaier#define TB_SHIFT 32 521130365Smlaier#define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT) 522130365Smlaier#define TB_UNSCALE(x) ((x) >> TB_SHIFT) 523130365Smlaier 524130365Smlaierstatic void 525130365Smlaiertb_import_profile(tb, profile) 526130365Smlaier struct tbe *tb; 527130365Smlaier struct tb_profile *profile; 528130365Smlaier{ 529130365Smlaier tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq; 530130365Smlaier tb->depth = TB_SCALE(profile->depth); 531130365Smlaier if (tb->rate > 0) 532130365Smlaier tb->filluptime = tb->depth / tb->rate; 533130365Smlaier else 534130365Smlaier tb->filluptime = 0xffffffffffffffffLL; 535130365Smlaier tb->token = tb->depth; 536130365Smlaier tb->last = read_machclk(); 537130365Smlaier} 538130365Smlaier 539130365Smlaier/* 540130365Smlaier * simple token bucket meter 541130365Smlaier */ 542130365Smlaierstatic struct tbmeter * 543130365Smlaiertbm_create(top, profile, in_action, out_action) 544130365Smlaier struct top_cdnr *top; 545130365Smlaier struct tb_profile *profile; 546130365Smlaier struct tc_action *in_action, *out_action; 547130365Smlaier{ 548130365Smlaier struct tbmeter *tbm = NULL; 549130365Smlaier 550130365Smlaier if (tca_verify_action(in_action) < 0 551130365Smlaier || tca_verify_action(out_action) < 0) 552130365Smlaier return (NULL); 553130365Smlaier 554130365Smlaier if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER, 555130365Smlaier tbm_input)) == NULL) 556130365Smlaier return (NULL); 557130365Smlaier 558130365Smlaier tb_import_profile(&tbm->tb, profile); 559130365Smlaier 560130365Smlaier tca_import_action(&tbm->in_action, in_action); 561130365Smlaier tca_import_action(&tbm->out_action, out_action); 562130365Smlaier 563130365Smlaier return (tbm); 564130365Smlaier} 565130365Smlaier 566130365Smlaierstatic int 567130365Smlaiertbm_destroy(tbm) 568130365Smlaier struct tbmeter *tbm; 569130365Smlaier{ 570130365Smlaier if (tbm->cdnrblk.cb_ref > 0) 571130365Smlaier return (EBUSY); 572130365Smlaier 573130365Smlaier tca_invalidate_action(&tbm->in_action); 574130365Smlaier tca_invalidate_action(&tbm->out_action); 575130365Smlaier 576130365Smlaier cdnr_cbdestroy(tbm); 577130365Smlaier return (0); 578130365Smlaier} 579130365Smlaier 580130365Smlaierstatic struct tc_action * 581130365Smlaiertbm_input(cb, pktinfo) 582130365Smlaier struct cdnr_block *cb; 583130365Smlaier struct cdnr_pktinfo *pktinfo; 584130365Smlaier{ 585130365Smlaier struct tbmeter *tbm = (struct tbmeter *)cb; 586130365Smlaier u_int64_t len; 587130365Smlaier u_int64_t interval, now; 588130365Smlaier 589130365Smlaier len = TB_SCALE(pktinfo->pkt_len); 590130365Smlaier 591130365Smlaier if (tbm->tb.token < len) { 592130365Smlaier now = read_machclk(); 593130365Smlaier interval = now - tbm->tb.last; 594130365Smlaier if (interval >= tbm->tb.filluptime) 595130365Smlaier tbm->tb.token = tbm->tb.depth; 596130365Smlaier else { 597130365Smlaier tbm->tb.token += interval * tbm->tb.rate; 598130365Smlaier if (tbm->tb.token > tbm->tb.depth) 599130365Smlaier tbm->tb.token = tbm->tb.depth; 600130365Smlaier } 601130365Smlaier tbm->tb.last = now; 602130365Smlaier } 603130365Smlaier 604130365Smlaier if (tbm->tb.token < len) { 605130365Smlaier PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len); 606130365Smlaier return (&tbm->out_action); 607130365Smlaier } 608130365Smlaier 609130365Smlaier tbm->tb.token -= len; 610130365Smlaier PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len); 611130365Smlaier return (&tbm->in_action); 612130365Smlaier} 613130365Smlaier 614130365Smlaier/* 615130365Smlaier * two rate three color marker 616130365Smlaier * as described in draft-heinanen-diffserv-trtcm-01.txt 617130365Smlaier */ 618130365Smlaierstatic struct trtcm * 619130365Smlaiertrtcm_create(top, cmtd_profile, peak_profile, 620130365Smlaier green_action, yellow_action, red_action, coloraware) 621130365Smlaier struct top_cdnr *top; 622130365Smlaier struct tb_profile *cmtd_profile, *peak_profile; 623130365Smlaier struct tc_action *green_action, *yellow_action, *red_action; 624130365Smlaier int coloraware; 625130365Smlaier{ 626130365Smlaier struct trtcm *tcm = NULL; 627130365Smlaier 628130365Smlaier if (tca_verify_action(green_action) < 0 629130365Smlaier || tca_verify_action(yellow_action) < 0 630130365Smlaier || tca_verify_action(red_action) < 0) 631130365Smlaier return (NULL); 632130365Smlaier 633130365Smlaier if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM, 634130365Smlaier trtcm_input)) == NULL) 635130365Smlaier return (NULL); 636130365Smlaier 637130365Smlaier tb_import_profile(&tcm->cmtd_tb, cmtd_profile); 638130365Smlaier tb_import_profile(&tcm->peak_tb, peak_profile); 639130365Smlaier 640130365Smlaier tca_import_action(&tcm->green_action, green_action); 641130365Smlaier tca_import_action(&tcm->yellow_action, yellow_action); 642130365Smlaier tca_import_action(&tcm->red_action, red_action); 643130365Smlaier 644130365Smlaier /* set dscps to use */ 645130365Smlaier if (tcm->green_action.tca_code == TCACODE_MARK) 646130365Smlaier tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK; 647130365Smlaier else 648130365Smlaier tcm->green_dscp = DSCP_AF11; 649130365Smlaier if (tcm->yellow_action.tca_code == TCACODE_MARK) 650130365Smlaier tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK; 651130365Smlaier else 652130365Smlaier tcm->yellow_dscp = DSCP_AF12; 653130365Smlaier if (tcm->red_action.tca_code == TCACODE_MARK) 654130365Smlaier tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK; 655130365Smlaier else 656130365Smlaier tcm->red_dscp = DSCP_AF13; 657130365Smlaier 658130365Smlaier tcm->coloraware = coloraware; 659130365Smlaier 660130365Smlaier return (tcm); 661130365Smlaier} 662130365Smlaier 663130365Smlaierstatic int 664130365Smlaiertrtcm_destroy(tcm) 665130365Smlaier struct trtcm *tcm; 666130365Smlaier{ 667130365Smlaier if (tcm->cdnrblk.cb_ref > 0) 668130365Smlaier return (EBUSY); 669130365Smlaier 670130365Smlaier tca_invalidate_action(&tcm->green_action); 671130365Smlaier tca_invalidate_action(&tcm->yellow_action); 672130365Smlaier tca_invalidate_action(&tcm->red_action); 673130365Smlaier 674130365Smlaier cdnr_cbdestroy(tcm); 675130365Smlaier return (0); 676130365Smlaier} 677130365Smlaier 678130365Smlaierstatic struct tc_action * 679130365Smlaiertrtcm_input(cb, pktinfo) 680130365Smlaier struct cdnr_block *cb; 681130365Smlaier struct cdnr_pktinfo *pktinfo; 682130365Smlaier{ 683130365Smlaier struct trtcm *tcm = (struct trtcm *)cb; 684130365Smlaier u_int64_t len; 685130365Smlaier u_int64_t interval, now; 686130365Smlaier u_int8_t color; 687130365Smlaier 688130365Smlaier len = TB_SCALE(pktinfo->pkt_len); 689130365Smlaier if (tcm->coloraware) { 690130365Smlaier color = pktinfo->pkt_dscp; 691130365Smlaier if (color != tcm->yellow_dscp && color != tcm->red_dscp) 692130365Smlaier color = tcm->green_dscp; 693130365Smlaier } else { 694130365Smlaier /* if color-blind, precolor it as green */ 695130365Smlaier color = tcm->green_dscp; 696130365Smlaier } 697130365Smlaier 698130365Smlaier now = read_machclk(); 699130365Smlaier if (tcm->cmtd_tb.token < len) { 700130365Smlaier interval = now - tcm->cmtd_tb.last; 701130365Smlaier if (interval >= tcm->cmtd_tb.filluptime) 702130365Smlaier tcm->cmtd_tb.token = tcm->cmtd_tb.depth; 703130365Smlaier else { 704130365Smlaier tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate; 705130365Smlaier if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth) 706130365Smlaier tcm->cmtd_tb.token = tcm->cmtd_tb.depth; 707130365Smlaier } 708130365Smlaier tcm->cmtd_tb.last = now; 709130365Smlaier } 710130365Smlaier if (tcm->peak_tb.token < len) { 711130365Smlaier interval = now - tcm->peak_tb.last; 712130365Smlaier if (interval >= tcm->peak_tb.filluptime) 713130365Smlaier tcm->peak_tb.token = tcm->peak_tb.depth; 714130365Smlaier else { 715130365Smlaier tcm->peak_tb.token += interval * tcm->peak_tb.rate; 716130365Smlaier if (tcm->peak_tb.token > tcm->peak_tb.depth) 717130365Smlaier tcm->peak_tb.token = tcm->peak_tb.depth; 718130365Smlaier } 719130365Smlaier tcm->peak_tb.last = now; 720130365Smlaier } 721130365Smlaier 722130365Smlaier if (color == tcm->red_dscp || tcm->peak_tb.token < len) { 723130365Smlaier pktinfo->pkt_dscp = tcm->red_dscp; 724130365Smlaier PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len); 725130365Smlaier return (&tcm->red_action); 726130365Smlaier } 727130365Smlaier 728130365Smlaier if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) { 729130365Smlaier pktinfo->pkt_dscp = tcm->yellow_dscp; 730130365Smlaier tcm->peak_tb.token -= len; 731130365Smlaier PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len); 732130365Smlaier return (&tcm->yellow_action); 733130365Smlaier } 734130365Smlaier 735130365Smlaier pktinfo->pkt_dscp = tcm->green_dscp; 736130365Smlaier tcm->cmtd_tb.token -= len; 737130365Smlaier tcm->peak_tb.token -= len; 738130365Smlaier PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len); 739130365Smlaier return (&tcm->green_action); 740130365Smlaier} 741130365Smlaier 742130365Smlaier/* 743130365Smlaier * time sliding window three color marker 744130365Smlaier * as described in draft-fang-diffserv-tc-tswtcm-00.txt 745130365Smlaier */ 746130365Smlaierstatic struct tswtcm * 747130365Smlaiertswtcm_create(top, cmtd_rate, peak_rate, avg_interval, 748130365Smlaier green_action, yellow_action, red_action) 749130365Smlaier struct top_cdnr *top; 750130365Smlaier u_int32_t cmtd_rate, peak_rate, avg_interval; 751130365Smlaier struct tc_action *green_action, *yellow_action, *red_action; 752130365Smlaier{ 753130365Smlaier struct tswtcm *tsw; 754130365Smlaier 755130365Smlaier if (tca_verify_action(green_action) < 0 756130365Smlaier || tca_verify_action(yellow_action) < 0 757130365Smlaier || tca_verify_action(red_action) < 0) 758130365Smlaier return (NULL); 759130365Smlaier 760130365Smlaier if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM, 761130365Smlaier tswtcm_input)) == NULL) 762130365Smlaier return (NULL); 763130365Smlaier 764130365Smlaier tca_import_action(&tsw->green_action, green_action); 765130365Smlaier tca_import_action(&tsw->yellow_action, yellow_action); 766130365Smlaier tca_import_action(&tsw->red_action, red_action); 767130365Smlaier 768130365Smlaier /* set dscps to use */ 769130365Smlaier if (tsw->green_action.tca_code == TCACODE_MARK) 770130365Smlaier tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK; 771130365Smlaier else 772130365Smlaier tsw->green_dscp = DSCP_AF11; 773130365Smlaier if (tsw->yellow_action.tca_code == TCACODE_MARK) 774130365Smlaier tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK; 775130365Smlaier else 776130365Smlaier tsw->yellow_dscp = DSCP_AF12; 777130365Smlaier if (tsw->red_action.tca_code == TCACODE_MARK) 778130365Smlaier tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK; 779130365Smlaier else 780130365Smlaier tsw->red_dscp = DSCP_AF13; 781130365Smlaier 782130365Smlaier /* convert rates from bits/sec to bytes/sec */ 783130365Smlaier tsw->cmtd_rate = cmtd_rate / 8; 784130365Smlaier tsw->peak_rate = peak_rate / 8; 785130365Smlaier tsw->avg_rate = 0; 786130365Smlaier 787130365Smlaier /* timewin is converted from msec to machine clock unit */ 788130365Smlaier tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000; 789130365Smlaier 790130365Smlaier return (tsw); 791130365Smlaier} 792130365Smlaier 793130365Smlaierstatic int 794130365Smlaiertswtcm_destroy(tsw) 795130365Smlaier struct tswtcm *tsw; 796130365Smlaier{ 797130365Smlaier if (tsw->cdnrblk.cb_ref > 0) 798130365Smlaier return (EBUSY); 799130365Smlaier 800130365Smlaier tca_invalidate_action(&tsw->green_action); 801130365Smlaier tca_invalidate_action(&tsw->yellow_action); 802130365Smlaier tca_invalidate_action(&tsw->red_action); 803130365Smlaier 804130365Smlaier cdnr_cbdestroy(tsw); 805130365Smlaier return (0); 806130365Smlaier} 807130365Smlaier 808130365Smlaierstatic struct tc_action * 809130365Smlaiertswtcm_input(cb, pktinfo) 810130365Smlaier struct cdnr_block *cb; 811130365Smlaier struct cdnr_pktinfo *pktinfo; 812130365Smlaier{ 813130365Smlaier struct tswtcm *tsw = (struct tswtcm *)cb; 814130365Smlaier int len; 815130365Smlaier u_int32_t avg_rate; 816130365Smlaier u_int64_t interval, now, tmp; 817130365Smlaier 818130365Smlaier /* 819130365Smlaier * rate estimator 820130365Smlaier */ 821130365Smlaier len = pktinfo->pkt_len; 822130365Smlaier now = read_machclk(); 823130365Smlaier 824130365Smlaier interval = now - tsw->t_front; 825130365Smlaier /* 826130365Smlaier * calculate average rate: 827130365Smlaier * avg = (avg * timewin + pkt_len)/(timewin + interval) 828130365Smlaier * pkt_len needs to be multiplied by machclk_freq in order to 829130365Smlaier * get (bytes/sec). 830130365Smlaier * note: when avg_rate (bytes/sec) and timewin (machclk unit) are 831130365Smlaier * less than 32 bits, the following 64-bit operation has enough 832130365Smlaier * precision. 833130365Smlaier */ 834130365Smlaier tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin 835130365Smlaier + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval); 836130365Smlaier tsw->avg_rate = avg_rate = (u_int32_t)tmp; 837130365Smlaier tsw->t_front = now; 838130365Smlaier 839130365Smlaier /* 840130365Smlaier * marker 841130365Smlaier */ 842130365Smlaier if (avg_rate > tsw->cmtd_rate) { 843130365Smlaier u_int32_t randval = arc4random() % avg_rate; 844130365Smlaier 845130365Smlaier if (avg_rate > tsw->peak_rate) { 846130365Smlaier if (randval < avg_rate - tsw->peak_rate) { 847130365Smlaier /* mark red */ 848130365Smlaier pktinfo->pkt_dscp = tsw->red_dscp; 849130365Smlaier PKTCNTR_ADD(&tsw->red_cnt, len); 850130365Smlaier return (&tsw->red_action); 851130365Smlaier } else if (randval < avg_rate - tsw->cmtd_rate) 852130365Smlaier goto mark_yellow; 853130365Smlaier } else { 854130365Smlaier /* peak_rate >= avg_rate > cmtd_rate */ 855130365Smlaier if (randval < avg_rate - tsw->cmtd_rate) { 856130365Smlaier mark_yellow: 857130365Smlaier pktinfo->pkt_dscp = tsw->yellow_dscp; 858130365Smlaier PKTCNTR_ADD(&tsw->yellow_cnt, len); 859130365Smlaier return (&tsw->yellow_action); 860130365Smlaier } 861130365Smlaier } 862130365Smlaier } 863130365Smlaier 864130365Smlaier /* mark green */ 865130365Smlaier pktinfo->pkt_dscp = tsw->green_dscp; 866130365Smlaier PKTCNTR_ADD(&tsw->green_cnt, len); 867130365Smlaier return (&tsw->green_action); 868130365Smlaier} 869130365Smlaier 870130365Smlaier/* 871130365Smlaier * ioctl requests 872130365Smlaier */ 873130365Smlaierstatic int 874130365Smlaiercdnrcmd_if_attach(ifname) 875130365Smlaier char *ifname; 876130365Smlaier{ 877130365Smlaier struct ifnet *ifp; 878130365Smlaier struct top_cdnr *top; 879130365Smlaier 880130365Smlaier if ((ifp = ifunit(ifname)) == NULL) 881130365Smlaier return (EBADF); 882130365Smlaier 883130365Smlaier if (ifp->if_snd.altq_cdnr != NULL) 884130365Smlaier return (EBUSY); 885130365Smlaier 886130365Smlaier if ((top = top_create(&ifp->if_snd)) == NULL) 887130365Smlaier return (ENOMEM); 888130365Smlaier return (0); 889130365Smlaier} 890130365Smlaier 891130365Smlaierstatic int 892130365Smlaiercdnrcmd_if_detach(ifname) 893130365Smlaier char *ifname; 894130365Smlaier{ 895130365Smlaier struct top_cdnr *top; 896130365Smlaier 897130365Smlaier if ((top = tcb_lookup(ifname)) == NULL) 898130365Smlaier return (EBADF); 899130365Smlaier 900130365Smlaier return top_destroy(top); 901130365Smlaier} 902130365Smlaier 903130365Smlaierstatic int 904130365Smlaiercdnrcmd_add_element(ap) 905130365Smlaier struct cdnr_add_element *ap; 906130365Smlaier{ 907130365Smlaier struct top_cdnr *top; 908130365Smlaier struct cdnr_block *cb; 909130365Smlaier 910130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 911130365Smlaier return (EBADF); 912130365Smlaier 913130365Smlaier cb = element_create(top, &ap->action); 914130365Smlaier if (cb == NULL) 915130365Smlaier return (EINVAL); 916130365Smlaier /* return a class handle to the user */ 917130365Smlaier ap->cdnr_handle = cdnr_cb2handle(cb); 918130365Smlaier return (0); 919130365Smlaier} 920130365Smlaier 921130365Smlaierstatic int 922130365Smlaiercdnrcmd_delete_element(ap) 923130365Smlaier struct cdnr_delete_element *ap; 924130365Smlaier{ 925130365Smlaier struct top_cdnr *top; 926130365Smlaier struct cdnr_block *cb; 927130365Smlaier 928130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 929130365Smlaier return (EBADF); 930130365Smlaier 931130365Smlaier if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL) 932130365Smlaier return (EINVAL); 933130365Smlaier 934130365Smlaier if (cb->cb_type != TCETYPE_ELEMENT) 935130365Smlaier return generic_element_destroy(cb); 936130365Smlaier 937130365Smlaier return element_destroy(cb); 938130365Smlaier} 939130365Smlaier 940130365Smlaierstatic int 941130365Smlaiercdnrcmd_add_filter(ap) 942130365Smlaier struct cdnr_add_filter *ap; 943130365Smlaier{ 944130365Smlaier struct top_cdnr *top; 945130365Smlaier struct cdnr_block *cb; 946130365Smlaier 947130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 948130365Smlaier return (EBADF); 949130365Smlaier 950130365Smlaier if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL) 951130365Smlaier return (EINVAL); 952130365Smlaier 953130365Smlaier return acc_add_filter(&top->tc_classifier, &ap->filter, 954130365Smlaier cb, &ap->filter_handle); 955130365Smlaier} 956130365Smlaier 957130365Smlaierstatic int 958130365Smlaiercdnrcmd_delete_filter(ap) 959130365Smlaier struct cdnr_delete_filter *ap; 960130365Smlaier{ 961130365Smlaier struct top_cdnr *top; 962130365Smlaier 963130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 964130365Smlaier return (EBADF); 965130365Smlaier 966130365Smlaier return acc_delete_filter(&top->tc_classifier, ap->filter_handle); 967130365Smlaier} 968130365Smlaier 969130365Smlaierstatic int 970130365Smlaiercdnrcmd_add_tbm(ap) 971130365Smlaier struct cdnr_add_tbmeter *ap; 972130365Smlaier{ 973130365Smlaier struct top_cdnr *top; 974130365Smlaier struct tbmeter *tbm; 975130365Smlaier 976130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 977130365Smlaier return (EBADF); 978130365Smlaier 979130365Smlaier tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action); 980130365Smlaier if (tbm == NULL) 981130365Smlaier return (EINVAL); 982130365Smlaier /* return a class handle to the user */ 983130365Smlaier ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk); 984130365Smlaier return (0); 985130365Smlaier} 986130365Smlaier 987130365Smlaierstatic int 988130365Smlaiercdnrcmd_modify_tbm(ap) 989130365Smlaier struct cdnr_modify_tbmeter *ap; 990130365Smlaier{ 991130365Smlaier struct tbmeter *tbm; 992130365Smlaier 993130365Smlaier if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL) 994130365Smlaier return (EINVAL); 995130365Smlaier 996130365Smlaier tb_import_profile(&tbm->tb, &ap->profile); 997130365Smlaier 998130365Smlaier return (0); 999130365Smlaier} 1000130365Smlaier 1001130365Smlaierstatic int 1002130365Smlaiercdnrcmd_tbm_stats(ap) 1003130365Smlaier struct cdnr_tbmeter_stats *ap; 1004130365Smlaier{ 1005130365Smlaier struct tbmeter *tbm; 1006130365Smlaier 1007130365Smlaier if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL) 1008130365Smlaier return (EINVAL); 1009130365Smlaier 1010130365Smlaier ap->in_cnt = tbm->in_cnt; 1011130365Smlaier ap->out_cnt = tbm->out_cnt; 1012130365Smlaier 1013130365Smlaier return (0); 1014130365Smlaier} 1015130365Smlaier 1016130365Smlaierstatic int 1017130365Smlaiercdnrcmd_add_trtcm(ap) 1018130365Smlaier struct cdnr_add_trtcm *ap; 1019130365Smlaier{ 1020130365Smlaier struct top_cdnr *top; 1021130365Smlaier struct trtcm *tcm; 1022130365Smlaier 1023130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 1024130365Smlaier return (EBADF); 1025130365Smlaier 1026130365Smlaier tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile, 1027130365Smlaier &ap->green_action, &ap->yellow_action, 1028130365Smlaier &ap->red_action, ap->coloraware); 1029130365Smlaier if (tcm == NULL) 1030130365Smlaier return (EINVAL); 1031130365Smlaier 1032130365Smlaier /* return a class handle to the user */ 1033130365Smlaier ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk); 1034130365Smlaier return (0); 1035130365Smlaier} 1036130365Smlaier 1037130365Smlaierstatic int 1038130365Smlaiercdnrcmd_modify_trtcm(ap) 1039130365Smlaier struct cdnr_modify_trtcm *ap; 1040130365Smlaier{ 1041130365Smlaier struct trtcm *tcm; 1042130365Smlaier 1043130365Smlaier if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL) 1044130365Smlaier return (EINVAL); 1045130365Smlaier 1046130365Smlaier tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile); 1047130365Smlaier tb_import_profile(&tcm->peak_tb, &ap->peak_profile); 1048130365Smlaier 1049130365Smlaier return (0); 1050130365Smlaier} 1051130365Smlaier 1052130365Smlaierstatic int 1053130365Smlaiercdnrcmd_tcm_stats(ap) 1054130365Smlaier struct cdnr_tcm_stats *ap; 1055130365Smlaier{ 1056130365Smlaier struct cdnr_block *cb; 1057130365Smlaier 1058130365Smlaier if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL) 1059130365Smlaier return (EINVAL); 1060130365Smlaier 1061130365Smlaier if (cb->cb_type == TCETYPE_TRTCM) { 1062130365Smlaier struct trtcm *tcm = (struct trtcm *)cb; 1063130365Smlaier 1064130365Smlaier ap->green_cnt = tcm->green_cnt; 1065130365Smlaier ap->yellow_cnt = tcm->yellow_cnt; 1066130365Smlaier ap->red_cnt = tcm->red_cnt; 1067130365Smlaier } else if (cb->cb_type == TCETYPE_TSWTCM) { 1068130365Smlaier struct tswtcm *tsw = (struct tswtcm *)cb; 1069130365Smlaier 1070130365Smlaier ap->green_cnt = tsw->green_cnt; 1071130365Smlaier ap->yellow_cnt = tsw->yellow_cnt; 1072130365Smlaier ap->red_cnt = tsw->red_cnt; 1073130365Smlaier } else 1074130365Smlaier return (EINVAL); 1075130365Smlaier 1076130365Smlaier return (0); 1077130365Smlaier} 1078130365Smlaier 1079130365Smlaierstatic int 1080130365Smlaiercdnrcmd_add_tswtcm(ap) 1081130365Smlaier struct cdnr_add_tswtcm *ap; 1082130365Smlaier{ 1083130365Smlaier struct top_cdnr *top; 1084130365Smlaier struct tswtcm *tsw; 1085130365Smlaier 1086130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 1087130365Smlaier return (EBADF); 1088130365Smlaier 1089130365Smlaier if (ap->cmtd_rate > ap->peak_rate) 1090130365Smlaier return (EINVAL); 1091130365Smlaier 1092130365Smlaier tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate, 1093130365Smlaier ap->avg_interval, &ap->green_action, 1094130365Smlaier &ap->yellow_action, &ap->red_action); 1095130365Smlaier if (tsw == NULL) 1096130365Smlaier return (EINVAL); 1097130365Smlaier 1098130365Smlaier /* return a class handle to the user */ 1099130365Smlaier ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk); 1100130365Smlaier return (0); 1101130365Smlaier} 1102130365Smlaier 1103130365Smlaierstatic int 1104130365Smlaiercdnrcmd_modify_tswtcm(ap) 1105130365Smlaier struct cdnr_modify_tswtcm *ap; 1106130365Smlaier{ 1107130365Smlaier struct tswtcm *tsw; 1108130365Smlaier 1109130365Smlaier if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL) 1110130365Smlaier return (EINVAL); 1111130365Smlaier 1112130365Smlaier if (ap->cmtd_rate > ap->peak_rate) 1113130365Smlaier return (EINVAL); 1114130365Smlaier 1115130365Smlaier /* convert rates from bits/sec to bytes/sec */ 1116130365Smlaier tsw->cmtd_rate = ap->cmtd_rate / 8; 1117130365Smlaier tsw->peak_rate = ap->peak_rate / 8; 1118130365Smlaier tsw->avg_rate = 0; 1119130365Smlaier 1120130365Smlaier /* timewin is converted from msec to machine clock unit */ 1121130365Smlaier tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000; 1122130365Smlaier 1123130365Smlaier return (0); 1124130365Smlaier} 1125130365Smlaier 1126130365Smlaierstatic int 1127130365Smlaiercdnrcmd_get_stats(ap) 1128130365Smlaier struct cdnr_get_stats *ap; 1129130365Smlaier{ 1130130365Smlaier struct top_cdnr *top; 1131130365Smlaier struct cdnr_block *cb; 1132130365Smlaier struct tbmeter *tbm; 1133130365Smlaier struct trtcm *tcm; 1134130365Smlaier struct tswtcm *tsw; 1135130365Smlaier struct tce_stats tce, *usp; 1136130365Smlaier int error, n, nskip, nelements; 1137130365Smlaier 1138130365Smlaier if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL) 1139130365Smlaier return (EBADF); 1140130365Smlaier 1141130365Smlaier /* copy action stats */ 1142130365Smlaier bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts)); 1143130365Smlaier 1144130365Smlaier /* stats for each element */ 1145130365Smlaier nelements = ap->nelements; 1146130365Smlaier usp = ap->tce_stats; 1147130365Smlaier if (nelements <= 0 || usp == NULL) 1148130365Smlaier return (0); 1149130365Smlaier 1150130365Smlaier nskip = ap->nskip; 1151130365Smlaier n = 0; 1152130365Smlaier LIST_FOREACH(cb, &top->tc_elements, cb_next) { 1153130365Smlaier if (nskip > 0) { 1154130365Smlaier nskip--; 1155130365Smlaier continue; 1156130365Smlaier } 1157130365Smlaier 1158130365Smlaier bzero(&tce, sizeof(tce)); 1159130365Smlaier tce.tce_handle = cb->cb_handle; 1160130365Smlaier tce.tce_type = cb->cb_type; 1161130365Smlaier switch (cb->cb_type) { 1162130365Smlaier case TCETYPE_TBMETER: 1163130365Smlaier tbm = (struct tbmeter *)cb; 1164130365Smlaier tce.tce_cnts[0] = tbm->in_cnt; 1165130365Smlaier tce.tce_cnts[1] = tbm->out_cnt; 1166130365Smlaier break; 1167130365Smlaier case TCETYPE_TRTCM: 1168130365Smlaier tcm = (struct trtcm *)cb; 1169130365Smlaier tce.tce_cnts[0] = tcm->green_cnt; 1170130365Smlaier tce.tce_cnts[1] = tcm->yellow_cnt; 1171130365Smlaier tce.tce_cnts[2] = tcm->red_cnt; 1172130365Smlaier break; 1173130365Smlaier case TCETYPE_TSWTCM: 1174130365Smlaier tsw = (struct tswtcm *)cb; 1175130365Smlaier tce.tce_cnts[0] = tsw->green_cnt; 1176130365Smlaier tce.tce_cnts[1] = tsw->yellow_cnt; 1177130365Smlaier tce.tce_cnts[2] = tsw->red_cnt; 1178130365Smlaier break; 1179130365Smlaier default: 1180130365Smlaier continue; 1181130365Smlaier } 1182130365Smlaier 1183130365Smlaier if ((error = copyout((caddr_t)&tce, (caddr_t)usp++, 1184130365Smlaier sizeof(tce))) != 0) 1185130365Smlaier return (error); 1186130365Smlaier 1187130365Smlaier if (++n == nelements) 1188130365Smlaier break; 1189130365Smlaier } 1190130365Smlaier ap->nelements = n; 1191130365Smlaier 1192130365Smlaier return (0); 1193130365Smlaier} 1194130365Smlaier 1195130365Smlaier/* 1196130365Smlaier * conditioner device interface 1197130365Smlaier */ 1198130365Smlaierint 1199130365Smlaiercdnropen(dev, flag, fmt, p) 1200130365Smlaier dev_t dev; 1201130365Smlaier int flag, fmt; 1202130365Smlaier#if (__FreeBSD_version > 500000) 1203130365Smlaier struct thread *p; 1204130365Smlaier#else 1205130365Smlaier struct proc *p; 1206130365Smlaier#endif 1207130365Smlaier{ 1208130365Smlaier if (machclk_freq == 0) 1209130365Smlaier init_machclk(); 1210130365Smlaier 1211130365Smlaier if (machclk_freq == 0) { 1212130365Smlaier printf("cdnr: no cpu clock available!\n"); 1213130365Smlaier return (ENXIO); 1214130365Smlaier } 1215130365Smlaier 1216130365Smlaier /* everything will be done when the queueing scheme is attached. */ 1217130365Smlaier return 0; 1218130365Smlaier} 1219130365Smlaier 1220130365Smlaierint 1221130365Smlaiercdnrclose(dev, flag, fmt, p) 1222130365Smlaier dev_t dev; 1223130365Smlaier int flag, fmt; 1224130365Smlaier#if (__FreeBSD_version > 500000) 1225130365Smlaier struct thread *p; 1226130365Smlaier#else 1227130365Smlaier struct proc *p; 1228130365Smlaier#endif 1229130365Smlaier{ 1230130365Smlaier struct top_cdnr *top; 1231130365Smlaier int err, error = 0; 1232130365Smlaier 1233130365Smlaier while ((top = LIST_FIRST(&tcb_list)) != NULL) { 1234130365Smlaier /* destroy all */ 1235130365Smlaier err = top_destroy(top); 1236130365Smlaier if (err != 0 && error == 0) 1237130365Smlaier error = err; 1238130365Smlaier } 1239130365Smlaier altq_input = NULL; 1240130365Smlaier 1241130365Smlaier return (error); 1242130365Smlaier} 1243130365Smlaier 1244130365Smlaierint 1245130365Smlaiercdnrioctl(dev, cmd, addr, flag, p) 1246130365Smlaier dev_t dev; 1247130365Smlaier ioctlcmd_t cmd; 1248130365Smlaier caddr_t addr; 1249130365Smlaier int flag; 1250130365Smlaier#if (__FreeBSD_version > 500000) 1251130365Smlaier struct thread *p; 1252130365Smlaier#else 1253130365Smlaier struct proc *p; 1254130365Smlaier#endif 1255130365Smlaier{ 1256130365Smlaier struct top_cdnr *top; 1257130365Smlaier struct cdnr_interface *ifacep; 1258130365Smlaier int s, error = 0; 1259130365Smlaier 1260130365Smlaier /* check super-user privilege */ 1261130365Smlaier switch (cmd) { 1262130365Smlaier case CDNR_GETSTATS: 1263130365Smlaier break; 1264130365Smlaier default: 1265164033Srwatson#if (__FreeBSD_version > 700000) 1266164033Srwatson if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0) 1267164033Srwatson#elsif (__FreeBSD_version > 400000) 1268130365Smlaier if ((error = suser(p)) != 0) 1269130365Smlaier#else 1270130365Smlaier if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 1271130365Smlaier#endif 1272130365Smlaier return (error); 1273130365Smlaier break; 1274130365Smlaier } 1275130365Smlaier 1276130365Smlaier#ifdef __NetBSD__ 1277130365Smlaier s = splnet(); 1278130365Smlaier#else 1279130365Smlaier s = splimp(); 1280130365Smlaier#endif 1281130365Smlaier switch (cmd) { 1282130365Smlaier 1283130365Smlaier case CDNR_IF_ATTACH: 1284130365Smlaier ifacep = (struct cdnr_interface *)addr; 1285130365Smlaier error = cdnrcmd_if_attach(ifacep->cdnr_ifname); 1286130365Smlaier break; 1287130365Smlaier 1288130365Smlaier case CDNR_IF_DETACH: 1289130365Smlaier ifacep = (struct cdnr_interface *)addr; 1290130365Smlaier error = cdnrcmd_if_detach(ifacep->cdnr_ifname); 1291130365Smlaier break; 1292130365Smlaier 1293130365Smlaier case CDNR_ENABLE: 1294130365Smlaier case CDNR_DISABLE: 1295130365Smlaier ifacep = (struct cdnr_interface *)addr; 1296130365Smlaier if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) { 1297130365Smlaier error = EBADF; 1298130365Smlaier break; 1299130365Smlaier } 1300130365Smlaier 1301130365Smlaier switch (cmd) { 1302130365Smlaier 1303130365Smlaier case CDNR_ENABLE: 1304130365Smlaier ALTQ_SET_CNDTNING(top->tc_ifq); 1305130365Smlaier if (altq_input == NULL) 1306130365Smlaier altq_input = altq_cdnr_input; 1307130365Smlaier break; 1308130365Smlaier 1309130365Smlaier case CDNR_DISABLE: 1310130365Smlaier ALTQ_CLEAR_CNDTNING(top->tc_ifq); 1311130365Smlaier LIST_FOREACH(top, &tcb_list, tc_next) 1312130365Smlaier if (ALTQ_IS_CNDTNING(top->tc_ifq)) 1313130365Smlaier break; 1314130365Smlaier if (top == NULL) 1315130365Smlaier altq_input = NULL; 1316130365Smlaier break; 1317130365Smlaier } 1318130365Smlaier break; 1319130365Smlaier 1320130365Smlaier case CDNR_ADD_ELEM: 1321130365Smlaier error = cdnrcmd_add_element((struct cdnr_add_element *)addr); 1322130365Smlaier break; 1323130365Smlaier 1324130365Smlaier case CDNR_DEL_ELEM: 1325130365Smlaier error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr); 1326130365Smlaier break; 1327130365Smlaier 1328130365Smlaier case CDNR_ADD_TBM: 1329130365Smlaier error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr); 1330130365Smlaier break; 1331130365Smlaier 1332130365Smlaier case CDNR_MOD_TBM: 1333130365Smlaier error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr); 1334130365Smlaier break; 1335130365Smlaier 1336130365Smlaier case CDNR_TBM_STATS: 1337130365Smlaier error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr); 1338130365Smlaier break; 1339130365Smlaier 1340130365Smlaier case CDNR_ADD_TCM: 1341130365Smlaier error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr); 1342130365Smlaier break; 1343130365Smlaier 1344130365Smlaier case CDNR_MOD_TCM: 1345130365Smlaier error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr); 1346130365Smlaier break; 1347130365Smlaier 1348130365Smlaier case CDNR_TCM_STATS: 1349130365Smlaier error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr); 1350130365Smlaier break; 1351130365Smlaier 1352130365Smlaier case CDNR_ADD_FILTER: 1353130365Smlaier error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr); 1354130365Smlaier break; 1355130365Smlaier 1356130365Smlaier case CDNR_DEL_FILTER: 1357130365Smlaier error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr); 1358130365Smlaier break; 1359130365Smlaier 1360130365Smlaier case CDNR_GETSTATS: 1361130365Smlaier error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr); 1362130365Smlaier break; 1363130365Smlaier 1364130365Smlaier case CDNR_ADD_TSW: 1365130365Smlaier error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr); 1366130365Smlaier break; 1367130365Smlaier 1368130365Smlaier case CDNR_MOD_TSW: 1369130365Smlaier error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr); 1370130365Smlaier break; 1371130365Smlaier 1372130365Smlaier default: 1373130365Smlaier error = EINVAL; 1374130365Smlaier break; 1375130365Smlaier } 1376130365Smlaier splx(s); 1377130365Smlaier 1378130365Smlaier return error; 1379130365Smlaier} 1380130365Smlaier 1381130365Smlaier#ifdef KLD_MODULE 1382130365Smlaier 1383130365Smlaierstatic struct altqsw cdnr_sw = 1384130365Smlaier {"cdnr", cdnropen, cdnrclose, cdnrioctl}; 1385130365Smlaier 1386130365SmlaierALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw); 1387130365Smlaier 1388130365Smlaier#endif /* KLD_MODULE */ 1389130365Smlaier 1390130365Smlaier#endif /* ALTQ3_COMPAT */ 1391130365Smlaier#endif /* ALTQ_CDNR */ 1392