ng_car.c (662c13053f4bf2d6245ba7e2b66c10d1cd5c1fb9) | ng_car.c (d0d2e523bafb74180f8bebb90788790f0d2f0290) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005 Nuno Antunes <nuno.antunes@gmail.com> 5 * Copyright (c) 2007 Alexander Motin <mav@freebsd.org> | 1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005 Nuno Antunes <nuno.antunes@gmail.com> 5 * Copyright (c) 2007 Alexander Motin <mav@freebsd.org> |
6 * Copyright (c) 2019 Lutz Donnerhacke <lutz@donnerhacke.de> |
|
6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright --- 15 unchanged lines hidden (view full) --- 29 * $FreeBSD$ 30 */ 31 32/* 33 * ng_car - An implementation of committed access rate for netgraph 34 * 35 * TODO: 36 * - Sanitize input config values (impose some limits) | 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright --- 15 unchanged lines hidden (view full) --- 30 * $FreeBSD$ 31 */ 32 33/* 34 * ng_car - An implementation of committed access rate for netgraph 35 * 36 * TODO: 37 * - Sanitize input config values (impose some limits) |
37 * - Implement internal packet painting (possibly using mbuf tags) 38 * - Implement color-aware mode | |
39 * - Implement DSCP marking for IPv4 | 38 * - Implement DSCP marking for IPv4 |
39 * - Decouple functionality into a simple classifier (g/y/r) 40 * and various action nodes (i.e. shape, dcsp, pcp) |
|
40 */ 41 42#include <sys/param.h> 43#include <sys/errno.h> 44#include <sys/kernel.h> 45#include <sys/malloc.h> 46#include <sys/mbuf.h> 47 48#include <netgraph/ng_message.h> 49#include <netgraph/ng_parse.h> 50#include <netgraph/netgraph.h> 51#include <netgraph/ng_car.h> 52 | 41 */ 42 43#include <sys/param.h> 44#include <sys/errno.h> 45#include <sys/kernel.h> 46#include <sys/malloc.h> 47#include <sys/mbuf.h> 48 49#include <netgraph/ng_message.h> 50#include <netgraph/ng_parse.h> 51#include <netgraph/netgraph.h> 52#include <netgraph/ng_car.h> 53 |
54#include "qos.h" 55 |
|
53#define NG_CAR_QUEUE_SIZE 100 /* Maximum queue size for SHAPE mode */ 54#define NG_CAR_QUEUE_MIN_TH 8 /* Minimum RED threshold for SHAPE mode */ 55 56/* Hook private info */ 57struct hookinfo { 58 hook_p hook; /* this (source) hook */ 59 hook_p dest; /* destination hook */ 60 --- 195 unchanged lines hidden (view full) --- 256/* 257 * Data has arrived. 258 */ 259static int 260ng_car_rcvdata(hook_p hook, item_p item ) 261{ 262 struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook); 263 struct mbuf *m; | 56#define NG_CAR_QUEUE_SIZE 100 /* Maximum queue size for SHAPE mode */ 57#define NG_CAR_QUEUE_MIN_TH 8 /* Minimum RED threshold for SHAPE mode */ 58 59/* Hook private info */ 60struct hookinfo { 61 hook_p hook; /* this (source) hook */ 62 hook_p dest; /* destination hook */ 63 --- 195 unchanged lines hidden (view full) --- 259/* 260 * Data has arrived. 261 */ 262static int 263ng_car_rcvdata(hook_p hook, item_p item ) 264{ 265 struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook); 266 struct mbuf *m; |
267 struct m_qos_color *colp; 268 enum qos_color col; |
|
264 int error = 0; 265 u_int len; 266 267 /* If queue is not empty now then enqueue packet. */ 268 if (hinfo->q_first != hinfo->q_last) { 269 ng_car_enqueue(hinfo, item); 270 return (0); 271 } 272 273 m = NGI_M(item); 274 | 269 int error = 0; 270 u_int len; 271 272 /* If queue is not empty now then enqueue packet. */ 273 if (hinfo->q_first != hinfo->q_last) { 274 ng_car_enqueue(hinfo, item); 275 return (0); 276 } 277 278 m = NGI_M(item); 279 |
275#define NG_CAR_PERFORM_MATCH_ACTION(a) \ | 280#define NG_CAR_PERFORM_MATCH_ACTION(a,col) \ |
276 do { \ 277 switch (a) { \ 278 case NG_CAR_ACTION_FORWARD: \ 279 /* Do nothing. */ \ 280 break; \ 281 case NG_CAR_ACTION_MARK: \ | 281 do { \ 282 switch (a) { \ 283 case NG_CAR_ACTION_FORWARD: \ 284 /* Do nothing. */ \ 285 break; \ 286 case NG_CAR_ACTION_MARK: \ |
282 /* XXX find a way to mark packets (mbuf tag?) */ \ 283 ++hinfo->stats.errors; \ | 287 if (colp == NULL) { \ 288 colp = (void *)m_tag_alloc( \ 289 M_QOS_COOKIE, M_QOS_COLOR, \ 290 MTAG_SIZE(m_qos_color), M_NOWAIT); \ 291 if (colp != NULL) \ 292 m_tag_prepend(m, &colp->tag); \ 293 } \ 294 if (colp != NULL) \ 295 colp->color = col; \ |
284 break; \ 285 case NG_CAR_ACTION_DROP: \ 286 default: \ 287 /* Drop packet and return. */ \ 288 NG_FREE_ITEM(item); \ 289 ++hinfo->stats.dropped_pkts; \ 290 return (0); \ 291 } \ 292 } while (0) 293 294 /* Packet is counted as 128 tokens for better resolution */ 295 if (hinfo->conf.opt & NG_CAR_COUNT_PACKETS) { 296 len = 128; 297 } else { 298 len = m->m_pkthdr.len; 299 } 300 | 296 break; \ 297 case NG_CAR_ACTION_DROP: \ 298 default: \ 299 /* Drop packet and return. */ \ 300 NG_FREE_ITEM(item); \ 301 ++hinfo->stats.dropped_pkts; \ 302 return (0); \ 303 } \ 304 } while (0) 305 306 /* Packet is counted as 128 tokens for better resolution */ 307 if (hinfo->conf.opt & NG_CAR_COUNT_PACKETS) { 308 len = 128; 309 } else { 310 len = m->m_pkthdr.len; 311 } 312 |
313 /* Determine current color of the packet (default green) */ 314 colp = (void *)m_tag_locate(m, M_QOS_COOKIE, M_QOS_COLOR, NULL); 315 if ((hinfo->conf.opt & NG_CAR_COLOR_AWARE) && (colp != NULL)) 316 col = colp->color; 317 else 318 col = QOS_COLOR_GREEN; 319 |
|
301 /* Check committed token bucket. */ | 320 /* Check committed token bucket. */ |
302 if (hinfo->tc - len >= 0) { | 321 if (hinfo->tc - len >= 0 && col <= QOS_COLOR_GREEN) { |
303 /* This packet is green. */ 304 ++hinfo->stats.green_pkts; 305 hinfo->tc -= len; | 322 /* This packet is green. */ 323 ++hinfo->stats.green_pkts; 324 hinfo->tc -= len; |
306 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action); | 325 NG_CAR_PERFORM_MATCH_ACTION( 326 hinfo->conf.green_action, 327 QOS_COLOR_GREEN); |
307 } else { 308 /* Refill only if not green without it. */ 309 ng_car_refillhook(hinfo); 310 311 /* Check committed token bucket again after refill. */ | 328 } else { 329 /* Refill only if not green without it. */ 330 ng_car_refillhook(hinfo); 331 332 /* Check committed token bucket again after refill. */ |
312 if (hinfo->tc - len >= 0) { | 333 if (hinfo->tc - len >= 0 && col <= QOS_COLOR_GREEN) { |
313 /* This packet is green */ 314 ++hinfo->stats.green_pkts; 315 hinfo->tc -= len; | 334 /* This packet is green */ 335 ++hinfo->stats.green_pkts; 336 hinfo->tc -= len; |
316 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action); | 337 NG_CAR_PERFORM_MATCH_ACTION( 338 hinfo->conf.green_action, 339 QOS_COLOR_GREEN); |
317 318 /* If not green and mode is SHAPE, enqueue packet. */ 319 } else if (hinfo->conf.mode == NG_CAR_SHAPE) { 320 ng_car_enqueue(hinfo, item); 321 return (0); 322 323 /* If not green and mode is RED, calculate probability. */ 324 } else if (hinfo->conf.mode == NG_CAR_RED) { 325 /* Is packet is bigger then extended burst? */ | 340 341 /* If not green and mode is SHAPE, enqueue packet. */ 342 } else if (hinfo->conf.mode == NG_CAR_SHAPE) { 343 ng_car_enqueue(hinfo, item); 344 return (0); 345 346 /* If not green and mode is RED, calculate probability. */ 347 } else if (hinfo->conf.mode == NG_CAR_RED) { 348 /* Is packet is bigger then extended burst? */ |
326 if (len - (hinfo->tc - len) > hinfo->conf.ebs) { | 349 if (len - (hinfo->tc - len) > hinfo->conf.ebs || 350 col >= QOS_COLOR_RED) { |
327 /* This packet is definitely red. */ 328 ++hinfo->stats.red_pkts; 329 hinfo->te = 0; | 351 /* This packet is definitely red. */ 352 ++hinfo->stats.red_pkts; 353 hinfo->te = 0; |
330 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action); | 354 NG_CAR_PERFORM_MATCH_ACTION( 355 hinfo->conf.red_action, 356 QOS_COLOR_RED); |
331 332 /* Use token bucket to simulate RED-like drop 333 probability. */ | 357 358 /* Use token bucket to simulate RED-like drop 359 probability. */ |
334 } else if (hinfo->te + (len - hinfo->tc) < 335 hinfo->conf.ebs) { | 360 } else if (hinfo->te + (len - hinfo->tc) < hinfo->conf.ebs && 361 col <= QOS_COLOR_YELLOW) { |
336 /* This packet is yellow */ 337 ++hinfo->stats.yellow_pkts; 338 hinfo->te += len - hinfo->tc; 339 /* Go to negative tokens. */ 340 hinfo->tc -= len; | 362 /* This packet is yellow */ 363 ++hinfo->stats.yellow_pkts; 364 hinfo->te += len - hinfo->tc; 365 /* Go to negative tokens. */ 366 hinfo->tc -= len; |
341 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action); | 367 NG_CAR_PERFORM_MATCH_ACTION( 368 hinfo->conf.yellow_action, 369 QOS_COLOR_YELLOW); |
342 } else { 343 /* This packet is probably red. */ 344 ++hinfo->stats.red_pkts; 345 hinfo->te = 0; | 370 } else { 371 /* This packet is probably red. */ 372 ++hinfo->stats.red_pkts; 373 hinfo->te = 0; |
346 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action); | 374 NG_CAR_PERFORM_MATCH_ACTION( 375 hinfo->conf.red_action, 376 QOS_COLOR_RED); |
347 } 348 /* If not green and mode is SINGLE/DOUBLE RATE. */ 349 } else { 350 /* Check extended token bucket. */ | 377 } 378 /* If not green and mode is SINGLE/DOUBLE RATE. */ 379 } else { 380 /* Check extended token bucket. */ |
351 if (hinfo->te - len >= 0) { | 381 if (hinfo->te - len >= 0 && col <= QOS_COLOR_YELLOW) { |
352 /* This packet is yellow */ 353 ++hinfo->stats.yellow_pkts; 354 hinfo->te -= len; | 382 /* This packet is yellow */ 383 ++hinfo->stats.yellow_pkts; 384 hinfo->te -= len; |
355 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action); | 385 NG_CAR_PERFORM_MATCH_ACTION( 386 hinfo->conf.yellow_action, 387 QOS_COLOR_YELLOW); |
356 } else { 357 /* This packet is red */ 358 ++hinfo->stats.red_pkts; | 388 } else { 389 /* This packet is red */ 390 ++hinfo->stats.red_pkts; |
359 NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action); | 391 NG_CAR_PERFORM_MATCH_ACTION( 392 hinfo->conf.red_action, 393 QOS_COLOR_RED); |
360 } 361 } 362 } 363 364#undef NG_CAR_PERFORM_MATCH_ACTION 365 366 NG_FWD_ITEM_HOOK(error, item, hinfo->dest); 367 if (error != 0) --- 336 unchanged lines hidden (view full) --- 704} 705 706/* 707 * Enqueue packet. 708 */ 709static void 710ng_car_enqueue(struct hookinfo *hinfo, item_p item) 711{ | 394 } 395 } 396 } 397 398#undef NG_CAR_PERFORM_MATCH_ACTION 399 400 NG_FWD_ITEM_HOOK(error, item, hinfo->dest); 401 if (error != 0) --- 336 unchanged lines hidden (view full) --- 738} 739 740/* 741 * Enqueue packet. 742 */ 743static void 744ng_car_enqueue(struct hookinfo *hinfo, item_p item) 745{ |
712 struct mbuf *m; 713 int len; | 746 struct mbuf *m; 747 int len; 748 struct m_qos_color *colp; 749 enum qos_color col; |
714 715 NGI_GET_M(item, m); 716 NG_FREE_ITEM(item); 717 | 750 751 NGI_GET_M(item, m); 752 NG_FREE_ITEM(item); 753 |
754 /* Determine current color of the packet (default green) */ 755 colp = (void *)m_tag_locate(m, M_QOS_COOKIE, M_QOS_COLOR, NULL); 756 if ((hinfo->conf.opt & NG_CAR_COLOR_AWARE) && (colp != NULL)) 757 col = colp->color; 758 else 759 col = QOS_COLOR_GREEN; 760 |
|
718 /* Lock queue mutex. */ 719 mtx_lock(&hinfo->q_mtx); 720 721 /* Calculate used queue length. */ 722 len = hinfo->q_last - hinfo->q_first; 723 if (len < 0) 724 len += NG_CAR_QUEUE_SIZE; 725 726 /* If queue is overflowed or we have no RED tokens. */ 727 if ((len >= (NG_CAR_QUEUE_SIZE - 1)) || | 761 /* Lock queue mutex. */ 762 mtx_lock(&hinfo->q_mtx); 763 764 /* Calculate used queue length. */ 765 len = hinfo->q_last - hinfo->q_first; 766 if (len < 0) 767 len += NG_CAR_QUEUE_SIZE; 768 769 /* If queue is overflowed or we have no RED tokens. */ 770 if ((len >= (NG_CAR_QUEUE_SIZE - 1)) || |
728 (hinfo->te + len >= NG_CAR_QUEUE_SIZE)) { | 771 (hinfo->te + len >= NG_CAR_QUEUE_SIZE) || 772 (col >= QOS_COLOR_RED)) { |
729 /* Drop packet. */ 730 ++hinfo->stats.red_pkts; 731 ++hinfo->stats.dropped_pkts; 732 NG_FREE_M(m); 733 734 hinfo->te = 0; 735 } else { 736 /* This packet is yellow. */ --- 28 unchanged lines hidden --- | 773 /* Drop packet. */ 774 ++hinfo->stats.red_pkts; 775 ++hinfo->stats.dropped_pkts; 776 NG_FREE_M(m); 777 778 hinfo->te = 0; 779 } else { 780 /* This packet is yellow. */ --- 28 unchanged lines hidden --- |