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