Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 26 Feb 2021 12:34:21 GMT
From:      Lutz Donnerhacke <donner@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: d88ac710ce58 - stable/12 - netgraph/ng_car: Add color marking code
Message-ID:  <202102261234.11QCYLNj024702@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by donner:

URL: https://cgit.FreeBSD.org/src/commit/?id=d88ac710ce5828aad6b2ea76b217f3a17ae64232

commit d88ac710ce5828aad6b2ea76b217f3a17ae64232
Author:     Lutz Donnerhacke <donner@FreeBSD.org>
AuthorDate: 2021-01-27 20:19:14 +0000
Commit:     Lutz Donnerhacke <donner@FreeBSD.org>
CommitDate: 2021-02-26 12:33:57 +0000

    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
    Sponsored by:   IKS Service GmbH
    Differential Revision: https://reviews.freebsd.org/D22110
    
    (cherry picked from commit d0d2e523bafb74180f8bebb90788790f0d2f0290)
---
 share/man/man4/ng_car.4 |  9 ++++--
 sys/netgraph/ng_car.c   | 86 +++++++++++++++++++++++++++++++++++++------------
 sys/netgraph/ng_car.h   |  5 ++-
 sys/netgraph/qos.h      | 83 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+), 27 deletions(-)

diff --git a/share/man/man4/ng_car.4 b/share/man/man4/ng_car.4
index cb1459fe6987..c42f955a106a 100644
--- a/share/man/man4/ng_car.4
+++ b/share/man/man4/ng_car.4
@@ -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 {
diff --git a/sys/netgraph/ng_car.c b/sys/netgraph/ng_car.c
index 897576349b22..d3ac2b7042a4 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,23 +310,34 @@ 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) {
@@ -324,40 +347,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);
 			}
 		}
 	}
@@ -711,12 +745,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);
 
@@ -727,7 +770,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.droped_pkts;
diff --git a/sys/netgraph/ng_car.h b/sys/netgraph/ng_car.h
index 7ca72ba929cc..d77d5dfc5f9b 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_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102261234.11QCYLNj024702>