netgraph/ng_car: Add color marking code
Chained policing should be able to reuse the classification of traffic. A new mbuf_tag type is defined to handle gereral QoS marking. A new subtype is defined to track the color marking. Reviewed by: manpages (bcr), melifaro, kp Approved by: kp (mentor) Sponsored by: IKS Service GmbH MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D22110
This commit is contained in:
parent
65efb73fbd
commit
d0d2e523ba
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 13, 2012
|
||||
.Dd January 27, 2021
|
||||
.Dt NG_CAR 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -108,6 +108,7 @@ Traffic shaping is much more polite to the TCP traffic than rate limit on
|
||||
links with bandwidth * delay product less than 6-8 TCP segments, but it
|
||||
consumes additional system resources for queue processing.
|
||||
.El
|
||||
.Pp
|
||||
By default, all information rates are measured in bits per second and bursts
|
||||
are measured in bytes.
|
||||
But when NG_CAR_COUNT_PACKETS option is enabled,
|
||||
@ -138,7 +139,8 @@ struct ng_car_hookconf {
|
||||
/* possible actions (..._action) */
|
||||
enum {
|
||||
NG_CAR_ACTION_FORWARD = 1,
|
||||
NG_CAR_ACTION_DROP
|
||||
NG_CAR_ACTION_DROP,
|
||||
NG_CAR_ACTION_MARK
|
||||
};
|
||||
|
||||
/* operation modes (mode) */
|
||||
@ -149,7 +151,8 @@ enum {
|
||||
NG_CAR_SHAPE
|
||||
};
|
||||
|
||||
/* mode options (opt) */
|
||||
/* mode options (bits for opt) */
|
||||
#define NG_CAR_COLOR_AWARE 1
|
||||
#define NG_CAR_COUNT_PACKETS 2
|
||||
|
||||
struct ng_car_bulkconf {
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2005 Nuno Antunes <nuno.antunes@gmail.com>
|
||||
* Copyright (c) 2007 Alexander Motin <mav@freebsd.org>
|
||||
* Copyright (c) 2019 Lutz Donnerhacke <lutz@donnerhacke.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -34,9 +35,9 @@
|
||||
*
|
||||
* TODO:
|
||||
* - Sanitize input config values (impose some limits)
|
||||
* - Implement internal packet painting (possibly using mbuf tags)
|
||||
* - Implement color-aware mode
|
||||
* - Implement DSCP marking for IPv4
|
||||
* - Decouple functionality into a simple classifier (g/y/r)
|
||||
* and various action nodes (i.e. shape, dcsp, pcp)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -50,6 +51,8 @@
|
||||
#include <netgraph/netgraph.h>
|
||||
#include <netgraph/ng_car.h>
|
||||
|
||||
#include "qos.h"
|
||||
|
||||
#define NG_CAR_QUEUE_SIZE 100 /* Maximum queue size for SHAPE mode */
|
||||
#define NG_CAR_QUEUE_MIN_TH 8 /* Minimum RED threshold for SHAPE mode */
|
||||
|
||||
@ -261,6 +264,8 @@ ng_car_rcvdata(hook_p hook, item_p item )
|
||||
{
|
||||
struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook);
|
||||
struct mbuf *m;
|
||||
struct m_qos_color *colp;
|
||||
enum qos_color col;
|
||||
int error = 0;
|
||||
u_int len;
|
||||
|
||||
@ -272,15 +277,22 @@ ng_car_rcvdata(hook_p hook, item_p item )
|
||||
|
||||
m = NGI_M(item);
|
||||
|
||||
#define NG_CAR_PERFORM_MATCH_ACTION(a) \
|
||||
#define NG_CAR_PERFORM_MATCH_ACTION(a,col) \
|
||||
do { \
|
||||
switch (a) { \
|
||||
case NG_CAR_ACTION_FORWARD: \
|
||||
/* Do nothing. */ \
|
||||
break; \
|
||||
case NG_CAR_ACTION_MARK: \
|
||||
/* XXX find a way to mark packets (mbuf tag?) */ \
|
||||
++hinfo->stats.errors; \
|
||||
if (colp == NULL) { \
|
||||
colp = (void *)m_tag_alloc( \
|
||||
M_QOS_COOKIE, M_QOS_COLOR, \
|
||||
MTAG_SIZE(m_qos_color), M_NOWAIT); \
|
||||
if (colp != NULL) \
|
||||
m_tag_prepend(m, &colp->tag); \
|
||||
} \
|
||||
if (colp != NULL) \
|
||||
colp->color = col; \
|
||||
break; \
|
||||
case NG_CAR_ACTION_DROP: \
|
||||
default: \
|
||||
@ -298,22 +310,33 @@ ng_car_rcvdata(hook_p hook, item_p item )
|
||||
len = m->m_pkthdr.len;
|
||||
}
|
||||
|
||||
/* Determine current color of the packet (default green) */
|
||||
colp = (void *)m_tag_locate(m, M_QOS_COOKIE, M_QOS_COLOR, NULL);
|
||||
if ((hinfo->conf.opt & NG_CAR_COLOR_AWARE) && (colp != NULL))
|
||||
col = colp->color;
|
||||
else
|
||||
col = QOS_COLOR_GREEN;
|
||||
|
||||
/* Check committed token bucket. */
|
||||
if (hinfo->tc - len >= 0) {
|
||||
if (hinfo->tc - len >= 0 && col <= QOS_COLOR_GREEN) {
|
||||
/* This packet is green. */
|
||||
++hinfo->stats.green_pkts;
|
||||
hinfo->tc -= len;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.green_action,
|
||||
QOS_COLOR_GREEN);
|
||||
} else {
|
||||
/* Refill only if not green without it. */
|
||||
ng_car_refillhook(hinfo);
|
||||
|
||||
/* Check committed token bucket again after refill. */
|
||||
if (hinfo->tc - len >= 0) {
|
||||
if (hinfo->tc - len >= 0 && col <= QOS_COLOR_GREEN) {
|
||||
/* This packet is green */
|
||||
++hinfo->stats.green_pkts;
|
||||
hinfo->tc -= len;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.green_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.green_action,
|
||||
QOS_COLOR_GREEN);
|
||||
|
||||
/* If not green and mode is SHAPE, enqueue packet. */
|
||||
} else if (hinfo->conf.mode == NG_CAR_SHAPE) {
|
||||
@ -323,40 +346,51 @@ ng_car_rcvdata(hook_p hook, item_p item )
|
||||
/* If not green and mode is RED, calculate probability. */
|
||||
} else if (hinfo->conf.mode == NG_CAR_RED) {
|
||||
/* Is packet is bigger then extended burst? */
|
||||
if (len - (hinfo->tc - len) > hinfo->conf.ebs) {
|
||||
if (len - (hinfo->tc - len) > hinfo->conf.ebs ||
|
||||
col >= QOS_COLOR_RED) {
|
||||
/* This packet is definitely red. */
|
||||
++hinfo->stats.red_pkts;
|
||||
hinfo->te = 0;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.red_action,
|
||||
QOS_COLOR_RED);
|
||||
|
||||
/* Use token bucket to simulate RED-like drop
|
||||
probability. */
|
||||
} else if (hinfo->te + (len - hinfo->tc) <
|
||||
hinfo->conf.ebs) {
|
||||
} else if (hinfo->te + (len - hinfo->tc) < hinfo->conf.ebs &&
|
||||
col <= QOS_COLOR_YELLOW) {
|
||||
/* This packet is yellow */
|
||||
++hinfo->stats.yellow_pkts;
|
||||
hinfo->te += len - hinfo->tc;
|
||||
/* Go to negative tokens. */
|
||||
hinfo->tc -= len;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.yellow_action,
|
||||
QOS_COLOR_YELLOW);
|
||||
} else {
|
||||
/* This packet is probably red. */
|
||||
++hinfo->stats.red_pkts;
|
||||
hinfo->te = 0;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.red_action,
|
||||
QOS_COLOR_RED);
|
||||
}
|
||||
/* If not green and mode is SINGLE/DOUBLE RATE. */
|
||||
} else {
|
||||
/* Check extended token bucket. */
|
||||
if (hinfo->te - len >= 0) {
|
||||
if (hinfo->te - len >= 0 && col <= QOS_COLOR_YELLOW) {
|
||||
/* This packet is yellow */
|
||||
++hinfo->stats.yellow_pkts;
|
||||
hinfo->te -= len;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.yellow_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.yellow_action,
|
||||
QOS_COLOR_YELLOW);
|
||||
} else {
|
||||
/* This packet is red */
|
||||
++hinfo->stats.red_pkts;
|
||||
NG_CAR_PERFORM_MATCH_ACTION(hinfo->conf.red_action);
|
||||
NG_CAR_PERFORM_MATCH_ACTION(
|
||||
hinfo->conf.red_action,
|
||||
QOS_COLOR_RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -709,12 +743,21 @@ ng_car_q_event(node_p node, hook_p hook, void *arg, int arg2)
|
||||
static void
|
||||
ng_car_enqueue(struct hookinfo *hinfo, item_p item)
|
||||
{
|
||||
struct mbuf *m;
|
||||
int len;
|
||||
struct mbuf *m;
|
||||
int len;
|
||||
struct m_qos_color *colp;
|
||||
enum qos_color col;
|
||||
|
||||
NGI_GET_M(item, m);
|
||||
NG_FREE_ITEM(item);
|
||||
|
||||
/* Determine current color of the packet (default green) */
|
||||
colp = (void *)m_tag_locate(m, M_QOS_COOKIE, M_QOS_COLOR, NULL);
|
||||
if ((hinfo->conf.opt & NG_CAR_COLOR_AWARE) && (colp != NULL))
|
||||
col = colp->color;
|
||||
else
|
||||
col = QOS_COLOR_GREEN;
|
||||
|
||||
/* Lock queue mutex. */
|
||||
mtx_lock(&hinfo->q_mtx);
|
||||
|
||||
@ -725,7 +768,8 @@ ng_car_enqueue(struct hookinfo *hinfo, item_p item)
|
||||
|
||||
/* If queue is overflowed or we have no RED tokens. */
|
||||
if ((len >= (NG_CAR_QUEUE_SIZE - 1)) ||
|
||||
(hinfo->te + len >= NG_CAR_QUEUE_SIZE)) {
|
||||
(hinfo->te + len >= NG_CAR_QUEUE_SIZE) ||
|
||||
(col >= QOS_COLOR_RED)) {
|
||||
/* Drop packet. */
|
||||
++hinfo->stats.red_pkts;
|
||||
++hinfo->stats.dropped_pkts;
|
||||
|
@ -103,8 +103,7 @@ struct ng_car_hookconf {
|
||||
enum {
|
||||
NG_CAR_ACTION_FORWARD = 1,
|
||||
NG_CAR_ACTION_DROP,
|
||||
NG_CAR_ACTION_MARK,
|
||||
NG_CAR_ACTION_SET_TOS
|
||||
NG_CAR_ACTION_MARK
|
||||
};
|
||||
|
||||
/* operation modes (mode) */
|
||||
@ -115,7 +114,7 @@ enum {
|
||||
NG_CAR_SHAPE
|
||||
};
|
||||
|
||||
/* mode options (opt) */
|
||||
/* mode options (bits in opt) */
|
||||
#define NG_CAR_COLOR_AWARE 1
|
||||
#define NG_CAR_COUNT_PACKETS 2
|
||||
|
||||
|
83
sys/netgraph/qos.h
Normal file
83
sys/netgraph/qos.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2019 Lutz Donnerhacke <lutz@donnerhacke.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETGRAPH_QOS_H_
|
||||
#define _NETGRAPH_QOS_H_
|
||||
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
/* ABI cookie */
|
||||
#define M_QOS_COOKIE 1571268051
|
||||
#define MTAG_SIZE(X) ( sizeof(struct X) - sizeof(struct m_tag) )
|
||||
|
||||
/*
|
||||
* Definition of types within this ABI:
|
||||
* - Choose a type (16bit) by i.e. "echo $((1000+$(date +%s)%64536))"
|
||||
* - Retry if the type is already in use
|
||||
* - Define the structure for the type according to mbuf_tags(9)
|
||||
* struct m_qos_foo {
|
||||
* struct m_tag tag;
|
||||
* ...
|
||||
* };
|
||||
* Preferred usage:
|
||||
* struct m_qos_foo *p = (void *)m_tag_locate(m,
|
||||
* M_QOS_COOKIE, M_QOS_FOO, ...);
|
||||
* or
|
||||
* p = (void *)m_tag_alloc(
|
||||
* M_QOS_COOKIE, M_QOS_FOO, MTAG_SIZE(foo), ...);
|
||||
m_tag_prepend(m, &p->tag);
|
||||
*/
|
||||
|
||||
/* Color marking type */
|
||||
#define M_QOS_COLOR 23568
|
||||
/* Keep colors ordered semantically in order to allow use of "<=" or ">=" */
|
||||
enum qos_color {
|
||||
QOS_COLOR_GREEN,
|
||||
QOS_COLOR_YELLOW,
|
||||
QOS_COLOR_RED
|
||||
};
|
||||
struct m_qos_color {
|
||||
struct m_tag tag;
|
||||
enum qos_color color;
|
||||
};
|
||||
|
||||
/*
|
||||
* Priority class
|
||||
*
|
||||
* Processing per priority requires an overhead, which should
|
||||
* be static (i.e. for alloctating queues) and small (for memory)
|
||||
* So keep your chosen range limited.
|
||||
*/
|
||||
#define M_QOS_PRIORITY 28858
|
||||
struct m_qos_priority {
|
||||
struct m_tag tag;
|
||||
uint8_t priority; /* 0 - lowest */
|
||||
};
|
||||
|
||||
#endif /* _NETGRAPH_QOS_H_ */
|
Loading…
Reference in New Issue
Block a user