From owner-dev-commits-src-all@freebsd.org Wed Jan 27 20:29:55 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 406C34E8ACC; Wed, 27 Jan 2021 20:29:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4DQwFb0Md8z3KxY; Wed, 27 Jan 2021 20:29:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id F37B72301E; Wed, 27 Jan 2021 20:29:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 10RKTsuO002836; Wed, 27 Jan 2021 20:29:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 10RKTsk5002835; Wed, 27 Jan 2021 20:29:54 GMT (envelope-from git) Date: Wed, 27 Jan 2021 20:29:54 GMT Message-Id: <202101272029.10RKTsk5002835@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Lutz Donnerhacke Subject: git: d0d2e523bafb - main - netgraph/ng_car: Add color marking code MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: donner X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d0d2e523bafb74180f8bebb90788790f0d2f0290 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Jan 2021 20:29:55 -0000 The branch main has been updated by donner: URL: https://cgit.FreeBSD.org/src/commit/?id=d0d2e523bafb74180f8bebb90788790f0d2f0290 commit d0d2e523bafb74180f8bebb90788790f0d2f0290 Author: Lutz Donnerhacke AuthorDate: 2021-01-27 20:19:14 +0000 Commit: Lutz Donnerhacke CommitDate: 2021-01-27 20:22:51 +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 Approved by: kp (mentor) Sponsored by: IKS Service GmbH MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D22110 --- 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 f3a01b6880e1..abb522ae151b 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 1f74c4b193d0..9474e2467439 100644 --- a/sys/netgraph/ng_car.c +++ b/sys/netgraph/ng_car.c @@ -3,6 +3,7 @@ * * Copyright (c) 2005 Nuno Antunes * Copyright (c) 2007 Alexander Motin + * Copyright (c) 2019 Lutz Donnerhacke * 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 @@ -50,6 +51,8 @@ #include #include +#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 + * + * 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 + +/* 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_ */