diff --git a/sys/altq/altq_cbq.c b/sys/altq/altq_cbq.c index d85d0c8c7d68a..c6e1da5f7cf91 100644 --- a/sys/altq/altq_cbq.c +++ b/sys/altq/altq_cbq.c @@ -37,7 +37,7 @@ __KERNEL_RCSID(0, "$NetBSD: altq_cbq.c,v 1.41 2024/09/26 02:39:09 ozaki-r Exp $" #ifdef _KERNEL_OPT #include "opt_altq.h" #include "opt_inet.h" -#include "pf.h" +#include "npf.h" #endif #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */ @@ -59,8 +59,8 @@ __KERNEL_RCSID(0, "$NetBSD: altq_cbq.c,v 1.41 2024/09/26 02:39:09 ozaki-r Exp $" #include #include -#if NPF > 0 -#include +#if NNPF > 0 +#include #endif #include #include @@ -242,9 +242,9 @@ get_class_stats(class_stats_t *statsp, struct rm_class *cl) #endif } -#if NPF > 0 +#if NNPF > 0 int -cbq_pfattach(struct pf_altq *a) +cbq_pfattach(struct npf_altq *a) { struct ifnet *ifp; int s, error; @@ -259,7 +259,7 @@ cbq_pfattach(struct pf_altq *a) } int -cbq_add_altq(struct pf_altq *a) +cbq_add_altq(struct npf_altq *a) { cbq_state_t *cbqp; struct ifnet *ifp; @@ -285,7 +285,7 @@ cbq_add_altq(struct pf_altq *a) } int -cbq_remove_altq(struct pf_altq *a) +cbq_remove_altq(struct npf_altq *a) { cbq_state_t *cbqp; @@ -308,7 +308,7 @@ cbq_remove_altq(struct pf_altq *a) #define NSEC_TO_PSEC(s) ((uint64_t)(s) * 1000) int -cbq_add_queue(struct pf_altq *a) +cbq_add_queue(struct npf_altq *a) { struct rm_class *borrow, *parent; cbq_state_t *cbqp; @@ -415,7 +415,7 @@ cbq_add_queue(struct pf_altq *a) } int -cbq_remove_queue(struct pf_altq *a) +cbq_remove_queue(struct npf_altq *a) { struct rm_class *cl; cbq_state_t *cbqp; @@ -451,7 +451,7 @@ cbq_remove_queue(struct pf_altq *a) } int -cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) +cbq_getqstats(struct npf_altq *a, void *ubuf, int *nbytes) { cbq_state_t *cbqp; struct rm_class *cl; @@ -475,7 +475,7 @@ cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) *nbytes = sizeof(stats); return (0); } -#endif /* NPF > 0 */ +#endif /* NNPF > 0 */ /* * int diff --git a/sys/altq/altq_hfsc.c b/sys/altq/altq_hfsc.c index c1feeada4b4f5..adbbb6a829f45 100644 --- a/sys/altq/altq_hfsc.c +++ b/sys/altq/altq_hfsc.c @@ -48,7 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: altq_hfsc.c,v 1.30 2021/09/21 14:30:15 christos Exp #ifdef _KERNEL_OPT #include "opt_altq.h" #include "opt_inet.h" -#include "pf.h" +#include "npf.h" #endif #ifdef ALTQ_HFSC /* hfsc is enabled by ALTQ_HFSC option in opt_altq.h */ @@ -70,8 +70,8 @@ __KERNEL_RCSID(0, "$NetBSD: altq_hfsc.c,v 1.30 2021/09/21 14:30:15 christos Exp #include #include -#if NPF > 0 -#include +#if NNPF > 0 +#include #endif #include #include @@ -173,9 +173,9 @@ altqdev_decl(hfsc); static struct hfsc_if *hif_list = NULL; #endif /* ALTQ3_COMPAT */ -#if NPF > 0 +#if NNPF > 0 int -hfsc_pfattach(struct pf_altq *a) +hfsc_pfattach(struct npf_altq *a) { struct ifnet *ifp; int s, error; @@ -190,7 +190,7 @@ hfsc_pfattach(struct pf_altq *a) } int -hfsc_add_altq(struct pf_altq *a) +hfsc_add_altq(struct npf_altq *a) { struct hfsc_if *hif; struct ifnet *ifp; @@ -219,7 +219,7 @@ hfsc_add_altq(struct pf_altq *a) } int -hfsc_remove_altq(struct pf_altq *a) +hfsc_remove_altq(struct npf_altq *a) { struct hfsc_if *hif; @@ -238,7 +238,7 @@ hfsc_remove_altq(struct pf_altq *a) } int -hfsc_add_queue(struct pf_altq *a) +hfsc_add_queue(struct npf_altq *a) { struct hfsc_if *hif; struct hfsc_class *cl, *parent; @@ -281,7 +281,7 @@ hfsc_add_queue(struct pf_altq *a) } int -hfsc_remove_queue(struct pf_altq *a) +hfsc_remove_queue(struct npf_altq *a) { struct hfsc_if *hif; struct hfsc_class *cl; @@ -296,7 +296,7 @@ hfsc_remove_queue(struct pf_altq *a) } int -hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) +hfsc_getqstats(struct npf_altq *a, void *ubuf, int *nbytes) { struct hfsc_if *hif; struct hfsc_class *cl; @@ -320,7 +320,7 @@ hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) *nbytes = sizeof(stats); return (0); } -#endif /* NPF > 0 */ +#endif /* NNPF > 0 */ /* * bring the interface back to the initial state by discarding diff --git a/sys/altq/altq_priq.c b/sys/altq/altq_priq.c index b8505ba7a9158..9f3edf245ba97 100644 --- a/sys/altq/altq_priq.c +++ b/sys/altq/altq_priq.c @@ -36,7 +36,7 @@ __KERNEL_RCSID(0, "$NetBSD: altq_priq.c,v 1.28 2021/09/21 14:30:15 christos Exp #ifdef _KERNEL_OPT #include "opt_altq.h" #include "opt_inet.h" -#include "pf.h" +#include "npf.h" #endif #ifdef ALTQ_PRIQ /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */ @@ -56,8 +56,8 @@ __KERNEL_RCSID(0, "$NetBSD: altq_priq.c,v 1.28 2021/09/21 14:30:15 christos Exp #include #include -#if NPF > 0 -#include +#if NNPF > 0 +#include #endif #include #include @@ -105,9 +105,9 @@ altqdev_decl(priq); static struct priq_if *pif_list = NULL; #endif /* ALTQ3_COMPAT */ -#if NPF > 0 +#if NNPF > 0 int -priq_pfattach(struct pf_altq *a) +priq_pfattach(struct npf_altq *a) { struct ifnet *ifp; int s, error; @@ -122,7 +122,7 @@ priq_pfattach(struct pf_altq *a) } int -priq_add_altq(struct pf_altq *a) +priq_add_altq(struct npf_altq *a) { struct priq_if *pif; struct ifnet *ifp; @@ -146,7 +146,7 @@ priq_add_altq(struct pf_altq *a) } int -priq_remove_altq(struct pf_altq *a) +priq_remove_altq(struct npf_altq *a) { struct priq_if *pif; @@ -161,7 +161,7 @@ priq_remove_altq(struct pf_altq *a) } int -priq_add_queue(struct pf_altq *a) +priq_add_queue(struct npf_altq *a) { struct priq_if *pif; struct priq_class *cl; @@ -188,7 +188,7 @@ priq_add_queue(struct pf_altq *a) } int -priq_remove_queue(struct pf_altq *a) +priq_remove_queue(struct npf_altq *a) { struct priq_if *pif; struct priq_class *cl; @@ -203,7 +203,7 @@ priq_remove_queue(struct pf_altq *a) } int -priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) +priq_getqstats(struct npf_altq *a, void *ubuf, int *nbytes) { struct priq_if *pif; struct priq_class *cl; @@ -227,7 +227,7 @@ priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) *nbytes = sizeof(stats); return (0); } -#endif /* NPF > 0 */ +#endif /* NNPF > 0 */ /* * bring the interface back to the initial state by discarding diff --git a/sys/altq/altq_subr.c b/sys/altq/altq_subr.c index 5c0c57b587f79..a6a6cd7cc6817 100644 --- a/sys/altq/altq_subr.c +++ b/sys/altq/altq_subr.c @@ -33,7 +33,7 @@ __KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.33 2017/03/14 09:03:08 ozaki-r Exp $ #ifdef _KERNEL_OPT #include "opt_altq.h" #include "opt_inet.h" -#include "pf.h" +#include "npf.h" #endif #include @@ -62,8 +62,8 @@ __KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.33 2017/03/14 09:03:08 ozaki-r Exp $ #include #include -#if NPF > 0 -#include +#if NNPF > 0 +#include #endif #include #ifdef ALTQ3_COMPAT @@ -400,13 +400,13 @@ tbr_get(struct ifaltq *ifq, struct tb_profile *profile) return (0); } -#if NPF > 0 +#if NNPF > 0 /* * attach a discipline to the interface. if one already exists, it is * overridden. */ int -altq_pfattach(struct pf_altq *a) +altq_pfattach(struct npf_altq *a) { int error = 0; @@ -441,7 +441,7 @@ altq_pfattach(struct pf_altq *a) * discipline. */ int -altq_pfdetach(struct pf_altq *a) +altq_pfdetach(struct npf_altq *a) { struct ifnet *ifp; int s, error = 0; @@ -467,7 +467,7 @@ altq_pfdetach(struct pf_altq *a) * add a discipline or a queue */ int -altq_add(struct pf_altq *a) +altq_add(struct npf_altq *a) { int error = 0; @@ -506,7 +506,7 @@ altq_add(struct pf_altq *a) * remove a discipline or a queue */ int -altq_remove(struct pf_altq *a) +altq_remove(struct npf_altq *a) { int error = 0; @@ -540,7 +540,7 @@ altq_remove(struct pf_altq *a) * add a queue to the discipline */ int -altq_add_queue(struct pf_altq *a) +altq_add_queue(struct npf_altq *a) { int error = 0; @@ -571,7 +571,7 @@ altq_add_queue(struct pf_altq *a) * remove a queue from the discipline */ int -altq_remove_queue(struct pf_altq *a) +altq_remove_queue(struct npf_altq *a) { int error = 0; @@ -602,7 +602,7 @@ altq_remove_queue(struct pf_altq *a) * get queue statistics */ int -altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) +altq_getqstats(struct npf_altq *a, void *ubuf, int *nbytes) { int error = 0; @@ -628,7 +628,7 @@ altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) return (error); } -#endif /* NPF > 0 */ +#endif /* NNPF > 0 */ /* * read and write diffserv field in IPv4 or IPv6 header diff --git a/sys/modules/npf/npf.h b/sys/modules/npf/npf.h new file mode 100644 index 0000000000000..8945345e2890c --- /dev/null +++ b/sys/modules/npf/npf.h @@ -0,0 +1 @@ +#define NNPF 1 \ No newline at end of file diff --git a/sys/net/npf/files.npf b/sys/net/npf/files.npf index 80727f79f5d39..c6346153abc69 100644 --- a/sys/net/npf/files.npf +++ b/sys/net/npf/files.npf @@ -10,7 +10,7 @@ defpseudo npf: ifnet, libnv # Core -file net/npf/npf.c npf +file net/npf/npf.c npf needs-flag file net/npf/npf_conf.c npf file net/npf/npf_ctl.c npf file net/npf/npf_handler.c npf diff --git a/sys/net/npf/npf_altq.h b/sys/net/npf/npf_altq.h new file mode 100644 index 0000000000000..bd46ae3e48f7a --- /dev/null +++ b/sys/net/npf/npf_altq.h @@ -0,0 +1,107 @@ +/* NetBSD */ +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Emmanuel Nyarko. + * + * 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 THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION 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. + */ +#include +#ifndef NPF_ALTQ_H_ +#define NPF_ALTQ_H_ + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +/* queueing flags */ +#ifndef NPF_QNAME_SIZE +#define NPF_QNAME_SIZE 64 +#endif +#ifndef TAGID_MAX +#define TAGID_MAX 50000 +#endif +#ifndef NPF_TAG_NAME_SIZE +#define NPF_TAG_NAME_SIZE 64 +#endif + +/* + * options defined on the cbq, priq and hfsc when configuring them + */ +struct npf_cbq_opts { + uint32_t minburst; + uint32_t maxburst; + uint32_t pktsize; + uint32_t maxpktsize; + uint32_t ns_per_byte; + uint32_t maxidle; + int minidle; + uint32_t offtime; + int flags; +}; + +struct npf_priq_opts { + int flags; +}; + +struct npf_hfsc_opts { + /* real-time service curve */ + uint32_t rtsc_m1; /* slope of the 1st segment in bps */ + uint32_t rtsc_d; /* the x-projection of m1 in msec */ + uint32_t rtsc_m2; /* slope of the 2nd segment in bps */ + /* link-sharing service curve */ + uint32_t lssc_m1; + uint32_t lssc_d; + uint32_t lssc_m2; + /* upper-limit service curve */ + uint32_t ulsc_m1; + uint32_t ulsc_d; + uint32_t ulsc_m2; + int flags; +}; + +/* entries for our tail queue for our altqs */ +struct npf_altq { + char ifname[IFNAMSIZ]; + void *altq_disc; /* discipline-specific state */ + TAILQ_ENTRY(npf_altq) entries; + /* scheduler spec */ + uint8_t scheduler; /* scheduler type */ + uint16_t tbrsize; /* tokenbucket regulator size */ + uint32_t ifbandwidth; /* interface bandwidth */ + /* queue spec */ + char qname[NPF_QNAME_SIZE]; /* queue name */ + char parent[NPF_QNAME_SIZE]; /* parent name */ + uint32_t parent_qid; /* parent queue id */ + uint32_t bandwidth; /* queue bandwidth */ + uint8_t priority; /* priority */ + uint16_t qlimit; /* queue size limit */ + uint16_t flags; /* misc flags */ + union { + struct npf_cbq_opts cbq_opts; + struct npf_priq_opts priq_opts; + struct npf_hfsc_opts hfsc_opts; + } pq_u; + u_int32_t qid; /* return value */ +}; +#endif /* NPF_ALTQ_H_ */ diff --git a/usr.sbin/npf/npfctl/npf_parse.y b/usr.sbin/npf/npfctl/npf_parse.y index d77f462cd8c58..4c710cacd1a0d 100644 --- a/usr.sbin/npf/npfctl/npf_parse.y +++ b/usr.sbin/npf/npfctl/npf_parse.y @@ -3,7 +3,8 @@ * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Martin Husemann, Christos Zoulas and Mindaugas Rasiukevicius. + * by Martin Husemann, Christos Zoulas, Mindaugas Rasiukevicius and + * Emmanuel Nyarko * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,6 +39,11 @@ #include #endif +#include +#include +#include +#include + #include "npfctl.h" #define YYSTACKSIZE 4096 @@ -48,6 +54,9 @@ const char * yyfilename; extern int yylineno, yycolumn; extern int yylex(int); +struct node_hfsc_opts hfsc_opts; +struct queue_opts queue_opts; + void yyerror(const char *fmt, ...) { @@ -167,7 +176,21 @@ yyerror(const char *fmt, ...) %token TCP %token TO %token TREE +%token ALTQ +%token CBQ +%token PRIQ +%token HFSC +%token BANDWIDTH +%token TBRSIZE +%token LINKSHARE +%token REALTIME +%token UPPERLIMIT +%token QUEUE +%token PRIORITY +%token QLIMIT +%token RTABLE %token TYPE + %token ICMP %token ICMP6 @@ -181,8 +204,9 @@ yyerror(const char *fmt, ...) %token PARAM %token TABLE_ID %token VAR_ID +%token BW_SPEC -%type addr some_name table_store dynamic_ifaddrs +%type addr some_name table_store dynamic_ifaddrs bw_spec %type proc_param_val opt_apply ifname on_ifname ifref %type port opt_final number afamily opt_family %type block_or_pass rule_dir group_dir block_opts @@ -199,6 +223,15 @@ yyerror(const char *fmt, ...) %type filt_opts all_or_filt_opts %type rawproto %type group_opts +%type queue_opts queue_opt queue_opts_l +%type rule_queue +%type qassign qassign_list qassign_item +%type scheduler +%type cbqflags_list cbqflags_item +%type priqflags_list priqflags_item +%type hfscopts_list hfscopts_item hfsc_opts +%type bandwidth +%type queue_flags %union { char * str; @@ -209,6 +242,12 @@ yyerror(const char *fmt, ...) filt_opts_t filtopts; opt_proto_t optproto; rule_group_t rulegroup; + struct node_queue *queue; + struct node_queue_opt queue_options; + struct node_queue_bw queue_bwspec; + struct node_qassign qassign; + struct queue_opts queue_opts; + struct node_hfsc_opts hfsc_opts; } %% @@ -232,9 +271,346 @@ line | rproc | alg | set + | altq + | queuespec | ; +altq : ALTQ on_ifname queue_opts QUEUE qassign { + struct npf_altq a; + + if ($3.scheduler.qtype == ALTQT_NONE) { + yyerror("no scheduler specified!"); + YYERROR; + } + memset(&a, 0, sizeof(a)); + a.scheduler = $3.scheduler.qtype; + a.qlimit = $3.qlimit; + a.tbrsize = $3.tbrsize; + if ($5 == NULL) { + yyerror("no child queues specified"); + YYERROR; + } + if (expand_altq(&a, $2, $5, $3.queue_bwspec, + &$3.scheduler)) + YYERROR; + } + ; + +queuespec : QUEUE IDENTIFIER on_ifname queue_opts qassign { + struct npf_altq a; + + memset(&a, 0, sizeof(a)); + if (strlcpy(a.qname, $2, sizeof(a.qname)) >= + sizeof(a.qname)) { + yyerror("queue name too long (max " + "%d chars)", NPF_QNAME_SIZE-1); + free($2); + YYERROR; + } + free($2); + if ($4.tbrsize) { + yyerror("cannot specify tbrsize for queue"); + YYERROR; + } + if ($4.priority > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + a.priority = $4.priority; + a.qlimit = $4.qlimit; + a.scheduler = $4.scheduler.qtype; + if (expand_queue(&a, $3, $5, $4.queue_bwspec, + &$4.scheduler)) { + yyerror("errors in queue definition"); + YYERROR; + } + } + ; + +queue_opts : { + memset(&queue_opts, 0, sizeof(queue_opts)); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + } + queue_opts_l + { $$ = queue_opts; } + | /* empty */ { + memset(&queue_opts, 0, sizeof(queue_opts)); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + $$ = queue_opts; + } + ; + +queue_opts_l : queue_opts_l queue_opt + | queue_opt + ; + +queue_opt : BANDWIDTH bandwidth { + if (queue_opts.marker & QOM_BWSPEC) { + yyerror("bandwidth cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_BWSPEC; + queue_opts.queue_bwspec = $2; + } + | PRIORITY number { + if (queue_opts.marker & QOM_PRIORITY) { + yyerror("priority cannot be respecified"); + YYERROR; + } + if ($2 > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + queue_opts.marker |= QOM_PRIORITY; + queue_opts.priority = $2; + } + | QLIMIT number { + if (queue_opts.marker & QOM_QLIMIT) { + yyerror("qlimit cannot be respecified"); + YYERROR; + } + if ($2 > 65535) { + yyerror("qlimit out of range: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_QLIMIT; + queue_opts.qlimit = $2; + } + | scheduler { + if (queue_opts.marker & QOM_SCHEDULER) { + yyerror("scheduler cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_SCHEDULER; + queue_opts.scheduler = $1; + } + | TBRSIZE number { + if (queue_opts.marker & QOM_TBRSIZE) { + yyerror("tbrsize cannot be respecified"); + YYERROR; + } + if ($2 > 65535) { + yyerror("tbrsize too big: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_TBRSIZE; + queue_opts.tbrsize = $2; + } + ; + +bandwidth : bw_spec { + struct node_queue_bw bw; + + if (npfctl_eval_bw(&bw, $1)) { + YYERROR; + free($1); + } + $$ = bw; + } + ; + +bw_spec : BW_SPEC {$$ = $1; } + ; + +scheduler : CBQ { + $$.qtype = ALTQT_CBQ; + $$.data.cbq_opts.flags = 0; + } + | CBQ PAR_OPEN cbqflags_list PAR_CLOSE { + $$.qtype = ALTQT_CBQ; + $$.data.cbq_opts.flags = $3; + } + | PRIQ { + $$.qtype = ALTQT_PRIQ; + $$.data.priq_opts.flags = 0; + } + | PRIQ PAR_OPEN priqflags_list PAR_CLOSE { + $$.qtype = ALTQT_PRIQ; + $$.data.priq_opts.flags = $3; + } + | HFSC { + $$.qtype = ALTQT_HFSC; + memset(&$$.data.hfsc_opts, 0, + sizeof($$.data.hfsc_opts)); + } + | HFSC PAR_OPEN hfsc_opts PAR_CLOSE { + $$.qtype = ALTQT_HFSC; + $$.data.hfsc_opts = $3; + } + ; + +cbqflags_list : cbqflags_item { $$ |= $1; } + | cbqflags_list COMMA cbqflags_item { $$ |= $3; } + ; + +cbqflags_item : IDENTIFIER { +#ifdef CBQCLF_BORROW + if (!strcmp($1, "borrow")) + $$ = CBQCLF_BORROW; +#endif + else if (!strcmp($1, "red")) + $$ = CBQCLF_RED; + else if (!strcmp($1, "ecn")) + $$ = CBQCLF_RED|CBQCLF_ECN; + else if (!strcmp($1, "rio")) + $$ = CBQCLF_RIO; + else { + yyerror("unknown cbq flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + | DEFAULT { $$ = CBQCLF_DEFCLASS; } + ; + +priqflags_list : priqflags_item { $$ |= $1; } + | priqflags_list COMMA priqflags_item { $$ |= $3; } + ; + +priqflags_item : IDENTIFIER { + if (!strcmp($1, "red")) + $$ = PRCF_RED; + else if (!strcmp($1, "ecn")) + $$ = PRCF_RED|PRCF_ECN; + else if (!strcmp($1, "rio")) + $$ = PRCF_RIO; + else { + yyerror("unknown priq flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + | DEFAULT { $$ = PRCF_DEFAULTCLASS; } + ; + +hfsc_opts : { + memset(&hfsc_opts, 0, + sizeof(hfsc_opts)); + } + hfsc_opts_list { + $$ = hfsc_opts; + } + ; + +hfscopts_list : hfscopts_item + | hfscopts_list COMMA hfscopts_item + ; + +hfscopts_item : LINKSHARE bandwidth { + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m2 = $2; + hfsc_opts.linkshare.used = 1; + } + | LINKSHARE PAR_OPEN bandwidth COMMA number COMMA bandwidth PAR_CLOSE + { + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m1 = $3; + hfsc_opts.linkshare.d = $5; + hfsc_opts.linkshare.m2 = $7; + hfsc_opts.linkshare.used = 1; + } + | REALTIME bandwidth { + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m2 = $2; + hfsc_opts.realtime.used = 1; + } + | REALTIME PAR_OPEN bandwidth COMMA number COMMA bandwidth PAR_CLOSE + { + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m1 = $3; + hfsc_opts.realtime.d = $5; + hfsc_opts.realtime.m2 = $7; + hfsc_opts.realtime.used = 1; + } + | UPPERLIMIT bandwidth { + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m2 = $2; + hfsc_opts.upperlimit.used = 1; + } + | UPPERLIMIT PAR_OPEN bandwidth COMMA number COMMA bandwidth PAR_CLOSE + { + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m1 = $3; + hfsc_opts.upperlimit.d = $5; + hfsc_opts.upperlimit.m2 = $7; + hfsc_opts.upperlimit.used = 1; + } + | IDENTIFIER { + if (!strcmp($1, "red")) + hfsc_opts.flags |= HFCF_RED; + else if (!strcmp($1, "ecn")) + hfsc_opts.flags |= HFCF_RED|HFCF_ECN; + else if (!strcmp($1, "rio")) + hfsc_opts.flags |= HFCF_RIO; + else { + yyerror("unknown hfsc flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + | DEFAULT { hfsc_opts.flags |= HFCF_DEFAULTCLASS; } + ; + +qassign : /* empty */ { $$ = NULL; } + | qassign_item { $$ = $1; } + | CURLY_OPEN qassign_list CURLY_CLOSE { $$ = $2; } + ; + +qassign_list : qassign_item { $$ = $1; } + | qassign_list COMMA qassign_item { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +qassign_item : IDENTIFIER { + $$ = calloc(1, sizeof(struct node_queue)); + + if ($$ == NULL) + err(1, "qassign_item: calloc"); + if (strlcpy($$->queue, $1, sizeof($$->queue)) >= + sizeof($$->queue)) { + yyerror("queue name '%s' too long (max " + "%lu chars)", $1, sizeof($$->queue) -1); + free($1); + free($$); + YYERROR; + } + free($1); + $$->next = NULL; + $$->tail = $$; + } + ; + alg : ALG STRING { @@ -544,20 +920,21 @@ rule_group /* * Rule and misc. + * Make rule with queue optional */ rule : block_or_pass opt_stateful rule_dir opt_final on_ifname - opt_family opt_proto all_or_filt_opts opt_apply + opt_family opt_proto all_or_filt_opts opt_apply rule_queue { npfctl_build_rule($1 | $2 | $3 | $4, $5, - $6, $7, &$8, NULL, $9); + $6, $7, &$8, NULL, $9, $10); } | block_or_pass opt_stateful rule_dir opt_final on_ifname - PCAP_FILTER STRING opt_apply + PCAP_FILTER STRING opt_apply rule_queue { npfctl_build_rule($1 | $2 | $3 | $4, $5, - AF_UNSPEC, NULL, NULL, $7, $8); + AF_UNSPEC, NULL, NULL, $7, $8, $9); } ; @@ -678,6 +1055,27 @@ opt_apply | { $$ = NULL; } ; +rule_queue + : /* Empty */ + { + $$.qname = NULL; + $$.pqname = NULL; + } + | QUEUE STRING + { + $$.qname = $2; + } + | QUEUE PAR_OPEN STRING PAR_CLOSE + { + $$.qname = $3; + } + | QUEUE PAR_OPEN STRING COMMA STRING PAR_CLOSE + { + $$.qname = $3; + $$.pqname = $5; + } + ; + block_opts : RETURNRST { $$ = NPF_RULE_RETRST; } | RETURNICMP { $$ = NPF_RULE_RETICMP; } diff --git a/usr.sbin/npf/npfctl/npf_scan.l b/usr.sbin/npf/npfctl/npf_scan.l index 28bc5e9665742..7c272aea75c2c 100644 --- a/usr.sbin/npf/npfctl/npf_scan.l +++ b/usr.sbin/npf/npfctl/npf_scan.l @@ -3,7 +3,7 @@ * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Martin Husemann. + * by Martin Husemann and Emmanuel Nyarko * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -96,6 +96,7 @@ DID [a-zA-Z_][a-zA-Z_0-9-]* SPID [a-zA-Z][a-zA-Z_0-9.]* NUMBER [0-9]+ HEXDIG [0-9a-fA-F]+ +BW_UNIT [A-Za-z%]+ %% %{ @@ -174,6 +175,19 @@ icmp-type return ICMPTYPE; code return CODE; any return ANY; +altq return ALTQ; +cbq return CBQ; +priq return PRIQ; +hfsc return HFSC; +bandwidth return BANDWIDTH; +tbrsize return TBRSIZE; +linkshare return LINKSHARE; +realtime return REALTIME; +uppertime return UPPERLIMIT; +queue return QUEUE; +priority return PRIORITY; +qlimit return QLIMIT; + "/" return SLASH; "{" return CURLY_OPEN; "}" return CURLY_CLOSE; @@ -183,6 +197,11 @@ any return ANY; "=" return EQ; "!" return EXCL_MARK; +{NUMBER}[\.]*[0-9]*{BW_UNIT} { + yylval.str = estrndup(yytext, yyleng); + return BW_SPEC; +} + "0x"{HEXDIG} { char *endp, *buf = ecalloc(1, yyleng + 1); buf[yyleng] = 0; diff --git a/usr.sbin/npf/npfctl/npfctl.h b/usr.sbin/npf/npfctl/npfctl.h index 4a17517488079..a99d3bd59328a 100644 --- a/usr.sbin/npf/npfctl/npfctl.h +++ b/usr.sbin/npf/npfctl/npfctl.h @@ -48,6 +48,78 @@ #define NPF_CONF_PATH "/etc/npf.conf" #define NPF_DB_PATH "/var/db/npf.db" +#ifndef DEFAULT_QLIMIT +#define DEFAULT_QLIMIT 50 +#endif +#ifndef DEFAULT_PRIORITY +#define DEFAULT_PRIORITY 1 +#endif + +struct node_queue_bw { + uint32_t bw_absolute; + uint16_t bw_percent; +}; + +struct node_hfsc_sc { + struct node_queue_bw m1; /* slope of 1st segment; bps */ + u_int d; /* x-projection of m1; msec */ + struct node_queue_bw m2; /* slope of 2nd segment; bps */ + uint8_t used; +}; + +struct node_hfsc_opts { + struct node_hfsc_sc realtime; + struct node_hfsc_sc linkshare; + struct node_hfsc_sc upperlimit; + int flags; +}; + +struct node_queue_opt { + int qtype; + union { + struct npf_cbq_opts cbq_opts; + struct npf_priq_opts priq_opts; + struct node_hfsc_opts hfsc_opts; + } data; +}; + +struct queue_opts { + int marker; +/* use flags for which option is set*/ +#define QOM_BWSPEC 0x01 +#define QOM_SCHEDULER 0x02 +#define QOM_PRIORITY 0x04 +#define QOM_TBRSIZE 0x08 +#define QOM_QLIMIT 0x10 + struct node_queue_bw queue_bwspec; + struct node_queue_opt scheduler; + int priority; + int tbrsize; + int qlimit; +}; + +struct node_queue { + char queue[NPF_QNAME_SIZE]; + char parent[NPF_QNAME_SIZE]; + char ifname[IFNAMSIZ]; + int scheduler; + struct node_queue *next; + struct node_queue *tail; +}; + +struct node_qassign { + char *qname; + char *pqname; +}; + +/* + * generalized service curve used for admission control + */ +struct segment { + LIST_ENTRY(segment) _next; + double x, y, d, m; +}; + typedef struct fam_addr_mask { sa_family_t fam_family; npf_addr_t fam_addr;