diff --git a/iproute2/Makefile b/iproute2/Makefile index ce04bf701..55c00a0d6 100644 --- a/iproute2/Makefile +++ b/iproute2/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=iproute2 -PKG_VERSION:=5.0.0 -PKG_RELEASE:=2.1 +PKG_VERSION:=5.15.0 +PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/net/iproute2 -PKG_HASH:=df047302a39650ef832c07e8dab5df7a23218cd398bd310c8628e386161d20ba +PKG_HASH:=38e3e4a5f9a7f5575c015027a10df097c149111eeb739993128e5b2b35b291ff PKG_BUILD_PARALLEL:=1 PKG_BUILD_DEPENDS:=iptables PKG_LICENSE:=GPL-2.0 @@ -33,81 +33,131 @@ endef define Package/ip-tiny $(call Package/iproute2/Default) - TITLE:=Routing control utility (Minimal) - VARIANT:=tiny - DEFAULT_VARIANT:=1 - PROVIDES:=ip - ALTERNATIVES:=200:/sbin/ip:/usr/libexec/ip-tiny - DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl + TITLE:=Routing control utility (minimal) + VARIANT:=iptiny + DEFAULT_VARIANT:=1 + PROVIDES:=ip + ALTERNATIVES:=200:/sbin/ip:/usr/libexec/ip-tiny + DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl endef define Package/ip-full $(call Package/iproute2/Default) - TITLE:=Routing control utility (Full) - VARIANT:=full - PROVIDES:=ip - ALTERNATIVES:=300:/sbin/ip:/usr/libexec/ip-full - DEPENDS:=+libnl-tiny +libelf +(PACKAGE_devlink||PACKAGE_rdma):libmnl +libcap + TITLE:=Routing control utility (full) + VARIANT:=ipfull + PROVIDES:=ip + ALTERNATIVES:=300:/sbin/ip:/usr/libexec/ip-full + DEPENDS:=+libnl-tiny +libbpf +(PACKAGE_devlink||PACKAGE_rdma):libmnl endef -define Package/tc +define Package/tc-tiny $(call Package/iproute2/Default) - TITLE:=Traffic control utility - VARIANT:=tc + TITLE:=Traffic control utility (minimal) + VARIANT:=tctiny + DEFAULT_VARIANT:=1 PROVIDES:=tc - DEPENDS:=+kmod-sched-core +libxtables +libelf +(PACKAGE_devlink||PACKAGE_rdma):libmnl +PACKAGE_ip-full:libcap + ALTERNATIVES:=200:/sbin/tc:/usr/libexec/tc-tiny + DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl +endef + +define Package/tc-bpf +$(call Package/iproute2/Default) + TITLE:=Traffic control utility (bpf) + VARIANT:=tcbpf + PROVIDES:=tc + ALTERNATIVES:=300:/sbin/tc:/usr/libexec/tc-bpf + DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl +libbpf +endef + +define Package/tc-full +$(call Package/iproute2/Default) + TITLE:=Traffic control utility (full) + VARIANT:=tcfull + PROVIDES:=tc + ALTERNATIVES:=400:/sbin/tc:/usr/libexec/tc-full + DEPENDS:=+kmod-sched-core +(PACKAGE_devlink||PACKAGE_rdma):libmnl +libbpf +libxtables +tc-mod-iptables +endef + +define Package/tc-mod-iptables +$(call Package/iproute2/Default) + TITLE:=Traffic control module - iptables action + VARIANT:=tcfull + DEPENDS:=+libxtables endef define Package/genl $(call Package/iproute2/Default) TITLE:=General netlink utility frontend - DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl endef define Package/ip-bridge $(call Package/iproute2/Default) TITLE:=Bridge configuration utility from iproute2 - DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl endef define Package/ss $(call Package/iproute2/Default) TITLE:=Socket statistics utility - DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl +kmod-netlink-diag endef define Package/nstat $(call Package/iproute2/Default) TITLE:=Network statistics utility - DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libnl-tiny +(PACKAGE_devlink||PACKAGE_rdma):libmnl endef define Package/devlink $(call Package/iproute2/Default) TITLE:=Network devlink utility - DEPENDS:=+libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libmnl endef define Package/rdma $(call Package/iproute2/Default) TITLE:=Network rdma utility - DEPENDS:=+libmnl +(PACKAGE_tc||PACKAGE_ip-full):libelf +PACKAGE_ip-full:libcap + DEPENDS:=+libmnl endef -ifeq ($(BUILD_VARIANT),tiny) +ifeq ($(BUILD_VARIANT),iptiny) IP_CONFIG_TINY:=y + LIBBPF_FORCE:=off endif -ifeq ($(BUILD_VARIANT),full) +ifeq ($(BUILD_VARIANT),ipfull) HAVE_ELF:=y - HAVE_CAP:=y + LIBBPF_FORCE:=on endif -ifeq ($(BUILD_VARIANT),tc) +ifeq ($(BUILD_VARIANT),tctiny) + LIBBPF_FORCE:=off +endif + +ifeq ($(BUILD_VARIANT),tcbpf) HAVE_ELF:=y + LIBBPF_FORCE:=on SHARED_LIBS:=y endif +ifeq ($(BUILD_VARIANT),tcfull) + #enable iptables/xtables requirement only if tciptables variant is selected + TC_CONFIG_XT:=y + TC_CONFIG_XT_OLD:=y + TC_CONFIG_XT_OLD_H:=y + TC_CONFIG_IPSET:=y + HAVE_ELF:=y + LIBBPF_FORCE:=on + SHARED_LIBS:=y +else + #disable iptables requirement by default + TC_CONFIG_XT:=n + TC_CONFIG_XT_OLD:=n + TC_CONFIG_XT_OLD_H:=n + TC_CONFIG_IPSET:=n +endif + ifdef CONFIG_PACKAGE_devlink HAVE_MNL:=y endif @@ -121,27 +171,35 @@ define Build/Configure > $(PKG_BUILD_DIR)/include/SNAPSHOT.h endef -TARGET_CFLAGS += -ffunction-sections -fdata-sections -TARGET_LDFLAGS += -Wl,--gc-sections +TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto +TARGET_LDFLAGS += -Wl,--gc-sections -Wl,--as-needed TARGET_CPPFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny MAKE_FLAGS += \ KERNEL_INCLUDE="$(LINUX_DIR)/user_headers/include" \ SHARED_LIBS=$(SHARED_LIBS) \ IP_CONFIG_TINY=$(IP_CONFIG_TINY) \ + BUILD_VARIANT=$(BUILD_VARIANT) \ + LIBBPF_FORCE=$(LIBBPF_FORCE) \ HAVE_ELF=$(HAVE_ELF) \ HAVE_MNL=$(HAVE_MNL) \ HAVE_CAP=$(HAVE_CAP) \ IPT_LIB_DIR=/usr/lib/iptables \ XT_LIB_DIR=/usr/lib/iptables \ - FPIC="$(FPIC)" + TC_CONFIG_XT=$(TC_CONFIG_XT) \ + TC_CONFIG_XT_OLD=$(TC_CONFIG_XT_OLD) \ + TC_CONFIG_XT_OLD_H=$(TC_CONFIG_XT_OLD_H) \ + TC_CONFIG_IPSET=$(TC_CONFIG_IPSET) \ + FPIC="$(FPIC)" \ + $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') define Build/Compile +$(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) $(MAKE_FLAGS) endef define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/include + $(INSTALL_DIR) $(1)/usr/include/iproute2 + $(CP) $(PKG_BUILD_DIR)/include/bpf_elf.h $(1)/usr/include/iproute2 $(CP) $(PKG_BUILD_DIR)/include/{libgenl,libnetlink}.h $(1)/usr/include/ $(INSTALL_DIR) $(1)/usr/lib $(CP) $(PKG_BUILD_DIR)/lib/libnetlink.a $(1)/usr/lib/ @@ -157,17 +215,24 @@ define Package/ip-full/install $(INSTALL_BIN) $(PKG_BUILD_DIR)/ip/ip $(1)/usr/libexec/ip-full endef -define Package/tc/install - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/sbin/ - $(INSTALL_DIR) $(1)/etc/hotplug.d/iface - $(INSTALL_BIN) ./files/15-teql $(1)/etc/hotplug.d/iface/ - $(INSTALL_DIR) $(1)/lib/debug - $(INSTALL_BIN) ./files/tc.debug $(1)/lib/debug/tc -ifeq ($(SHARED_LIBS),y) +define Package/tc-tiny/install + $(INSTALL_DIR) $(1)/usr/libexec + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-tiny +endef + +define Package/tc-bpf/install + $(INSTALL_DIR) $(1)/usr/libexec + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-bpf +endef + +define Package/tc-full/install + $(INSTALL_DIR) $(1)/usr/libexec + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/libexec/tc-full +endef + +define Package/tc-mod-iptables/install $(INSTALL_DIR) $(1)/usr/lib/tc - $(CP) $(PKG_BUILD_DIR)/tc/*.so $(1)/usr/lib/tc -endif + $(CP) $(PKG_BUILD_DIR)/tc/m_xt.so $(1)/usr/lib/tc endef define Package/genl/install @@ -202,7 +267,12 @@ endef $(eval $(call BuildPackage,ip-tiny)) $(eval $(call BuildPackage,ip-full)) -$(eval $(call BuildPackage,tc)) +# build tc-mod-iptables before its dependents, to avoid +# spurious rebuilds when building multiple variants. +$(eval $(call BuildPackage,tc-mod-iptables)) +$(eval $(call BuildPackage,tc-tiny)) +$(eval $(call BuildPackage,tc-bpf)) +$(eval $(call BuildPackage,tc-full)) $(eval $(call BuildPackage,genl)) $(eval $(call BuildPackage,ip-bridge)) $(eval $(call BuildPackage,ss)) diff --git a/iproute2/files/15-teql b/iproute2/files/15-teql deleted file mode 100644 index a0c0e503a..000000000 --- a/iproute2/files/15-teql +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -. /lib/functions.sh - -if [ "$ACTION" != "ifup" ]; then - exit -fi - -config_load network - -config_get teql $INTERFACE teql - -if [ "$teql" != "" ]; then - logger Adding device $DEVICE to TEQL master $teql - insmod sch_teql - tc qdisc add dev $DEVICE root $teql - - # The kernel doesn't let us bring it up until it has at least one - # slave. So bring it up now, if it isn't already. - if ! cat /sys/class/net/$teql/carrier &>/dev/null; then - ifup $teql & - fi -fi diff --git a/iproute2/files/tc.debug b/iproute2/files/tc.debug deleted file mode 100644 index 88a4bcb9c..000000000 --- a/iproute2/files/tc.debug +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh /sbin/sysdebug -# -# Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -for dev in $(ls -1 /sys/class/net/); do - [ -d /sys/class/net/${dev} ] || continue - log tc -s qdisc show dev ${dev} -done diff --git a/iproute2/patches/010-cake-fwmark.patch b/iproute2/patches/010-cake-fwmark.patch deleted file mode 100644 index 46981067b..000000000 --- a/iproute2/patches/010-cake-fwmark.patch +++ /dev/null @@ -1,152 +0,0 @@ -From a7cd7badedcb643dc1adb41edeb4cf8e4d9ec063 Mon Sep 17 00:00:00 2001 -From: Stephen Hemminger -Date: Tue, 19 Mar 2019 10:36:56 -0700 -Subject: uapi: add CAKE FWMARK - -Signed-off-by: Stephen Hemminger ---- - include/uapi/linux/pkt_sched.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h -index 1eb572e..7ee74c3 100644 ---- a/include/uapi/linux/pkt_sched.h -+++ b/include/uapi/linux/pkt_sched.h -@@ -1021,6 +1021,7 @@ enum { - TCA_CAKE_INGRESS, - TCA_CAKE_ACK_FILTER, - TCA_CAKE_SPLIT_GSO, -+ TCA_CAKE_FWMARK, - __TCA_CAKE_MAX - }; - #define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1) - -From 5ebfe1f6fea2bb3bfccf4cf93829516caaa0233d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= -Date: Mon, 18 Mar 2019 01:30:45 +0100 -Subject: [PATCH] q_cake: Add support for setting the fwmark option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds support for the newly added fwmark option to CAKE, which allows -overriding the tin selection from the per-packet firewall marks. The fwmark -field is a bitmask that is applied to the fwmark to select the tin. - -Signed-off-by: Toke Høiland-Jørgensen ---- - man/man8/tc-cake.8 | 16 ++++++++++++++++ - tc/q_cake.c | 24 ++++++++++++++++++++++++ - 2 files changed, 40 insertions(+) - -diff --git a/man/man8/tc-cake.8 b/man/man8/tc-cake.8 -index eda436e1..8c57eadd 100644 ---- a/man/man8/tc-cake.8 -+++ b/man/man8/tc-cake.8 -@@ -91,6 +91,10 @@ TIME | - LIMIT ] - .br - [ -+.BR fwmark -+MASK ] -+.br -+[ - .BR ptm - | - .BR atm -@@ -524,6 +528,18 @@ preset on the modern Internet is firmly discouraged. - .br - Voice (CS7, CS6, EF, VA, TOS4), 25% threshold, reduced Codel interval. - -+.PP -+.B fwmark -+MASK -+.br -+ This options turns on fwmark-based overriding of CAKE's tin selection. -+If set, the option specifies a bitmask that will be applied to the fwmark -+associated with each packet. If the result of this masking is non-zero, the -+result will be right-shifted by the number of least-significant unset bits in -+the mask value, and the result will be used as a the tin number for that packet. -+This can be used to set policies in a firewall script that will override CAKE's -+built-in tin selection. -+ - .SH OTHER PARAMETERS - .B memlimit - LIMIT -diff --git a/tc/q_cake.c b/tc/q_cake.c -index e827e3f1..307a12c0 100644 ---- a/tc/q_cake.c -+++ b/tc/q_cake.c -@@ -82,6 +82,7 @@ static void explain(void) - " [ split-gso* | no-split-gso ]\n" - " [ ack-filter | ack-filter-aggressive | no-ack-filter* ]\n" - " [ memlimit LIMIT ]\n" -+" [ fwmark MASK ]\n" - " [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n" - " [ mpu N ] [ ingress | egress* ]\n" - " (* marks defaults)\n"); -@@ -106,6 +107,7 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, - int autorate = -1; - int ingress = -1; - int overhead = 0; -+ int fwmark = -1; - int wash = -1; - int nat = -1; - int atm = -1; -@@ -332,6 +334,16 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, - "Illegal value for \"memlimit\": \"%s\"\n", *argv); - return -1; - } -+ } else if (strcmp(*argv, "fwmark") == 0) { -+ unsigned int fwm; -+ -+ NEXT_ARG(); -+ if (get_u32(&fwm, *argv, 0)) { -+ fprintf(stderr, -+ "Illegal value for \"fwmark\": \"%s\"\n", *argv); -+ return -1; -+ } -+ fwmark = fwm; - } else if (strcmp(*argv, "help") == 0) { - explain(); - return -1; -@@ -376,6 +388,9 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, - if (memlimit) - addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit, - sizeof(memlimit)); -+ if (fwmark != -1) -+ addattr_l(n, 1024, TCA_CAKE_FWMARK, &fwmark, -+ sizeof(fwmark)); - if (nat != -1) - addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat)); - if (wash != -1) -@@ -409,6 +424,7 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) - struct rtattr *tb[TCA_CAKE_MAX + 1]; - unsigned int interval = 0; - unsigned int memlimit = 0; -+ unsigned int fwmark = 0; - __u64 bandwidth = 0; - int ack_filter = 0; - int split_gso = 0; -@@ -507,6 +523,10 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) - RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) { - interval = rta_getattr_u32(tb[TCA_CAKE_RTT]); - } -+ if (tb[TCA_CAKE_FWMARK] && -+ RTA_PAYLOAD(tb[TCA_CAKE_FWMARK]) >= sizeof(__u32)) { -+ fwmark = rta_getattr_u32(tb[TCA_CAKE_FWMARK]); -+ } - - if (wash) - print_string(PRINT_FP, NULL, "wash ", NULL); -@@ -559,6 +579,10 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) - sprint_size(memlimit, b1)); - } - -+ if (fwmark) -+ print_uint(PRINT_FP, NULL, "fwmark 0x%x ", fwmark); -+ print_0xhex(PRINT_JSON, "fwmark", NULL, fwmark); -+ - return 0; - } - diff --git a/iproute2/patches/090-tc-add-support-for-action-act_ctinfo.patch b/iproute2/patches/090-tc-add-support-for-action-act_ctinfo.patch deleted file mode 100644 index 6335cca03..000000000 --- a/iproute2/patches/090-tc-add-support-for-action-act_ctinfo.patch +++ /dev/null @@ -1,589 +0,0 @@ -From dff8eadcab33209e040e77a5d56d5def04808144 Mon Sep 17 00:00:00 2001 -From: Kevin Darbyshire-Bryant -Date: Fri, 15 Mar 2019 09:35:37 +0000 -Subject: [PATCH] tc: add support for action act_ctinfo -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -ctinfo is a tc action restoring data stored in conntrack marks to -various fields. At present it has two independent modes of operation, -restoration of DSCP into IPv4/v6 diffserv and restoration of conntrack -marks into packet skb marks. - -It understands a number of parameters specific to this action in -additional to the usual action syntax. Each operating mode is -independent of the other so all options are optional, however not -specifying at least one mode is a bit pointless. - -Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] - [CONTROL] [index ] - -DSCP mode - -dscp enables copying of a DSCP stored in the conntrack mark into the -ipv4/v6 diffserv field. The mask is a 32bit field and specifies where -in the conntrack mark the DSCP value is located. It must be 6 -contiguous bits long. eg. 0xfc000000 would restore the DSCP from the -upper 6 bits of the conntrack mark. - -The DSCP copying may be optionally controlled by a statemask. The -statemask is a 32bit field, usually with a single bit set and must not -overlap the dscp mask. The DSCP restore operation will only take place -if the corresponding bit/s in conntrack mark ANDed with the statemask -yield a non zero result. - -eg. dscp 0xfc000000 0x01000000 would retrieve the DSCP from the top 6 -bits, whilst using bit 25 as a flag to do so. Bit 26 is unused in this -example. - -CPMARK mode - -cpmark enables copying of the conntrack mark to the packet skb mark. In -this mode it is completely equivalent to the existing act_connmark -action. Additional functionality is provided by the optional mask -parameter, whereby the stored conntrack mark is logically ANDed with the -cpmark mask before being stored into skb mark. This allows shared usage -of the conntrack mark between applications. - -eg. cpmark 0x00ffffff would restore only the lower 24 bits of the -conntrack mark, thus may be useful in the event that the upper 8 bits -are used by the DSCP function. - -Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] - [CONTROL] [index ] -where : - dscp MASK is the bitmask to restore DSCP - STATEMASK is the bitmask to determine conditional restoring - cpmark MASK mask applied to restored packet mark - ZONE is the conntrack zone - CONTROL := reclassify | pipe | drop | continue | ok | - goto chain - -Signed-off-by: Kevin Darbyshire-Bryant -Reviewed-by: Toke Høiland-Jørgensen ---- - include/uapi/linux/pkt_cls.h | 3 +- - include/uapi/linux/tc_act/tc_ctinfo.h | 29 +++ - man/man8/tc-ctinfo.8 | 170 ++++++++++++++++ - tc/Makefile | 1 + - tc/m_ctinfo.c | 268 ++++++++++++++++++++++++++ - 5 files changed, 470 insertions(+), 1 deletion(-) - create mode 100644 include/uapi/linux/tc_act/tc_ctinfo.h - create mode 100644 man/man8/tc-ctinfo.8 - create mode 100644 tc/m_ctinfo.c - -diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h -index 95d0db2a..a6e7e176 100644 ---- a/include/uapi/linux/pkt_cls.h -+++ b/include/uapi/linux/pkt_cls.h -@@ -68,7 +68,8 @@ enum { - TCA_ID_UNSPEC=0, - TCA_ID_POLICE=1, - /* other actions go here */ -- __TCA_ID_MAX=255 -+ TCA_ID_CTINFO=27, -+ __TCA_ID_MAX = 255 - }; - - #define TCA_ID_MAX __TCA_ID_MAX -diff --git a/include/uapi/linux/tc_act/tc_ctinfo.h b/include/uapi/linux/tc_act/tc_ctinfo.h -new file mode 100644 -index 00000000..f5f26d95 ---- /dev/null -+++ b/include/uapi/linux/tc_act/tc_ctinfo.h -@@ -0,0 +1,29 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef __UAPI_TC_CTINFO_H -+#define __UAPI_TC_CTINFO_H -+ -+#include -+#include -+ -+struct tc_ctinfo { -+ tc_gen; -+}; -+ -+enum { -+ TCA_CTINFO_UNSPEC, -+ TCA_CTINFO_PAD, -+ TCA_CTINFO_TM, -+ TCA_CTINFO_ACT, -+ TCA_CTINFO_ZONE, -+ TCA_CTINFO_PARMS_DSCP_MASK, -+ TCA_CTINFO_PARMS_DSCP_STATEMASK, -+ TCA_CTINFO_PARMS_CPMARK_MASK, -+ TCA_CTINFO_STATS_DSCP_SET, -+ TCA_CTINFO_STATS_DSCP_ERROR, -+ TCA_CTINFO_STATS_CPMARK_SET, -+ __TCA_CTINFO_MAX -+}; -+ -+#define TCA_CTINFO_MAX (__TCA_CTINFO_MAX - 1) -+ -+#endif -diff --git a/man/man8/tc-ctinfo.8 b/man/man8/tc-ctinfo.8 -new file mode 100644 -index 00000000..096590d1 ---- /dev/null -+++ b/man/man8/tc-ctinfo.8 -@@ -0,0 +1,170 @@ -+.TH "ctinfo action in tc" 8 "4 Jun 2019" "iproute2" "Linux" -+.SH NAME -+ctinfo \- tc connmark processing action -+.SH SYNOPSIS -+.B tc ... action ctinfo -+[ -+.B dscp -+MASK [STATEMASK] ] [ -+.B cpmark -+[MASK] ] [ -+.B zone -+ZONE ] [ -+.B CONTROL -+] [ -+.B index -+ -+] -+ -+.SH DESCRIPTION -+CTINFO (Conntrack Information) is a tc action for retrieving data from -+conntrack marks into various fields. At present it has two independent -+processing modes which may be viewed as sub-functions. -+ -+DSCP mode copies a DSCP stored in conntrack's connmark into the IPv4/v6 diffserv -+field. The copying may conditionally occur based on a flag also stored in the -+connmark. DSCP mode was designed to assist in restoring packet classifications on -+ingress, classifications which may then be used by qdiscs such as CAKE. It may be -+used in any circumstance where ingress classification needs to be maintained across -+links that otherwise bleach or remap according to their own policies. -+ -+CPMARK (copymark) mode copies the conntrack connmark into the packet's mark field. Without -+additional parameters it is functionally completely equivalent to the existing -+connmark action. An optional mask may be specified to mask which bits of the -+connmark are restored. This may be useful when DSCP and CPMARK modes are combined. -+ -+Simple statistics (tc -s) on DSCP restores and CPMARK copies are maintained where values for -+set indicate a count of packets altered for that mode. DSCP includes an error count -+where the destination packet's diffserv field was unwriteable. -+.SH PARAMETERS -+.SS DSCP mode parameters: -+.IP mask -+A mask of 6 contiguous bits indicating where the DSCP value is located in the 32 bit -+conntrack mark field. A mask must be provided for this mode. mask is a 32 bit -+unsigned value. -+.IP statemask -+A mask of at least 1 bit indicating where a conditional restore flag is located in the -+32 bit conntrack mark field. The statemask bit/s must NOT overlap the mask bits. The -+DSCP will be restored if the conntrack mark logically ANDed with the statemask yields -+a non-zero result. statemask is an optional unsigned 32 bit value. -+.SS CPMARK mode parameters: -+.IP mask -+Store the logically ANDed result of conntrack mark and mask into the packet's mark -+field. Default is 0xffffffff i.e. the whole mark field. mask is an optional unsigned 32 bit -+value -+.SS Overall action parameters: -+.IP zone -+Specify the conntrack zone when doing conntrack lookups for packets. -+zone is a 16bit unsigned decimal value. -+Default is 0. -+.IP CONTROL -+The following keywords allow to control how the tree of qdisc, classes, -+filters and actions is further traversed after this action. -+.RS -+.TP -+.B reclassify -+Restart with the first filter in the current list. -+.TP -+.B pipe -+Continue with the next action attached to the same filter. -+.TP -+.B drop -+Drop the packet. -+.TP -+.B shot -+synonym for -+.B drop -+.TP -+.B continue -+Continue classification with the next filter in line. -+.TP -+.B pass -+Finish classification process and return to calling qdisc for further packet -+processing. This is the default. -+.RE -+.IP index -+Specify an index for this action in order to being able to identify it in later -+commands. index is a 32bit unsigned decimal value. -+.SH EXAMPLES -+Example showing conditional restoration of DSCP on ingress via an IFB -+.RS -+.EX -+ -+#Set up the IFB interface -+.br -+tc qdisc add dev ifb4eth0 handle ffff: ingress -+ -+#Put CAKE qdisc on it -+.br -+tc qdisc add dev ifb4eth0 root cake bandwidth 40mbit -+ -+#Set interface UP -+.br -+ip link set dev ifb4eth0 up -+ -+#Add 2 actions, ctinfo to restore dscp & mirred to redirect the packets to IFB -+.br -+tc filter add dev eth0 parent ffff: protocol all prio 10 u32 \\ -+ match u32 0 0 flowid 1:1 action \\ -+ ctinfo dscp 0xfc000000 0x01000000 \\ -+ mirred egress redirect dev ifb4eth0 -+ -+tc -s qdisc show dev eth0 ingress -+ -+ filter parent ffff: protocol all pref 10 u32 chain 0 -+ filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 -+ filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw -+ match 00000000/00000000 at 0 -+ action order 1: ctinfo zone 0 pipe -+ index 2 ref 1 bind 1 dscp 0xfc000000 0x01000000 installed 72 sec used 0 sec DSCP set 1333 error 0 CPMARK set 0 -+ Action statistics: -+ Sent 658484 bytes 1833 pkt (dropped 0, overlimits 0 requeues 0) -+ backlog 0b 0p requeues 0 -+ -+ action order 2: mirred (Egress Redirect to device ifb4eth0) stolen -+ index 1 ref 1 bind 1 installed 72 sec used 0 sec -+ Action statistics: -+ Sent 658484 bytes 1833 pkt (dropped 0, overlimits 0 requeues 0) -+ backlog 0b 0p requeues 0 -+.EE -+.RE -+ -+Example showing conditional restoration of DSCP on egress -+ -+This may appear nonsensical since iptables marking of egress packets is easy -+to achieve, however the iptables flow classification rules may be extensive -+and so some sort of set once and forget may be useful especially on cpu -+constrained devices. -+.RS -+.EX -+ -+# Send unmarked connections to a marking chain which needs to store a DSCP -+and set statemask bit in the connmark -+.br -+iptables -t mangle -A POSTROUTING -o eth0 -m connmark \\ -+ --mark 0x00000000/0x01000000 -g CLASS_MARKING_CHAIN -+ -+# Apply marked DSCP to the packets -+.br -+tc filter add dev eth0 protocol all prio 10 u32 \\ -+ match u32 0 0 flowid 1:1 action \\ -+ ctinfo dscp 0xfc000000 0x01000000 -+ -+tc -s filter show dev eth0 -+ filter parent 800e: protocol all pref 10 u32 chain 0 -+ filter parent 800e: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 -+ filter parent 800e: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw -+ match 00000000/00000000 at 0 -+ action order 1: ctinfo zone 0 pipe -+ index 1 ref 1 bind 1 dscp 0xfc000000 0x01000000 installed 7414 sec used 0 sec DSCP set 53404 error 0 CPMARK set 0 -+ Action statistics: -+ Sent 32890260 bytes 120441 pkt (dropped 0, overlimits 0 requeues 0) -+ backlog 0b 0p requeues 0 -+.br -+.SH SEE ALSO -+.BR tc (8), -+.BR tc-cake (8) -+.BR tc-connmark (8) -+.BR tc-mirred (8) -+.SH AUTHORS -+ctinfo was written by Kevin Darbyshire-Bryant. -diff --git a/tc/Makefile b/tc/Makefile -index 2edaf2c8..ec93a9a1 100644 ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -48,6 +48,7 @@ TCMODULES += m_csum.o - TCMODULES += m_simple.o - TCMODULES += m_vlan.o - TCMODULES += m_connmark.o -+TCMODULES += m_ctinfo.o - TCMODULES += m_bpf.o - TCMODULES += m_tunnel_key.o - TCMODULES += m_sample.o -diff --git a/tc/m_ctinfo.c b/tc/m_ctinfo.c -new file mode 100644 -index 00000000..5e451f87 ---- /dev/null -+++ b/tc/m_ctinfo.c -@@ -0,0 +1,268 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * m_ctinfo.c netfilter ctinfo mark action -+ * -+ * Copyright (c) 2019 Kevin Darbyshire-Bryant -+ */ -+ -+#include -+#include -+#include -+#include -+#include "utils.h" -+#include "tc_util.h" -+#include -+ -+static void -+explain(void) -+{ -+ fprintf(stderr, -+ "Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] [CONTROL] [index ]\n" -+ "where :\n" -+ "\tdscp MASK bitmask location of stored DSCP\n" -+ "\t STATEMASK bitmask to determine conditional restoring\n" -+ "\tcpmark MASK mask applied to mark on restoration\n" -+ "\tZONE is the conntrack zone\n" -+ "\tCONTROL := reclassify | pipe | drop | continue | ok |\n" -+ "\t goto chain \n"); -+} -+ -+static void -+usage(void) -+{ -+ explain(); -+ exit(-1); -+} -+ -+static int -+parse_ctinfo(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, -+ struct nlmsghdr *n) -+{ -+ unsigned int cpmarkmask = 0, dscpmask = 0, dscpstatemask = 0; -+ struct tc_ctinfo sel = {}; -+ unsigned short zone = 0; -+ char **argv = *argv_p; -+ struct rtattr *tail; -+ int argc = *argc_p; -+ int ok = 0; -+ __u8 i; -+ -+ while (argc > 0) { -+ if (matches(*argv, "ctinfo") == 0) { -+ ok = 1; -+ NEXT_ARG_FWD(); -+ } else if (matches(*argv, "help") == 0) { -+ usage(); -+ } else { -+ break; -+ } -+ -+ } -+ -+ if (!ok) { -+ explain(); -+ return -1; -+ } -+ -+ if (argc) { -+ if (matches(*argv, "dscp") == 0) { -+ NEXT_ARG(); -+ if (get_u32(&dscpmask, *argv, 0)) { -+ fprintf(stderr, -+ "ctinfo: Illegal dscp \"mask\"\n"); -+ return -1; -+ } -+ if (NEXT_ARG_OK()) { -+ NEXT_ARG_FWD(); -+ if (!get_u32(&dscpstatemask, *argv, 0)) -+ NEXT_ARG_FWD(); /* was a statemask */ -+ } else { -+ NEXT_ARG_FWD(); -+ } -+ } -+ } -+ -+ /* cpmark has optional mask parameter, so the next arg might not */ -+ /* exist, or it might be the next option, or it may actually be a */ -+ /* 32bit mask */ -+ if (argc) { -+ if (matches(*argv, "cpmark") == 0) { -+ cpmarkmask = ~0; -+ if (NEXT_ARG_OK()) { -+ NEXT_ARG_FWD(); -+ if (!get_u32(&cpmarkmask, *argv, 0)) -+ NEXT_ARG_FWD(); /* was a mask */ -+ } else { -+ NEXT_ARG_FWD(); -+ } -+ } -+ } -+ -+ if (argc) { -+ if (matches(*argv, "zone") == 0) { -+ NEXT_ARG(); -+ if (get_u16(&zone, *argv, 10)) { -+ fprintf(stderr, "ctinfo: Illegal \"zone\"\n"); -+ return -1; -+ } -+ NEXT_ARG_FWD(); -+ } -+ } -+ -+ parse_action_control_dflt(&argc, &argv, &sel.action, -+ false, TC_ACT_PIPE); -+ -+ if (argc) { -+ if (matches(*argv, "index") == 0) { -+ NEXT_ARG(); -+ if (get_u32(&sel.index, *argv, 10)) { -+ fprintf(stderr, "ctinfo: Illegal \"index\"\n"); -+ return -1; -+ } -+ NEXT_ARG_FWD(); -+ } -+ } -+ -+ if (dscpmask & dscpstatemask) { -+ fprintf(stderr, -+ "ctinfo: dscp mask & statemask must NOT overlap\n"); -+ return -1; -+ } -+ -+ i = ffs(dscpmask); -+ if (i && ((~0 & (dscpmask >> (i - 1))) != 0x3f)) { -+ fprintf(stderr, -+ "ctinfo: dscp mask must be 6 contiguous bits long\n"); -+ return -1; -+ } -+ -+ tail = addattr_nest(n, MAX_MSG, tca_id); -+ addattr_l(n, MAX_MSG, TCA_CTINFO_ACT, &sel, sizeof(sel)); -+ addattr16(n, MAX_MSG, TCA_CTINFO_ZONE, zone); -+ -+ if (dscpmask) -+ addattr32(n, MAX_MSG, -+ TCA_CTINFO_PARMS_DSCP_MASK, dscpmask); -+ -+ if (dscpstatemask) -+ addattr32(n, MAX_MSG, -+ TCA_CTINFO_PARMS_DSCP_STATEMASK, dscpstatemask); -+ -+ if (cpmarkmask) -+ addattr32(n, MAX_MSG, -+ TCA_CTINFO_PARMS_CPMARK_MASK, cpmarkmask); -+ -+ addattr_nest_end(n, tail); -+ -+ *argc_p = argc; -+ *argv_p = argv; -+ return 0; -+} -+ -+static void print_ctinfo_stats(FILE *f, struct rtattr *tb[TCA_CTINFO_MAX + 1]) -+{ -+ struct tcf_t *tm; -+ -+ if (tb[TCA_CTINFO_TM]) { -+ tm = RTA_DATA(tb[TCA_CTINFO_TM]); -+ -+ print_tm(f, tm); -+ } -+ -+ if (tb[TCA_CTINFO_STATS_DSCP_SET]) -+ print_lluint(PRINT_ANY, "dscpset", " DSCP set %llu", -+ rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_SET])); -+ if (tb[TCA_CTINFO_STATS_DSCP_ERROR]) -+ print_lluint(PRINT_ANY, "dscperror", " error %llu", -+ rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_ERROR])); -+ -+ if (tb[TCA_CTINFO_STATS_CPMARK_SET]) -+ print_lluint(PRINT_ANY, "cpmarkset", " CPMARK set %llu", -+ rta_getattr_u64(tb[TCA_CTINFO_STATS_CPMARK_SET])); -+} -+ -+static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg) -+{ -+ unsigned int cpmarkmask = ~0, dscpmask = 0, dscpstatemask = 0; -+ struct rtattr *tb[TCA_CTINFO_MAX + 1]; -+ unsigned short zone = 0; -+ struct tc_ctinfo *ci; -+ -+ if (arg == NULL) -+ return -1; -+ -+ parse_rtattr_nested(tb, TCA_CTINFO_MAX, arg); -+ if (!tb[TCA_CTINFO_ACT]) { -+ print_string(PRINT_FP, NULL, "%s", -+ "[NULL ctinfo action parameters]"); -+ return -1; -+ } -+ -+ ci = RTA_DATA(tb[TCA_CTINFO_ACT]); -+ -+ if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) { -+ if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_MASK]) >= -+ sizeof(__u32)) -+ dscpmask = rta_getattr_u32( -+ tb[TCA_CTINFO_PARMS_DSCP_MASK]); -+ else -+ print_string(PRINT_FP, NULL, "%s", -+ "[invalid dscp mask parameter]"); -+ } -+ -+ if (tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) { -+ if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) >= -+ sizeof(__u32)) -+ dscpstatemask = rta_getattr_u32( -+ tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]); -+ else -+ print_string(PRINT_FP, NULL, "%s", -+ "[invalid dscp statemask parameter]"); -+ } -+ -+ if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) { -+ if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_CPMARK_MASK]) >= -+ sizeof(__u32)) -+ cpmarkmask = rta_getattr_u32( -+ tb[TCA_CTINFO_PARMS_CPMARK_MASK]); -+ else -+ print_string(PRINT_FP, NULL, "%s", -+ "[invalid cpmark mask parameter]"); -+ } -+ -+ if (tb[TCA_CTINFO_ZONE] && RTA_PAYLOAD(tb[TCA_CTINFO_ZONE]) >= -+ sizeof(__u16)) -+ zone = rta_getattr_u16(tb[TCA_CTINFO_ZONE]); -+ -+ print_string(PRINT_ANY, "kind", "%s ", "ctinfo"); -+ print_hu(PRINT_ANY, "zone", "zone %u", zone); -+ print_action_control(f, " ", ci->action, ""); -+ -+ print_string(PRINT_FP, NULL, "%s", _SL_); -+ print_uint(PRINT_ANY, "index", "\t index %u", ci->index); -+ print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt); -+ print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt); -+ -+ if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) { -+ print_0xhex(PRINT_ANY, "dscpmask", " dscp %#010llx", dscpmask); -+ print_0xhex(PRINT_ANY, "dscpstatemask", " %#010llx", -+ dscpstatemask); -+ } -+ -+ if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) -+ print_0xhex(PRINT_ANY, "cpmark", " cpmark %#010llx", -+ cpmarkmask); -+ -+ if (show_stats) -+ print_ctinfo_stats(f, tb); -+ -+ print_string(PRINT_FP, NULL, "%s", _SL_); -+ -+ return 0; -+} -+ -+struct action_util ctinfo_action_util = { -+ .id = "ctinfo", -+ .parse_aopt = parse_ctinfo, -+ .print_aopt = print_ctinfo, -+}; --- -2.20.1 (Apple Git-117) - diff --git a/iproute2/patches/100-configure.patch b/iproute2/patches/100-configure.patch index 248b1c0e0..0c19b2086 100644 --- a/iproute2/patches/100-configure.patch +++ b/iproute2/patches/100-configure.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -32,7 +32,8 @@ int main(int argc, char **argv) { +@@ -34,7 +34,8 @@ int main(int argc, char **argv) { } EOF diff --git a/iproute2/patches/115-add-config-xtlibdir.patch b/iproute2/patches/115-add-config-xtlibdir.patch index 6795be74b..8702d5fd2 100644 --- a/iproute2/patches/115-add-config-xtlibdir.patch +++ b/iproute2/patches/115-add-config-xtlibdir.patch @@ -1,6 +1,6 @@ --- a/tc/Makefile +++ b/tc/Makefile -@@ -120,6 +120,9 @@ CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PR +@@ -128,6 +128,9 @@ CFLAGS += -DCONFIG_GACT -DCONFIG_GACT_PR ifneq ($(IPT_LIB_DIR),) CFLAGS += -DIPT_LIB_DIR=\"$(IPT_LIB_DIR)\" endif @@ -8,5 +8,5 @@ + CFLAGS += -DXT_LIB_DIR=\"$(XT_LIB_DIR)\" +endif - YACC := bison LEX := flex + CFLAGS += -DYY_NO_INPUT diff --git a/iproute2/patches/120-no_arpd.patch b/iproute2/patches/120-no_arpd_ifstat_rtacct_lnstat.patch similarity index 56% rename from iproute2/patches/120-no_arpd.patch rename to iproute2/patches/120-no_arpd_ifstat_rtacct_lnstat.patch index 772398140..bb6a8d018 100644 --- a/iproute2/patches/120-no_arpd.patch +++ b/iproute2/patches/120-no_arpd_ifstat_rtacct_lnstat.patch @@ -1,6 +1,11 @@ --- a/misc/Makefile +++ b/misc/Makefile -@@ -6,9 +6,9 @@ TARGETS=ss nstat ifstat rtacct lnstat +@@ -2,13 +2,13 @@ + SSOBJ=ss.o ssfilter_check.o ssfilter.tab.o + LNSTATOBJ=lnstat.o lnstat_util.o + +-TARGETS=ss nstat ifstat rtacct lnstat ++TARGETS=ss nstat include ../config.mk diff --git a/iproute2/patches/130-no_netem.patch b/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch similarity index 69% rename from iproute2/patches/130-no_netem.patch rename to iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch index aa93366f2..8ddb31674 100644 --- a/iproute2/patches/130-no_netem.patch +++ b/iproute2/patches/130-no_netem_tipc_dcb_man_vdpa.patch @@ -4,8 +4,8 @@ CFLAGS := $(WFLAGS) $(CCOPTS) -I../include -I../include/uapi $(DEFINES) $(CFLAGS) YACCFLAGS = -d -t -v --SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man -+SUBDIRS=lib ip tc bridge misc genl tipc devlink rdma man +-SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma dcb man vdpa ++SUBDIRS=lib ip tc bridge misc genl devlink rdma LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a LDLIBS += $(LIBNETLINK) diff --git a/iproute2/patches/135-sync-iptables-header.patch b/iproute2/patches/135-sync-iptables-header.patch deleted file mode 100644 index bba90e69a..000000000 --- a/iproute2/patches/135-sync-iptables-header.patch +++ /dev/null @@ -1,101 +0,0 @@ -Description: Sync header from iptables - The current versions in several suites have the same content: - - 1.6.1-2 (unstable) -Bug: https://bugs.debian.org/868059 -Forwarded: not-needed -Author: Cyril Brulebois -Last-Update: 2017-11-22 ---- a/include/xtables.h -+++ b/include/xtables.h -@@ -206,9 +206,24 @@ enum xtables_ext_flags { - XTABLES_EXT_ALIAS = 1 << 0, - }; - -+struct xt_xlate; -+ -+struct xt_xlate_mt_params { -+ const void *ip; -+ const struct xt_entry_match *match; -+ int numeric; -+ bool escape_quotes; -+}; -+ -+struct xt_xlate_tg_params { -+ const void *ip; -+ const struct xt_entry_target *target; -+ int numeric; -+ bool escape_quotes; -+}; -+ - /* Include file for additions: new matches and targets. */ --struct xtables_match --{ -+struct xtables_match { - /* - * ABI/API version this module requires. Must be first member, - * as the rest of this struct may be subject to ABI changes. -@@ -270,6 +285,10 @@ struct xtables_match - void (*x6_fcheck)(struct xt_fcheck_call *); - const struct xt_option_entry *x6_options; - -+ /* Translate iptables to nft */ -+ int (*xlate)(struct xt_xlate *xl, -+ const struct xt_xlate_mt_params *params); -+ - /* Size of per-extension instance extra "global" scratch space */ - size_t udata_size; - -@@ -281,8 +300,7 @@ struct xtables_match - unsigned int loaded; /* simulate loading so options are merged properly */ - }; - --struct xtables_target --{ -+struct xtables_target { - /* - * ABI/API version this module requires. Must be first member, - * as the rest of this struct may be subject to ABI changes. -@@ -347,6 +365,10 @@ struct xtables_target - void (*x6_fcheck)(struct xt_fcheck_call *); - const struct xt_option_entry *x6_options; - -+ /* Translate iptables to nft */ -+ int (*xlate)(struct xt_xlate *xl, -+ const struct xt_xlate_tg_params *params); -+ - size_t udata_size; - - /* Ignore these men behind the curtain: */ -@@ -407,6 +429,17 @@ struct xtables_globals - - #define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false} - -+/* -+ * enum op- -+ * -+ * For writing clean nftables translations code -+ */ -+enum xt_op { -+ XT_OP_EQ, -+ XT_OP_NEQ, -+ XT_OP_MAX, -+}; -+ - #ifdef __cplusplus - extern "C" { - #endif -@@ -549,6 +582,14 @@ extern void xtables_lmap_free(struct xta - extern int xtables_lmap_name2id(const struct xtables_lmap *, const char *); - extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); - -+/* xlate infrastructure */ -+struct xt_xlate *xt_xlate_alloc(int size); -+void xt_xlate_free(struct xt_xlate *xl); -+void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...); -+void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment); -+const char *xt_xlate_get_comment(struct xt_xlate *xl); -+const char *xt_xlate_get(struct xt_xlate *xl); -+ - #ifdef XTABLES_INTERNAL - - /* Shipped modules rely on this... */ diff --git a/iproute2/patches/140-allow_pfifo_fast.patch b/iproute2/patches/140-allow_pfifo_fast.patch index bb898a40d..13de48f41 100644 --- a/iproute2/patches/140-allow_pfifo_fast.patch +++ b/iproute2/patches/140-allow_pfifo_fast.patch @@ -1,6 +1,6 @@ --- a/tc/q_fifo.c +++ b/tc/q_fifo.c -@@ -99,5 +99,6 @@ struct qdisc_util pfifo_head_drop_qdisc_ +@@ -95,5 +95,6 @@ struct qdisc_util pfifo_head_drop_qdisc_ struct qdisc_util pfifo_fast_qdisc_util = { .id = "pfifo_fast", diff --git a/iproute2/patches/140-keep_libmnl_optional.patch b/iproute2/patches/140-keep_libmnl_optional.patch index d255ae7b0..ff7e9ca4e 100644 --- a/iproute2/patches/140-keep_libmnl_optional.patch +++ b/iproute2/patches/140-keep_libmnl_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -255,7 +255,7 @@ check_selinux() +@@ -387,7 +387,7 @@ check_selinux() check_mnl() { diff --git a/iproute2/patches/145-keep_libelf_optional.patch b/iproute2/patches/145-keep_libelf_optional.patch index 2e3ad1880..079ca0512 100644 --- a/iproute2/patches/145-keep_libelf_optional.patch +++ b/iproute2/patches/145-keep_libelf_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -228,7 +228,7 @@ EOF +@@ -255,7 +255,7 @@ EOF check_elf() { diff --git a/iproute2/patches/150-keep_libcap_optional.patch b/iproute2/patches/150-keep_libcap_optional.patch index 05336a737..68e162416 100644 --- a/iproute2/patches/150-keep_libcap_optional.patch +++ b/iproute2/patches/150-keep_libcap_optional.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -313,7 +313,7 @@ EOF +@@ -445,7 +445,7 @@ EOF check_cap() { diff --git a/iproute2/patches/160-libnetlink-pic.patch b/iproute2/patches/160-libnetlink-pic.patch index aad87a1e4..145ec7a9e 100644 --- a/iproute2/patches/160-libnetlink-pic.patch +++ b/iproute2/patches/160-libnetlink-pic.patch @@ -7,5 +7,5 @@ -CFLAGS += -fPIC +CFLAGS += $(FPIC) - UTILOBJ = utils.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \ - inet_proto.o namespace.o json_writer.o json_print.o \ + UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \ + inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \ diff --git a/iproute2/patches/170-ip_tiny.patch b/iproute2/patches/170-ip_tiny.patch index fb5a6466e..cd687e760 100644 --- a/iproute2/patches/170-ip_tiny.patch +++ b/iproute2/patches/170-ip_tiny.patch @@ -1,6 +1,6 @@ --- a/ip/Makefile +++ b/ip/Makefile -@@ -16,6 +16,13 @@ RTMONOBJ=rtmon.o +@@ -17,6 +17,13 @@ RTMONOBJ=rtmon.o include ../config.mk @@ -14,7 +14,7 @@ ALLOBJ=$(IPOBJ) $(RTMONOBJ) SCRIPTS=ifcfg rtpr routel routef TARGETS=ip rtmon -@@ -45,7 +52,7 @@ else +@@ -46,7 +53,7 @@ else ip: static-syms.o static-syms.o: static-syms.h @@ -25,24 +25,25 @@ sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \ --- a/ip/ip.c +++ b/ip/ip.c -@@ -47,10 +47,16 @@ static void usage(void) +@@ -64,11 +64,17 @@ static void usage(void) fprintf(stderr, - "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" - " ip [ -force ] -batch filename\n" + "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" + " ip [ -force ] -batch filename\n" +#ifndef IPROUTE2_TINY - "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" - " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" - " netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n" - " vrf | sr }\n" + "where OBJECT := { address | addrlabel | fou | help | ila | ioam | l2tp | link |\n" + " macsec | maddress | monitor | mptcp | mroute | mrule |\n" + " neighbor | neighbour | netconf | netns | nexthop | ntable |\n" + " ntbl | route | rule | sr | tap | tcpmetrics |\n" + " token | tunnel | tuntap | vrf | xfrm }\n" +#else -+"where OBJECT := { link | address | route | rule | neigh | tunnel | maddress |\n" -+" mroute | mrule | monitor | netns | macsec | token | ila |\n" -+" vrf | sr }\n" ++ "where OBJECT := { address | ila | link | macsec | maddress | monitor |\n" ++ " mroute | mrule | neighbor | neighbour | netns | route |\n" ++ " rule | sr | token | tunnel | vrf }\n" +#endif - " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" - " -h[uman-readable] | -iec | -j[son] | -p[retty] |\n" - " -f[amily] { inet | inet6 | mpls | bridge | link } |\n" -@@ -72,32 +78,44 @@ static const struct cmd { + " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" + " -h[uman-readable] | -iec | -j[son] | -p[retty] |\n" + " -f[amily] { inet | inet6 | mpls | bridge | link } |\n" +@@ -91,37 +97,51 @@ static const struct cmd { int (*func)(int argc, char **argv); } cmds[] = { { "address", do_ipaddr }, @@ -86,7 +87,14 @@ +#endif { "vrf", do_ipvrf}, { "sr", do_seg6 }, ++#ifndef IPROUTE2_TINY + { "nexthop", do_ipnh }, + { "mptcp", do_mptcp }, + { "ioam", do_ioam6 }, ++#endif { "help", do_help }, + { 0 } + }; --- a/lib/Makefile +++ b/lib/Makefile @@ -3,6 +3,10 @@ include ../config.mk @@ -97,6 +105,6 @@ + CFLAGS += -DIPROUTE2_TINY +endif + - UTILOBJ = utils.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \ - inet_proto.o namespace.o json_writer.o json_print.o \ - names.o color.o bpf.o exec.o fs.o + UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \ + inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \ + names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o diff --git a/iproute2/patches/175-reduce-dynamic-syms.patch b/iproute2/patches/175-reduce-dynamic-syms.patch index aaed2f1a4..c3892e5a0 100644 --- a/iproute2/patches/175-reduce-dynamic-syms.patch +++ b/iproute2/patches/175-reduce-dynamic-syms.patch @@ -1,6 +1,6 @@ --- a/tc/Makefile +++ b/tc/Makefile -@@ -108,7 +108,7 @@ LDLIBS += -L. -lm +@@ -114,7 +114,7 @@ LDLIBS += -L. -lm ifeq ($(SHARED_LIBS),y) LDLIBS += -ldl @@ -9,7 +9,7 @@ endif TCLIB := tc_core.o -@@ -138,7 +138,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc +@@ -144,7 +144,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc all: tc $(TCSO) tc: $(TCOBJ) $(LIBNETLINK) libtc.a @@ -18,15 +18,15 @@ libtc.a: $(TCLIB) $(QUIET_AR)$(AR) rcs $@ $^ -@@ -160,6 +160,7 @@ install: all +@@ -166,6 +166,7 @@ install: all clean: - rm -f $(TCOBJ) $(TCLIB) libtc.a tc *.so emp_ematch.yacc.h; \ - rm -f emp_ematch.yacc.* + rm -f $(TCOBJ) $(TCLIB) libtc.a tc *.so emp_ematch.tab.h; \ + rm -f emp_ematch.tab.* + rm -f dynsyms.list q_atm.so: q_atm.c $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm -@@ -199,4 +200,16 @@ static-syms.h: $(wildcard *.c) +@@ -205,4 +206,16 @@ static-syms.h: $(wildcard *.c) sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \ done > $@ @@ -40,6 +40,6 @@ + for s in `grep -B 3 '\> $@ ; \ -+ echo "show_stats; print_tm; parse_rtattr; get_u32; matches; addattr_l; addattr_nest; addattr_nest_end; };" >> $@ ++ echo "show_stats; print_nl; print_tm; parse_rtattr; parse_rtattr_flags; get_u32; matches; addattr_l; addattr_nest; addattr_nest_end; };" >> $@ + endif diff --git a/iproute2/patches/180-drop_FAILED_POLICY.patch b/iproute2/patches/180-drop_FAILED_POLICY.patch index 5de663f5c..07d5230a6 100644 --- a/iproute2/patches/180-drop_FAILED_POLICY.patch +++ b/iproute2/patches/180-drop_FAILED_POLICY.patch @@ -11,7 +11,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY --- a/ip/rtm_map.c +++ b/ip/rtm_map.c -@@ -48,6 +48,8 @@ char *rtnl_rtntype_n2a(int id, char *buf +@@ -54,6 +54,8 @@ char *rtnl_rtntype_n2a(int id, char *buf return "nat"; case RTN_XRESOLVE: return "xresolve"; @@ -20,7 +20,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY default: snprintf(buf, len, "%d", id); return buf; -@@ -83,6 +85,8 @@ int rtnl_rtntype_a2n(int *id, char *arg) +@@ -89,6 +91,8 @@ int rtnl_rtntype_a2n(int *id, char *arg) res = RTN_UNICAST; else if (strcmp(arg, "throw") == 0) res = RTN_THROW; @@ -31,7 +31,7 @@ Subject: [PATCH] add support for dropping with FAILED_POLICY if (!end || end == arg || *end || res > 255) --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h -@@ -228,6 +228,7 @@ enum { +@@ -256,6 +256,7 @@ enum { RTN_THROW, /* Not in this table */ RTN_NAT, /* Translate this address */ RTN_XRESOLVE, /* Use external resolver */ diff --git a/iproute2/patches/190-fix-nls-rpath-link.patch b/iproute2/patches/190-fix-nls-rpath-link.patch new file mode 100644 index 000000000..92d02b9a4 --- /dev/null +++ b/iproute2/patches/190-fix-nls-rpath-link.patch @@ -0,0 +1,20 @@ +--- a/configure ++++ b/configure +@@ -279,7 +279,7 @@ int main(int argc, char **argv) { + } + EOF + +- $CC -o $TMPDIR/libbpf_test $TMPDIR/libbpf_test.c $LIBBPF_CFLAGS $LIBBPF_LDLIBS >/dev/null 2>&1 ++ $CC -o $TMPDIR/libbpf_test $TMPDIR/libbpf_test.c $LIBBPF_CFLAGS $LIBBPF_LDLIBS $LDFLAGS >/dev/null 2>&1 + local ret=$? + + rm -f $TMPDIR/libbpf_test.c $TMPDIR/libbpf_test +@@ -297,7 +297,7 @@ int main(int argc, char **argv) { + } + EOF + +- $CC -o $TMPDIR/libbpf_sec_test $TMPDIR/libbpf_sec_test.c $LIBBPF_CFLAGS $LIBBPF_LDLIBS >/dev/null 2>&1 ++ $CC -o $TMPDIR/libbpf_sec_test $TMPDIR/libbpf_sec_test.c $LIBBPF_CFLAGS $LIBBPF_LDLIBS $LDFLAGS >/dev/null 2>&1 + local ret=$? + + rm -f $TMPDIR/libbpf_sec_test.c $TMPDIR/libbpf_sec_test diff --git a/iproute2/patches/195-build_variant_ip_tc.patch b/iproute2/patches/195-build_variant_ip_tc.patch new file mode 100644 index 000000000..13418662e --- /dev/null +++ b/iproute2/patches/195-build_variant_ip_tc.patch @@ -0,0 +1,22 @@ +--- a/ip/Makefile ++++ b/ip/Makefile +@@ -26,7 +26,7 @@ STATIC_SYM_SOURCES:=$(filter-out $(STATI + + ALLOBJ=$(IPOBJ) $(RTMONOBJ) + SCRIPTS=ifcfg rtpr routel routef +-TARGETS=ip rtmon ++TARGETS=$(findstring ip,$(BUILD_VARIANT)) rtmon + + all: $(TARGETS) $(SCRIPTS) + +--- a/tc/Makefile ++++ b/tc/Makefile +@@ -141,7 +141,7 @@ MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc + $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fpic $< -o $@ + + +-all: tc $(TCSO) ++all: $(findstring tc,$(BUILD_VARIANT)) $(TCSO) + + tc: $(TCOBJ) $(LIBNETLINK) libtc.a + $(QUIET_LINK)$(CC) $(filter-out dynsyms.list, $^) $(LDFLAGS) $(LDLIBS) -o $@ diff --git a/iproute2/patches/200-drop_libbsd_dependency.patch b/iproute2/patches/200-drop_libbsd_dependency.patch index f6ec94529..12a1ccfa3 100644 --- a/iproute2/patches/200-drop_libbsd_dependency.patch +++ b/iproute2/patches/200-drop_libbsd_dependency.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -299,14 +299,8 @@ EOF +@@ -431,14 +431,8 @@ EOF if $CC -I$INCLUDE -o $TMPDIR/strtest $TMPDIR/strtest.c >/dev/null 2>&1; then echo "no" else diff --git a/iproute2/patches/300-selinux-configurable.patch b/iproute2/patches/300-selinux-configurable.patch new file mode 100644 index 000000000..b7e61fd3b --- /dev/null +++ b/iproute2/patches/300-selinux-configurable.patch @@ -0,0 +1,11 @@ +--- a/configure ++++ b/configure +@@ -374,7 +374,7 @@ check_libbpf() + check_selinux() + # SELinux is a compile time option in the ss utility + { +- if ${PKG_CONFIG} libselinux --exists; then ++ if [ "${HAVE_SELINUX}" = "y" ] && ${PKG_CONFIG} libselinux --exists; then + echo "HAVE_SELINUX:=y" >>$CONFIG + echo "yes" + diff --git a/iproute2/patches/400-add-nss-qdisc.patch b/iproute2/patches/400-add-nss-qdisc.patch deleted file mode 100644 index a2840f788..000000000 --- a/iproute2/patches/400-add-nss-qdisc.patch +++ /dev/null @@ -1,2096 +0,0 @@ ---- a/include/uapi/linux/pkt_sched.h -+++ b/include/uapi/linux/pkt_sched.h -@@ -118,6 +118,250 @@ enum { - - #define TCA_STAB_MAX (__TCA_STAB_MAX - 1) - -+enum { -+ TCA_NSS_ACCEL_MODE_NSS_FW, -+ TCA_NSS_ACCEL_MODE_PPE, -+ TCA_NSS_ACCEL_MODE_MAX -+}; -+ -+/* NSSFIFO section */ -+ -+enum { -+ TCA_NSSFIFO_UNSPEC, -+ TCA_NSSFIFO_PARMS, -+ __TCA_NSSFIFO_MAX -+}; -+ -+#define TCA_NSSFIFO_MAX (__TCA_NSSFIFO_MAX - 1) -+ -+struct tc_nssfifo_qopt { -+ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ -+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSWRED section */ -+ -+enum { -+ TCA_NSSWRED_UNSPEC, -+ TCA_NSSWRED_PARMS, -+ __TCA_NSSWRED_MAX -+}; -+ -+#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1) -+#define NSSWRED_CLASS_MAX 6 -+struct tc_red_alg_parameter { -+ __u32 min; /* qlen_avg < min: pkts are all enqueued */ -+ __u32 max; /* qlen_avg > max: pkts are all dropped */ -+ __u32 probability;/* Drop probability at qlen_avg = max */ -+ __u32 exp_weight_factor;/* exp_weight_factor for calculate qlen_avg */ -+}; -+ -+struct tc_nsswred_traffic_class { -+ __u32 limit; /* Queue length */ -+ __u32 weight_mode_value; /* Weight mode value */ -+ struct tc_red_alg_parameter rap;/* Parameters for RED alg */ -+}; -+ -+/* -+ * Weight modes for WRED -+ */ -+enum tc_nsswred_weight_modes { -+ TC_NSSWRED_WEIGHT_MODE_DSCP = 0,/* Weight mode is DSCP */ -+ TC_NSSWRED_WEIGHT_MODES, /* Must be last */ -+}; -+typedef enum tc_nsswred_weight_modes tc_nsswred_weight_mode_t; -+ -+struct tc_nsswred_qopt { -+ __u32 limit; /* Queue length */ -+ enum tc_nsswred_weight_modes weight_mode; -+ /* Weight mode */ -+ __u32 traffic_classes; /* How many traffic classes: DPs */ -+ __u32 def_traffic_class; /* Default traffic if no match: def_DP */ -+ __u32 traffic_id; /* The traffic id to be configured: DP */ -+ __u32 weight_mode_value; /* Weight mode value */ -+ struct tc_red_alg_parameter rap;/* RED algorithm parameters */ -+ struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX]; -+ /* Traffic settings for dumpping */ -+ __u8 ecn; /* Setting ECN bit or dropping */ -+ __u8 set_default; /* Sets qdisc to be the default for enqueue */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSCODEL section */ -+ -+enum { -+ TCA_NSSCODEL_UNSPEC, -+ TCA_NSSCODEL_PARMS, -+ __TCA_NSSCODEL_MAX -+}; -+ -+#define TCA_NSSCODEL_MAX (__TCA_NSSCODEL_MAX - 1) -+ -+struct tc_nsscodel_qopt { -+ __u32 target; /* Acceptable queueing delay */ -+ __u32 limit; /* Max number of packets that can be held in the queue */ -+ __u32 interval; /* Monitoring interval */ -+ __u32 flows; /* Number of flow buckets */ -+ __u32 quantum; /* Weight (in bytes) used for DRR of flow buckets */ -+ __u8 ecn; /* 0 - disable ECN, 1 - enable ECN */ -+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+struct tc_nsscodel_xstats { -+ __u32 peak_queue_delay; /* Peak delay experienced by a dequeued packet */ -+ __u32 peak_drop_delay; /* Peak delay experienced by a dropped packet */ -+}; -+ -+/* NSSFQ_CODEL section */ -+ -+struct tc_nssfq_codel_xstats { -+ __u32 new_flow_count; /* Total number of new flows seen */ -+ __u32 new_flows_len; /* Current number of new flows */ -+ __u32 old_flows_len; /* Current number of old flows */ -+ __u32 ecn_mark; /* Number of packets marked with ECN */ -+ __u32 drop_overlimit; /* Number of packets dropped due to overlimit */ -+ __u32 maxpacket; /* The largest packet seen so far in the queue */ -+}; -+ -+/* NSSTBL section */ -+ -+enum { -+ TCA_NSSTBL_UNSPEC, -+ TCA_NSSTBL_PARMS, -+ __TCA_NSSTBL_MAX -+}; -+ -+#define TCA_NSSTBL_MAX (__TCA_NSSTBL_MAX - 1) -+ -+struct tc_nsstbl_qopt { -+ __u32 burst; /* Maximum burst size */ -+ __u32 rate; /* Limiting rate of TBF */ -+ __u32 peakrate; /* Maximum rate at which TBF is allowed to send */ -+ __u32 mtu; /* Max size of packet, or minumim burst size */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSPRIO section */ -+ -+#define TCA_NSSPRIO_MAX_BANDS 256 -+ -+enum { -+ TCA_NSSPRIO_UNSPEC, -+ TCA_NSSPRIO_PARMS, -+ __TCA_NSSPRIO_MAX -+}; -+ -+#define TCA_NSSPRIO_MAX (__TCA_NSSPRIO_MAX - 1) -+ -+struct tc_nssprio_qopt { -+ __u32 bands; /* Number of bands */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSBF section */ -+ -+enum { -+ TCA_NSSBF_UNSPEC, -+ TCA_NSSBF_CLASS_PARMS, -+ TCA_NSSBF_QDISC_PARMS, -+ __TCA_NSSBF_MAX -+}; -+ -+#define TCA_NSSBF_MAX (__TCA_NSSBF_MAX - 1) -+ -+struct tc_nssbf_class_qopt { -+ __u32 burst; /* Maximum burst size */ -+ __u32 rate; /* Allowed bandwidth for this class */ -+ __u32 mtu; /* MTU of the associated interface */ -+ __u32 quantum; /* Quantum allocation for DRR */ -+}; -+ -+struct tc_nssbf_qopt { -+ __u16 defcls; /* Default class value */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSWRR section */ -+ -+enum { -+ TCA_NSSWRR_UNSPEC, -+ TCA_NSSWRR_CLASS_PARMS, -+ TCA_NSSWRR_QDISC_PARMS, -+ __TCA_NSSWRR_MAX -+}; -+ -+#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1) -+ -+struct tc_nsswrr_class_qopt { -+ __u32 quantum; /* Weight associated to this class */ -+}; -+ -+struct tc_nsswrr_qopt { -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSWFQ section */ -+ -+enum { -+ TCA_NSSWFQ_UNSPEC, -+ TCA_NSSWFQ_CLASS_PARMS, -+ TCA_NSSWFQ_QDISC_PARMS, -+ __TCA_NSSWFQ_MAX -+}; -+ -+#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1) -+ -+struct tc_nsswfq_class_qopt { -+ __u32 quantum; /* Weight associated to this class */ -+}; -+ -+struct tc_nsswfq_qopt { -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSHTB section */ -+ -+enum { -+ TCA_NSSHTB_UNSPEC, -+ TCA_NSSHTB_CLASS_PARMS, -+ TCA_NSSHTB_QDISC_PARMS, -+ __TCA_NSSHTB_MAX -+}; -+ -+#define TCA_NSSHTB_MAX (__TCA_NSSHTB_MAX - 1) -+ -+struct tc_nsshtb_class_qopt { -+ __u32 burst; /* Allowed burst size */ -+ __u32 rate; /* Allowed bandwidth for this class */ -+ __u32 cburst; /* Maximum burst size */ -+ __u32 crate; /* Maximum bandwidth for this class */ -+ __u32 quantum; /* Quantum allocation for DRR */ -+ __u32 priority; /* Priority value associated with this class */ -+ __u32 overhead; /* Overhead in bytes per packet */ -+}; -+ -+struct tc_nsshtb_qopt { -+ __u32 r2q; /* Rate to quantum ratio */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ -+/* NSSBLACKHOLE section */ -+ -+enum { -+ TCA_NSSBLACKHOLE_UNSPEC, -+ TCA_NSSBLACKHOLE_PARMS, -+ __TCA_NSSBLACKHOLE_MAX -+}; -+ -+#define TCA_NSSBLACKHOLE_MAX (__TCA_NSSBLACKHOLE_MAX - 1) -+ -+struct tc_nssblackhole_qopt { -+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ -+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ -+}; -+ - /* FIFO section */ - - struct tc_fifo_qopt { ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -76,6 +76,7 @@ TCMODULES += f_matchall.o - TCMODULES += q_cbs.o - TCMODULES += q_etf.o - TCMODULES += q_taprio.o -+TCMODULES += q_nss.o - - TCSO := - ifeq ($(TC_CONFIG_ATM),y) ---- /dev/null -+++ b/tc/q_nss.c -@@ -0,0 +1,1830 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2015, 2018, 2020, The Linux Foundation. All rights reserved. -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ ************************************************************************** -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "utils.h" -+#include "tc_util.h" -+#include "tc_red.h" -+ -+/* ======================== NSSWRED =======================*/ -+ -+static void nssred_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nssred limit BYTES avpkt BYTES [ min BYTES ] [ max BYTES ] [ probability VALUE ]\n"); -+ fprintf(stderr, " [ burst PACKETS ] [ecn] [ set_default ] [ accel_mode ]\n"); -+} -+ -+static void nsswred_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsswred setup DPs NUMBER dp_default NUMBER [ weight_mode dscp ] [ecn] [ set_default ] [ accel_mode ]\n"); -+ fprintf(stderr, " nsswred limit BYTES DP NUMBER min BYTES max BYTES avpkt BYTES dscp NUMBER [ probability VALUE ] [ burst PACKETS ]\n"); -+} -+ -+static int nsswred_setup(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) -+{ -+ struct rtattr *tail; -+ struct tc_nsswred_qopt opt; -+ -+ memset(&opt, 0, sizeof(opt)); -+ unsigned int dps = 0; -+ unsigned int def_dp = 0; -+ bool accel_mode = false; -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "DPs") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&dps, *argv, 0) || dps > NSSWRED_CLASS_MAX) { -+ -+ fprintf(stderr, "DPs should be between 1 - %d\n", NSSWRED_CLASS_MAX); -+ return -1; -+ } -+ } else if (strcmp(*argv, "weight_mode") == 0) { -+ NEXT_ARG(); -+ if (strcmp(*argv, "dscp") == 0) { -+ opt.weight_mode = TC_NSSWRED_WEIGHT_MODE_DSCP; -+ } else { -+ fprintf(stderr, "Illegal \"weight_mode\", we only support dscp at this moment\n"); -+ } -+ } else if (strcmp(*argv, "ecn") == 0) { -+ opt.ecn = 1; -+ } else if (strcmp(*argv, "dp_default") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&def_dp, *argv, 0) || def_dp > dps) { -+ fprintf(stderr, "Illegal dp_default value\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "help") == 0) { -+ nsswred_explain(); -+ return -1; -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsswred_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ if (!dps || !def_dp) { -+ fprintf(stderr, "Illegal nsswred setup parameters\n"); -+ return -1; -+ } -+ opt.traffic_classes = dps; -+ opt.def_traffic_class = def_dp; -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWRED_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct rtattr *tail; -+ struct tc_nsswred_qopt opt; -+ -+ int total_args = argc; -+ unsigned burst = 0; -+ unsigned avpkt = 0; -+ double probability = 0.0; -+ unsigned char weighted = (strcmp(qu->id, "nsswred") == 0); -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "limit") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.limit, *argv)) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "min") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.rap.min, *argv)) { -+ fprintf(stderr, "Illegal \"min\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "max") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.rap.max, *argv)) { -+ fprintf(stderr, "Illegal \"max\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "burst") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&burst, *argv, 0)) { -+ fprintf(stderr, "Illegal \"burst\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "avpkt") == 0) { -+ NEXT_ARG(); -+ if (get_size(&avpkt, *argv)) { -+ fprintf(stderr, "Illegal \"avpkt\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "probability") == 0) { -+ NEXT_ARG(); -+ if (sscanf(*argv, "%lg", &probability) != 1) { -+ fprintf(stderr, "Illegal \"probability\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "ecn") == 0) { -+ opt.ecn = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ if (weighted) { -+ nsswred_explain(); -+ } else { -+ nssred_explain(); -+ } -+ return -1; -+ } else if (weighted) { -+ if (strcmp(*argv, "setup") == 0) { -+ if (argc != total_args) { -+ fprintf(stderr, "Setup command must be the first parameter\n"); -+ return -1; -+ } -+ return nsswred_setup(qu, argc-1, argv+1, n); -+ } else if (strcmp(*argv, "DP") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&opt.traffic_id, *argv, 0)) { -+ fprintf(stderr, "Illegal \"DP\""); -+ return -1; -+ } -+ } else if (strcmp(*argv, "dscp") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&opt.weight_mode_value, *argv, 0)) { -+ fprintf(stderr, "Illegal \"dscp\" value\n"); -+ return -1; -+ } -+ } -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ if (weighted) { -+ nsswred_explain(); -+ } else { -+ nssred_explain(); -+ } -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "Accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ if (weighted) { -+ if (!opt.limit || !opt.rap.min || !opt.rap.max || !opt.traffic_id || !avpkt || !opt.weight_mode_value) { -+ fprintf(stderr, "Require limit, min, max, avpkt, DP, weight_mode_value\n"); -+ return -1; -+ } -+ } else { -+ if (!opt.limit || !avpkt) { -+ fprintf(stderr, "Require limit, avpkt"); -+ return -1; -+ } -+ } -+ -+ /* -+ * Compute default min/max thresholds based on -+ * Sally Floyd's recommendations: -+ * http://www.icir.org/floyd/REDparameters.txt -+ */ -+ if (!opt.rap.max) -+ opt.rap.max = opt.rap.min ? opt.rap.min * 3 : opt.limit / 4; -+ if (!opt.rap.min) -+ opt.rap.min = opt.rap.max / 3; -+ if (!burst) -+ burst = (2 * opt.rap.min + opt.rap.max) / (3 * avpkt); -+ if ((opt.rap.exp_weight_factor = tc_red_eval_ewma(opt.rap.min, burst, avpkt)) < 0) { -+ fprintf(stderr, "Failed to calculate EWMA constant.\n"); -+ return -1; -+ } -+ -+ /* -+ * project [0.0-1.0] to [0-255] to avoid floating point calculation -+ */ -+ opt.rap.probability = probability * (pow(2, 8)-1); -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWRED_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWRED_MAX + 1]; -+ struct tc_nsswred_qopt *qopt; -+ int i; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWRED_MAX, opt); -+ -+ if (tb[TCA_NSSWRED_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWRED_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWRED_PARMS]); -+ -+ if (strcmp(qu->id, "nsswred") == 0) { -+ fprintf(f, "DPs %d def_DP %d weight mode: " , qopt->traffic_classes, qopt->def_traffic_class); -+ if (qopt->weight_mode == TC_NSSWRED_WEIGHT_MODE_DSCP) -+ fprintf(f, "DSCP\n"); -+ else -+ fprintf(f, "Unknown\n"); -+ for (i = 0;i < qopt->traffic_classes; i ++) { -+ if (qopt->tntc[i].rap.exp_weight_factor) { -+ double prob = (double)qopt->tntc[i].rap.probability; -+ fprintf(f, "DP %d: limit %d, weight mode value: %d min: %d max: %d exp_weight_factor: %d probability %.2f\n", -+ i + 1, qopt->tntc[i].limit, qopt->tntc[i].weight_mode_value -+ , qopt->tntc[i].rap.min,qopt->tntc[i].rap.max,qopt->tntc[i].rap.exp_weight_factor,prob/255); -+ } -+ } -+ } else { -+ double prob = (double)qopt->rap.probability; -+ fprintf(f, "limit %d, min: %d max: %d exp_weight_factor: %d probability %.2f\n", -+ qopt->limit, qopt->rap.min,qopt->rap.max,qopt->rap.exp_weight_factor,prob/255); -+ } -+ -+ if (qopt->ecn) -+ fprintf(f, "ECN enabled "); -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode: %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nssred_qdisc_util = { -+ .id = "nssred", -+ .parse_qopt = nsswred_parse_opt, -+ .print_qopt = nsswred_print_opt, -+}; -+ -+struct qdisc_util nsswred_qdisc_util = { -+ .id = "nsswred", -+ .parse_qopt = nsswred_parse_opt, -+ .print_qopt = nsswred_print_opt, -+}; -+ -+/* ======================== NSSFIFO =======================*/ -+ -+static void nssfifo_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsspfifo [ limit PACKETS ] [ set_default ] [ accel_mode ]\n"); -+} -+ -+static int nssfifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct rtattr *tail; -+ struct tc_nssfifo_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "limit") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.limit, *argv) || opt.limit == 0) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssfifo_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssfifo_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSFIFO_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssfifo_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSFIFO_MAX + 1]; -+ struct tc_nssfifo_qopt *qopt; -+ SPRINT_BUF(b1); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSFIFO_MAX, opt); -+ -+ if (tb[TCA_NSSFIFO_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSFIFO_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSFIFO_PARMS]); -+ -+ if (strcmp(qu->id, "nssbfifo") == 0) -+ fprintf(f, "limit %s ", sprint_size(qopt->limit, b1)); -+ else -+ fprintf(f, "limit %up ", qopt->limit); -+ -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nsspfifo_qdisc_util = { -+ .id = "nsspfifo", -+ .parse_qopt = nssfifo_parse_opt, -+ .print_qopt = nssfifo_print_opt, -+}; -+ -+struct qdisc_util nssbfifo_qdisc_util = { -+ .id = "nssbfifo", -+ .parse_qopt = nssfifo_parse_opt, -+ .print_qopt = nssfifo_print_opt, -+}; -+ -+/* ======================== NSSFQ_CODEL =======================*/ -+ -+static void nssfq_codel_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nssfq_codel target TIME interval TIME [ flows NUMBER ] [ quantum BYTES ]" -+ "[ limit PACKETS ] [ set_default ] [ accel_mode ]\n"); -+} -+ -+static void nssfq_codel_explain_err1(void) -+{ -+ fprintf(stderr, "Value of target and interval should be greater than 1ms\n"); -+} -+ -+static int nssfq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct rtattr *tail; -+ struct tc_nsscodel_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "target") == 0) { -+ NEXT_ARG(); -+ if (get_time(&opt.target, *argv)) { -+ fprintf(stderr, "Illegal \"target\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "limit") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.limit, *argv) || opt.limit == 0) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "flows") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.flows, *argv) || opt.flows == 0) { -+ fprintf(stderr, "Illegal \"flows\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.quantum, *argv) || opt.quantum == 0) { -+ fprintf(stderr, "Illegal \"quantum\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "interval") == 0) { -+ NEXT_ARG(); -+ if (get_time(&opt.interval, *argv)) { -+ fprintf(stderr, "Illegal \"interval\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "ecn") == 0) { -+ fprintf(stderr, "Illegal, ECN not supported\n"); -+ nssfq_codel_explain(); -+ return -1; -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssfq_codel_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssfq_codel_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ if (!opt.target || !opt.interval) { -+ nssfq_codel_explain(); -+ return -1; -+ } -+ -+ if (opt.target < 1000 || opt.interval < 1000) { -+ nssfq_codel_explain_err1(); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSCODEL_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssfq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSCODEL_MAX + 1]; -+ struct tc_nsscodel_qopt *qopt; -+ SPRINT_BUF(b1); -+ SPRINT_BUF(b2); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSCODEL_MAX, opt); -+ -+ if (tb[TCA_NSSCODEL_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSCODEL_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSCODEL_PARMS]); -+ -+ fprintf(f, "target %s limit %up interval %s flows %u quantum %u ", -+ sprint_time(qopt->target, b1), -+ qopt->limit, -+ sprint_time(qopt->interval, b2), -+ qopt->flows, -+ qopt->quantum); -+ -+ if (qopt->ecn) -+ fprintf(f, "ecn "); -+ -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nssfq_codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) -+{ -+ struct tc_nssfq_codel_xstats *st; -+ -+ if (xstats == NULL) -+ return 0; -+ -+ if (RTA_PAYLOAD(xstats) < sizeof(*st)) -+ return -1; -+ -+ st = RTA_DATA(xstats); -+ fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u\n", -+ st->maxpacket, st->drop_overlimit, st->new_flow_count, st->ecn_mark); -+ fprintf(f, " new_flows_len %u old_flows_len %u", st->new_flows_len, st->old_flows_len); -+ -+ return 0; -+} -+ -+struct qdisc_util nssfq_codel_qdisc_util = { -+ .id = "nssfq_codel", -+ .parse_qopt = nssfq_codel_parse_opt, -+ .print_qopt = nssfq_codel_print_opt, -+ .print_xstats = nssfq_codel_print_xstats, -+}; -+ -+/* ======================== NSSCODEL =======================*/ -+ -+static void nsscodel_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsscodel target TIME interval TIME [ limit PACKETS ] [ set_default ] [ accel_mode ]\n"); -+} -+ -+static void nsscodel_explain_err1(void) -+{ -+ fprintf(stderr, "Value of target and interval should be greater than 1ms\n"); -+} -+ -+static int nsscodel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct rtattr *tail; -+ struct tc_nsscodel_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "target") == 0) { -+ NEXT_ARG(); -+ if (get_time(&opt.target, *argv)) { -+ fprintf(stderr, "Illegal \"target\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "limit") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.limit, *argv) || opt.limit == 0) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "interval") == 0) { -+ NEXT_ARG(); -+ if (get_time(&opt.interval, *argv)) { -+ fprintf(stderr, "Illegal \"interval\"\n"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsscodel_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsscodel_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ if (!opt.target || !opt.interval) { -+ nsscodel_explain(); -+ return -1; -+ } -+ -+ if (opt.target < 1000 || opt.interval < 1000) { -+ nsscodel_explain_err1(); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSCODEL_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsscodel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSCODEL_MAX + 1]; -+ struct tc_nsscodel_qopt *qopt; -+ SPRINT_BUF(b1); -+ SPRINT_BUF(b2); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSCODEL_MAX, opt); -+ -+ if (tb[TCA_NSSCODEL_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSCODEL_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSCODEL_PARMS]); -+ -+ fprintf(f, "target %s limit %up interval %s ", -+ sprint_time(qopt->target, b1), -+ qopt->limit, -+ sprint_time(qopt->interval, b2)); -+ -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nsscodel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) -+{ -+ struct tc_nsscodel_xstats *st; -+ -+ if (xstats == NULL) -+ return 0; -+ -+ if (RTA_PAYLOAD(xstats) < sizeof(*st)) -+ return -1; -+ -+ st = RTA_DATA(xstats); -+ fprintf(f, " peak queue delay %ums peak drop delay %ums", -+ st->peak_queue_delay, st->peak_drop_delay); -+ -+ return 0; -+} -+ -+struct qdisc_util nsscodel_qdisc_util = { -+ .id = "nsscodel", -+ .parse_qopt = nsscodel_parse_opt, -+ .print_qopt = nsscodel_print_opt, -+ .print_xstats = nsscodel_print_xstats, -+}; -+ -+/* ======================== NSSTBL =======================*/ -+ -+static void nsstbl_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nsstbl burst BYTES rate BPS [ mtu BYTES ] [ accel_mode ]\n"); -+} -+ -+static int nsstbl_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nsstbl_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "burst") == 0 || -+ strcmp(*argv, "buffer") == 0 || -+ strcmp(*argv, "maxburst") == 0) { -+ NEXT_ARG(); -+ if (opt.burst) { -+ fprintf(stderr, "Double \"buffer/burst\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.burst, *argv)) { -+ fprintf(stderr, "Illegal \"burst\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "mtu") == 0 || -+ strcmp(*argv, "minburst") == 0) { -+ NEXT_ARG(); -+ if (opt.mtu) { -+ fprintf(stderr, "Double \"mtu/minburst\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.mtu, *argv)) { -+ fprintf(stderr, "Illegal \"mtu\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "rate") == 0) { -+ NEXT_ARG(); -+ if (opt.rate) { -+ fprintf(stderr, "Double \"rate\" spec\n"); -+ return -1; -+ } -+ if (get_rate(&opt.rate, *argv)) { -+ fprintf(stderr, "Illegal \"rate\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsstbl_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsstbl_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ nsstbl_explain(); -+ return -1; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ if (!opt.rate || !opt.burst) { -+ fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n"); -+ return -1; -+ } -+ -+ /* -+ * Peakrate is currently not supported, but we keep the infrastructure -+ * for future use. However, we have disabled taking input for this. -+ */ -+ if (opt.peakrate) { -+ if (!opt.mtu) { -+ fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n"); -+ return -1; -+ } -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSTBL_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsstbl_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSTBL_MAX + 1]; -+ struct tc_nsstbl_qopt *qopt; -+ SPRINT_BUF(b1); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSTBL_MAX, opt); -+ -+ if (tb[TCA_NSSTBL_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSTBL_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSTBL_PARMS]); -+ -+ fprintf(f, "buffer/maxburst %s ", sprint_size(qopt->burst, b1)); -+ fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); -+ fprintf(f, "mtu %s ", sprint_size(qopt->mtu, b1)); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nsstbl_qdisc_util = { -+ .id = "nsstbl", -+ .parse_qopt = nsstbl_parse_opt, -+ .print_qopt = nsstbl_print_opt, -+}; -+ -+/* ======================== NSSPRIO =======================*/ -+ -+static void nssprio_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nssprio [ bands NUMBER (default 256) ] [ accel_mode ]\n"); -+} -+ -+static int nssprio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nssprio_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "bands") == 0) { -+ NEXT_ARG(); -+ if (get_unsigned(&opt.bands, *argv, 0)) { -+ fprintf(stderr, "Illegal \"limit\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssprio_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssprio_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ opt.bands = TCA_NSSPRIO_MAX_BANDS; -+ } else if (opt.bands > TCA_NSSPRIO_MAX_BANDS) { -+ nssprio_explain(); -+ return -1; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSPRIO_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSPRIO_MAX + 1]; -+ struct tc_nssprio_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSPRIO_MAX, opt); -+ -+ if (tb[TCA_NSSPRIO_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSPRIO_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSPRIO_PARMS]); -+ -+ fprintf(f, "bands %u ", qopt->bands); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nssprio_qdisc_util = { -+ .id = "nssprio", -+ .parse_qopt = nssprio_parse_opt, -+ .print_qopt = nssprio_print_opt, -+}; -+ -+/* ======================== NSSBF =======================*/ -+ -+static void nssbf_explain_qdisc(void) -+{ -+ fprintf(stderr, -+ "Usage: ... nssbf [ accel_mode ]\n" -+ ); -+} -+ -+static void nssbf_explain_class(void) -+{ -+ fprintf(stderr, "Usage: ... nssbf rate BPS burst BYTES [ mtu BYTES ]\n"); -+ fprintf(stderr, " [ quantum BYTES ]\n"); -+} -+ -+static void nssbf_explain1(char *arg) -+{ -+ fprintf(stderr, "NSSBF: Illegal \"%s\"\n", arg); -+} -+ -+static int nssbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct tc_nssbf_qopt opt; -+ struct rtattr *tail; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (matches(*argv, "default") == 0) { -+ NEXT_ARG(); -+ if (opt.defcls != 0) { -+ fprintf(stderr, "NSSBF: Double \"default\"\n"); -+ return -1; -+ } -+ if (get_u16(&opt.defcls, *argv, 16) < 0) { -+ nssbf_explain1("default"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (matches(*argv, "help") == 0) { -+ nssbf_explain_qdisc(); -+ return -1; -+ } else { -+ fprintf(stderr, "NSSBF: What is \"%s\" ?\n", *argv); -+ nssbf_explain_qdisc(); -+ return -1; -+ } -+ argc--, argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_NSS_FW; -+ } else if (opt.accel_mode != TCA_NSS_ACCEL_MODE_NSS_FW) { -+ fprintf(stderr, "accel_mode should be %d\n", TCA_NSS_ACCEL_MODE_NSS_FW); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSBF_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSBF_MAX + 1]; -+ struct tc_nssbf_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSBF_MAX, opt); -+ -+ if (tb[TCA_NSSBF_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSBF_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSBF_QDISC_PARMS]); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nssbf_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nssbf_class_qopt opt; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "burst") == 0 || -+ strcmp(*argv, "buffer") == 0 || -+ strcmp(*argv, "maxburst") == 0) { -+ NEXT_ARG(); -+ if (opt.burst) { -+ fprintf(stderr, "Double \"buffer/burst\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.burst, *argv)) { -+ fprintf(stderr, "Illegal \"burst\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "mtu") == 0) { -+ NEXT_ARG(); -+ if (opt.mtu) { -+ fprintf(stderr, "Double \"mtu\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.mtu, *argv)) { -+ fprintf(stderr, "Illegal \"mtu\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (opt.quantum) { -+ fprintf(stderr, "Double \"quantum\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.quantum, *argv)) { -+ fprintf(stderr, "Illegal \"quantum\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "rate") == 0) { -+ NEXT_ARG(); -+ if (opt.rate) { -+ fprintf(stderr, "Double \"rate\" spec\n"); -+ return -1; -+ } -+ if (get_rate(&opt.rate, *argv)) { -+ fprintf(stderr, "Illegal \"rate\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssbf_explain_class(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssbf_explain_class(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ nssbf_explain_class(); -+ return -1; -+ } -+ -+ if (!opt.rate || !opt.burst) { -+ fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n"); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSBF_CLASS_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssbf_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSBF_MAX + 1]; -+ struct tc_nssbf_class_qopt *qopt; -+ SPRINT_BUF(b1); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSBF_MAX, opt); -+ -+ if (tb[TCA_NSSBF_CLASS_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSBF_CLASS_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSBF_CLASS_PARMS]); -+ -+ fprintf(f, "burst %s ", sprint_size(qopt->burst, b1)); -+ fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); -+ fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); -+ fprintf(f, "mtu %s ", sprint_size(qopt->mtu, b1)); -+ -+ return 0; -+} -+ -+struct qdisc_util nssbf_qdisc_util = { -+ .id = "nssbf", -+ .parse_qopt = nssbf_parse_opt, -+ .print_qopt = nssbf_print_opt, -+ .parse_copt = nssbf_parse_class_opt, -+ .print_copt = nssbf_print_class_opt, -+}; -+ -+/* ======================== NSSWRR =======================*/ -+ -+static void nsswrr_explain_qdisc(void) -+{ -+ fprintf(stderr, "Usage (qdisc): ... nsswrr [ accel_mode ]\n"); -+} -+ -+static void nsswrr_explain_class(void) -+{ -+ fprintf(stderr, "Usage (class): ... nsswrr quantum PACKETS ]\n"); -+} -+ -+static int nsswrr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct tc_nsswrr_qopt opt; -+ bool accel_mode = false; -+ struct rtattr *tail; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (matches(*argv, "help") == 0) { -+ nsswrr_explain_qdisc(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\" ?\n", *argv); -+ nsswrr_explain_qdisc(); -+ return -1; -+ } -+ argc--, argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWRR_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswrr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWRR_MAX + 1]; -+ struct tc_nsswrr_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWRR_MAX, opt); -+ -+ if (tb[TCA_NSSWRR_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWRR_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWRR_QDISC_PARMS]); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nsswrr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nsswrr_class_qopt opt; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (get_u32(&opt.quantum, *argv, 10)) { -+ fprintf(stderr, "Illegal \"quantum\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsswrr_explain_class(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsswrr_explain_class(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ nsswrr_explain_class(); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWRR_CLASS_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswrr_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWRR_MAX + 1]; -+ struct tc_nsswrr_class_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWRR_MAX, opt); -+ -+ if (tb[TCA_NSSWRR_CLASS_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWRR_CLASS_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWRR_CLASS_PARMS]); -+ -+ fprintf(f, "quantum %up ", qopt->quantum); -+ return 0; -+} -+ -+struct qdisc_util nsswrr_qdisc_util = { -+ .id = "nsswrr", -+ .parse_qopt = nsswrr_parse_opt, -+ .print_qopt = nsswrr_print_opt, -+ .parse_copt = nsswrr_parse_class_opt, -+ .print_copt = nsswrr_print_class_opt, -+}; -+ -+/* ======================== NSSWFQ =======================*/ -+ -+static void nsswfq_explain_qdisc(void) -+{ -+ fprintf(stderr, "Usage (qdisc): ... nsswfq [ accel_mode ]\n"); -+} -+ -+static void nsswfq_explain_class(void) -+{ -+ fprintf(stderr, "Usage (class): ... nsswfq quantum BYTES ]\n"); -+} -+ -+static int nsswfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct tc_nsswfq_qopt opt; -+ bool accel_mode = false; -+ struct rtattr *tail; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (matches(*argv, "help") == 0) { -+ nsswfq_explain_qdisc(); -+ return -1; -+ } else { -+ fprintf(stderr, "NSSWFQ: What is \"%s\" ?\n", *argv); -+ nsswfq_explain_qdisc(); -+ return -1; -+ } -+ argc--, argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWFQ_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWFQ_MAX + 1]; -+ struct tc_nsswfq_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWFQ_MAX, opt); -+ -+ if (tb[TCA_NSSWFQ_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWFQ_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWFQ_QDISC_PARMS]); -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nsswfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nsswfq_class_qopt opt; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (get_size(&opt.quantum, *argv)) { -+ fprintf(stderr, "Illegal \"quantum\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsswfq_explain_class(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsswfq_explain_class(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ nsswfq_explain_class(); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSWFQ_CLASS_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsswfq_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSWFQ_MAX + 1]; -+ struct tc_nsswfq_class_qopt *qopt; -+ SPRINT_BUF(b1); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSWFQ_MAX, opt); -+ -+ if (tb[TCA_NSSWFQ_CLASS_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSWFQ_CLASS_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSWFQ_CLASS_PARMS]); -+ -+ fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); -+ -+ return 0; -+} -+ -+struct qdisc_util nsswfq_qdisc_util = { -+ .id = "nsswfq", -+ .parse_qopt = nsswfq_parse_opt, -+ .print_qopt = nsswfq_print_opt, -+ .parse_copt = nsswfq_parse_class_opt, -+ .print_copt = nsswfq_print_class_opt, -+}; -+ -+/* ======================== NSSHTB =======================*/ -+ -+static void nsshtb_explain_qdisc(void) -+{ -+ fprintf(stderr, -+ "Usage: ... nsshtb [ r2q ] [ accel_mode ]\n" -+ ); -+} -+ -+static void nsshtb_explain_class(void) -+{ -+ fprintf(stderr, "Usage: ... nsshtb priority 0-3 [ quantum BYTES ] [ rate BPS ] [ burst BYTES ] [crate BPS ] [ cburst BYTES ]\n"); -+ fprintf(stderr, " [ overhead BYTES ] \n"); -+} -+ -+static void nsshtb_explain1(char *arg) -+{ -+ fprintf(stderr, "NSSHTB: Illegal \"%s\"\n", arg); -+} -+ -+static int nsshtb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct tc_nsshtb_qopt opt; -+ struct rtattr *tail; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "r2q") == 0) { -+ NEXT_ARG(); -+ if (opt.r2q != 0) { -+ fprintf(stderr, "NSSHTB: Double \"r2q\"\n"); -+ return -1; -+ } -+ if (get_u32(&opt.r2q, *argv, 10) < 0) { -+ nsshtb_explain1("r2q"); -+ return -1; -+ } -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsshtb_explain_qdisc(); -+ return -1; -+ } else { -+ fprintf(stderr, "NSSHTB: What is \"%s\" ?\n", *argv); -+ nsshtb_explain_qdisc(); -+ return -1; -+ } -+ argc--, argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSHTB_QDISC_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsshtb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSHTB_MAX + 1]; -+ struct tc_nsshtb_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSHTB_MAX, opt); -+ -+ if (tb[TCA_NSSHTB_QDISC_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSHTB_QDISC_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSHTB_QDISC_PARMS]); -+ -+ if (qopt->r2q != 0) -+ fprintf(f, "r2q %u ", qopt->r2q); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+static int nsshtb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ int ok = 0; -+ struct rtattr *tail; -+ struct tc_nsshtb_class_qopt opt; -+ int crate = 0; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "burst") == 0) { -+ NEXT_ARG(); -+ if (opt.burst) { -+ fprintf(stderr, "Double \"burst\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.burst, *argv)) { -+ fprintf(stderr, "Illegal \"burst\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "rate") == 0) { -+ NEXT_ARG(); -+ if (opt.rate) { -+ fprintf(stderr, "Double \"rate\" spec\n"); -+ return -1; -+ } -+ if (get_rate(&opt.rate, *argv)) { -+ fprintf(stderr, "Illegal \"rate\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "cburst") == 0) { -+ NEXT_ARG(); -+ if (opt.cburst) { -+ fprintf(stderr, "Double \"cburst\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.cburst, *argv)) { -+ fprintf(stderr, "Illegal \"cburst\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "crate") == 0) { -+ NEXT_ARG(); -+ if (opt.crate) { -+ fprintf(stderr, "Double \"crate\" spec\n"); -+ return -1; -+ } -+ if (get_rate(&opt.crate, *argv)) { -+ fprintf(stderr, "Illegal \"crate\"\n"); -+ return -1; -+ } -+ crate++; -+ ok++; -+ } else if (strcmp(*argv, "priority") == 0) { -+ NEXT_ARG(); -+ if (opt.priority) { -+ fprintf(stderr, "Double \"priority\" spec\n"); -+ return -1; -+ } -+ if (get_u32(&opt.priority, *argv, 10) < 0) { -+ fprintf(stderr, "Illegal \"priority\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "quantum") == 0) { -+ NEXT_ARG(); -+ if (opt.quantum) { -+ fprintf(stderr, "Double \"quantum\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.quantum, *argv)) { -+ fprintf(stderr, "Illegal \"quantum\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "overhead") == 0) { -+ NEXT_ARG(); -+ if (opt.overhead) { -+ fprintf(stderr, "Double \"overhead\" spec\n"); -+ return -1; -+ } -+ if (get_size(&opt.overhead, *argv)) { -+ fprintf(stderr, "Illegal \"overhead\"\n"); -+ return -1; -+ } -+ ok++; -+ } else if (strcmp(*argv, "help") == 0) { -+ nsshtb_explain_class(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nsshtb_explain_class(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!ok) { -+ nsshtb_explain_class(); -+ return -1; -+ } -+ -+ if (opt.rate && !opt.burst) { -+ fprintf(stderr, "\"burst\" required if \"rate\" is specified.\n"); -+ return -1; -+ } -+ -+ if (!crate) { -+ fprintf(stderr, "\"crate\" is required.\n"); -+ return -1; -+ } -+ -+ if (opt.crate && !opt.cburst) { -+ fprintf(stderr, "\"cburst\" required if \"crate\" is non-zero.\n"); -+ return -1; -+ } -+ -+ if (opt.priority > 3) { -+ fprintf(stderr, "\"priority\" should be an integer between 0 and 3.\n"); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSHTB_CLASS_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nsshtb_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSHTB_MAX + 1]; -+ struct tc_nsshtb_class_qopt *qopt; -+ SPRINT_BUF(b1); -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSHTB_MAX, opt); -+ -+ if (tb[TCA_NSSHTB_CLASS_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSHTB_CLASS_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSHTB_CLASS_PARMS]); -+ -+ fprintf(f, "burst %s ", sprint_size(qopt->burst, b1)); -+ fprintf(f, "rate %s ", sprint_rate(qopt->rate, b1)); -+ fprintf(f, "cburst %s ", sprint_size(qopt->cburst, b1)); -+ fprintf(f, "crate %s ", sprint_rate(qopt->crate, b1)); -+ fprintf(f, "priority %u ", qopt->priority); -+ fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); -+ fprintf(f, "overhead %s ", sprint_size(qopt->overhead, b1)); -+ -+ return 0; -+} -+ -+struct qdisc_util nsshtb_qdisc_util = { -+ .id = "nsshtb", -+ .parse_qopt = nsshtb_parse_opt, -+ .print_qopt = nsshtb_print_opt, -+ .parse_copt = nsshtb_parse_class_opt, -+ .print_copt = nsshtb_print_class_opt, -+}; -+ -+/* ======================== NSSBLACKHOLE ======================= */ -+ -+static void nssblackhole_explain(void) -+{ -+ fprintf(stderr, "Usage: ... nssblackhole [ set_default ] [ accel_mode ]\n"); -+} -+ -+static int nssblackhole_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) -+{ -+ struct rtattr *tail; -+ struct tc_nssblackhole_qopt opt; -+ bool accel_mode = false; -+ -+ memset(&opt, 0, sizeof(opt)); -+ -+ while (argc > 0) { -+ if (strcmp(*argv, "set_default") == 0) { -+ opt.set_default = 1; -+ } else if (strcmp(*argv, "accel_mode") == 0) { -+ NEXT_ARG(); -+ if (get_u8(&opt.accel_mode, *argv, 0)) { -+ fprintf(stderr, "Illegal accel_mode value\n"); -+ return -1; -+ } -+ accel_mode = true; -+ } else if (strcmp(*argv, "help") == 0) { -+ nssblackhole_explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ nssblackhole_explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (!accel_mode) { -+ opt.accel_mode = TCA_NSS_ACCEL_MODE_PPE; -+ } else if (opt.accel_mode >= TCA_NSS_ACCEL_MODE_MAX) { -+ fprintf(stderr, "accel_mode should be < %d\n", TCA_NSS_ACCEL_MODE_MAX); -+ return -1; -+ } -+ -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); -+ addattr_l(n, 1024, TCA_NSSBLACKHOLE_PARMS, &opt, sizeof(opt)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ -+ return 0; -+} -+ -+static int nssblackhole_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) -+{ -+ struct rtattr *tb[TCA_NSSBLACKHOLE_MAX + 1]; -+ struct tc_nssblackhole_qopt *qopt; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_NSSBLACKHOLE_MAX, opt); -+ -+ if (tb[TCA_NSSBLACKHOLE_PARMS] == NULL) -+ return -1; -+ -+ if (RTA_PAYLOAD(tb[TCA_NSSBLACKHOLE_PARMS]) < sizeof(*qopt)) -+ return -1; -+ -+ qopt = RTA_DATA(tb[TCA_NSSBLACKHOLE_PARMS]); -+ -+ if (qopt->set_default) -+ fprintf(f, "set_default "); -+ -+ fprintf(f, "accel_mode %d ", qopt->accel_mode); -+ -+ return 0; -+} -+ -+struct qdisc_util nssblackhole_qdisc_util = { -+ .id = "nssblackhole", -+ .parse_qopt = nssblackhole_parse_opt, -+ .print_qopt = nssblackhole_print_opt, -+}; diff --git a/iproute2/patches/500-add-nssmirred.patch b/iproute2/patches/500-add-nssmirred.patch deleted file mode 100644 index 3ce6eab60..000000000 --- a/iproute2/patches/500-add-nssmirred.patch +++ /dev/null @@ -1,247 +0,0 @@ ---- /dev/null -+++ b/include/uapi/linux/tc_act/tc_nssmirred.h -@@ -0,0 +1,46 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2019, The Linux Foundation. All rights reserved. -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ ************************************************************************** -+ */ -+ -+#ifndef __LINUX_TC_NSS_MIR_H -+#define __LINUX_TC_NSS_MIR_H -+ -+#include -+#include -+ -+/* -+ * tc_nss_mirred -+ * Structure for nssmirred action. -+ */ -+struct tc_nss_mirred { -+ tc_gen; -+ __u32 from_ifindex; /* ifindex of the port to be redirected from */ -+ __u32 to_ifindex; /* ifindex of the port to be redirected to */ -+}; -+ -+/* -+ * Types of nssmirred action parameters. -+ */ -+enum { -+ TCA_NSS_MIRRED_UNSPEC, -+ TCA_NSS_MIRRED_TM, -+ TCA_NSS_MIRRED_PARMS, -+ __TCA_NSS_MIRRED_MAX -+}; -+#define TCA_NSS_MIRRED_MAX (__TCA_NSS_MIRRED_MAX - 1) -+ -+#endif /* __LINUX_TC_NSS_MIR_H */ ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -39,6 +39,7 @@ TCMODULES += q_drr.o - TCMODULES += q_qfq.o - TCMODULES += m_gact.o - TCMODULES += m_mirred.o -+TCMODULES += m_nssmirred.o - TCMODULES += m_nat.o - TCMODULES += m_pedit.o - TCMODULES += m_ife.o ---- /dev/null -+++ b/tc/m_nssmirred.c -@@ -0,0 +1,185 @@ -+/* -+ ************************************************************************** -+ * Copyright (c) 2019, The Linux Foundation. All rights reserved. -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ ************************************************************************** -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "utils.h" -+#include "tc_util.h" -+#include "tc_common.h" -+#include -+ -+/* -+ * explain() -+ * API to print the explaination of nssmirred action statement's -+ * elements. -+ */ -+static void explain(void) -+{ -+ fprintf(stderr, "Usage: nssmirred redirect \n"); -+ fprintf(stderr, "where: \n"); -+ fprintf(stderr, "\tTO_DEVICENAME is the devicename to redirect to\n"); -+ fprintf(stderr, "\tFROM_DEVICENAME is the devicename to redirect from\n"); -+} -+ -+/* -+ * usage() -+ * API to show the usage of the nssmirred action. -+ */ -+static void usage(void) -+{ -+ explain(); -+ exit(-1); -+} -+ -+/* -+ * parse_nss_mirred() -+ * Parse and validate the nssmirred action statement. -+ */ -+static int parse_nss_mirred(struct action_util *a, int *argc_p, char ***argv_p, -+ int tca_id, struct nlmsghdr *n) -+{ -+ int idx, argc = *argc_p; -+ char **argv = *argv_p; -+ struct tc_nss_mirred p; -+ struct rtattr *tail; -+ -+ if (argc < 0) { -+ fprintf(stderr, "nssmirred bad argument count %d. Try option \"help\"\n", argc); -+ goto error; -+ } -+ -+ if (matches(*argv, "nssmirred")) { -+ fprintf(stderr, "nssmirred bad argument %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if (!matches(*argv, "help")) { -+ usage(); -+ } -+ -+ if (matches(*argv, "redirect")) { -+ fprintf(stderr, "nssmirred bad argument %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if (matches(*argv, "dev")) { -+ fprintf(stderr, "nssmirred: bad value %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ memset(&p, 0, sizeof(struct tc_nss_mirred)); -+ if ((idx = ll_name_to_index(*argv)) == 0) { -+ fprintf(stderr, "Cannot find to device \"%s\"\n", *argv); -+ goto error; -+ } -+ -+ p.to_ifindex = idx; -+ NEXT_ARG(); -+ if (matches(*argv, "fromdev")) { -+ fprintf(stderr, "nssmirred: bad value %s. Try option \"help\"\n", *argv); -+ goto error; -+ } -+ -+ NEXT_ARG(); -+ if ((idx = ll_name_to_index(*argv)) == 0) { -+ fprintf(stderr, "Cannot find from device \"%s\"\n", *argv); -+ goto error; -+ } -+ -+ p.from_ifindex = idx; -+ p.action = TC_ACT_STOLEN; -+ tail = NLMSG_TAIL(n); -+ addattr_l(n, MAX_MSG, tca_id, NULL, 0); -+ addattr_l(n, MAX_MSG, TCA_NSS_MIRRED_PARMS, &p, sizeof (p)); -+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; -+ argc--; -+ argv++; -+ *argc_p = argc; -+ *argv_p = argv; -+ return 0; -+ -+error: -+ return -1; -+} -+ -+/* -+ * print_nss_mirred() -+ * Print information related to nssmirred action. -+ */ -+static int print_nss_mirred(struct action_util *au, FILE * f, struct rtattr *arg) -+{ -+ struct tc_nss_mirred *p; -+ struct rtattr *tb[TCA_NSS_MIRRED_MAX + 1]; -+ const char *from_dev, *to_dev; -+ -+ if (arg == NULL) { -+ return -1; -+ } -+ -+ parse_rtattr_nested(tb, TCA_NSS_MIRRED_MAX, arg); -+ -+ if (tb[TCA_NSS_MIRRED_PARMS] == NULL) { -+ fprintf(f, "[NULL nssmirred parameters]"); -+ goto error; -+ } -+ -+ p = RTA_DATA(tb[TCA_NSS_MIRRED_PARMS]); -+ if ((from_dev = ll_index_to_name(p->from_ifindex)) == 0) { -+ fprintf(stderr, "Invalid interface (index: %d)\n", p->from_ifindex); -+ goto error; -+ } -+ -+ if ((to_dev = ll_index_to_name(p->to_ifindex)) == 0) { -+ fprintf(stderr, "Invalid interface (index: %d)\n", p->to_ifindex); -+ goto error; -+ } -+ -+ fprintf(f, "nssmirred (%s to device %s) stolen\n", from_dev, to_dev); -+ fprintf(f, "\tindex %d ref %d bind %d\n",p->index,p->refcnt,p->bindcnt); -+ -+ if (show_stats) { -+ if (tb[TCA_NSS_MIRRED_TM]) { -+ struct tcf_t *tm = RTA_DATA(tb[TCA_NSS_MIRRED_TM]); -+ print_tm(f,tm); -+ } -+ } -+ return 0; -+ -+error: -+ return -1; -+} -+ -+/* -+ * nssmirred_action_util -+ * nssmirred action utility structure. -+ */ -+struct action_util nssmirred_action_util = { -+ .id = "nssmirred", -+ .parse_aopt = parse_nss_mirred, -+ .print_aopt = print_nss_mirred, -+};