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 ---