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:
Lutz Donnerhacke 2021-01-27 21:19:14 +01:00
parent 65efb73fbd
commit d0d2e523ba
4 changed files with 156 additions and 27 deletions

View File

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

View File

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

View File

@ -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
View 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_ */