aboutsummaryrefslogtreecommitdiff
path: root/sys/netgraph
diff options
context:
space:
mode:
authorLutz Donnerhacke <donner@FreeBSD.org>2021-01-27 20:19:14 +0000
committerLutz Donnerhacke <donner@FreeBSD.org>2021-01-27 20:22:51 +0000
commitd0d2e523bafb74180f8bebb90788790f0d2f0290 (patch)
tree27e970939c8ff95d39b94dd189e1650ae133989b /sys/netgraph
parent65efb73fbddd44116fd39b03991386a67422ba6d (diff)
downloadsrc-d0d2e523bafb74180f8bebb90788790f0d2f0290.tar.gz
src-d0d2e523bafb74180f8bebb90788790f0d2f0290.zip
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
Diffstat (limited to 'sys/netgraph')
-rw-r--r--sys/netgraph/ng_car.c86
-rw-r--r--sys/netgraph/ng_car.h5
-rw-r--r--sys/netgraph/qos.h83
3 files changed, 150 insertions, 24 deletions
diff --git a/sys/netgraph/ng_car.c b/sys/netgraph/ng_car.c
index 1f74c4b193d0..9474e2467439 100644
--- a/sys/netgraph/ng_car.c
+++ b/sys/netgraph/ng_car.c
@@ -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;
diff --git a/sys/netgraph/ng_car.h b/sys/netgraph/ng_car.h
index 7f07f87e52b8..410161af29ee 100644
--- a/sys/netgraph/ng_car.h
+++ b/sys/netgraph/ng_car.h
@@ -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
diff --git a/sys/netgraph/qos.h b/sys/netgraph/qos.h
new file mode 100644
index 000000000000..0e5dfec479eb
--- /dev/null
+++ b/sys/netgraph/qos.h
@@ -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_ */