From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id DDB22A0487 for ; Mon, 1 Jul 2019 06:36:40 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2CF4231FC; Mon, 1 Jul 2019 06:36:39 +0200 (CEST) Received: from EUR02-VE1-obe.outbound.protection.outlook.com (mail-eopbgr20053.outbound.protection.outlook.com [40.107.2.53]) by dpdk.org (Postfix) with ESMTP id 407BD3195 for ; Mon, 1 Jul 2019 06:36:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bOcqL95vMHzYoDZ5BNZt/HHQV43CBN7rm8lxcLnVqGs=; b=bzDYbrHOUaJ8eLrvtArn62zRHnhQKn3Mbm9J0cuqK0d33o8Mkk6oB0K86OPQCS1g0WDHFByDnbbAdb2zw6q0VMDQqYiA7HPYhV0l6Ntf/aoeauekwHs/20yme4QvoUGNti1gOOtysQ0A397zBbM3WUftMzk1f4+zKxdRwKjXkFA= Received: from AM4PR05MB3265.eurprd05.prod.outlook.com (10.171.188.154) by AM4PR05MB3460.eurprd05.prod.outlook.com (10.171.187.153) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2032.20; Mon, 1 Jul 2019 04:36:29 +0000 Received: from AM4PR05MB3265.eurprd05.prod.outlook.com ([fe80::1442:fc4d:41ad:29d2]) by AM4PR05MB3265.eurprd05.prod.outlook.com ([fe80::1442:fc4d:41ad:29d2%5]) with mapi id 15.20.2032.019; Mon, 1 Jul 2019 04:36:29 +0000 From: Slava Ovsiienko To: Raslan Darawsheh CC: "dev@dpdk.org" , Moti Haimovsky Thread-Topic: [dpdk-dev] [PATCH v4 2/2] net/mlx5: remove TCF support from PMD Thread-Index: AQHVJcdGwNg267a/yUyy4M7ZJhJR0Ka1QK4w Date: Mon, 1 Jul 2019 04:36:29 +0000 Message-ID: References: <1560856539-16521-3-git-send-email-motih@mellanox.com> In-Reply-To: <1560856539-16521-3-git-send-email-motih@mellanox.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=viacheslavo@mellanox.com; x-originating-ip: [95.67.35.250] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 1b06d26e-2205-4c1f-b620-08d6fdddaf85 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600148)(711020)(4605104)(1401327)(4618075)(2017052603328)(7193020); SRVR:AM4PR05MB3460; x-ms-traffictypediagnostic: AM4PR05MB3460: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:91; x-forefront-prvs: 00851CA28B x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(4636009)(366004)(136003)(376002)(346002)(396003)(39860400002)(189003)(199004)(52314003)(13464003)(186003)(229853002)(26005)(5660300002)(99286004)(30864003)(102836004)(7696005)(76176011)(33656002)(5024004)(14444005)(256004)(6506007)(53546011)(9686003)(74316002)(6436002)(2906002)(478600001)(107886003)(86362001)(68736007)(8936002)(4326008)(7736002)(305945005)(3846002)(6116002)(8676002)(6862004)(53936002)(55016002)(25786009)(6246003)(316002)(6636002)(81166006)(81156014)(53946003)(66446008)(66556008)(66476007)(66946007)(64756008)(446003)(66066001)(71200400001)(71190400001)(14454004)(76116006)(11346002)(476003)(73956011)(54906003)(486006)(52536014)(21314003)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:AM4PR05MB3460; H:AM4PR05MB3265.eurprd05.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: mellanox.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: l1P2YQwGiLAZQBcAOk3JJcS0K/k33SWBiMVVPz5BRaqQIMOVLqw86+HQ97W4hDmwSahQ0/x1YlzNnlxON0FEKnoE28jO7Lbw2/GDbX3hOhTAXw6p9KtBKRE7kT4SNsFP1xTDpLF2Z7DKmgebTSHGgBBTyOX2sRj7OWXkRc6V+yzhV71EIiLRpwxL6iqST2HPfZMTWQpvu43MYx6I1ARFDuPrJR5YPfD2nYDpg7YCkxTMp0poibKSsP/ePmBz3jGAX1tkmhkBqpfh9KkkXIg35YcFcv/tiKgCun/SHq2caBKwS1vgMjB9QmI6iQYX6eivquuHLp0guojkQp7iFBP/+eTG2gTU41B56cDLdErfIqwub5vnbOj2kgNTqlevqp0z/Y+VLndYYLTccc63GiLBLXEJLoVl12ToL2D0+OhruR0= Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1b06d26e-2205-4c1f-b620-08d6fdddaf85 X-MS-Exchange-CrossTenant-originalarrivaltime: 01 Jul 2019 04:36:29.1061 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: viacheslavo@mellanox.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM4PR05MB3460 Subject: Re: [dpdk-dev] [PATCH v4 2/2] net/mlx5: remove TCF support from PMD X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Acked-by: Viacheslav Ovsiienko Thanks > -----Original Message----- > From: dev On Behalf Of Moti Haimovsky > Sent: Tuesday, June 18, 2019 14:16 > To: Shahaf Shuler > Cc: dev@dpdk.org; Moti Haimovsky > Subject: [dpdk-dev] [PATCH v4 2/2] net/mlx5: remove TCF support from PMD >=20 > This commit removes the support of configuring the device E-switch > using TCF since it is now possible to configure it via DR (direct > verbs rules), and by that to also remove the PMD dependency in libmnl. >=20 > Signed-off-by: Moti Haimovsky >-- > v4: > * Resend the message from a server not inserting DOS line-termination > symbols. >=20 > v3: > * Modified patch subject. >=20 > v2: > * Fixed checkpatch warnings. > --- > doc/build-sdk-meson.txt | 2 +- > doc/guides/nics/mlx5.rst | 19 - > doc/guides/platform/bluefield.rst | 4 - > drivers/net/mlx5/Makefile | 303 -- > drivers/net/mlx5/meson.build | 123 +- > drivers/net/mlx5/mlx5.c | 32 - > drivers/net/mlx5/mlx5.h | 3 - > drivers/net/mlx5/mlx5_flow.c | 14 +- > drivers/net/mlx5/mlx5_flow.h | 25 - > drivers/net/mlx5/mlx5_flow_tcf.c | 6382 -------------------------------= ------ > mk/rte.app.mk | 2 +- > 11 files changed, 9 insertions(+), 6900 deletions(-) > delete mode 100644 drivers/net/mlx5/mlx5_flow_tcf.c >=20 > diff --git a/doc/build-sdk-meson.txt b/doc/build-sdk-meson.txt > index 7b80244..981f88e 100644 > --- a/doc/build-sdk-meson.txt > +++ b/doc/build-sdk-meson.txt > @@ -207,5 +207,5 @@ From examples/helloworld/Makefile:: > NOTE: for --static builds, DPDK needs to be built with Meson >=3D 0.46 i= n order > to > fully generate the list of private dependencies. If DPDK is built with a= n older > version of Meson, it might be necessary to manually specify dependencies= of > DPDK > -PMDs/libraries, for example -lmlx5 -lmnl for librte-pmd-mlx5, or the sta= tic > link > +PMDs/libraries, for example -lmlx5 for librte-pmd-mlx5, or the static li= nk > step might fail. > diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst > index 5176aa8..1311863 100644 > --- a/doc/guides/nics/mlx5.rst > +++ b/doc/guides/nics/mlx5.rst > @@ -544,12 +544,6 @@ DPDK and must be installed separately: > This library basically implements send/receive calls to the hardware > queues. >=20 > -- **libmnl** > - > - Minimalistic Netlink library mainly relied on to manage E-Switch flow > - rules (i.e. those with the "transfer" attribute and typically involvin= g > - port representors). > - > - **Kernel modules** >=20 > They provide the kernel-side Verbs API and low level device drivers th= at > @@ -645,19 +639,6 @@ required from that distribution. > this DPDK release was developed and tested against is strongly > recommended. Please check the `prerequisites`_. >=20 > -Libmnl > -^^^^^^ > - > -Minimal version for libmnl is **1.0.3**. > - > -As a dependency of the **iproute2** suite, this library is often install= ed > -by default. It is otherwise readily available through standard system > -packages. > - > -Its development headers must be installed in order to compile this PMD. > -These packages are usually named **libmnl-dev** or **libmnl-devel** > -depending on the Linux distribution. > - > Supported NICs > -------------- >=20 > diff --git a/doc/guides/platform/bluefield.rst > b/doc/guides/platform/bluefield.rst > index 894db2c..deda675 100644 > --- a/doc/guides/platform/bluefield.rst > +++ b/doc/guides/platform/bluefield.rst > @@ -84,7 +84,6 @@ toolchain for ARM64. Base on that, additional header > files and libraries are > required: >=20 > - libibverbs > - - libmnl > - libmlx5 > - libnl-3 > - libnl-route-3 > @@ -105,19 +104,16 @@ tarball for the cross toolchain. > # Copy libraries > mkdir -p lib64 > cp -a /lib64/libibverbs* lib64/ > - cp -a /lib64/libmnl* lib64/ > cp -a /lib64/libmlx5* lib64/ > cp -a /lib64/libnl-3* lib64/ > cp -a /lib64/libnl-route-3* lib64/ >=20 > # Copy header files > mkdir -p usr/include/infiniband > - mkdir -p usr/include/libmnl > cp -a /usr/include/infiniband/ib_user_ioctl_verbs.h > usr/include/infiniband/ > cp -a /usr/include/infiniband/mlx5*.h usr/include/infiniband/ > cp -a /usr/include/infiniband/tm_types.h usr/include/infiniband/ > cp -a /usr/include/infiniband/verbs*.h usr/include/infiniband/ > - cp -a /usr/include/libmnl/libmnl.h usr/include/libmnl/ >=20 > # Create supplementary tarball > popd > diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile > index 2694916..619e6b6 100644 > --- a/drivers/net/mlx5/Makefile > +++ b/drivers/net/mlx5/Makefile > @@ -32,7 +32,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D > mlx5_rss.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_mr.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_flow.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_flow_dv.c > -SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_flow_tcf.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_flow_verbs.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_mp.c > SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D mlx5_nl.c > @@ -52,7 +51,6 @@ CFLAGS +=3D -D_DEFAULT_SOURCE > CFLAGS +=3D -D_XOPEN_SOURCE=3D600 > CFLAGS +=3D $(WERROR_FLAGS) > CFLAGS +=3D -Wno-strict-prototypes > -CFLAGS +=3D $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config= -- > cflags libmnl) > ifeq ($(CONFIG_RTE_IBVERBS_LINK_DLOPEN),y) > CFLAGS +=3D -DMLX5_GLUE=3D'"$(LIB_GLUE)"' > CFLAGS +=3D -DMLX5_GLUE_VERSION=3D'"$(LIB_GLUE_VERSION)"' > @@ -63,7 +61,6 @@ LDLIBS +=3D $(shell $(RTE_SDK)/buildtools/options- > ibverbs-static.sh) > else > LDLIBS +=3D -libverbs -lmlx5 > endif > -LDLIBS +=3D $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config= -- > libs libmnl || echo "-lmnl") > LDLIBS +=3D -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring > LDLIBS +=3D -lrte_ethdev -lrte_net -lrte_kvargs > LDLIBS +=3D -lrte_bus_pci > @@ -256,306 +253,6 @@ mlx5_autoconf.h.new: > $(RTE_SDK)/buildtools/auto-config-h.sh > enum IFLA_PHYS_PORT_NAME \ > $(AUTOCONF_OUTPUT) > $Q sh -- '$<' '$@' \ > - HAVE_IFLA_VXLAN_COLLECT_METADATA \ > - linux/if_link.h \ > - enum IFLA_VXLAN_COLLECT_METADATA \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_CHAIN \ > - linux/rtnetlink.h \ > - enum TCA_CHAIN \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_ACT \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_ACT \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_FLAGS \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_FLAGS \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ETH_TYPE \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ETH_TYPE \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ETH_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ETH_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ETH_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ETH_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ETH_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ETH_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ETH_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IP_PROTO \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IP_PROTO \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV4_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV4_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV4_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV4_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV4_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV4_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV6_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV6_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV6_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV6_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV6_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IPV6_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_UDP_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_UDP_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_UDP_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_UDP_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_UDP_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_UDP_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_UDP_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_VLAN_ID \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_VLAN_ID \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_VLAN_PRIO \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_VLAN_PRIO \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_VLAN_ETH_TYPE \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_FLAGS \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_FLAGS \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_TCP_FLAGS_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IP_TOS \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IP_TOS \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IP_TOS_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IP_TOS_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IP_TTL \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IP_TTL \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_IP_TTL_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_IP_TTL_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TC_ACT_GOTO_CHAIN \ > - linux/pkt_cls.h \ > - define TC_ACT_GOTO_CHAIN \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TC_ACT_VLAN \ > - linux/tc_act/tc_vlan.h \ > - enum TCA_VLAN_PUSH_VLAN_PRIORITY \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_KEY_ID \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_KEY_ID \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV4_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV4_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV4_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV6_SRC \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV6_DST \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IPV6_DST_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_UDP_SRC_PORT \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_UDP_DST_PORT \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IP_TOS \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IP_TOS \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IP_TOS_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IP_TOS_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IP_TTL \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IP_TTL \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_FLOWER_KEY_ENC_IP_TTL_MASK \ > - linux/pkt_cls.h \ > - enum TCA_FLOWER_KEY_ENC_IP_TTL_MASK \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TC_ACT_TUNNEL_KEY \ > - linux/tc_act/tc_tunnel_key.h \ > - define TCA_ACT_TUNNEL_KEY \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_TUNNEL_KEY_ENC_DST_PORT \ > - linux/tc_act/tc_tunnel_key.h \ > - enum TCA_TUNNEL_KEY_ENC_DST_PORT \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_TUNNEL_KEY_ENC_TOS \ > - linux/tc_act/tc_tunnel_key.h \ > - enum TCA_TUNNEL_KEY_ENC_TOS \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_TUNNEL_KEY_ENC_TTL \ > - linux/tc_act/tc_tunnel_key.h \ > - enum TCA_TUNNEL_KEY_ENC_TTL \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TCA_TUNNEL_KEY_NO_CSUM \ > - linux/tc_act/tc_tunnel_key.h \ > - enum TCA_TUNNEL_KEY_NO_CSUM \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > - HAVE_TC_ACT_PEDIT \ > - linux/tc_act/tc_pedit.h \ > - enum TCA_PEDIT_KEY_EX_HDR_TYPE_UDP \ > - $(AUTOCONF_OUTPUT) > - $Q sh -- '$<' '$@' \ > HAVE_SUPPORTED_40000baseKR4_Full \ > /usr/include/linux/ethtool.h \ > define SUPPORTED_40000baseKR4_Full \ > diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build > index ac3b529..4dc5ddd 100644 > --- a/drivers/net/mlx5/meson.build > +++ b/drivers/net/mlx5/meson.build > @@ -13,7 +13,7 @@ if pmd_dlopen > '- > DMLX5_GLUE_VERSION=3D"@0@"'.format(LIB_GLUE_VERSION), > ] > endif > -libnames =3D [ 'mnl', 'mlx5', 'ibverbs' ] > +libnames =3D [ 'mlx5', 'ibverbs' ] > libs =3D [] > build =3D true > foreach libname:libnames > @@ -35,7 +35,6 @@ if build > 'mlx5_ethdev.c', > 'mlx5_flow.c', > 'mlx5_flow_dv.c', > - 'mlx5_flow_tcf.c', > 'mlx5_flow_verbs.c', > 'mlx5_mac.c', > 'mlx5_mr.c', > @@ -148,126 +147,6 @@ if build > 'IFLA_PHYS_SWITCH_ID' ], > [ 'HAVE_IFLA_PHYS_PORT_NAME', 'linux/if_link.h', > 'IFLA_PHYS_PORT_NAME' ], > - [ 'HAVE_IFLA_VXLAN_COLLECT_METADATA', 'linux/if_link.h', > - 'IFLA_VXLAN_COLLECT_METADATA' ], > - [ 'HAVE_TCA_CHAIN', 'linux/rtnetlink.h', > - 'TCA_CHAIN' ], > - [ 'HAVE_TCA_FLOWER_ACT', 'linux/pkt_cls.h', > - 'TCA_FLOWER_ACT' ], > - [ 'HAVE_TCA_FLOWER_FLAGS', 'linux/pkt_cls.h', > - 'TCA_FLOWER_FLAGS' ], > - [ 'HAVE_TCA_FLOWER_KEY_ETH_TYPE', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ETH_TYPE' ], > - [ 'HAVE_TCA_FLOWER_KEY_ETH_DST', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ETH_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_ETH_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ETH_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ETH_SRC', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ETH_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ETH_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IP_PROTO', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IP_PROTO' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV4_SRC', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV4_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV4_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV4_DST', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV4_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV4_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV6_SRC', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV6_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV6_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV6_DST', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV6_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IPV6_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_SRC', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_DST', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_UDP_SRC', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_UDP_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_UDP_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_UDP_DST', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_UDP_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_UDP_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_UDP_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_VLAN_ID', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_VLAN_ID' ], > - [ 'HAVE_TCA_FLOWER_KEY_VLAN_PRIO', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_VLAN_PRIO' ], > - [ 'HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_VLAN_ETH_TYPE' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_FLAGS' ], > - [ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_TCP_FLAGS_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IP_TOS', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IP_TOS' ], > - [ 'HAVE_TCA_FLOWER_KEY_IP_TOS_MASK', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IP_TOS_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_IP_TTL', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IP_TTL' ], > - [ 'HAVE_TCA_FLOWER_KEY_IP_TTL_MASK', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_IP_TTL_MASK' ], > - [ 'HAVE_TC_ACT_GOTO_CHAIN', 'linux/pkt_cls.h', > - 'TC_ACT_GOTO_CHAIN' ], > - [ 'HAVE_TC_ACT_VLAN', 'linux/tc_act/tc_vlan.h', > - 'TCA_VLAN_PUSH_VLAN_PRIORITY' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_KEY_ID', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_KEY_ID' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV4_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV4_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV4_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV6_SRC' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV6_DST' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IPV6_DST_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_UDP_SRC_PORT' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_UDP_DST_PORT' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IP_TOS', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IP_TOS' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IP_TOS_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IP_TOS_MASK' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IP_TTL', 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IP_TTL' ], > - [ 'HAVE_TCA_FLOWER_KEY_ENC_IP_TTL_MASK', > 'linux/pkt_cls.h', > - 'TCA_FLOWER_KEY_ENC_IP_TTL_MASK' ], > - [ 'HAVE_TC_ACT_TUNNEL_KEY', > 'linux/tc_act/tc_tunnel_key.h', > - 'TCA_ACT_TUNNEL_KEY' ], > - [ 'HAVE_TCA_TUNNEL_KEY_ENC_DST_PORT', > 'linux/tc_act/tc_tunnel_key.h', > - 'TCA_TUNNEL_KEY_ENC_DST_PORT' ], > - [ 'HAVE_TCA_TUNNEL_KEY_ENC_TOS', > 'linux/tc_act/tc_tunnel_key.h', > - 'TCA_TUNNEL_KEY_ENC_TOS' ], > - [ 'HAVE_TCA_TUNNEL_KEY_ENC_TTL', > 'linux/tc_act/tc_tunnel_key.h', > - 'TCA_TUNNEL_KEY_ENC_TTL' ], > - [ 'HAVE_TCA_TUNNEL_KEY_NO_CSUM', > 'linux/tc_act/tc_tunnel_key.h', > - 'TCA_TUNNEL_KEY_NO_CSUM' ], > - [ 'HAVE_TC_ACT_PEDIT', 'linux/tc_act/tc_pedit.h', > - 'TCA_PEDIT_KEY_EX_HDR_TYPE_UDP' ], > [ 'HAVE_RDMA_NL_NLDEV', 'rdma/rdma_netlink.h', > 'RDMA_NL_NLDEV' ], > [ 'HAVE_RDMA_NLDEV_CMD_GET', 'rdma/rdma_netlink.h', > diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c > index e074047..bfce591 100644 > --- a/drivers/net/mlx5/mlx5.c > +++ b/drivers/net/mlx5/mlx5.c > @@ -687,8 +687,6 @@ struct mlx5_dev_spawn_data { > close(priv->nl_socket_route); > if (priv->nl_socket_rdma >=3D 0) > close(priv->nl_socket_rdma); > - if (priv->tcf_context) > - mlx5_flow_tcf_context_destroy(priv->tcf_context); > if (priv->sh) { > /* > * Free the shared context in last turn, because the cleanup > @@ -1493,34 +1491,6 @@ struct mlx5_dev_spawn_data { > claim_zero(mlx5_mac_addr_add(eth_dev, &mac, 0, 0)); > if (config.vf && config.vf_nl_en) > mlx5_nl_mac_addr_sync(eth_dev); > - priv->tcf_context =3D mlx5_flow_tcf_context_create(); > - if (!priv->tcf_context) { > - err =3D -rte_errno; > - DRV_LOG(WARNING, > - "flow rules relying on switch offloads will not be" > - " supported: cannot open libmnl socket: %s", > - strerror(rte_errno)); > - } else { > - struct rte_flow_error error; > - unsigned int ifindex =3D mlx5_ifindex(eth_dev); > - > - if (!ifindex) { > - err =3D -rte_errno; > - error.message =3D > - "cannot retrieve network interface index"; > - } else { > - err =3D mlx5_flow_tcf_init(priv->tcf_context, > - ifindex, &error); > - } > - if (err) { > - DRV_LOG(WARNING, > - "flow rules relying on switch offloads will" > - " not be supported: %s: %s", > - error.message, strerror(rte_errno)); > - mlx5_flow_tcf_context_destroy(priv->tcf_context); > - priv->tcf_context =3D NULL; > - } > - } > TAILQ_INIT(&priv->flows); > TAILQ_INIT(&priv->ctrl_flows); > /* Hint libmlx5 to use PMD allocator for data plane resources */ > @@ -1586,8 +1556,6 @@ struct mlx5_dev_spawn_data { > close(priv->nl_socket_route); > if (priv->nl_socket_rdma >=3D 0) > close(priv->nl_socket_rdma); > - if (priv->tcf_context) > - mlx5_flow_tcf_context_destroy(priv->tcf_context); > if (own_domain_id) > claim_zero(rte_eth_switch_domain_free(priv- > >domain_id)); > rte_free(priv); > diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h > index 0abce90..4e38611 100644 > --- a/drivers/net/mlx5/mlx5.h > +++ b/drivers/net/mlx5/mlx5.h > @@ -237,8 +237,6 @@ struct mlx5_drop { > struct mlx5_rxq_ibv *rxq; /* Verbs Rx queue. */ > }; >=20 > -struct mlx5_flow_tcf_context; > - > /* Per port data of shared IB device. */ > struct mlx5_ibv_shared_port { > uint32_t ih_port_id; > @@ -382,7 +380,6 @@ struct mlx5_priv { > rte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX]; > /* UAR same-page access control required in 32bit implementations. > */ > #endif > - struct mlx5_flow_tcf_context *tcf_context; /* TC flower context. */ > }; >=20 > #define PORT_ID(priv) ((priv)->dev_data->port_id) > diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c > index e5a8e33..2f45225 100644 > --- a/drivers/net/mlx5/mlx5_flow.c > +++ b/drivers/net/mlx5/mlx5_flow.c > @@ -42,7 +42,6 @@ > #ifdef HAVE_IBV_FLOW_DV_SUPPORT > extern const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops; > #endif > -extern const struct mlx5_flow_driver_ops mlx5_flow_tcf_drv_ops; > extern const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops; >=20 > const struct mlx5_flow_driver_ops mlx5_flow_null_drv_ops; > @@ -52,7 +51,6 @@ > #ifdef HAVE_IBV_FLOW_DV_SUPPORT > [MLX5_FLOW_TYPE_DV] =3D &mlx5_flow_dv_drv_ops, > #endif > - [MLX5_FLOW_TYPE_TCF] =3D &mlx5_flow_tcf_drv_ops, > [MLX5_FLOW_TYPE_VERBS] =3D &mlx5_flow_verbs_drv_ops, > [MLX5_FLOW_TYPE_MAX] =3D &mlx5_flow_null_drv_ops > }; > @@ -1037,7 +1035,7 @@ uint32_t mlx5_flow_adjust_priority(struct > rte_eth_dev *dev, int32_t priority, > return rte_flow_error_set(error, ENOTSUP, >=20 > RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL, > "egress is not supported"); > - if (attributes->transfer) > + if (attributes->transfer && !priv->config.dv_esw_en) > return rte_flow_error_set(error, ENOTSUP, >=20 > RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, > NULL, "transfer is not supported"); > @@ -1294,7 +1292,7 @@ uint32_t mlx5_flow_adjust_priority(struct > rte_eth_dev *dev, int32_t priority, > * @param[in] target_protocol > * The next protocol in the previous item. > * @param[in] flow_mask > - * mlx5 flow-specific (TCF, DV, verbs, etc.) supported header fields m= ask. > + * mlx5 flow-specific (DV, verbs, etc.) supported header fields mask. > * @param[out] error > * Pointer to error structure. > * > @@ -1784,9 +1782,9 @@ uint32_t mlx5_flow_adjust_priority(struct > rte_eth_dev *dev, int32_t priority, > struct mlx5_priv *priv =3D dev->data->dev_private; > enum mlx5_flow_drv_type type =3D MLX5_FLOW_TYPE_MAX; >=20 > - if (attr->transfer && !priv->config.dv_esw_en) > - type =3D MLX5_FLOW_TYPE_TCF; > - else > + if (attr->transfer && priv->config.dv_esw_en) > + type =3D MLX5_FLOW_TYPE_DV; > + if (!attr->transfer) > type =3D priv->config.dv_flow_en ? MLX5_FLOW_TYPE_DV : > MLX5_FLOW_TYPE_VERBS; > return type; > @@ -1833,7 +1831,7 @@ uint32_t mlx5_flow_adjust_priority(struct > rte_eth_dev *dev, int32_t priority, > * initializes the device flow and returns the pointer. > * > * @note > - * This function initializes device flow structure such as dv, tcf or = verbs in > + * This function initializes device flow structure such as dv or verbs= in > * struct mlx5_flow. However, it is caller's responsibility to initial= ize the > * rest. For example, adding returning device flow to flow->dev_flow l= ist > and > * setting backward reference to the flow should be done out of this > function. > diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h > index b665420..65cfdbd 100644 > --- a/drivers/net/mlx5/mlx5_flow.h > +++ b/drivers/net/mlx5/mlx5_flow.h > @@ -188,7 +188,6 @@ > enum mlx5_flow_drv_type { > MLX5_FLOW_TYPE_MIN, > MLX5_FLOW_TYPE_DV, > - MLX5_FLOW_TYPE_TCF, > MLX5_FLOW_TYPE_VERBS, > MLX5_FLOW_TYPE_MAX, > }; > @@ -309,22 +308,6 @@ struct mlx5_flow_dv { > int actions_n; /**< number of actions. */ > }; >=20 > -/** Linux TC flower driver for E-Switch flow. */ > -struct mlx5_flow_tcf { > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - uint32_t *ptc_flags; /**< tc rule applied flags. */ > - union { /**< Tunnel encap/decap descriptor. */ > - struct flow_tcf_tunnel_hdr *tunnel; > - struct flow_tcf_vxlan_decap *vxlan_decap; > - struct flow_tcf_vxlan_encap *vxlan_encap; > - }; > - uint32_t applied:1; /**< Whether rule is currently applied. */ > -#ifndef NDEBUG > - uint32_t nlsize; /**< Size of NL message buffer for debug check. */ > -#endif > -}; > - > /* Verbs specification header. */ > struct ibv_spec_header { > enum ibv_flow_spec_type type; > @@ -355,7 +338,6 @@ struct mlx5_flow { > #ifdef HAVE_IBV_FLOW_DV_SUPPORT > struct mlx5_flow_dv dv; > #endif > - struct mlx5_flow_tcf tcf; > struct mlx5_flow_verbs verbs; > }; > }; > @@ -513,11 +495,4 @@ int mlx5_flow_validate_item_vxlan_gpe(const > struct rte_flow_item *item, > struct rte_eth_dev *dev, > struct rte_flow_error *error); >=20 > -/* mlx5_flow_tcf.c */ > - > -int mlx5_flow_tcf_init(struct mlx5_flow_tcf_context *ctx, > - unsigned int ifindex, struct rte_flow_error *error); > -struct mlx5_flow_tcf_context *mlx5_flow_tcf_context_create(void); > -void mlx5_flow_tcf_context_destroy(struct mlx5_flow_tcf_context *ctx); > - > #endif /* RTE_PMD_MLX5_FLOW_H_ */ > diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c > b/drivers/net/mlx5/mlx5_flow_tcf.c > deleted file mode 100644 > index 223ee4f..0000000 > --- a/drivers/net/mlx5/mlx5_flow_tcf.c > +++ /dev/null > @@ -1,6382 +0,0 @@ > -/* SPDX-License-Identifier: BSD-3-Clause > - * Copyright 2018 6WIND S.A. > - * Copyright 2018 Mellanox Technologies, Ltd > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include "mlx5.h" > -#include "mlx5_flow.h" > -#include "mlx5_autoconf.h" > - > -#ifdef HAVE_TC_ACT_VLAN > - > -#include > - > -#else /* HAVE_TC_ACT_VLAN */ > - > -#define TCA_VLAN_ACT_POP 1 > -#define TCA_VLAN_ACT_PUSH 2 > -#define TCA_VLAN_ACT_MODIFY 3 > -#define TCA_VLAN_PARMS 2 > -#define TCA_VLAN_PUSH_VLAN_ID 3 > -#define TCA_VLAN_PUSH_VLAN_PROTOCOL 4 > -#define TCA_VLAN_PAD 5 > -#define TCA_VLAN_PUSH_VLAN_PRIORITY 6 > - > -struct tc_vlan { > - tc_gen; > - int v_action; > -}; > - > -#endif /* HAVE_TC_ACT_VLAN */ > - > -#ifdef HAVE_TC_ACT_PEDIT > - > -#include > - > -#else /* HAVE_TC_ACT_VLAN */ > - > -enum { > - TCA_PEDIT_UNSPEC, > - TCA_PEDIT_TM, > - TCA_PEDIT_PARMS, > - TCA_PEDIT_PAD, > - TCA_PEDIT_PARMS_EX, > - TCA_PEDIT_KEYS_EX, > - TCA_PEDIT_KEY_EX, > - __TCA_PEDIT_MAX > -}; > - > -enum { > - TCA_PEDIT_KEY_EX_HTYPE =3D 1, > - TCA_PEDIT_KEY_EX_CMD =3D 2, > - __TCA_PEDIT_KEY_EX_MAX > -}; > - > -enum pedit_header_type { > - TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK =3D 0, > - TCA_PEDIT_KEY_EX_HDR_TYPE_ETH =3D 1, > - TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 =3D 2, > - TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 =3D 3, > - TCA_PEDIT_KEY_EX_HDR_TYPE_TCP =3D 4, > - TCA_PEDIT_KEY_EX_HDR_TYPE_UDP =3D 5, > - __PEDIT_HDR_TYPE_MAX, > -}; > - > -enum pedit_cmd { > - TCA_PEDIT_KEY_EX_CMD_SET =3D 0, > - TCA_PEDIT_KEY_EX_CMD_ADD =3D 1, > - __PEDIT_CMD_MAX, > -}; > - > -struct tc_pedit_key { > - __u32 mask; /* AND */ > - __u32 val; /*XOR */ > - __u32 off; /*offset */ > - __u32 at; > - __u32 offmask; > - __u32 shift; > -}; > - > -__extension__ > -struct tc_pedit_sel { > - tc_gen; > - unsigned char nkeys; > - unsigned char flags; > - struct tc_pedit_key keys[0]; > -}; > - > -#endif /* HAVE_TC_ACT_VLAN */ > - > -#ifdef HAVE_TC_ACT_TUNNEL_KEY > - > -#include > - > -#ifndef HAVE_TCA_TUNNEL_KEY_ENC_DST_PORT > -#define TCA_TUNNEL_KEY_ENC_DST_PORT 9 > -#endif > - > -#ifndef HAVE_TCA_TUNNEL_KEY_NO_CSUM > -#define TCA_TUNNEL_KEY_NO_CSUM 10 > -#endif > - > -#ifndef HAVE_TCA_TUNNEL_KEY_ENC_TOS > -#define TCA_TUNNEL_KEY_ENC_TOS 12 > -#endif > - > -#ifndef HAVE_TCA_TUNNEL_KEY_ENC_TTL > -#define TCA_TUNNEL_KEY_ENC_TTL 13 > -#endif > - > -#else /* HAVE_TC_ACT_TUNNEL_KEY */ > - > -#define TCA_ACT_TUNNEL_KEY 17 > -#define TCA_TUNNEL_KEY_ACT_SET 1 > -#define TCA_TUNNEL_KEY_ACT_RELEASE 2 > -#define TCA_TUNNEL_KEY_PARMS 2 > -#define TCA_TUNNEL_KEY_ENC_IPV4_SRC 3 > -#define TCA_TUNNEL_KEY_ENC_IPV4_DST 4 > -#define TCA_TUNNEL_KEY_ENC_IPV6_SRC 5 > -#define TCA_TUNNEL_KEY_ENC_IPV6_DST 6 > -#define TCA_TUNNEL_KEY_ENC_KEY_ID 7 > -#define TCA_TUNNEL_KEY_ENC_DST_PORT 9 > -#define TCA_TUNNEL_KEY_NO_CSUM 10 > -#define TCA_TUNNEL_KEY_ENC_TOS 12 > -#define TCA_TUNNEL_KEY_ENC_TTL 13 > - > -struct tc_tunnel_key { > - tc_gen; > - int t_action; > -}; > - > -#endif /* HAVE_TC_ACT_TUNNEL_KEY */ > - > -/* Normally found in linux/netlink.h. */ > -#ifndef NETLINK_CAP_ACK > -#define NETLINK_CAP_ACK 10 > -#endif > - > -/* Normally found in linux/pkt_sched.h. */ > -#ifndef TC_H_MIN_INGRESS > -#define TC_H_MIN_INGRESS 0xfff2u > -#endif > - > -/* Normally found in linux/pkt_cls.h. */ > -#ifndef TCA_CLS_FLAGS_SKIP_SW > -#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) > -#endif > -#ifndef TCA_CLS_FLAGS_IN_HW > -#define TCA_CLS_FLAGS_IN_HW (1 << 2) > -#endif > -#ifndef HAVE_TCA_CHAIN > -#define TCA_CHAIN 11 > -#endif > -#ifndef HAVE_TCA_FLOWER_ACT > -#define TCA_FLOWER_ACT 3 > -#endif > -#ifndef HAVE_TCA_FLOWER_FLAGS > -#define TCA_FLOWER_FLAGS 22 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ETH_TYPE > -#define TCA_FLOWER_KEY_ETH_TYPE 8 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST > -#define TCA_FLOWER_KEY_ETH_DST 4 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST_MASK > -#define TCA_FLOWER_KEY_ETH_DST_MASK 5 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC > -#define TCA_FLOWER_KEY_ETH_SRC 6 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK > -#define TCA_FLOWER_KEY_ETH_SRC_MASK 7 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IP_PROTO > -#define TCA_FLOWER_KEY_IP_PROTO 9 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC > -#define TCA_FLOWER_KEY_IPV4_SRC 10 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK > -#define TCA_FLOWER_KEY_IPV4_SRC_MASK 11 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST > -#define TCA_FLOWER_KEY_IPV4_DST 12 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK > -#define TCA_FLOWER_KEY_IPV4_DST_MASK 13 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC > -#define TCA_FLOWER_KEY_IPV6_SRC 14 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK > -#define TCA_FLOWER_KEY_IPV6_SRC_MASK 15 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST > -#define TCA_FLOWER_KEY_IPV6_DST 16 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK > -#define TCA_FLOWER_KEY_IPV6_DST_MASK 17 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC > -#define TCA_FLOWER_KEY_TCP_SRC 18 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK > -#define TCA_FLOWER_KEY_TCP_SRC_MASK 35 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST > -#define TCA_FLOWER_KEY_TCP_DST 19 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST_MASK > -#define TCA_FLOWER_KEY_TCP_DST_MASK 36 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC > -#define TCA_FLOWER_KEY_UDP_SRC 20 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK > -#define TCA_FLOWER_KEY_UDP_SRC_MASK 37 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST > -#define TCA_FLOWER_KEY_UDP_DST 21 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST_MASK > -#define TCA_FLOWER_KEY_UDP_DST_MASK 38 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_VLAN_ID > -#define TCA_FLOWER_KEY_VLAN_ID 23 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_VLAN_PRIO > -#define TCA_FLOWER_KEY_VLAN_PRIO 24 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE > -#define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_KEY_ID > -#define TCA_FLOWER_KEY_ENC_KEY_ID 26 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC > -#define TCA_FLOWER_KEY_ENC_IPV4_SRC 27 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK > -#define TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK 28 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST > -#define TCA_FLOWER_KEY_ENC_IPV4_DST 29 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST_MASK > -#define TCA_FLOWER_KEY_ENC_IPV4_DST_MASK 30 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC > -#define TCA_FLOWER_KEY_ENC_IPV6_SRC 31 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK > -#define TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK 32 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST > -#define TCA_FLOWER_KEY_ENC_IPV6_DST 33 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST_MASK > -#define TCA_FLOWER_KEY_ENC_IPV6_DST_MASK 34 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT > -#define TCA_FLOWER_KEY_ENC_UDP_SRC_PORT 43 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK > -#define TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK 44 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT > -#define TCA_FLOWER_KEY_ENC_UDP_DST_PORT 45 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK > -#define TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK 46 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS > -#define TCA_FLOWER_KEY_TCP_FLAGS 71 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK > -#define TCA_FLOWER_KEY_TCP_FLAGS_MASK 72 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IP_TOS > -#define TCA_FLOWER_KEY_IP_TOS 73 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IP_TOS_MASK > -#define TCA_FLOWER_KEY_IP_TOS_MASK 74 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IP_TTL > -#define TCA_FLOWER_KEY_IP_TTL 75 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_IP_TTL_MASK > -#define TCA_FLOWER_KEY_IP_TTL_MASK 76 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IP_TOS > -#define TCA_FLOWER_KEY_ENC_IP_TOS 80 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IP_TOS_MASK > -#define TCA_FLOWER_KEY_ENC_IP_TOS_MASK 81 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IP_TTL > -#define TCA_FLOWER_KEY_ENC_IP_TTL 82 > -#endif > -#ifndef HAVE_TCA_FLOWER_KEY_ENC_IP_TTL_MASK > -#define TCA_FLOWER_KEY_ENC_IP_TTL_MASK 83 > -#endif > - > -#ifndef HAVE_TC_ACT_GOTO_CHAIN > -#define TC_ACT_GOTO_CHAIN 0x20000000 > -#endif > - > -#ifndef IPV6_ADDR_LEN > -#define IPV6_ADDR_LEN 16 > -#endif > - > -#ifndef IPV4_ADDR_LEN > -#define IPV4_ADDR_LEN 4 > -#endif > - > -#ifndef TP_PORT_LEN > -#define TP_PORT_LEN 2 /* Transport Port (UDP/TCP) Length */ > -#endif > - > -#ifndef TTL_LEN > -#define TTL_LEN 1 > -#endif > - > -#ifndef TCA_ACT_MAX_PRIO > -#define TCA_ACT_MAX_PRIO 32 > -#endif > - > -/** Parameters of VXLAN devices created by driver. */ > -#define MLX5_VXLAN_DEFAULT_VNI 1 > -#define MLX5_VXLAN_DEVICE_PFX "vmlx_" > -/** > - * Timeout in milliseconds to wait VXLAN UDP offloaded port > - * registration completed within the mlx5 driver. > - */ > -#define MLX5_VXLAN_WAIT_PORT_REG_MS 250 > - > -/** Tunnel action type, used for @p type in header structure. */ > -enum flow_tcf_tunact_type { > - FLOW_TCF_TUNACT_VXLAN_DECAP, > - FLOW_TCF_TUNACT_VXLAN_ENCAP, > -}; > - > -/** Flags used for @p mask in tunnel action encap descriptors. */ > -#define FLOW_TCF_ENCAP_ETH_SRC (1u << 0) > -#define FLOW_TCF_ENCAP_ETH_DST (1u << 1) > -#define FLOW_TCF_ENCAP_IPV4_SRC (1u << 2) > -#define FLOW_TCF_ENCAP_IPV4_DST (1u << 3) > -#define FLOW_TCF_ENCAP_IPV6_SRC (1u << 4) > -#define FLOW_TCF_ENCAP_IPV6_DST (1u << 5) > -#define FLOW_TCF_ENCAP_UDP_SRC (1u << 6) > -#define FLOW_TCF_ENCAP_UDP_DST (1u << 7) > -#define FLOW_TCF_ENCAP_VXLAN_VNI (1u << 8) > -#define FLOW_TCF_ENCAP_IP_TTL (1u << 9) > -#define FLOW_TCF_ENCAP_IP_TOS (1u << 10) > - > -/** > - * Structure for holding netlink context. > - * Note the size of the message buffer which is MNL_SOCKET_BUFFER_SIZE. > - * Using this (8KB) buffer size ensures that netlink messages will never= be > - * truncated. > - */ > -struct mlx5_flow_tcf_context { > - struct mnl_socket *nl; /* NETLINK_ROUTE libmnl socket. */ > - uint32_t seq; /* Message sequence number. */ > - uint32_t buf_size; /* Message buffer size. */ > - uint8_t *buf; /* Message buffer. */ > -}; > - > -/** > - * Neigh rule structure. The neigh rule is applied via Netlink to > - * outer tunnel iface in order to provide destination MAC address > - * for the VXLAN encapsultion. The neigh rule is implicitly related > - * to the Flow itself and can be shared by multiple Flows. > - */ > -struct tcf_neigh_rule { > - LIST_ENTRY(tcf_neigh_rule) next; > - uint32_t refcnt; > - struct rte_ether_addr eth; > - uint16_t mask; > - union { > - struct { > - rte_be32_t dst; > - } ipv4; > - struct { > - uint8_t dst[IPV6_ADDR_LEN]; > - } ipv6; > - }; > -}; > - > -/** > - * Local rule structure. The local rule is applied via Netlink to > - * outer tunnel iface in order to provide local and peer IP addresses > - * of the VXLAN tunnel for encapsulation. The local rule is implicitly > - * related to the Flow itself and can be shared by multiple Flows. > - */ > -struct tcf_local_rule { > - LIST_ENTRY(tcf_local_rule) next; > - uint32_t refcnt; > - uint16_t mask; > - union { > - struct { > - rte_be32_t dst; > - rte_be32_t src; > - } ipv4; > - struct { > - uint8_t dst[IPV6_ADDR_LEN]; > - uint8_t src[IPV6_ADDR_LEN]; > - } ipv6; > - }; > -}; > - > -/** Outer interface VXLAN encapsulation rules container. */ > -struct tcf_irule { > - LIST_ENTRY(tcf_irule) next; > - LIST_HEAD(, tcf_neigh_rule) neigh; > - LIST_HEAD(, tcf_local_rule) local; > - uint32_t refcnt; > - unsigned int ifouter; /**< Own interface index. */ > -}; > - > -/** VXLAN virtual netdev. */ > -struct tcf_vtep { > - LIST_ENTRY(tcf_vtep) next; > - uint32_t refcnt; > - unsigned int ifindex; /**< Own interface index. */ > - uint16_t port; > - uint32_t created:1; /**< Actually created by PMD. */ > - uint32_t waitreg:1; /**< Wait for VXLAN UDP port registration. */ > -}; > - > -/** Tunnel descriptor header, common for all tunnel types. */ > -struct flow_tcf_tunnel_hdr { > - uint32_t type; /**< Tunnel action type. */ > - struct tcf_vtep *vtep; /**< Virtual tunnel endpoint device. */ > - unsigned int ifindex_org; /**< Original dst/src interface */ > - unsigned int *ifindex_ptr; /**< Interface ptr in message. */ > -}; > - > -struct flow_tcf_vxlan_decap { > - struct flow_tcf_tunnel_hdr hdr; > - uint16_t udp_port; > -}; > - > -struct flow_tcf_vxlan_encap { > - struct flow_tcf_tunnel_hdr hdr; > - struct tcf_irule *iface; > - uint32_t mask; > - uint8_t ip_tos; > - uint8_t ip_ttl_hop; > - struct { > - struct rte_ether_addr dst; > - struct rte_ether_addr src; > - } eth; > - union { > - struct { > - rte_be32_t dst; > - rte_be32_t src; > - } ipv4; > - struct { > - uint8_t dst[IPV6_ADDR_LEN]; > - uint8_t src[IPV6_ADDR_LEN]; > - } ipv6; > - }; > - struct { > - rte_be16_t src; > - rte_be16_t dst; > - } udp; > - struct { > - uint8_t vni[3]; > - } vxlan; > -}; > - > -/** Structure used when extracting the values of a flow counters > - * from a netlink message. > - */ > -struct flow_tcf_stats_basic { > - bool valid; > - struct gnet_stats_basic counters; > -}; > - > -/** Empty masks for known item types. */ > -static const union { > - struct rte_flow_item_port_id port_id; > - struct rte_flow_item_eth eth; > - struct rte_flow_item_vlan vlan; > - struct rte_flow_item_ipv4 ipv4; > - struct rte_flow_item_ipv6 ipv6; > - struct rte_flow_item_tcp tcp; > - struct rte_flow_item_udp udp; > - struct rte_flow_item_vxlan vxlan; > -} flow_tcf_mask_empty =3D { > - {0}, > -}; > - > -/** Supported masks for known item types. */ > -static const struct { > - struct rte_flow_item_port_id port_id; > - struct rte_flow_item_eth eth; > - struct rte_flow_item_vlan vlan; > - struct rte_flow_item_ipv4 ipv4; > - struct rte_flow_item_ipv6 ipv6; > - struct rte_flow_item_tcp tcp; > - struct rte_flow_item_udp udp; > - struct rte_flow_item_vxlan vxlan; > -} flow_tcf_mask_supported =3D { > - .port_id =3D { > - .id =3D 0xffffffff, > - }, > - .eth =3D { > - .type =3D RTE_BE16(0xffff), > - .dst.addr_bytes =3D "\xff\xff\xff\xff\xff\xff", > - .src.addr_bytes =3D "\xff\xff\xff\xff\xff\xff", > - }, > - .vlan =3D { > - /* PCP and VID only, no DEI. */ > - .tci =3D RTE_BE16(0xefff), > - .inner_type =3D RTE_BE16(0xffff), > - }, > - .ipv4.hdr =3D { > - .next_proto_id =3D 0xff, > - .time_to_live =3D 0xff, > - .type_of_service =3D 0xff, > - .src_addr =3D RTE_BE32(0xffffffff), > - .dst_addr =3D RTE_BE32(0xffffffff), > - }, > - .ipv6.hdr =3D { > - .proto =3D 0xff, > - .vtc_flow =3D RTE_BE32(0xfful << RTE_IPV6_HDR_FL_SHIFT), > - .hop_limits =3D 0xff, > - .src_addr =3D > - "\xff\xff\xff\xff\xff\xff\xff\xff" > - "\xff\xff\xff\xff\xff\xff\xff\xff", > - .dst_addr =3D > - "\xff\xff\xff\xff\xff\xff\xff\xff" > - "\xff\xff\xff\xff\xff\xff\xff\xff", > - }, > - .tcp.hdr =3D { > - .src_port =3D RTE_BE16(0xffff), > - .dst_port =3D RTE_BE16(0xffff), > - .tcp_flags =3D 0xff, > - }, > - .udp.hdr =3D { > - .src_port =3D RTE_BE16(0xffff), > - .dst_port =3D RTE_BE16(0xffff), > - }, > - .vxlan =3D { > - .vni =3D "\xff\xff\xff", > - }, > -}; > - > -#define SZ_NLATTR_HDR MNL_ALIGN(sizeof(struct nlattr)) > -#define SZ_NLATTR_NEST SZ_NLATTR_HDR > -#define SZ_NLATTR_DATA_OF(len) MNL_ALIGN(SZ_NLATTR_HDR + (len)) > -#define SZ_NLATTR_TYPE_OF(typ) SZ_NLATTR_DATA_OF(sizeof(typ)) > -#define SZ_NLATTR_STRZ_OF(str) SZ_NLATTR_DATA_OF(strlen(str) + 1) > - > -#define PTOI_TABLE_SZ_MAX(dev) (mlx5_dev_to_port_id((dev)->device, > NULL, 0) + 2) > - > -/** DPDK port to network interface index (ifindex) conversion. */ > -struct flow_tcf_ptoi { > - uint16_t port_id; /**< DPDK port ID. */ > - unsigned int ifindex; /**< Network interface index. */ > -}; > - > -/* Due to a limitation on driver/FW. */ > -#define MLX5_TCF_GROUP_ID_MAX 3 > - > -/* > - * Due to a limitation on driver/FW, priority ranges from 1 to 16 in ker= nel. > - * Priority in rte_flow attribute starts from 0 and is added by 1 in > - * translation. This is subject to be changed to determine the max prior= ity > - * based on trial-and-error like Verbs driver once the restriction is li= fted or > - * the range is extended. > - */ > -#define MLX5_TCF_GROUP_PRIORITY_MAX 15 > - > -#define MLX5_TCF_FATE_ACTIONS \ > - (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \ > - MLX5_FLOW_ACTION_JUMP) > - > -#define MLX5_TCF_VLAN_ACTIONS \ > - (MLX5_FLOW_ACTION_OF_POP_VLAN | > MLX5_FLOW_ACTION_OF_PUSH_VLAN | \ > - MLX5_FLOW_ACTION_OF_SET_VLAN_VID | > MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) > - > -#define MLX5_TCF_VXLAN_ACTIONS \ > - (MLX5_FLOW_ACTION_VXLAN_ENCAP | > MLX5_FLOW_ACTION_VXLAN_DECAP) > - > -#define MLX5_TCF_PEDIT_ACTIONS \ > - (MLX5_FLOW_ACTION_SET_IPV4_SRC | > MLX5_FLOW_ACTION_SET_IPV4_DST | \ > - MLX5_FLOW_ACTION_SET_IPV6_SRC | > MLX5_FLOW_ACTION_SET_IPV6_DST | \ > - MLX5_FLOW_ACTION_SET_TP_SRC | > MLX5_FLOW_ACTION_SET_TP_DST | \ > - MLX5_FLOW_ACTION_SET_TTL | MLX5_FLOW_ACTION_DEC_TTL | > \ > - MLX5_FLOW_ACTION_SET_MAC_SRC | > MLX5_FLOW_ACTION_SET_MAC_DST) > - > -#define MLX5_TCF_CONFIG_ACTIONS \ > - (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_JUMP | \ > - MLX5_FLOW_ACTION_OF_PUSH_VLAN | > MLX5_FLOW_ACTION_OF_SET_VLAN_VID | \ > - MLX5_FLOW_ACTION_OF_SET_VLAN_PCP | \ > - (MLX5_TCF_PEDIT_ACTIONS & ~MLX5_FLOW_ACTION_DEC_TTL)) > - > -#define MAX_PEDIT_KEYS 128 > -#define SZ_PEDIT_KEY_VAL 4 > - > -#define NUM_OF_PEDIT_KEYS(sz) \ > - (((sz) / SZ_PEDIT_KEY_VAL) + (((sz) % SZ_PEDIT_KEY_VAL) ? 1 : 0)) > - > -struct pedit_key_ex { > - enum pedit_header_type htype; > - enum pedit_cmd cmd; > -}; > - > -struct pedit_parser { > - struct tc_pedit_sel sel; > - struct tc_pedit_key keys[MAX_PEDIT_KEYS]; > - struct pedit_key_ex keys_ex[MAX_PEDIT_KEYS]; > -}; > - > -/** > - * Create space for using the implicitly created TC flow counter. > - * > - * @param[in] dev > - * Pointer to the Ethernet device structure. > - * > - * @return > - * A pointer to the counter data structure, NULL otherwise and > - * rte_errno is set. > - */ > -static struct mlx5_flow_counter * > -flow_tcf_counter_new(void) > -{ > - struct mlx5_flow_counter *cnt; > - > - /* > - * eswitch counter cannot be shared and its id is unknown. > - * currently returning all with id 0. > - * in the future maybe better to switch to unique numbers. > - */ > - struct mlx5_flow_counter tmpl =3D { > - .ref_cnt =3D 1, > - }; > - cnt =3D rte_calloc(__func__, 1, sizeof(*cnt), 0); > - if (!cnt) { > - rte_errno =3D ENOMEM; > - return NULL; > - } > - *cnt =3D tmpl; > - /* Implicit counter, do not add to list. */ > - return cnt; > -} > - > -/** > - * Set pedit key of MAC address > - * > - * @param[in] actions > - * pointer to action specification > - * @param[in,out] p_parser > - * pointer to pedit_parser > - */ > -static void > -flow_tcf_pedit_key_set_mac(const struct rte_flow_action *actions, > - struct pedit_parser *p_parser) > -{ > - int idx =3D p_parser->sel.nkeys; > - uint32_t off =3D actions->type =3D=3D > RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ? > - offsetof(struct rte_ether_hdr, > s_addr) : > - offsetof(struct rte_ether_hdr, > d_addr); > - const struct rte_flow_action_set_mac *conf =3D > - (const struct rte_flow_action_set_mac *)actions->conf; > - > - p_parser->keys[idx].off =3D off; > - p_parser->keys[idx].mask =3D ~UINT32_MAX; > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_ETH; > - p_parser->keys_ex[idx].cmd =3D TCA_PEDIT_KEY_EX_CMD_SET; > - memcpy(&p_parser->keys[idx].val, > - conf->mac_addr, SZ_PEDIT_KEY_VAL); > - idx++; > - p_parser->keys[idx].off =3D off + SZ_PEDIT_KEY_VAL; > - p_parser->keys[idx].mask =3D 0xFFFF0000; > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_ETH; > - p_parser->keys_ex[idx].cmd =3D TCA_PEDIT_KEY_EX_CMD_SET; > - memcpy(&p_parser->keys[idx].val, > - conf->mac_addr + SZ_PEDIT_KEY_VAL, > - RTE_ETHER_ADDR_LEN - SZ_PEDIT_KEY_VAL); > - p_parser->sel.nkeys =3D (++idx); > -} > - > -/** > - * Set pedit key of decrease/set ttl > - * > - * @param[in] actions > - * pointer to action specification > - * @param[in,out] p_parser > - * pointer to pedit_parser > - * @param[in] item_flags > - * flags of all items presented > - */ > -static void > -flow_tcf_pedit_key_set_dec_ttl(const struct rte_flow_action *actions, > - struct pedit_parser *p_parser, > - uint64_t item_flags) > -{ > - int idx =3D p_parser->sel.nkeys; > - > - p_parser->keys[idx].mask =3D 0xFFFFFF00; > - if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) { > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_IP4; > - p_parser->keys[idx].off =3D > - offsetof(struct rte_ipv4_hdr, time_to_live); > - } > - if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6) { > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_IP6; > - p_parser->keys[idx].off =3D > - offsetof(struct rte_ipv6_hdr, hop_limits); > - } > - if (actions->type =3D=3D RTE_FLOW_ACTION_TYPE_DEC_TTL) { > - p_parser->keys_ex[idx].cmd =3D > TCA_PEDIT_KEY_EX_CMD_ADD; > - p_parser->keys[idx].val =3D 0x000000FF; > - } else { > - p_parser->keys_ex[idx].cmd =3D > TCA_PEDIT_KEY_EX_CMD_SET; > - p_parser->keys[idx].val =3D > - (__u32)((const struct rte_flow_action_set_ttl *) > - actions->conf)->ttl_value; > - } > - p_parser->sel.nkeys =3D (++idx); > -} > - > -/** > - * Set pedit key of transport (TCP/UDP) port value > - * > - * @param[in] actions > - * pointer to action specification > - * @param[in,out] p_parser > - * pointer to pedit_parser > - * @param[in] item_flags > - * flags of all items presented > - */ > -static void > -flow_tcf_pedit_key_set_tp_port(const struct rte_flow_action *actions, > - struct pedit_parser *p_parser, > - uint64_t item_flags) > -{ > - int idx =3D p_parser->sel.nkeys; > - > - if (item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP) > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_UDP; > - if (item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP) > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_TCP; > - p_parser->keys_ex[idx].cmd =3D TCA_PEDIT_KEY_EX_CMD_SET; > - /* offset of src/dst port is same for TCP and UDP */ > - p_parser->keys[idx].off =3D > - actions->type =3D=3D RTE_FLOW_ACTION_TYPE_SET_TP_SRC ? > - offsetof(struct rte_tcp_hdr, src_port) : > - offsetof(struct rte_tcp_hdr, dst_port); > - p_parser->keys[idx].mask =3D 0xFFFF0000; > - p_parser->keys[idx].val =3D > - (__u32)((const struct rte_flow_action_set_tp *) > - actions->conf)->port; > - p_parser->sel.nkeys =3D (++idx); > -} > - > -/** > - * Set pedit key of ipv6 address > - * > - * @param[in] actions > - * pointer to action specification > - * @param[in,out] p_parser > - * pointer to pedit_parser > - */ > -static void > -flow_tcf_pedit_key_set_ipv6_addr(const struct rte_flow_action *actions, > - struct pedit_parser *p_parser) > -{ > - int idx =3D p_parser->sel.nkeys; > - int keys =3D NUM_OF_PEDIT_KEYS(IPV6_ADDR_LEN); > - int off_base =3D > - actions->type =3D=3D RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ? > - offsetof(struct rte_ipv6_hdr, src_addr) : > - offsetof(struct rte_ipv6_hdr, dst_addr); > - const struct rte_flow_action_set_ipv6 *conf =3D > - (const struct rte_flow_action_set_ipv6 *)actions->conf; > - > - for (int i =3D 0; i < keys; i++, idx++) { > - p_parser->keys_ex[idx].htype =3D > TCA_PEDIT_KEY_EX_HDR_TYPE_IP6; > - p_parser->keys_ex[idx].cmd =3D > TCA_PEDIT_KEY_EX_CMD_SET; > - p_parser->keys[idx].off =3D off_base + i * SZ_PEDIT_KEY_VAL; > - p_parser->keys[idx].mask =3D ~UINT32_MAX; > - memcpy(&p_parser->keys[idx].val, > - conf->ipv6_addr + i * SZ_PEDIT_KEY_VAL, > - SZ_PEDIT_KEY_VAL); > - } > - p_parser->sel.nkeys +=3D keys; > -} > - > -/** > - * Set pedit key of ipv4 address > - * > - * @param[in] actions > - * pointer to action specification > - * @param[in,out] p_parser > - * pointer to pedit_parser > - */ > -static void > -flow_tcf_pedit_key_set_ipv4_addr(const struct rte_flow_action *actions, > - struct pedit_parser *p_parser) > -{ > - int idx =3D p_parser->sel.nkeys; > - > - p_parser->keys_ex[idx].htype =3D TCA_PEDIT_KEY_EX_HDR_TYPE_IP4; > - p_parser->keys_ex[idx].cmd =3D TCA_PEDIT_KEY_EX_CMD_SET; > - p_parser->keys[idx].off =3D > - actions->type =3D=3D RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ? > - offsetof(struct rte_ipv4_hdr, src_addr) : > - offsetof(struct rte_ipv4_hdr, dst_addr); > - p_parser->keys[idx].mask =3D ~UINT32_MAX; > - p_parser->keys[idx].val =3D > - ((const struct rte_flow_action_set_ipv4 *) > - actions->conf)->ipv4_addr; > - p_parser->sel.nkeys =3D (++idx); > -} > - > -/** > - * Create the pedit's na attribute in netlink message > - * on pre-allocate message buffer > - * > - * @param[in,out] nl > - * pointer to pre-allocated netlink message buffer > - * @param[in,out] actions > - * pointer to pointer of actions specification. > - * @param[in,out] action_flags > - * pointer to actions flags > - * @param[in] item_flags > - * flags of all item presented > - */ > -static void > -flow_tcf_create_pedit_mnl_msg(struct nlmsghdr *nl, > - const struct rte_flow_action **actions, > - uint64_t item_flags) > -{ > - struct pedit_parser p_parser; > - struct nlattr *na_act_options; > - struct nlattr *na_pedit_keys; > - > - memset(&p_parser, 0, sizeof(p_parser)); > - mnl_attr_put_strz(nl, TCA_ACT_KIND, "pedit"); > - na_act_options =3D mnl_attr_nest_start(nl, TCA_ACT_OPTIONS); > - /* all modify header actions should be in one tc-pedit action */ > - for (; (*actions)->type !=3D RTE_FLOW_ACTION_TYPE_END; > (*actions)++) { > - switch ((*actions)->type) { > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: > - flow_tcf_pedit_key_set_ipv4_addr(*actions, > &p_parser); > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: > - flow_tcf_pedit_key_set_ipv6_addr(*actions, > &p_parser); > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_TP_DST: > - flow_tcf_pedit_key_set_tp_port(*actions, > - &p_parser, > item_flags); > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TTL: > - case RTE_FLOW_ACTION_TYPE_DEC_TTL: > - flow_tcf_pedit_key_set_dec_ttl(*actions, > - &p_parser, > item_flags); > - break; > - case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > - flow_tcf_pedit_key_set_mac(*actions, &p_parser); > - break; > - default: > - goto pedit_mnl_msg_done; > - } > - } > -pedit_mnl_msg_done: > - p_parser.sel.action =3D TC_ACT_PIPE; > - mnl_attr_put(nl, TCA_PEDIT_PARMS_EX, > - sizeof(p_parser.sel) + > - p_parser.sel.nkeys * sizeof(struct tc_pedit_key), > - &p_parser); > - na_pedit_keys =3D > - mnl_attr_nest_start(nl, TCA_PEDIT_KEYS_EX | > NLA_F_NESTED); > - for (int i =3D 0; i < p_parser.sel.nkeys; i++) { > - struct nlattr *na_pedit_key =3D > - mnl_attr_nest_start(nl, > - TCA_PEDIT_KEY_EX | > NLA_F_NESTED); > - mnl_attr_put_u16(nl, TCA_PEDIT_KEY_EX_HTYPE, > - p_parser.keys_ex[i].htype); > - mnl_attr_put_u16(nl, TCA_PEDIT_KEY_EX_CMD, > - p_parser.keys_ex[i].cmd); > - mnl_attr_nest_end(nl, na_pedit_key); > - } > - mnl_attr_nest_end(nl, na_pedit_keys); > - mnl_attr_nest_end(nl, na_act_options); > - (*actions)--; > -} > - > -/** > - * Calculate max memory size of one TC-pedit actions. > - * One TC-pedit action can contain set of keys each defining > - * a rewrite element (rte_flow action) > - * > - * @param[in,out] actions > - * actions specification. > - * @param[in,out] action_flags > - * actions flags > - * @param[in,out] size > - * accumulated size > - * @return > - * Max memory size of one TC-pedit action > - */ > -static int > -flow_tcf_get_pedit_actions_size(const struct rte_flow_action **actions, > - uint64_t *action_flags) > -{ > - int pedit_size =3D 0; > - int keys =3D 0; > - uint64_t flags =3D 0; > - > - pedit_size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("pedit") + > - SZ_NLATTR_NEST; /* TCA_ACT_OPTIONS. */ > - for (; (*actions)->type !=3D RTE_FLOW_ACTION_TYPE_END; > (*actions)++) { > - switch ((*actions)->type) { > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: > - keys +=3D NUM_OF_PEDIT_KEYS(IPV4_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_IPV4_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: > - keys +=3D NUM_OF_PEDIT_KEYS(IPV4_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_IPV4_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: > - keys +=3D NUM_OF_PEDIT_KEYS(IPV6_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_IPV6_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: > - keys +=3D NUM_OF_PEDIT_KEYS(IPV6_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_IPV6_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: > - /* TCP is as same as UDP */ > - keys +=3D NUM_OF_PEDIT_KEYS(TP_PORT_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_TP_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TP_DST: > - /* TCP is as same as UDP */ > - keys +=3D NUM_OF_PEDIT_KEYS(TP_PORT_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_TP_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TTL: > - keys +=3D NUM_OF_PEDIT_KEYS(TTL_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_TTL; > - break; > - case RTE_FLOW_ACTION_TYPE_DEC_TTL: > - keys +=3D NUM_OF_PEDIT_KEYS(TTL_LEN); > - flags |=3D MLX5_FLOW_ACTION_DEC_TTL; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > - keys +=3D > NUM_OF_PEDIT_KEYS(RTE_ETHER_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_MAC_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > - keys +=3D > NUM_OF_PEDIT_KEYS(RTE_ETHER_ADDR_LEN); > - flags |=3D MLX5_FLOW_ACTION_SET_MAC_DST; > - break; > - default: > - goto get_pedit_action_size_done; > - } > - } > -get_pedit_action_size_done: > - /* TCA_PEDIT_PARAMS_EX */ > - pedit_size +=3D > - SZ_NLATTR_DATA_OF(sizeof(struct tc_pedit_sel) + > - keys * sizeof(struct tc_pedit_key)); > - pedit_size +=3D SZ_NLATTR_NEST; /* TCA_PEDIT_KEYS */ > - pedit_size +=3D keys * > - /* TCA_PEDIT_KEY_EX + HTYPE + CMD */ > - (SZ_NLATTR_NEST + SZ_NLATTR_DATA_OF(2) + > - SZ_NLATTR_DATA_OF(2)); > - (*action_flags) |=3D flags; > - (*actions)--; > - return pedit_size; > -} > - > -/** > - * Retrieve mask for pattern item. > - * > - * This function does basic sanity checks on a pattern item in order to > - * return the most appropriate mask for it. > - * > - * @param[in] item > - * Item specification. > - * @param[in] mask_default > - * Default mask for pattern item as specified by the flow API. > - * @param[in] mask_supported > - * Mask fields supported by the implementation. > - * @param[in] mask_empty > - * Empty mask to return when there is no specification. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * Either @p item->mask or one of the mask parameters on success, NULL > - * otherwise and rte_errno is set. > - */ > -static const void * > -flow_tcf_item_mask(const struct rte_flow_item *item, const void > *mask_default, > - const void *mask_supported, const void *mask_empty, > - size_t mask_size, struct rte_flow_error *error) > -{ > - const uint8_t *mask; > - size_t i; > - > - /* item->last and item->mask cannot exist without item->spec. */ > - if (!item->spec && (item->mask || item->last)) { > - rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, item, > - "\"mask\" or \"last\" field provided > without" > - " a corresponding \"spec\""); > - return NULL; > - } > - /* No spec, no mask, no problem. */ > - if (!item->spec) > - return mask_empty; > - mask =3D item->mask ? item->mask : mask_default; > - assert(mask); > - /* > - * Single-pass check to make sure that: > - * - Mask is supported, no bits are set outside mask_supported. > - * - Both item->spec and item->last are included in mask. > - */ > - for (i =3D 0; i !=3D mask_size; ++i) { > - if (!mask[i]) > - continue; > - if ((mask[i] | ((const uint8_t *)mask_supported)[i]) !=3D > - ((const uint8_t *)mask_supported)[i]) { > - rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "unsupported field found" > - " in \"mask\""); > - return NULL; > - } > - if (item->last && > - (((const uint8_t *)item->spec)[i] & mask[i]) !=3D > - (((const uint8_t *)item->last)[i] & mask[i])) { > - rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM_LAST, > - item->last, > - "range between \"spec\" and > \"last\"" > - " not comprised in \"mask\""); > - return NULL; > - } > - } > - return mask; > -} > - > -/** > - * Build a conversion table between port ID and ifindex. > - * > - * @param[in] dev > - * Pointer to Ethernet device. > - * @param[out] ptoi > - * Pointer to ptoi table. > - * @param[in] len > - * Size of ptoi table provided. > - * > - * @return > - * Size of ptoi table filled. > - */ > -static unsigned int > -flow_tcf_build_ptoi_table(struct rte_eth_dev *dev, struct flow_tcf_ptoi > *ptoi, > - unsigned int len) > -{ > - unsigned int n =3D mlx5_dev_to_port_id(dev->device, NULL, 0); > - uint16_t port_id[n + 1]; > - unsigned int i; > - unsigned int own =3D 0; > - > - /* At least one port is needed when no switch domain is present. */ > - if (!n) { > - n =3D 1; > - port_id[0] =3D dev->data->port_id; > - } else { > - n =3D RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, n), > n); > - } > - if (n > len) > - return 0; > - for (i =3D 0; i !=3D n; ++i) { > - struct rte_eth_dev_info dev_info; > - > - rte_eth_dev_info_get(port_id[i], &dev_info); > - if (port_id[i] =3D=3D dev->data->port_id) > - own =3D i; > - ptoi[i].port_id =3D port_id[i]; > - ptoi[i].ifindex =3D dev_info.if_index; > - } > - /* Ensure first entry of ptoi[] is the current device. */ > - if (own) { > - ptoi[n] =3D ptoi[0]; > - ptoi[0] =3D ptoi[own]; > - ptoi[own] =3D ptoi[n]; > - } > - /* An entry with zero ifindex terminates ptoi[]. */ > - ptoi[n].port_id =3D 0; > - ptoi[n].ifindex =3D 0; > - return n; > -} > - > -/** > - * Verify the @p attr will be correctly understood by the E-switch. > - * > - * @param[in] attr > - * Pointer to flow attributes > - * @param[out] error > - * Pointer to error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_validate_attributes(const struct rte_flow_attr *attr, > - struct rte_flow_error *error) > -{ > - /* > - * Supported attributes: groups, some priorities and ingress only. > - * group is supported only if kernel supports chain. Don't care about > - * transfer as it is the caller's problem. > - */ > - if (attr->group > MLX5_TCF_GROUP_ID_MAX) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr, > - "group ID larger than " > - > RTE_STR(MLX5_TCF_GROUP_ID_MAX) > - " isn't supported"); > - else if (attr->priority > MLX5_TCF_GROUP_PRIORITY_MAX) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, > - attr, > - "priority more than " > - > RTE_STR(MLX5_TCF_GROUP_PRIORITY_MAX) > - " is not supported"); > - if (!attr->ingress) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, > - attr, "only ingress is supported"); > - if (attr->egress) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, > - attr, "egress is not supported"); > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_ETH item for E- > Switch. > - * The routine checks the L2 fields to be used in encapsulation header. > - * > - * @param[in] item > - * Pointer to the item structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap_eth(const struct rte_flow_item *item, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_eth *spec =3D item->spec; > - const struct rte_flow_item_eth *mask =3D item->mask; > - > - if (!spec) { > - /* > - * Specification for L2 addresses can be empty > - * because these ones are optional and not > - * required directly by tc rule. Kernel tries > - * to resolve these ones on its own > - */ > - return 0; > - } > - if (!mask) { > - /* If mask is not specified use the default one. */ > - mask =3D &rte_flow_item_eth_mask; > - } > - if (memcmp(&mask->dst, > - &flow_tcf_mask_empty.eth.dst, > - sizeof(flow_tcf_mask_empty.eth.dst))) { > - if (memcmp(&mask->dst, > - &rte_flow_item_eth_mask.dst, > - sizeof(rte_flow_item_eth_mask.dst))) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM_MASK, > mask, > - "no support for partial mask on" > - " \"eth.dst\" field"); > - } > - if (memcmp(&mask->src, > - &flow_tcf_mask_empty.eth.src, > - sizeof(flow_tcf_mask_empty.eth.src))) { > - if (memcmp(&mask->src, > - &rte_flow_item_eth_mask.src, > - sizeof(rte_flow_item_eth_mask.src))) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM_MASK, > mask, > - "no support for partial mask on" > - " \"eth.src\" field"); > - } > - if (mask->type !=3D RTE_BE16(0x0000)) { > - if (mask->type !=3D RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM_MASK, > mask, > - "no support for partial mask on" > - " \"eth.type\" field"); > - DRV_LOG(WARNING, > - "outer ethernet type field" > - " cannot be forced for vxlan" > - " encapsulation, parameter ignored"); > - } > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_IPV4 item for E- > Switch. > - * The routine checks the IPv4 fields to be used in encapsulation header= . > - * > - * @param[in] item > - * Pointer to the item structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap_ipv4(const struct rte_flow_item *item, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_ipv4 *spec =3D item->spec; > - const struct rte_flow_item_ipv4 *mask =3D item->mask; > - > - if (!spec) { > - /* > - * Specification for IP addresses cannot be empty > - * because it is required by tunnel_key parameter. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "NULL outer ipv4 address" > - " specification for vxlan" > - " encapsulation"); > - } > - if (!mask) > - mask =3D &rte_flow_item_ipv4_mask; > - if (mask->hdr.dst_addr !=3D RTE_BE32(0x00000000)) { > - if (mask->hdr.dst_addr !=3D RTE_BE32(0xffffffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM_MASK, > mask, > - "no support for partial mask on" > - " \"ipv4.hdr.dst_addr\" field" > - " for vxlan encapsulation"); > - /* More IPv4 address validations can be put here. */ > - } else { > - /* > - * Kernel uses the destination IP address to determine > - * the routing path and obtain the MAC destination > - * address, so IP destination address must be > - * specified in the tc rule. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer ipv4 destination address" > - " must be specified for" > - " vxlan encapsulation"); > - } > - if (mask->hdr.src_addr !=3D RTE_BE32(0x00000000)) { > - if (mask->hdr.src_addr !=3D RTE_BE32(0xffffffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM_MASK, > mask, > - "no support for partial mask on" > - " \"ipv4.hdr.src_addr\" field" > - " for vxlan encapsulation"); > - /* More IPv4 address validations can be put here. */ > - } else { > - /* > - * Kernel uses the source IP address to select the > - * interface for egress encapsulated traffic, so > - * it must be specified in the tc rule. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer ipv4 source address" > - " must be specified for" > - " vxlan encapsulation"); > - } > - if (mask->hdr.type_of_service && > - mask->hdr.type_of_service !=3D 0xff) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv4.hdr.type_of_service\" field" > - " for vxlan encapsulation"); > - if (mask->hdr.time_to_live && > - mask->hdr.time_to_live !=3D 0xff) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv4.hdr.time_to_live\" field" > - " for vxlan encapsulation"); > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_IPV6 item for E- > Switch. > - * The routine checks the IPv6 fields to be used in encapsulation header= . > - * > - * @param[in] item > - * Pointer to the item structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap_ipv6(const struct rte_flow_item *item, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_ipv6 *spec =3D item->spec; > - const struct rte_flow_item_ipv6 *mask =3D item->mask; > - uint8_t msk6; > - > - if (!spec) { > - /* > - * Specification for IP addresses cannot be empty > - * because it is required by tunnel_key parameter. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "NULL outer ipv6 address" > - " specification for" > - " vxlan encapsulation"); > - } > - if (!mask) > - mask =3D &rte_flow_item_ipv6_mask; > - if (memcmp(&mask->hdr.dst_addr, > - &flow_tcf_mask_empty.ipv6.hdr.dst_addr, > - IPV6_ADDR_LEN)) { > - if (memcmp(&mask->hdr.dst_addr, > - &rte_flow_item_ipv6_mask.hdr.dst_addr, > - IPV6_ADDR_LEN)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv6.hdr.dst_addr\" field" > - " for vxlan encapsulation"); > - /* More IPv6 address validations can be put here. */ > - } else { > - /* > - * Kernel uses the destination IP address to determine > - * the routing path and obtain the MAC destination > - * address (heigh or gate), so IP destination address > - * must be specified within the tc rule. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer ipv6 destination address" > - " must be specified for" > - " vxlan encapsulation"); > - } > - if (memcmp(&mask->hdr.src_addr, > - &flow_tcf_mask_empty.ipv6.hdr.src_addr, > - IPV6_ADDR_LEN)) { > - if (memcmp(&mask->hdr.src_addr, > - &rte_flow_item_ipv6_mask.hdr.src_addr, > - IPV6_ADDR_LEN)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv6.hdr.src_addr\" field" > - " for vxlan encapsulation"); > - /* More L3 address validation can be put here. */ > - } else { > - /* > - * Kernel uses the source IP address to select the > - * interface for egress encapsulated traffic, so > - * it must be specified in the tc rule. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer L3 source address" > - " must be specified for" > - " vxlan encapsulation"); > - } > - msk6 =3D (rte_be_to_cpu_32(mask->hdr.vtc_flow) >> > - RTE_IPV6_HDR_TC_SHIFT) & 0xff; > - if (msk6 && msk6 !=3D 0xff) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv6.hdr.vtc_flow.tos\" field" > - " for vxlan encapsulation"); > - if (mask->hdr.hop_limits && mask->hdr.hop_limits !=3D 0xff) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"ipv6.hdr.hop_limits\" field" > - " for vxlan encapsulation"); > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_UDP item for E- > Switch. > - * The routine checks the UDP fields to be used in encapsulation header. > - * > - * @param[in] item > - * Pointer to the item structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap_udp(const struct rte_flow_item *item, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_udp *spec =3D item->spec; > - const struct rte_flow_item_udp *mask =3D item->mask; > - > - if (!spec) { > - /* > - * Specification for UDP ports cannot be empty > - * because it is required by tunnel_key parameter. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "NULL UDP port specification " > - " for vxlan encapsulation"); > - } > - if (!mask) > - mask =3D &rte_flow_item_udp_mask; > - if (mask->hdr.dst_port !=3D RTE_BE16(0x0000)) { > - if (mask->hdr.dst_port !=3D RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"udp.hdr.dst_port\" field" > - " for vxlan encapsulation"); > - if (!spec->hdr.dst_port) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer UDP remote port cannot be" > - " 0 for vxlan encapsulation"); > - } else { > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer UDP remote port" > - " must be specified for" > - " vxlan encapsulation"); > - } > - if (mask->hdr.src_port !=3D RTE_BE16(0x0000)) { > - if (mask->hdr.src_port !=3D RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"udp.hdr.src_port\" field" > - " for vxlan encapsulation"); > - DRV_LOG(WARNING, > - "outer UDP source port cannot be" > - " forced for vxlan encapsulation," > - " parameter ignored"); > - } > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_VXLAN item for E- > Switch. > - * The routine checks the VNIP fields to be used in encapsulation header= . > - * > - * @param[in] item > - * Pointer to the item structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap_vni(const struct rte_flow_item *item, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_vxlan *spec =3D item->spec; > - const struct rte_flow_item_vxlan *mask =3D item->mask; > - > - if (!spec) { > - /* Outer VNI is required by tunnel_key parameter. */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "NULL VNI specification" > - " for vxlan encapsulation"); > - } > - if (!mask) > - mask =3D &rte_flow_item_vxlan_mask; > - if (!mask->vni[0] && !mask->vni[1] && !mask->vni[2]) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "outer VNI must be specified " > - "for vxlan encapsulation"); > - if (mask->vni[0] !=3D 0xff || > - mask->vni[1] !=3D 0xff || > - mask->vni[2] !=3D 0xff) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"vxlan.vni\" field"); > - > - if (!spec->vni[0] && !spec->vni[1] && !spec->vni[2]) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > item, > - "vxlan vni cannot be 0"); > - return 0; > -} > - > -/** > - * Validate VXLAN_ENCAP action item list for E-Switch. > - * The routine checks items to be used in encapsulation header. > - * > - * @param[in] action > - * Pointer to the VXLAN_ENCAP action structure. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_encap(const struct rte_flow_action *action, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item *items; > - int ret; > - uint32_t item_flags =3D 0; > - > - if (!action->conf) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > action, > - "Missing vxlan tunnel" > - " action configuration"); > - items =3D ((const struct rte_flow_action_vxlan_encap *) > - action->conf)->definition; > - if (!items) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > action, > - "Missing vxlan tunnel" > - " encapsulation parameters"); > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - ret =3D mlx5_flow_validate_item_eth(items, > item_flags, > - error); > - if (ret < 0) > - return ret; > - ret =3D flow_tcf_validate_vxlan_encap_eth(items, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_L2; > - break; > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: > - ret =3D mlx5_flow_validate_item_ipv4 > - (items, item_flags, > - &flow_tcf_mask_supported.ipv4, > error); > - if (ret < 0) > - return ret; > - ret =3D flow_tcf_validate_vxlan_encap_ipv4(items, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_L3_IPV4; > - break; > - case RTE_FLOW_ITEM_TYPE_IPV6: > - ret =3D mlx5_flow_validate_item_ipv6 > - (items, item_flags, > - &flow_tcf_mask_supported.ipv6, > error); > - if (ret < 0) > - return ret; > - ret =3D flow_tcf_validate_vxlan_encap_ipv6(items, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_L3_IPV6; > - break; > - case RTE_FLOW_ITEM_TYPE_UDP: > - ret =3D mlx5_flow_validate_item_udp(items, > item_flags, > - 0xFF, error); > - if (ret < 0) > - return ret; > - ret =3D flow_tcf_validate_vxlan_encap_udp(items, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_L4_UDP; > - break; > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - ret =3D mlx5_flow_validate_item_vxlan(items, > - item_flags, error); > - if (ret < 0) > - return ret; > - ret =3D flow_tcf_validate_vxlan_encap_vni(items, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_VXLAN; > - break; > - default: > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM, > items, > - "vxlan encap item not supported"); > - } > - } > - if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L3)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > action, > - "no outer IP layer found" > - " for vxlan encapsulation"); > - if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > action, > - "no outer UDP layer found" > - " for vxlan encapsulation"); > - if (!(item_flags & MLX5_FLOW_LAYER_VXLAN)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > action, > - "no VXLAN VNI found" > - " for vxlan encapsulation"); > - return 0; > -} > - > -/** > - * Validate outer RTE_FLOW_ITEM_TYPE_UDP item if tunnel item > - * RTE_FLOW_ITEM_TYPE_VXLAN is present in item list. > - * > - * @param[in] udp > - * Outer UDP layer item (if any, NULL otherwise). > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - **/ > -static int > -flow_tcf_validate_vxlan_decap_udp(const struct rte_flow_item *udp, > - struct rte_flow_error *error) > -{ > - const struct rte_flow_item_udp *spec =3D udp->spec; > - const struct rte_flow_item_udp *mask =3D udp->mask; > - > - if (!spec) > - /* > - * Specification for UDP ports cannot be empty > - * because it is required as decap parameter. > - */ > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > udp, > - "NULL UDP port specification" > - " for VXLAN decapsulation"); > - if (!mask) > - mask =3D &rte_flow_item_udp_mask; > - if (mask->hdr.dst_port !=3D RTE_BE16(0x0000)) { > - if (mask->hdr.dst_port !=3D RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"udp.hdr.dst_port\" field"); > - if (!spec->hdr.dst_port) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > udp, > - "zero decap local UDP port"); > - } else { > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > udp, > - "outer UDP destination port must > be " > - "specified for vxlan decapsulation"); > - } > - if (mask->hdr.src_port !=3D RTE_BE16(0x0000)) { > - if (mask->hdr.src_port !=3D RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask, > - "no support for partial mask on" > - " \"udp.hdr.src_port\" field"); > - DRV_LOG(WARNING, > - "outer UDP local port cannot be " > - "forced for VXLAN encapsulation, " > - "parameter ignored"); > - } > - return 0; > -} > - > -/** > - * Validate flow for E-Switch. > - * > - * @param[in] priv > - * Pointer to the priv structure. > - * @param[in] attr > - * Pointer to the flow attributes. > - * @param[in] items > - * Pointer to the list of items. > - * @param[in] actions > - * Pointer to the list of actions. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_validate(struct rte_eth_dev *dev, > - const struct rte_flow_attr *attr, > - const struct rte_flow_item items[], > - const struct rte_flow_action actions[], > - struct rte_flow_error *error) > -{ > - union { > - const struct rte_flow_item_port_id *port_id; > - const struct rte_flow_item_eth *eth; > - const struct rte_flow_item_vlan *vlan; > - const struct rte_flow_item_ipv4 *ipv4; > - const struct rte_flow_item_ipv6 *ipv6; > - const struct rte_flow_item_tcp *tcp; > - const struct rte_flow_item_udp *udp; > - const struct rte_flow_item_vxlan *vxlan; > - } spec, mask; > - union { > - const struct rte_flow_action_port_id *port_id; > - const struct rte_flow_action_jump *jump; > - const struct rte_flow_action_of_push_vlan *of_push_vlan; > - const struct rte_flow_action_of_set_vlan_vid * > - of_set_vlan_vid; > - const struct rte_flow_action_of_set_vlan_pcp * > - of_set_vlan_pcp; > - const struct rte_flow_action_vxlan_encap *vxlan_encap; > - const struct rte_flow_action_set_ipv4 *set_ipv4; > - const struct rte_flow_action_set_ipv6 *set_ipv6; > - } conf; > - const struct rte_flow_item *outer_udp =3D NULL; > - rte_be16_t inner_etype =3D RTE_BE16(ETH_P_ALL); > - rte_be16_t outer_etype =3D RTE_BE16(ETH_P_ALL); > - rte_be16_t vlan_etype =3D RTE_BE16(ETH_P_ALL); > - uint64_t item_flags =3D 0; > - uint64_t action_flags =3D 0; > - uint8_t next_protocol =3D 0xff; > - unsigned int tcm_ifindex =3D 0; > - uint8_t pedit_validated =3D 0; > - struct flow_tcf_ptoi ptoi[PTOI_TABLE_SZ_MAX(dev)]; > - struct rte_eth_dev *port_id_dev =3D NULL; > - bool in_port_id_set; > - int ret; > - > - claim_nonzero(flow_tcf_build_ptoi_table(dev, ptoi, > - PTOI_TABLE_SZ_MAX(dev))); > - ret =3D flow_tcf_validate_attributes(attr, error); > - if (ret < 0) > - return ret; > - for (; actions->type !=3D RTE_FLOW_ACTION_TYPE_END; actions++) { > - unsigned int i; > - uint64_t current_action_flag =3D 0; > - > - switch (actions->type) { > - case RTE_FLOW_ACTION_TYPE_VOID: > - break; > - case RTE_FLOW_ACTION_TYPE_PORT_ID: > - current_action_flag =3D > MLX5_FLOW_ACTION_PORT_ID; > - if (!actions->conf) > - break; > - conf.port_id =3D actions->conf; > - if (conf.port_id->original) > - i =3D 0; > - else > - for (i =3D 0; ptoi[i].ifindex; ++i) > - if (ptoi[i].port_id =3D=3D conf.port_id->id) > - break; > - if (!ptoi[i].ifindex) > - return rte_flow_error_set > - (error, ENODEV, > - > RTE_FLOW_ERROR_TYPE_ACTION_CONF, > - conf.port_id, > - "missing data to convert port ID to" > - " ifindex"); > - port_id_dev =3D &rte_eth_devices[conf.port_id->id]; > - break; > - case RTE_FLOW_ACTION_TYPE_JUMP: > - current_action_flag =3D MLX5_FLOW_ACTION_JUMP; > - if (!actions->conf) > - break; > - conf.jump =3D actions->conf; > - if (attr->group >=3D conf.jump->group) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "can jump only to a group forward"); > - break; > - case RTE_FLOW_ACTION_TYPE_DROP: > - current_action_flag =3D MLX5_FLOW_ACTION_DROP; > - break; > - case RTE_FLOW_ACTION_TYPE_COUNT: > - break; > - case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: > - current_action_flag =3D > MLX5_FLOW_ACTION_OF_POP_VLAN; > - break; > - case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: { > - rte_be16_t ethertype; > - > - current_action_flag =3D > MLX5_FLOW_ACTION_OF_PUSH_VLAN; > - if (!actions->conf) > - break; > - conf.of_push_vlan =3D actions->conf; > - ethertype =3D conf.of_push_vlan->ethertype; > - if (ethertype !=3D RTE_BE16(ETH_P_8021Q) && > - ethertype !=3D RTE_BE16(ETH_P_8021AD)) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "vlan push TPID must be " > - "802.1Q or 802.1AD"); > - break; > - } > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: > - if (!(action_flags & > MLX5_FLOW_ACTION_OF_PUSH_VLAN)) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "vlan modify is not supported," > - " set action must follow push > action"); > - current_action_flag =3D > MLX5_FLOW_ACTION_OF_SET_VLAN_VID; > - break; > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: > - if (!(action_flags & > MLX5_FLOW_ACTION_OF_PUSH_VLAN)) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "vlan modify is not supported," > - " set action must follow push > action"); > - current_action_flag =3D > MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: > - current_action_flag =3D > MLX5_FLOW_ACTION_VXLAN_DECAP; > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: > - ret =3D flow_tcf_validate_vxlan_encap(actions, error); > - if (ret < 0) > - return ret; > - current_action_flag =3D > MLX5_FLOW_ACTION_VXLAN_ENCAP; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_IPV4_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_IPV4_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_IPV6_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_IPV6_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_TP_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TP_DST: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_TP_DST; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_TTL: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_TTL; > - break; > - case RTE_FLOW_ACTION_TYPE_DEC_TTL: > - current_action_flag =3D > MLX5_FLOW_ACTION_DEC_TTL; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_MAC_SRC; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > - current_action_flag =3D > MLX5_FLOW_ACTION_SET_MAC_DST; > - break; > - default: > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "action not supported"); > - } > - if (current_action_flag & MLX5_TCF_CONFIG_ACTIONS) { > - if (!actions->conf) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION_CONF, > - actions, > - "action configuration not set"); > - } > - if ((current_action_flag & MLX5_TCF_PEDIT_ACTIONS) && > - pedit_validated) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "set actions should be " > - "listed successively"); > - if ((current_action_flag & ~MLX5_TCF_PEDIT_ACTIONS) && > - (action_flags & MLX5_TCF_PEDIT_ACTIONS)) > - pedit_validated =3D 1; > - if ((current_action_flag & MLX5_TCF_FATE_ACTIONS) && > - (action_flags & MLX5_TCF_FATE_ACTIONS)) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "can't have multiple fate" > - " actions"); > - if ((current_action_flag & MLX5_TCF_VXLAN_ACTIONS) && > - (action_flags & MLX5_TCF_VXLAN_ACTIONS)) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "can't have multiple vxlan" > - " actions"); > - if ((current_action_flag & MLX5_TCF_VXLAN_ACTIONS) && > - (action_flags & MLX5_TCF_VLAN_ACTIONS)) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "can't have vxlan and vlan" > - " actions in the same rule"); > - action_flags |=3D current_action_flag; > - } > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - unsigned int i; > - > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_PORT_ID: > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM, > items, > - "inner tunnel port id" > - " item is not supported"); > - mask.port_id =3D flow_tcf_item_mask > - (items, &rte_flow_item_port_id_mask, > - &flow_tcf_mask_supported.port_id, > - &flow_tcf_mask_empty.port_id, > - sizeof(flow_tcf_mask_supported.port_id), > - error); > - if (!mask.port_id) > - return -rte_errno; > - if (mask.port_id =3D=3D &flow_tcf_mask_empty.port_id) > { > - in_port_id_set =3D 1; > - break; > - } > - spec.port_id =3D items->spec; > - if (mask.port_id->id && mask.port_id->id !=3D > 0xffffffff) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.port_id, > - "no support for partial mask on" > - " \"id\" field"); > - if (!mask.port_id->id) > - i =3D 0; > - else > - for (i =3D 0; ptoi[i].ifindex; ++i) > - if (ptoi[i].port_id =3D=3D spec.port_id->id) > - break; > - if (!ptoi[i].ifindex) > - return rte_flow_error_set > - (error, ENODEV, > - > RTE_FLOW_ERROR_TYPE_ITEM_SPEC, > - spec.port_id, > - "missing data to convert port ID to" > - " ifindex"); > - if (in_port_id_set && ptoi[i].ifindex !=3D tcm_ifindex) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_SPEC, > - spec.port_id, > - "cannot match traffic for" > - " several port IDs through" > - " a single flow rule"); > - tcm_ifindex =3D ptoi[i].ifindex; > - in_port_id_set =3D 1; > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - ret =3D mlx5_flow_validate_item_eth(items, > item_flags, > - error); > - if (ret < 0) > - return ret; > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L2 : > - MLX5_FLOW_LAYER_OUTER_L2; > - /* TODO: > - * Redundant check due to different supported mask. > - * Same for the rest of items. > - */ > - mask.eth =3D flow_tcf_item_mask > - (items, &rte_flow_item_eth_mask, > - &flow_tcf_mask_supported.eth, > - &flow_tcf_mask_empty.eth, > - sizeof(flow_tcf_mask_supported.eth), > - error); > - if (!mask.eth) > - return -rte_errno; > - if (mask.eth->type && mask.eth->type !=3D > - RTE_BE16(0xffff)) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.eth, > - "no support for partial mask on" > - " \"type\" field"); > - assert(items->spec); > - spec.eth =3D items->spec; > - if (mask.eth->type && > - (item_flags & MLX5_FLOW_LAYER_TUNNEL) && > - inner_etype !=3D RTE_BE16(ETH_P_ALL) && > - inner_etype !=3D spec.eth->type) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "inner eth_type conflict"); > - if (mask.eth->type && > - !(item_flags & MLX5_FLOW_LAYER_TUNNEL) && > - outer_etype !=3D RTE_BE16(ETH_P_ALL) && > - outer_etype !=3D spec.eth->type) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "outer eth_type conflict"); > - if (mask.eth->type) { > - if (item_flags & > MLX5_FLOW_LAYER_TUNNEL) > - inner_etype =3D spec.eth->type; > - else > - outer_etype =3D spec.eth->type; > - } > - break; > - case RTE_FLOW_ITEM_TYPE_VLAN: > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM, > items, > - "inner tunnel VLAN" > - " is not supported"); > - ret =3D mlx5_flow_validate_item_vlan(items, > item_flags, > - error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_VLAN; > - mask.vlan =3D flow_tcf_item_mask > - (items, &rte_flow_item_vlan_mask, > - &flow_tcf_mask_supported.vlan, > - &flow_tcf_mask_empty.vlan, > - sizeof(flow_tcf_mask_supported.vlan), > - error); > - if (!mask.vlan) > - return -rte_errno; > - if ((mask.vlan->tci & RTE_BE16(0xe000) && > - (mask.vlan->tci & RTE_BE16(0xe000)) !=3D > - RTE_BE16(0xe000)) || > - (mask.vlan->tci & RTE_BE16(0x0fff) && > - (mask.vlan->tci & RTE_BE16(0x0fff)) !=3D > - RTE_BE16(0x0fff)) || > - (mask.vlan->inner_type && > - mask.vlan->inner_type !=3D RTE_BE16(0xffff))) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.vlan, > - "no support for partial masks on" > - " \"tci\" (PCP and VID parts) and" > - " \"inner_type\" fields"); > - if (outer_etype !=3D RTE_BE16(ETH_P_ALL) && > - outer_etype !=3D RTE_BE16(ETH_P_8021Q)) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "outer eth_type conflict," > - " must be 802.1Q"); > - outer_etype =3D RTE_BE16(ETH_P_8021Q); > - assert(items->spec); > - spec.vlan =3D items->spec; > - if (mask.vlan->inner_type && > - vlan_etype !=3D RTE_BE16(ETH_P_ALL) && > - vlan_etype !=3D spec.vlan->inner_type) > - return rte_flow_error_set > - (error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "vlan eth_type conflict"); > - if (mask.vlan->inner_type) > - vlan_etype =3D spec.vlan->inner_type; > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: > - ret =3D mlx5_flow_validate_item_ipv4 > - (items, item_flags, > - &flow_tcf_mask_supported.ipv4, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L3_IPV4 : > - MLX5_FLOW_LAYER_OUTER_L3_IPV4; > - mask.ipv4 =3D flow_tcf_item_mask > - (items, &rte_flow_item_ipv4_mask, > - &flow_tcf_mask_supported.ipv4, > - &flow_tcf_mask_empty.ipv4, > - sizeof(flow_tcf_mask_supported.ipv4), > - error); > - if (!mask.ipv4) > - return -rte_errno; > - if (mask.ipv4->hdr.next_proto_id && > - mask.ipv4->hdr.next_proto_id !=3D 0xff) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.ipv4, > - "no support for partial mask on" > - " \"hdr.next_proto_id\" field"); > - else if (mask.ipv4->hdr.next_proto_id) > - next_protocol =3D > - ((const struct rte_flow_item_ipv4 *) > - (items->spec))->hdr.next_proto_id; > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) { > - if (inner_etype !=3D RTE_BE16(ETH_P_ALL) && > - inner_etype !=3D RTE_BE16(ETH_P_IP)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "inner eth_type conflict," > - " IPv4 is required"); > - inner_etype =3D RTE_BE16(ETH_P_IP); > - } else if (item_flags & > MLX5_FLOW_LAYER_OUTER_VLAN) { > - if (vlan_etype !=3D RTE_BE16(ETH_P_ALL) && > - vlan_etype !=3D RTE_BE16(ETH_P_IP)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "vlan eth_type conflict," > - " IPv4 is required"); > - vlan_etype =3D RTE_BE16(ETH_P_IP); > - } else { > - if (outer_etype !=3D RTE_BE16(ETH_P_ALL) && > - outer_etype !=3D RTE_BE16(ETH_P_IP)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "eth_type conflict," > - " IPv4 is required"); > - outer_etype =3D RTE_BE16(ETH_P_IP); > - } > - break; > - case RTE_FLOW_ITEM_TYPE_IPV6: > - ret =3D mlx5_flow_validate_item_ipv6 > - (items, item_flags, > - &flow_tcf_mask_supported.ipv6, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L3_IPV6 : > - MLX5_FLOW_LAYER_OUTER_L3_IPV6; > - mask.ipv6 =3D flow_tcf_item_mask > - (items, &rte_flow_item_ipv6_mask, > - &flow_tcf_mask_supported.ipv6, > - &flow_tcf_mask_empty.ipv6, > - sizeof(flow_tcf_mask_supported.ipv6), > - error); > - if (!mask.ipv6) > - return -rte_errno; > - if (mask.ipv6->hdr.proto && > - mask.ipv6->hdr.proto !=3D 0xff) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.ipv6, > - "no support for partial mask on" > - " \"hdr.proto\" field"); > - else if (mask.ipv6->hdr.proto) > - next_protocol =3D > - ((const struct rte_flow_item_ipv6 *) > - (items->spec))->hdr.proto; > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) { > - if (inner_etype !=3D RTE_BE16(ETH_P_ALL) && > - inner_etype !=3D RTE_BE16(ETH_P_IPV6)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "inner eth_type conflict," > - " IPv6 is required"); > - inner_etype =3D RTE_BE16(ETH_P_IPV6); > - } else if (item_flags & > MLX5_FLOW_LAYER_OUTER_VLAN) { > - if (vlan_etype !=3D RTE_BE16(ETH_P_ALL) && > - vlan_etype !=3D RTE_BE16(ETH_P_IPV6)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "vlan eth_type conflict," > - " IPv6 is required"); > - vlan_etype =3D RTE_BE16(ETH_P_IPV6); > - } else { > - if (outer_etype !=3D RTE_BE16(ETH_P_ALL) && > - outer_etype !=3D RTE_BE16(ETH_P_IPV6)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, > - "eth_type conflict," > - " IPv6 is required"); > - outer_etype =3D RTE_BE16(ETH_P_IPV6); > - } > - break; > - case RTE_FLOW_ITEM_TYPE_UDP: > - ret =3D mlx5_flow_validate_item_udp(items, > item_flags, > - next_protocol, > error); > - if (ret < 0) > - return ret; > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L4_UDP : > - MLX5_FLOW_LAYER_OUTER_L4_UDP; > - mask.udp =3D flow_tcf_item_mask > - (items, &rte_flow_item_udp_mask, > - &flow_tcf_mask_supported.udp, > - &flow_tcf_mask_empty.udp, > - sizeof(flow_tcf_mask_supported.udp), > - error); > - if (!mask.udp) > - return -rte_errno; > - /* > - * Save the presumed outer UDP item for extra check > - * if the tunnel item will be found later in the list. > - */ > - if (!(item_flags & MLX5_FLOW_LAYER_TUNNEL)) > - outer_udp =3D items; > - break; > - case RTE_FLOW_ITEM_TYPE_TCP: > - ret =3D mlx5_flow_validate_item_tcp > - (items, item_flags, > - next_protocol, > - &flow_tcf_mask_supported.tcp, > - error); > - if (ret < 0) > - return ret; > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L4_TCP : > - MLX5_FLOW_LAYER_OUTER_L4_TCP; > - mask.tcp =3D flow_tcf_item_mask > - (items, &rte_flow_item_tcp_mask, > - &flow_tcf_mask_supported.tcp, > - &flow_tcf_mask_empty.tcp, > - sizeof(flow_tcf_mask_supported.tcp), > - error); > - if (!mask.tcp) > - return -rte_errno; > - break; > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - if (item_flags & MLX5_FLOW_LAYER_OUTER_VLAN) > - return rte_flow_error_set > - (error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ITEM, > items, > - "vxlan tunnel over vlan" > - " is not supported"); > - ret =3D mlx5_flow_validate_item_vxlan(items, > - item_flags, error); > - if (ret < 0) > - return ret; > - item_flags |=3D MLX5_FLOW_LAYER_VXLAN; > - mask.vxlan =3D flow_tcf_item_mask > - (items, &rte_flow_item_vxlan_mask, > - &flow_tcf_mask_supported.vxlan, > - &flow_tcf_mask_empty.vxlan, > - sizeof(flow_tcf_mask_supported.vxlan), > error); > - if (!mask.vxlan) > - return -rte_errno; > - if (mask.vxlan->vni[0] !=3D 0xff || > - mask.vxlan->vni[1] !=3D 0xff || > - mask.vxlan->vni[2] !=3D 0xff) > - return rte_flow_error_set > - (error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM_MASK, > - mask.vxlan, > - "no support for partial or " > - "empty mask on \"vxlan.vni\" field"); > - /* > - * The VNI item assumes the VXLAN tunnel, it > requires > - * at least the outer destination UDP port must be > - * specified without wildcards to allow kernel select > - * the virtual VXLAN device by port. Also outer IPv4 > - * or IPv6 item must be specified (wilcards or even > - * zero mask are allowed) to let driver know the > tunnel > - * IP version and process UDP traffic correctly. > - */ > - if (!(item_flags & > - (MLX5_FLOW_LAYER_OUTER_L3_IPV4 | > - MLX5_FLOW_LAYER_OUTER_L3_IPV6))) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - NULL, > - "no outer IP pattern found" > - " for vxlan tunnel"); > - if (!(item_flags & > MLX5_FLOW_LAYER_OUTER_L4_UDP)) > - return rte_flow_error_set > - (error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - NULL, > - "no outer UDP pattern > found" > - " for vxlan tunnel"); > - /* > - * All items preceding the tunnel item become outer > - * ones and we should do extra validation for them > - * due to tc limitations for tunnel outer parameters. > - * Currently only outer UDP item requres extra check, > - * use the saved pointer instead of item list rescan. > - */ > - assert(outer_udp); > - ret =3D flow_tcf_validate_vxlan_decap_udp > - (outer_udp, error); > - if (ret < 0) > - return ret; > - /* Reset L4 protocol for inner parameters. */ > - next_protocol =3D 0xff; > - break; > - default: > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - items, "item not > supported"); > - } > - } > - if ((action_flags & MLX5_TCF_PEDIT_ACTIONS) && > - (action_flags & MLX5_FLOW_ACTION_DROP)) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "set action is not compatible with " > - "drop action"); > - if ((action_flags & MLX5_TCF_PEDIT_ACTIONS) && > - !(action_flags & MLX5_FLOW_ACTION_PORT_ID)) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "set action must be followed by " > - "port_id action"); > - if (action_flags & > - (MLX5_FLOW_ACTION_SET_IPV4_SRC | > MLX5_FLOW_ACTION_SET_IPV4_DST)) { > - if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "no ipv4 item found in" > - " pattern"); > - } > - if (action_flags & > - (MLX5_FLOW_ACTION_SET_IPV6_SRC | > MLX5_FLOW_ACTION_SET_IPV6_DST)) { > - if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "no ipv6 item found in" > - " pattern"); > - } > - if (action_flags & > - (MLX5_FLOW_ACTION_SET_TP_SRC | > MLX5_FLOW_ACTION_SET_TP_DST)) { > - if (!(item_flags & > - (MLX5_FLOW_LAYER_OUTER_L4_UDP | > - MLX5_FLOW_LAYER_OUTER_L4_TCP))) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "no TCP/UDP item found in" > - " pattern"); > - } > - /* > - * FW syndrome (0xA9C090): > - * set_flow_table_entry: push vlan action fte in fdb can ONLY be > - * forward to the uplink. > - */ > - if ((action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) && > - (action_flags & MLX5_FLOW_ACTION_PORT_ID) && > - ((struct mlx5_priv *)port_id_dev->data->dev_private)- > >representor) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "vlan push can only be applied" > - " when forwarding to uplink port"); > - /* > - * FW syndrome (0x294609): > - * set_flow_table_entry: modify/pop/push actions in fdb flow > table > - * are supported only while forwarding to vport. > - */ > - if ((action_flags & MLX5_TCF_VLAN_ACTIONS) && > - !(action_flags & MLX5_FLOW_ACTION_PORT_ID)) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "vlan actions are supported" > - " only with port_id action"); > - if ((action_flags & MLX5_TCF_VXLAN_ACTIONS) && > - !(action_flags & MLX5_FLOW_ACTION_PORT_ID)) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ACTION, > NULL, > - "vxlan actions are supported" > - " only with port_id action"); > - if (!(action_flags & MLX5_TCF_FATE_ACTIONS)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > actions, > - "no fate action is found"); > - if (action_flags & > - (MLX5_FLOW_ACTION_SET_TTL | > MLX5_FLOW_ACTION_DEC_TTL)) { > - if (!(item_flags & > - (MLX5_FLOW_LAYER_OUTER_L3_IPV4 | > - MLX5_FLOW_LAYER_OUTER_L3_IPV6))) > - return rte_flow_error_set(error, EINVAL, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "no IP found in pattern"); > - } > - if (action_flags & > - (MLX5_FLOW_ACTION_SET_MAC_SRC | > MLX5_FLOW_ACTION_SET_MAC_DST)) { > - if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L2)) > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "no ethernet found in" > - " pattern"); > - } > - if ((action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) && > - !(item_flags & MLX5_FLOW_LAYER_VXLAN)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > - NULL, > - "no VNI pattern found" > - " for vxlan decap action"); > - if ((action_flags & MLX5_FLOW_ACTION_VXLAN_ENCAP) && > - (item_flags & MLX5_FLOW_LAYER_TUNNEL)) > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > - NULL, > - "vxlan encap not supported" > - " for tunneled traffic"); > - return 0; > -} > - > -/** > - * Calculate maximum size of memory for flow items of Linux TC flower. > - * > - * @param[in] attr > - * Pointer to the flow attributes. > - * @param[in] items > - * Pointer to the list of items. > - * @param[out] action_flags > - * Pointer to the detected actions. > - * > - * @return > - * Maximum size of memory for items. > - */ > -static int > -flow_tcf_get_items_size(const struct rte_flow_attr *attr, > - const struct rte_flow_item items[], > - uint64_t *action_flags) > -{ > - int size =3D 0; > - > - size +=3D SZ_NLATTR_STRZ_OF("flower") + > - SZ_NLATTR_TYPE_OF(uint16_t) + /* Outer ether type. */ > - SZ_NLATTR_NEST + /* TCA_OPTIONS. */ > - SZ_NLATTR_TYPE_OF(uint32_t); /* > TCA_CLS_FLAGS_SKIP_SW. */ > - if (attr->group > 0) > - size +=3D SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CHAIN. */ > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_PORT_ID: > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - size +=3D > SZ_NLATTR_DATA_OF(RTE_ETHER_ADDR_LEN) * 4; > - /* dst/src MAC addr and mask. */ > - break; > - case RTE_FLOW_ITEM_TYPE_VLAN: > - size +=3D SZ_NLATTR_TYPE_OF(uint16_t) + > - /* VLAN Ether type. */ > - SZ_NLATTR_TYPE_OF(uint8_t) + /* VLAN > prio. */ > - SZ_NLATTR_TYPE_OF(uint16_t); /* VLAN ID. > */ > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: { > - const struct rte_flow_item_ipv4 *ipv4 =3D items- > >mask; > - > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. > */ > - SZ_NLATTR_TYPE_OF(uint32_t) * 4; > - /* dst/src IP addr and mask. */ > - if (ipv4 && ipv4->hdr.time_to_live) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - if (ipv4 && ipv4->hdr.type_of_service) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - break; > - } > - case RTE_FLOW_ITEM_TYPE_IPV6: { > - const struct rte_flow_item_ipv6 *ipv6 =3D items- > >mask; > - > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. > */ > - SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) * 4; > - /* dst/src IP addr and mask. */ > - if (ipv6 && ipv6->hdr.hop_limits) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - if (ipv6 && (rte_be_to_cpu_32(ipv6->hdr.vtc_flow) & > - (0xfful << RTE_IPV6_HDR_TC_SHIFT))) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - break; > - } > - case RTE_FLOW_ITEM_TYPE_UDP: > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. > */ > - SZ_NLATTR_TYPE_OF(uint16_t) * 4; > - /* dst/src port and mask. */ > - break; > - case RTE_FLOW_ITEM_TYPE_TCP: > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. > */ > - SZ_NLATTR_TYPE_OF(uint16_t) * 4; > - /* dst/src port and mask. */ > - break; > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - size +=3D SZ_NLATTR_TYPE_OF(uint32_t); > - /* > - * There might be no VXLAN decap action in the > action > - * list, nonetheless the VXLAN tunnel flow requires > - * the decap structure to be correctly applied to > - * VXLAN device, set the flag to create the structure. > - * Translation routine will not put the decap action > - * in tne Netlink message if there is no actual action > - * in the list. > - */ > - *action_flags |=3D > MLX5_FLOW_ACTION_VXLAN_DECAP; > - break; > - default: > - DRV_LOG(WARNING, > - "unsupported item %p type %d," > - " items must be validated before flow > creation", > - (const void *)items, items->type); > - break; > - } > - } > - return size; > -} > - > -/** > - * Calculate size of memory to store the VXLAN encapsultion > - * related items in the Netlink message buffer. Items list > - * is specified by RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP action. > - * The item list should be validated. > - * > - * @param[in] action > - * RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP action object. > - * List of pattern items to scan data from. > - * > - * @return > - * The size the part of Netlink message buffer to store the > - * VXLAN encapsulation item attributes. > - */ > -static int > -flow_tcf_vxlan_encap_size(const struct rte_flow_action *action) > -{ > - const struct rte_flow_item *items; > - int size =3D 0; > - > - assert(action->type =3D=3D RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP); > - assert(action->conf); > - > - items =3D ((const struct rte_flow_action_vxlan_encap *) > - action->conf)->definition; > - assert(items); > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - /* This item does not require message buffer. */ > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: { > - const struct rte_flow_item_ipv4 *ipv4 =3D items- > >mask; > - > - size +=3D SZ_NLATTR_DATA_OF(IPV4_ADDR_LEN) * 2; > - if (ipv4 && ipv4->hdr.time_to_live) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - if (ipv4 && ipv4->hdr.type_of_service) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - break; > - } > - case RTE_FLOW_ITEM_TYPE_IPV6: { > - const struct rte_flow_item_ipv6 *ipv6 =3D items- > >mask; > - > - size +=3D SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) * 2; > - if (ipv6 && ipv6->hdr.hop_limits) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - if (ipv6 && (rte_be_to_cpu_32(ipv6->hdr.vtc_flow) & > - (0xfful << RTE_IPV6_HDR_TC_SHIFT))) > - size +=3D SZ_NLATTR_TYPE_OF(uint8_t) * 2; > - break; > - } > - case RTE_FLOW_ITEM_TYPE_UDP: { > - const struct rte_flow_item_udp *udp =3D items->mask; > - > - size +=3D SZ_NLATTR_TYPE_OF(uint16_t); > - if (!udp || udp->hdr.src_port !=3D RTE_BE16(0x0000)) > - size +=3D SZ_NLATTR_TYPE_OF(uint16_t); > - break; > - } > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - size +=3D SZ_NLATTR_TYPE_OF(uint32_t); > - break; > - default: > - assert(false); > - DRV_LOG(WARNING, > - "unsupported item %p type %d," > - " items must be validated" > - " before flow creation", > - (const void *)items, items->type); > - return 0; > - } > - } > - return size; > -} > - > -/** > - * Calculate maximum size of memory for flow actions of Linux TC flower > and > - * extract specified actions. > - * > - * @param[in] actions > - * Pointer to the list of actions. > - * @param[out] action_flags > - * Pointer to the detected actions. > - * > - * @return > - * Maximum size of memory for actions. > - */ > -static int > -flow_tcf_get_actions_and_size(const struct rte_flow_action actions[], > - uint64_t *action_flags) > -{ > - int size =3D 0; > - uint64_t flags =3D *action_flags; > - > - size +=3D SZ_NLATTR_NEST; /* TCA_FLOWER_ACT. */ > - for (; actions->type !=3D RTE_FLOW_ACTION_TYPE_END; actions++) { > - switch (actions->type) { > - case RTE_FLOW_ACTION_TYPE_VOID: > - break; > - case RTE_FLOW_ACTION_TYPE_PORT_ID: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("mirred") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(struct tc_mirred); > - flags |=3D MLX5_FLOW_ACTION_PORT_ID; > - break; > - case RTE_FLOW_ACTION_TYPE_JUMP: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("gact") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(struct tc_gact); > - flags |=3D MLX5_FLOW_ACTION_JUMP; > - break; > - case RTE_FLOW_ACTION_TYPE_DROP: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("gact") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(struct tc_gact); > - flags |=3D MLX5_FLOW_ACTION_DROP; > - break; > - case RTE_FLOW_ACTION_TYPE_COUNT: > - break; > - case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: > - flags |=3D MLX5_FLOW_ACTION_OF_POP_VLAN; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: > - flags |=3D MLX5_FLOW_ACTION_OF_PUSH_VLAN; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: > - flags |=3D MLX5_FLOW_ACTION_OF_SET_VLAN_VID; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: > - flags |=3D MLX5_FLOW_ACTION_OF_SET_VLAN_PCP; > - goto action_of_vlan; > -action_of_vlan: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("vlan") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(struct tc_vlan) + > - SZ_NLATTR_TYPE_OF(uint16_t) + > - /* VLAN protocol. */ > - SZ_NLATTR_TYPE_OF(uint16_t) + /* VLAN ID. > */ > - SZ_NLATTR_TYPE_OF(uint8_t); /* VLAN prio. > */ > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("tunnel_key") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(uint8_t); > - size +=3D SZ_NLATTR_TYPE_OF(struct tc_tunnel_key); > - size +=3D flow_tcf_vxlan_encap_size(actions) + > - RTE_ALIGN_CEIL /* preceding encap params. > */ > - (sizeof(struct flow_tcf_vxlan_encap), > - MNL_ALIGNTO); > - flags |=3D MLX5_FLOW_ACTION_VXLAN_ENCAP; > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: > - size +=3D SZ_NLATTR_NEST + /* na_act_index. */ > - SZ_NLATTR_STRZ_OF("tunnel_key") + > - SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. > */ > - SZ_NLATTR_TYPE_OF(uint8_t); > - size +=3D SZ_NLATTR_TYPE_OF(struct tc_tunnel_key); > - size +=3D RTE_ALIGN_CEIL /* preceding decap params. > */ > - (sizeof(struct flow_tcf_vxlan_decap), > - MNL_ALIGNTO); > - flags |=3D MLX5_FLOW_ACTION_VXLAN_DECAP; > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: > - case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_TP_DST: > - case RTE_FLOW_ACTION_TYPE_SET_TTL: > - case RTE_FLOW_ACTION_TYPE_DEC_TTL: > - case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > - size +=3D flow_tcf_get_pedit_actions_size(&actions, > - &flags); > - break; > - default: > - DRV_LOG(WARNING, > - "unsupported action %p type %d," > - " items must be validated before flow > creation", > - (const void *)actions, actions->type); > - break; > - } > - } > - *action_flags =3D flags; > - return size; > -} > - > -/** > - * Prepare a flow object for Linux TC flower. It calculates the maximum = size > of > - * memory required, allocates the memory, initializes Netlink message > headers > - * and set unique TC message handle. > - * > - * @param[in] attr > - * Pointer to the flow attributes. > - * @param[in] items > - * Pointer to the list of items. > - * @param[in] actions > - * Pointer to the list of actions. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * Pointer to mlx5_flow object on success, > - * otherwise NULL and rte_errno is set. > - */ > -static struct mlx5_flow * > -flow_tcf_prepare(const struct rte_flow_attr *attr, > - const struct rte_flow_item items[], > - const struct rte_flow_action actions[], > - struct rte_flow_error *error) > -{ > - size_t size =3D RTE_ALIGN_CEIL > - (sizeof(struct mlx5_flow), > - alignof(struct flow_tcf_tunnel_hdr)) + > - MNL_ALIGN(sizeof(struct nlmsghdr)) + > - MNL_ALIGN(sizeof(struct tcmsg)); > - struct mlx5_flow *dev_flow; > - uint64_t action_flags =3D 0; > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - uint8_t *sp, *tun =3D NULL; > - > - size +=3D flow_tcf_get_items_size(attr, items, &action_flags); > - size +=3D flow_tcf_get_actions_and_size(actions, &action_flags); > - dev_flow =3D rte_zmalloc(__func__, size, MNL_ALIGNTO); > - if (!dev_flow) { > - rte_flow_error_set(error, ENOMEM, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "not enough memory to create E-Switch > flow"); > - return NULL; > - } > - sp =3D (uint8_t *)(dev_flow + 1); > - if (action_flags & MLX5_FLOW_ACTION_VXLAN_ENCAP) { > - sp =3D RTE_PTR_ALIGN > - (sp, alignof(struct flow_tcf_tunnel_hdr)); > - tun =3D sp; > - sp +=3D RTE_ALIGN_CEIL > - (sizeof(struct flow_tcf_vxlan_encap), > - MNL_ALIGNTO); > -#ifndef NDEBUG > - size -=3D RTE_ALIGN_CEIL > - (sizeof(struct flow_tcf_vxlan_encap), > - MNL_ALIGNTO); > -#endif > - } else if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) { > - sp =3D RTE_PTR_ALIGN > - (sp, alignof(struct flow_tcf_tunnel_hdr)); > - tun =3D sp; > - sp +=3D RTE_ALIGN_CEIL > - (sizeof(struct flow_tcf_vxlan_decap), > - MNL_ALIGNTO); > -#ifndef NDEBUG > - size -=3D RTE_ALIGN_CEIL > - (sizeof(struct flow_tcf_vxlan_decap), > - MNL_ALIGNTO); > -#endif > - } else { > - sp =3D RTE_PTR_ALIGN(sp, MNL_ALIGNTO); > - } > - nlh =3D mnl_nlmsg_put_header(sp); > - tcm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm)); > - *dev_flow =3D (struct mlx5_flow){ > - .tcf =3D (struct mlx5_flow_tcf){ > -#ifndef NDEBUG > - .nlsize =3D size - RTE_ALIGN_CEIL > - (sizeof(struct mlx5_flow), > - alignof(struct flow_tcf_tunnel_hdr)), > -#endif > - .tunnel =3D (struct flow_tcf_tunnel_hdr *)tun, > - .nlh =3D nlh, > - .tcm =3D tcm, > - }, > - }; > - if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) > - dev_flow->tcf.tunnel->type =3D > FLOW_TCF_TUNACT_VXLAN_DECAP; > - else if (action_flags & MLX5_FLOW_ACTION_VXLAN_ENCAP) > - dev_flow->tcf.tunnel->type =3D > FLOW_TCF_TUNACT_VXLAN_ENCAP; > - return dev_flow; > -} > - > -/** > - * Make adjustments for supporting count actions. > - * > - * @param[in] dev > - * Pointer to the Ethernet device structure. > - * @param[in] dev_flow > - * Pointer to mlx5_flow. > - * @param[out] error > - * Pointer to error structure. > - * > - * @return > - * 0 On success else a negative errno value is returned and rte_errno = is set. > - */ > -static int > -flow_tcf_translate_action_count(struct rte_eth_dev *dev __rte_unused, > - struct mlx5_flow *dev_flow, > - struct rte_flow_error *error) > -{ > - struct rte_flow *flow =3D dev_flow->flow; > - > - if (!flow->counter) { > - flow->counter =3D flow_tcf_counter_new(); > - if (!flow->counter) > - return rte_flow_error_set(error, rte_errno, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - NULL, > - "cannot get counter" > - " context."); > - } > - return 0; > -} > - > -/** > - * Convert VXLAN VNI to 32-bit integer. > - * > - * @param[in] vni > - * VXLAN VNI in 24-bit wire format. > - * > - * @return > - * VXLAN VNI as a 32-bit integer value in network endianness. > - */ > -static inline rte_be32_t > -vxlan_vni_as_be32(const uint8_t vni[3]) > -{ > - union { > - uint8_t vni[4]; > - rte_be32_t dword; > - } ret =3D { > - .vni =3D { 0, vni[0], vni[1], vni[2] }, > - }; > - return ret.dword; > -} > - > -/** > - * Helper function to process RTE_FLOW_ITEM_TYPE_ETH entry in > configuration > - * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the MAC > address fields > - * in the encapsulation parameters structure. The item must be prevalida= ted, > - * no any validation checks performed by function. > - * > - * @param[in] spec > - * RTE_FLOW_ITEM_TYPE_ETH entry specification. > - * @param[in] mask > - * RTE_FLOW_ITEM_TYPE_ETH entry mask. > - * @param[out] encap > - * Structure to fill the gathered MAC address data. > - */ > -static void > -flow_tcf_parse_vxlan_encap_eth(const struct rte_flow_item_eth *spec, > - const struct rte_flow_item_eth *mask, > - struct flow_tcf_vxlan_encap *encap) > -{ > - /* Item must be validated before. No redundant checks. */ > - assert(spec); > - if (!mask || !memcmp(&mask->dst, > - &rte_flow_item_eth_mask.dst, > - sizeof(rte_flow_item_eth_mask.dst))) { > - /* > - * Ethernet addresses are not supported by > - * tc as tunnel_key parameters. Destination > - * address is needed to form encap packet > - * header and retrieved by kernel from > - * implicit sources (ARP table, etc), > - * address masks are not supported at all. > - */ > - encap->eth.dst =3D spec->dst; > - encap->mask |=3D FLOW_TCF_ENCAP_ETH_DST; > - } > - if (!mask || !memcmp(&mask->src, > - &rte_flow_item_eth_mask.src, > - sizeof(rte_flow_item_eth_mask.src))) { > - /* > - * Ethernet addresses are not supported by > - * tc as tunnel_key parameters. Source ethernet > - * address is ignored anyway. > - */ > - encap->eth.src =3D spec->src; > - encap->mask |=3D FLOW_TCF_ENCAP_ETH_SRC; > - } > -} > - > -/** > - * Helper function to process RTE_FLOW_ITEM_TYPE_IPV4 entry in > configuration > - * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the IPV4 > address fields > - * in the encapsulation parameters structure. The item must be prevalida= ted, > - * no any validation checks performed by function. > - * > - * @param[in] spec > - * RTE_FLOW_ITEM_TYPE_IPV4 entry specification. > - * @param[in] mask > - * RTE_FLOW_ITEM_TYPE_IPV4 entry mask. > - * @param[out] encap > - * Structure to fill the gathered IPV4 address data. > - */ > -static void > -flow_tcf_parse_vxlan_encap_ipv4(const struct rte_flow_item_ipv4 *spec, > - const struct rte_flow_item_ipv4 *mask, > - struct flow_tcf_vxlan_encap *encap) > -{ > - /* Item must be validated before. No redundant checks. */ > - assert(spec); > - encap->ipv4.dst =3D spec->hdr.dst_addr; > - encap->ipv4.src =3D spec->hdr.src_addr; > - encap->mask |=3D FLOW_TCF_ENCAP_IPV4_SRC | > - FLOW_TCF_ENCAP_IPV4_DST; > - if (mask && mask->hdr.type_of_service) { > - encap->mask |=3D FLOW_TCF_ENCAP_IP_TOS; > - encap->ip_tos =3D spec->hdr.type_of_service; > - } > - if (mask && mask->hdr.time_to_live) { > - encap->mask |=3D FLOW_TCF_ENCAP_IP_TTL; > - encap->ip_ttl_hop =3D spec->hdr.time_to_live; > - } > -} > - > -/** > - * Helper function to process RTE_FLOW_ITEM_TYPE_IPV6 entry in > configuration > - * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the IPV6 > address fields > - * in the encapsulation parameters structure. The item must be prevalida= ted, > - * no any validation checks performed by function. > - * > - * @param[in] spec > - * RTE_FLOW_ITEM_TYPE_IPV6 entry specification. > - * @param[in] mask > - * RTE_FLOW_ITEM_TYPE_IPV6 entry mask. > - * @param[out] encap > - * Structure to fill the gathered IPV6 address data. > - */ > -static void > -flow_tcf_parse_vxlan_encap_ipv6(const struct rte_flow_item_ipv6 *spec, > - const struct rte_flow_item_ipv6 *mask, > - struct flow_tcf_vxlan_encap *encap) > -{ > - /* Item must be validated before. No redundant checks. */ > - assert(spec); > - memcpy(encap->ipv6.dst, spec->hdr.dst_addr, IPV6_ADDR_LEN); > - memcpy(encap->ipv6.src, spec->hdr.src_addr, IPV6_ADDR_LEN); > - encap->mask |=3D FLOW_TCF_ENCAP_IPV6_SRC | > - FLOW_TCF_ENCAP_IPV6_DST; > - if (mask) { > - if ((rte_be_to_cpu_32(mask->hdr.vtc_flow) >> > - RTE_IPV6_HDR_TC_SHIFT) & 0xff) { > - encap->mask |=3D FLOW_TCF_ENCAP_IP_TOS; > - encap->ip_tos =3D (rte_be_to_cpu_32 > - (spec->hdr.vtc_flow) >> > - RTE_IPV6_HDR_TC_SHIFT) & > 0xff; > - } > - if (mask->hdr.hop_limits) { > - encap->mask |=3D FLOW_TCF_ENCAP_IP_TTL; > - encap->ip_ttl_hop =3D spec->hdr.hop_limits; > - } > - } > -} > - > -/** > - * Helper function to process RTE_FLOW_ITEM_TYPE_UDP entry in > configuration > - * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the UDP port > fields > - * in the encapsulation parameters structure. The item must be prevalida= ted, > - * no any validation checks performed by function. > - * > - * @param[in] spec > - * RTE_FLOW_ITEM_TYPE_UDP entry specification. > - * @param[in] mask > - * RTE_FLOW_ITEM_TYPE_UDP entry mask. > - * @param[out] encap > - * Structure to fill the gathered UDP port data. > - */ > -static void > -flow_tcf_parse_vxlan_encap_udp(const struct rte_flow_item_udp *spec, > - const struct rte_flow_item_udp *mask, > - struct flow_tcf_vxlan_encap *encap) > -{ > - assert(spec); > - encap->udp.dst =3D spec->hdr.dst_port; > - encap->mask |=3D FLOW_TCF_ENCAP_UDP_DST; > - if (!mask || mask->hdr.src_port !=3D RTE_BE16(0x0000)) { > - encap->udp.src =3D spec->hdr.src_port; > - encap->mask |=3D FLOW_TCF_ENCAP_IPV4_SRC; > - } > -} > - > -/** > - * Helper function to process RTE_FLOW_ITEM_TYPE_VXLAN entry in > configuration > - * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the VNI fields > - * in the encapsulation parameters structure. The item must be prevalida= ted, > - * no any validation checks performed by function. > - * > - * @param[in] spec > - * RTE_FLOW_ITEM_TYPE_VXLAN entry specification. > - * @param[out] encap > - * Structure to fill the gathered VNI address data. > - */ > -static void > -flow_tcf_parse_vxlan_encap_vni(const struct rte_flow_item_vxlan *spec, > - struct flow_tcf_vxlan_encap *encap) > -{ > - /* Item must be validated before. Do not redundant checks. */ > - assert(spec); > - memcpy(encap->vxlan.vni, spec->vni, sizeof(encap->vxlan.vni)); > - encap->mask |=3D FLOW_TCF_ENCAP_VXLAN_VNI; > -} > - > -/** > - * Populate consolidated encapsulation object from list of pattern items= . > - * > - * Helper function to process configuration of action such as > - * RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. The item list should be > - * validated, there is no way to return an meaningful error. > - * > - * @param[in] action > - * RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP action object. > - * List of pattern items to gather data from. > - * @param[out] src > - * Structure to fill gathered data. > - */ > -static void > -flow_tcf_vxlan_encap_parse(const struct rte_flow_action *action, > - struct flow_tcf_vxlan_encap *encap) > -{ > - union { > - const struct rte_flow_item_eth *eth; > - const struct rte_flow_item_ipv4 *ipv4; > - const struct rte_flow_item_ipv6 *ipv6; > - const struct rte_flow_item_udp *udp; > - const struct rte_flow_item_vxlan *vxlan; > - } spec, mask; > - const struct rte_flow_item *items; > - > - assert(action->type =3D=3D RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP); > - assert(action->conf); > - > - items =3D ((const struct rte_flow_action_vxlan_encap *) > - action->conf)->definition; > - assert(items); > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - mask.eth =3D items->mask; > - spec.eth =3D items->spec; > - flow_tcf_parse_vxlan_encap_eth(spec.eth, > mask.eth, > - encap); > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: > - spec.ipv4 =3D items->spec; > - mask.ipv4 =3D items->mask; > - flow_tcf_parse_vxlan_encap_ipv4(spec.ipv4, > mask.ipv4, > - encap); > - break; > - case RTE_FLOW_ITEM_TYPE_IPV6: > - spec.ipv6 =3D items->spec; > - mask.ipv6 =3D items->mask; > - flow_tcf_parse_vxlan_encap_ipv6(spec.ipv6, > mask.ipv6, > - encap); > - break; > - case RTE_FLOW_ITEM_TYPE_UDP: > - mask.udp =3D items->mask; > - spec.udp =3D items->spec; > - flow_tcf_parse_vxlan_encap_udp(spec.udp, > mask.udp, > - encap); > - break; > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - spec.vxlan =3D items->spec; > - flow_tcf_parse_vxlan_encap_vni(spec.vxlan, encap); > - break; > - default: > - assert(false); > - DRV_LOG(WARNING, > - "unsupported item %p type %d," > - " items must be validated" > - " before flow creation", > - (const void *)items, items->type); > - encap->mask =3D 0; > - return; > - } > - } > -} > - > -/** > - * Translate flow for Linux TC flower and construct Netlink message. > - * > - * @param[in] priv > - * Pointer to the priv structure. > - * @param[in, out] flow > - * Pointer to the sub flow. > - * @param[in] attr > - * Pointer to the flow attributes. > - * @param[in] items > - * Pointer to the list of items. > - * @param[in] actions > - * Pointer to the list of actions. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_translate(struct rte_eth_dev *dev, struct mlx5_flow *dev_flow, > - const struct rte_flow_attr *attr, > - const struct rte_flow_item items[], > - const struct rte_flow_action actions[], > - struct rte_flow_error *error) > -{ > - union { > - const struct rte_flow_item_port_id *port_id; > - const struct rte_flow_item_eth *eth; > - const struct rte_flow_item_vlan *vlan; > - const struct rte_flow_item_ipv4 *ipv4; > - const struct rte_flow_item_ipv6 *ipv6; > - const struct rte_flow_item_tcp *tcp; > - const struct rte_flow_item_udp *udp; > - const struct rte_flow_item_vxlan *vxlan; > - } spec, mask; > - union { > - const struct rte_flow_action_port_id *port_id; > - const struct rte_flow_action_jump *jump; > - const struct rte_flow_action_of_push_vlan *of_push_vlan; > - const struct rte_flow_action_of_set_vlan_vid * > - of_set_vlan_vid; > - const struct rte_flow_action_of_set_vlan_pcp * > - of_set_vlan_pcp; > - } conf; > - union { > - struct flow_tcf_tunnel_hdr *hdr; > - struct flow_tcf_vxlan_decap *vxlan; > - } decap =3D { > - .hdr =3D NULL, > - }; > - union { > - struct flow_tcf_tunnel_hdr *hdr; > - struct flow_tcf_vxlan_encap *vxlan; > - } encap =3D { > - .hdr =3D NULL, > - }; > - struct flow_tcf_ptoi ptoi[PTOI_TABLE_SZ_MAX(dev)]; > - struct nlmsghdr *nlh =3D dev_flow->tcf.nlh; > - struct tcmsg *tcm =3D dev_flow->tcf.tcm; > - uint32_t na_act_index_cur; > - rte_be16_t inner_etype =3D RTE_BE16(ETH_P_ALL); > - rte_be16_t outer_etype =3D RTE_BE16(ETH_P_ALL); > - rte_be16_t vlan_etype =3D RTE_BE16(ETH_P_ALL); > - bool ip_proto_set =3D 0; > - bool tunnel_outer =3D 0; > - struct nlattr *na_flower; > - struct nlattr *na_flower_act; > - struct nlattr *na_vlan_id =3D NULL; > - struct nlattr *na_vlan_priority =3D NULL; > - uint64_t item_flags =3D 0; > - int ret; > - > - claim_nonzero(flow_tcf_build_ptoi_table(dev, ptoi, > - PTOI_TABLE_SZ_MAX(dev))); > - if (dev_flow->tcf.tunnel) { > - switch (dev_flow->tcf.tunnel->type) { > - case FLOW_TCF_TUNACT_VXLAN_DECAP: > - decap.vxlan =3D dev_flow->tcf.vxlan_decap; > - tunnel_outer =3D 1; > - break; > - case FLOW_TCF_TUNACT_VXLAN_ENCAP: > - encap.vxlan =3D dev_flow->tcf.vxlan_encap; > - break; > - /* New tunnel actions can be added here. */ > - default: > - assert(false); > - break; > - } > - } > - nlh =3D dev_flow->tcf.nlh; > - tcm =3D dev_flow->tcf.tcm; > - /* Prepare API must have been called beforehand. */ > - assert(nlh !=3D NULL && tcm !=3D NULL); > - tcm->tcm_family =3D AF_UNSPEC; > - tcm->tcm_ifindex =3D ptoi[0].ifindex; > - tcm->tcm_parent =3D TC_H_MAKE(TC_H_INGRESS, > TC_H_MIN_INGRESS); > - /* > - * Priority cannot be zero to prevent the kernel from picking one > - * automatically. > - */ > - tcm->tcm_info =3D TC_H_MAKE((attr->priority + 1) << 16, > outer_etype); > - if (attr->group > 0) > - mnl_attr_put_u32(nlh, TCA_CHAIN, attr->group); > - mnl_attr_put_strz(nlh, TCA_KIND, "flower"); > - na_flower =3D mnl_attr_nest_start(nlh, TCA_OPTIONS); > - for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > - unsigned int i; > - > - switch (items->type) { > - case RTE_FLOW_ITEM_TYPE_VOID: > - break; > - case RTE_FLOW_ITEM_TYPE_PORT_ID: > - mask.port_id =3D flow_tcf_item_mask > - (items, &rte_flow_item_port_id_mask, > - &flow_tcf_mask_supported.port_id, > - &flow_tcf_mask_empty.port_id, > - sizeof(flow_tcf_mask_supported.port_id), > - error); > - assert(mask.port_id); > - if (mask.port_id =3D=3D &flow_tcf_mask_empty.port_id) > - break; > - spec.port_id =3D items->spec; > - if (!mask.port_id->id) > - i =3D 0; > - else > - for (i =3D 0; ptoi[i].ifindex; ++i) > - if (ptoi[i].port_id =3D=3D spec.port_id->id) > - break; > - assert(ptoi[i].ifindex); > - tcm->tcm_ifindex =3D ptoi[i].ifindex; > - break; > - case RTE_FLOW_ITEM_TYPE_ETH: > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L2 : > - MLX5_FLOW_LAYER_OUTER_L2; > - mask.eth =3D flow_tcf_item_mask > - (items, &rte_flow_item_eth_mask, > - &flow_tcf_mask_supported.eth, > - &flow_tcf_mask_empty.eth, > - sizeof(flow_tcf_mask_supported.eth), > - error); > - assert(mask.eth); > - if (mask.eth =3D=3D &flow_tcf_mask_empty.eth) > - break; > - spec.eth =3D items->spec; > - if (mask.eth->type) { > - if (item_flags & > MLX5_FLOW_LAYER_TUNNEL) > - inner_etype =3D spec.eth->type; > - else > - outer_etype =3D spec.eth->type; > - } > - if (tunnel_outer) { > - DRV_LOG(WARNING, > - "outer L2 addresses cannot be" > - " forced is outer ones for tunnel," > - " parameter is ignored"); > - break; > - } > - if (!rte_is_zero_ether_addr(&mask.eth->dst)) { > - mnl_attr_put(nlh, > TCA_FLOWER_KEY_ETH_DST, > - RTE_ETHER_ADDR_LEN, > - spec.eth->dst.addr_bytes); > - mnl_attr_put(nlh, > TCA_FLOWER_KEY_ETH_DST_MASK, > - RTE_ETHER_ADDR_LEN, > - mask.eth->dst.addr_bytes); > - } > - if (!rte_is_zero_ether_addr(&mask.eth->src)) { > - mnl_attr_put(nlh, > TCA_FLOWER_KEY_ETH_SRC, > - RTE_ETHER_ADDR_LEN, > - spec.eth->src.addr_bytes); > - mnl_attr_put(nlh, > TCA_FLOWER_KEY_ETH_SRC_MASK, > - RTE_ETHER_ADDR_LEN, > - mask.eth->src.addr_bytes); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ITEM_TYPE_VLAN: > - assert(!encap.hdr); > - assert(!decap.hdr); > - assert(!tunnel_outer); > - item_flags |=3D MLX5_FLOW_LAYER_OUTER_VLAN; > - mask.vlan =3D flow_tcf_item_mask > - (items, &rte_flow_item_vlan_mask, > - &flow_tcf_mask_supported.vlan, > - &flow_tcf_mask_empty.vlan, > - sizeof(flow_tcf_mask_supported.vlan), > - error); > - assert(mask.vlan); > - if (mask.vlan =3D=3D &flow_tcf_mask_empty.vlan) > - break; > - spec.vlan =3D items->spec; > - assert(outer_etype =3D=3D RTE_BE16(ETH_P_ALL) || > - outer_etype =3D=3D RTE_BE16(ETH_P_8021Q)); > - outer_etype =3D RTE_BE16(ETH_P_8021Q); > - if (mask.vlan->inner_type) > - vlan_etype =3D spec.vlan->inner_type; > - if (mask.vlan->tci & RTE_BE16(0xe000)) > - mnl_attr_put_u8(nlh, > TCA_FLOWER_KEY_VLAN_PRIO, > - (rte_be_to_cpu_16 > - (spec.vlan->tci) >> 13) & > 0x7); > - if (mask.vlan->tci & RTE_BE16(0x0fff)) > - mnl_attr_put_u16(nlh, > TCA_FLOWER_KEY_VLAN_ID, > - rte_be_to_cpu_16 > - (spec.vlan->tci & > - RTE_BE16(0x0fff))); > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ITEM_TYPE_IPV4: > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L3_IPV4 : > - MLX5_FLOW_LAYER_OUTER_L3_IPV4; > - mask.ipv4 =3D flow_tcf_item_mask > - (items, &rte_flow_item_ipv4_mask, > - &flow_tcf_mask_supported.ipv4, > - &flow_tcf_mask_empty.ipv4, > - sizeof(flow_tcf_mask_supported.ipv4), > - error); > - assert(mask.ipv4); > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) { > - assert(inner_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - inner_etype =3D=3D RTE_BE16(ETH_P_IP)); > - inner_etype =3D RTE_BE16(ETH_P_IP); > - } else if (outer_etype =3D=3D RTE_BE16(ETH_P_8021Q)) { > - assert(vlan_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - vlan_etype =3D=3D RTE_BE16(ETH_P_IP)); > - vlan_etype =3D RTE_BE16(ETH_P_IP); > - } else { > - assert(outer_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - outer_etype =3D=3D RTE_BE16(ETH_P_IP)); > - outer_etype =3D RTE_BE16(ETH_P_IP); > - } > - spec.ipv4 =3D items->spec; > - if (!tunnel_outer && mask.ipv4->hdr.next_proto_id) { > - /* > - * No way to set IP protocol for outer tunnel > - * layers. Usually it is fixed, for example, > - * to UDP for VXLAN/GPE. > - */ > - assert(spec.ipv4); /* Mask is not empty. */ > - mnl_attr_put_u8(nlh, > TCA_FLOWER_KEY_IP_PROTO, > - spec.ipv4- > >hdr.next_proto_id); > - ip_proto_set =3D 1; > - } > - if (mask.ipv4 =3D=3D &flow_tcf_mask_empty.ipv4 || > - (!mask.ipv4->hdr.src_addr && > - !mask.ipv4->hdr.dst_addr)) { > - if (!tunnel_outer) > - break; > - /* > - * For tunnel outer we must set outer IP key > - * anyway, even if the specification/mask is > - * empty. There is no another way to tell > - * kernel about he outer layer protocol. > - */ > - mnl_attr_put_u32 > - (nlh, > TCA_FLOWER_KEY_ENC_IPV4_SRC, > - mask.ipv4->hdr.src_addr); > - mnl_attr_put_u32 > - (nlh, > TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, > - mask.ipv4->hdr.src_addr); > - assert(dev_flow->tcf.nlsize >=3D nlh- > >nlmsg_len); > - break; > - } > - if (mask.ipv4->hdr.src_addr) { > - mnl_attr_put_u32 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IPV4_SRC : > - TCA_FLOWER_KEY_IPV4_SRC, > - spec.ipv4->hdr.src_addr); > - mnl_attr_put_u32 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK : > - > TCA_FLOWER_KEY_IPV4_SRC_MASK, > - mask.ipv4->hdr.src_addr); > - } > - if (mask.ipv4->hdr.dst_addr) { > - mnl_attr_put_u32 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IPV4_DST : > - TCA_FLOWER_KEY_IPV4_DST, > - spec.ipv4->hdr.dst_addr); > - mnl_attr_put_u32 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV4_DST_MASK : > - > TCA_FLOWER_KEY_IPV4_DST_MASK, > - mask.ipv4->hdr.dst_addr); > - } > - if (mask.ipv4->hdr.time_to_live) { > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IP_TTL : > - TCA_FLOWER_KEY_IP_TTL, > - spec.ipv4->hdr.time_to_live); > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IP_TTL_MASK : > - TCA_FLOWER_KEY_IP_TTL_MASK, > - mask.ipv4->hdr.time_to_live); > - } > - if (mask.ipv4->hdr.type_of_service) { > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IP_TOS : > - TCA_FLOWER_KEY_IP_TOS, > - spec.ipv4->hdr.type_of_service); > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IP_TOS_MASK : > - TCA_FLOWER_KEY_IP_TOS_MASK, > - mask.ipv4->hdr.type_of_service); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ITEM_TYPE_IPV6: { > - bool ipv6_src, ipv6_dst; > - uint8_t msk6, tos6; > - > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L3_IPV6 : > - MLX5_FLOW_LAYER_OUTER_L3_IPV6; > - mask.ipv6 =3D flow_tcf_item_mask > - (items, &rte_flow_item_ipv6_mask, > - &flow_tcf_mask_supported.ipv6, > - &flow_tcf_mask_empty.ipv6, > - sizeof(flow_tcf_mask_supported.ipv6), > - error); > - assert(mask.ipv6); > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) { > - assert(inner_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - inner_etype =3D=3D RTE_BE16(ETH_P_IPV6)); > - inner_etype =3D RTE_BE16(ETH_P_IPV6); > - } else if (outer_etype =3D=3D RTE_BE16(ETH_P_8021Q)) { > - assert(vlan_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - vlan_etype =3D=3D RTE_BE16(ETH_P_IPV6)); > - vlan_etype =3D RTE_BE16(ETH_P_IPV6); > - } else { > - assert(outer_etype =3D=3D RTE_BE16(ETH_P_ALL) > || > - outer_etype =3D=3D RTE_BE16(ETH_P_IPV6)); > - outer_etype =3D RTE_BE16(ETH_P_IPV6); > - } > - spec.ipv6 =3D items->spec; > - if (!tunnel_outer && mask.ipv6->hdr.proto) { > - /* > - * No way to set IP protocol for outer tunnel > - * layers. Usually it is fixed, for example, > - * to UDP for VXLAN/GPE. > - */ > - assert(spec.ipv6); /* Mask is not empty. */ > - mnl_attr_put_u8(nlh, > TCA_FLOWER_KEY_IP_PROTO, > - spec.ipv6->hdr.proto); > - ip_proto_set =3D 1; > - } > - ipv6_dst =3D !IN6_IS_ADDR_UNSPECIFIED > - (mask.ipv6->hdr.dst_addr); > - ipv6_src =3D !IN6_IS_ADDR_UNSPECIFIED > - (mask.ipv6->hdr.src_addr); > - if (mask.ipv6 =3D=3D &flow_tcf_mask_empty.ipv6 || > - (!ipv6_dst && !ipv6_src)) { > - if (!tunnel_outer) > - break; > - /* > - * For tunnel outer we must set outer IP key > - * anyway, even if the specification/mask is > - * empty. There is no another way to tell > - * kernel about he outer layer protocol. > - */ > - mnl_attr_put(nlh, > - > TCA_FLOWER_KEY_ENC_IPV6_SRC, > - IPV6_ADDR_LEN, > - mask.ipv6->hdr.src_addr); > - mnl_attr_put(nlh, > - > TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, > - IPV6_ADDR_LEN, > - mask.ipv6->hdr.src_addr); > - assert(dev_flow->tcf.nlsize >=3D nlh- > >nlmsg_len); > - break; > - } > - if (ipv6_src) { > - mnl_attr_put(nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV6_SRC : > - TCA_FLOWER_KEY_IPV6_SRC, > - IPV6_ADDR_LEN, > - spec.ipv6->hdr.src_addr); > - mnl_attr_put(nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK : > - > TCA_FLOWER_KEY_IPV6_SRC_MASK, > - IPV6_ADDR_LEN, > - mask.ipv6->hdr.src_addr); > - } > - if (ipv6_dst) { > - mnl_attr_put(nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV6_DST : > - TCA_FLOWER_KEY_IPV6_DST, > - IPV6_ADDR_LEN, > - spec.ipv6->hdr.dst_addr); > - mnl_attr_put(nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IPV6_DST_MASK : > - > TCA_FLOWER_KEY_IPV6_DST_MASK, > - IPV6_ADDR_LEN, > - mask.ipv6->hdr.dst_addr); > - } > - if (mask.ipv6->hdr.hop_limits) { > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IP_TTL : > - TCA_FLOWER_KEY_IP_TTL, > - spec.ipv6->hdr.hop_limits); > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IP_TTL_MASK : > - TCA_FLOWER_KEY_IP_TTL_MASK, > - mask.ipv6->hdr.hop_limits); > - } > - msk6 =3D (rte_be_to_cpu_32(mask.ipv6->hdr.vtc_flow) > >> > - RTE_IPV6_HDR_TC_SHIFT) & 0xff; > - if (msk6) { > - tos6 =3D (rte_be_to_cpu_32 > - (spec.ipv6->hdr.vtc_flow) >> > - RTE_IPV6_HDR_TC_SHIFT) & > 0xff; > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - TCA_FLOWER_KEY_ENC_IP_TOS : > - TCA_FLOWER_KEY_IP_TOS, tos6); > - mnl_attr_put_u8 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_IP_TOS_MASK : > - TCA_FLOWER_KEY_IP_TOS_MASK, > msk6); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - } > - case RTE_FLOW_ITEM_TYPE_UDP: > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L4_UDP : > - MLX5_FLOW_LAYER_OUTER_L4_UDP; > - mask.udp =3D flow_tcf_item_mask > - (items, &rte_flow_item_udp_mask, > - &flow_tcf_mask_supported.udp, > - &flow_tcf_mask_empty.udp, > - sizeof(flow_tcf_mask_supported.udp), > - error); > - assert(mask.udp); > - spec.udp =3D items->spec; > - if (!tunnel_outer) { > - if (!ip_proto_set) > - mnl_attr_put_u8 > - (nlh, > TCA_FLOWER_KEY_IP_PROTO, > - IPPROTO_UDP); > - if (mask.udp =3D=3D &flow_tcf_mask_empty.udp) > - break; > - } else { > - assert(mask.udp !=3D > &flow_tcf_mask_empty.udp); > - decap.vxlan->udp_port =3D > - rte_be_to_cpu_16 > - (spec.udp->hdr.dst_port); > - } > - if (mask.udp->hdr.src_port) { > - mnl_attr_put_u16 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_UDP_SRC_PORT : > - TCA_FLOWER_KEY_UDP_SRC, > - spec.udp->hdr.src_port); > - mnl_attr_put_u16 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK : > - > TCA_FLOWER_KEY_UDP_SRC_MASK, > - mask.udp->hdr.src_port); > - } > - if (mask.udp->hdr.dst_port) { > - mnl_attr_put_u16 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_UDP_DST_PORT : > - TCA_FLOWER_KEY_UDP_DST, > - spec.udp->hdr.dst_port); > - mnl_attr_put_u16 > - (nlh, tunnel_outer ? > - > TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK : > - > TCA_FLOWER_KEY_UDP_DST_MASK, > - mask.udp->hdr.dst_port); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ITEM_TYPE_TCP: > - item_flags |=3D (item_flags & > MLX5_FLOW_LAYER_TUNNEL) ? > - MLX5_FLOW_LAYER_INNER_L4_TCP : > - MLX5_FLOW_LAYER_OUTER_L4_TCP; > - mask.tcp =3D flow_tcf_item_mask > - (items, &rte_flow_item_tcp_mask, > - &flow_tcf_mask_supported.tcp, > - &flow_tcf_mask_empty.tcp, > - sizeof(flow_tcf_mask_supported.tcp), > - error); > - assert(mask.tcp); > - if (!ip_proto_set) > - mnl_attr_put_u8(nlh, > TCA_FLOWER_KEY_IP_PROTO, > - IPPROTO_TCP); > - if (mask.tcp =3D=3D &flow_tcf_mask_empty.tcp) > - break; > - spec.tcp =3D items->spec; > - if (mask.tcp->hdr.src_port) { > - mnl_attr_put_u16(nlh, > TCA_FLOWER_KEY_TCP_SRC, > - spec.tcp->hdr.src_port); > - mnl_attr_put_u16(nlh, > - > TCA_FLOWER_KEY_TCP_SRC_MASK, > - mask.tcp->hdr.src_port); > - } > - if (mask.tcp->hdr.dst_port) { > - mnl_attr_put_u16(nlh, > TCA_FLOWER_KEY_TCP_DST, > - spec.tcp->hdr.dst_port); > - mnl_attr_put_u16(nlh, > - > TCA_FLOWER_KEY_TCP_DST_MASK, > - mask.tcp->hdr.dst_port); > - } > - if (mask.tcp->hdr.tcp_flags) { > - mnl_attr_put_u16 > - (nlh, > - TCA_FLOWER_KEY_TCP_FLAGS, > - rte_cpu_to_be_16 > - (spec.tcp->hdr.tcp_flags)); > - mnl_attr_put_u16 > - (nlh, > - > TCA_FLOWER_KEY_TCP_FLAGS_MASK, > - rte_cpu_to_be_16 > - (mask.tcp->hdr.tcp_flags)); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ITEM_TYPE_VXLAN: > - assert(decap.vxlan); > - tunnel_outer =3D 0; > - item_flags |=3D MLX5_FLOW_LAYER_VXLAN; > - spec.vxlan =3D items->spec; > - mnl_attr_put_u32(nlh, > - TCA_FLOWER_KEY_ENC_KEY_ID, > - vxlan_vni_as_be32(spec.vxlan- > >vni)); > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - default: > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ITEM, > - NULL, "item not > supported"); > - } > - } > - /* > - * Set the ether_type flower key and tc rule protocol: > - * - if there is nor VLAN neither VXLAN the key is taken from > - * eth item directly or deduced from L3 items. > - * - if there is vlan item then key is fixed to 802.1q. > - * - if there is vxlan item then key is set to inner tunnel type. > - * - simultaneous vlan and vxlan items are prohibited. > - */ > - if (outer_etype !=3D RTE_BE16(ETH_P_ALL)) { > - tcm->tcm_info =3D TC_H_MAKE((attr->priority + 1) << 16, > - outer_etype); > - if (item_flags & MLX5_FLOW_LAYER_TUNNEL) { > - if (inner_etype !=3D RTE_BE16(ETH_P_ALL)) > - mnl_attr_put_u16(nlh, > - > TCA_FLOWER_KEY_ETH_TYPE, > - inner_etype); > - } else { > - mnl_attr_put_u16(nlh, > - TCA_FLOWER_KEY_ETH_TYPE, > - outer_etype); > - if (outer_etype =3D=3D RTE_BE16(ETH_P_8021Q) && > - vlan_etype !=3D RTE_BE16(ETH_P_ALL)) > - mnl_attr_put_u16(nlh, > - > TCA_FLOWER_KEY_VLAN_ETH_TYPE, > - vlan_etype); > - } > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - } > - na_flower_act =3D mnl_attr_nest_start(nlh, TCA_FLOWER_ACT); > - na_act_index_cur =3D 1; > - for (; actions->type !=3D RTE_FLOW_ACTION_TYPE_END; actions++) { > - struct nlattr *na_act_index; > - struct nlattr *na_act; > - unsigned int vlan_act; > - unsigned int i; > - > - switch (actions->type) { > - case RTE_FLOW_ACTION_TYPE_VOID: > - break; > - case RTE_FLOW_ACTION_TYPE_PORT_ID: > - conf.port_id =3D actions->conf; > - if (conf.port_id->original) > - i =3D 0; > - else > - for (i =3D 0; ptoi[i].ifindex; ++i) > - if (ptoi[i].port_id =3D=3D conf.port_id->id) > - break; > - assert(ptoi[i].ifindex); > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, "mirred"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - if (encap.hdr) { > - assert(dev_flow->tcf.tunnel); > - dev_flow->tcf.tunnel->ifindex_ptr =3D > - &((struct tc_mirred *) > - mnl_attr_get_payload > - (mnl_nlmsg_get_payload_tail > - (nlh)))->ifindex; > - } else if (decap.hdr) { > - assert(dev_flow->tcf.tunnel); > - dev_flow->tcf.tunnel->ifindex_ptr =3D > - (unsigned int *)&tcm->tcm_ifindex; > - } > - mnl_attr_put(nlh, TCA_MIRRED_PARMS, > - sizeof(struct tc_mirred), > - &(struct tc_mirred){ > - .action =3D TC_ACT_STOLEN, > - .eaction =3D TCA_EGRESS_REDIR, > - .ifindex =3D ptoi[i].ifindex, > - }); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - break; > - case RTE_FLOW_ACTION_TYPE_JUMP: > - conf.jump =3D actions->conf; > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, "gact"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - mnl_attr_put(nlh, TCA_GACT_PARMS, > - sizeof(struct tc_gact), > - &(struct tc_gact){ > - .action =3D TC_ACT_GOTO_CHAIN | > - conf.jump->group, > - }); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - break; > - case RTE_FLOW_ACTION_TYPE_DROP: > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, "gact"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - mnl_attr_put(nlh, TCA_GACT_PARMS, > - sizeof(struct tc_gact), > - &(struct tc_gact){ > - .action =3D TC_ACT_SHOT, > - }); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - break; > - case RTE_FLOW_ACTION_TYPE_COUNT: > - /* > - * Driver adds the count action implicitly for > - * each rule it creates. > - */ > - ret =3D flow_tcf_translate_action_count(dev, > - dev_flow, error); > - if (ret < 0) > - return ret; > - break; > - case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: > - conf.of_push_vlan =3D NULL; > - vlan_act =3D TCA_VLAN_ACT_POP; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: > - conf.of_push_vlan =3D actions->conf; > - vlan_act =3D TCA_VLAN_ACT_PUSH; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: > - conf.of_set_vlan_vid =3D actions->conf; > - if (na_vlan_id) > - goto override_na_vlan_id; > - vlan_act =3D TCA_VLAN_ACT_MODIFY; > - goto action_of_vlan; > - case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: > - conf.of_set_vlan_pcp =3D actions->conf; > - if (na_vlan_priority) > - goto override_na_vlan_priority; > - vlan_act =3D TCA_VLAN_ACT_MODIFY; > - goto action_of_vlan; > -action_of_vlan: > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, "vlan"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - mnl_attr_put(nlh, TCA_VLAN_PARMS, > - sizeof(struct tc_vlan), > - &(struct tc_vlan){ > - .action =3D TC_ACT_PIPE, > - .v_action =3D vlan_act, > - }); > - if (vlan_act =3D=3D TCA_VLAN_ACT_POP) { > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - break; > - } > - if (vlan_act =3D=3D TCA_VLAN_ACT_PUSH) > - mnl_attr_put_u16(nlh, > - > TCA_VLAN_PUSH_VLAN_PROTOCOL, > - conf.of_push_vlan- > >ethertype); > - na_vlan_id =3D mnl_nlmsg_get_payload_tail(nlh); > - mnl_attr_put_u16(nlh, TCA_VLAN_PAD, 0); > - na_vlan_priority =3D mnl_nlmsg_get_payload_tail(nlh); > - mnl_attr_put_u8(nlh, TCA_VLAN_PAD, 0); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - if (actions->type =3D=3D > - RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) { > -override_na_vlan_id: > - na_vlan_id->nla_type =3D > TCA_VLAN_PUSH_VLAN_ID; > - *(uint16_t > *)mnl_attr_get_payload(na_vlan_id) =3D > - rte_be_to_cpu_16 > - (conf.of_set_vlan_vid->vlan_vid); > - } else if (actions->type =3D=3D > - > RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) { > -override_na_vlan_priority: > - na_vlan_priority->nla_type =3D > - TCA_VLAN_PUSH_VLAN_PRIORITY; > - *(uint8_t *)mnl_attr_get_payload > - (na_vlan_priority) =3D > - conf.of_set_vlan_pcp->vlan_pcp; > - } > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: > - assert(decap.vxlan); > - assert(dev_flow->tcf.tunnel); > - dev_flow->tcf.tunnel->ifindex_ptr =3D > - (unsigned int *)&tcm->tcm_ifindex; > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, > "tunnel_key"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - mnl_attr_put(nlh, TCA_TUNNEL_KEY_PARMS, > - sizeof(struct tc_tunnel_key), > - &(struct tc_tunnel_key){ > - .action =3D TC_ACT_PIPE, > - .t_action =3D > TCA_TUNNEL_KEY_ACT_RELEASE, > - }); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: > - assert(encap.vxlan); > - flow_tcf_vxlan_encap_parse(actions, encap.vxlan); > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - assert(na_act_index); > - mnl_attr_put_strz(nlh, TCA_ACT_KIND, > "tunnel_key"); > - na_act =3D mnl_attr_nest_start(nlh, > TCA_ACT_OPTIONS); > - assert(na_act); > - mnl_attr_put(nlh, TCA_TUNNEL_KEY_PARMS, > - sizeof(struct tc_tunnel_key), > - &(struct tc_tunnel_key){ > - .action =3D TC_ACT_PIPE, > - .t_action =3D > TCA_TUNNEL_KEY_ACT_SET, > - }); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_UDP_DST) > - mnl_attr_put_u16(nlh, > - TCA_TUNNEL_KEY_ENC_DST_PORT, > - encap.vxlan->udp.dst); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_IPV4_SRC) > - mnl_attr_put_u32(nlh, > - TCA_TUNNEL_KEY_ENC_IPV4_SRC, > - encap.vxlan->ipv4.src); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_IPV4_DST) > - mnl_attr_put_u32(nlh, > - TCA_TUNNEL_KEY_ENC_IPV4_DST, > - encap.vxlan->ipv4.dst); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_IPV6_SRC) > - mnl_attr_put(nlh, > - TCA_TUNNEL_KEY_ENC_IPV6_SRC, > - sizeof(encap.vxlan->ipv6.src), > - &encap.vxlan->ipv6.src); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_IPV6_DST) > - mnl_attr_put(nlh, > - TCA_TUNNEL_KEY_ENC_IPV6_DST, > - sizeof(encap.vxlan->ipv6.dst), > - &encap.vxlan->ipv6.dst); > - if (encap.vxlan->mask & FLOW_TCF_ENCAP_IP_TTL) > - mnl_attr_put_u8(nlh, > - TCA_TUNNEL_KEY_ENC_TTL, > - encap.vxlan->ip_ttl_hop); > - if (encap.vxlan->mask & FLOW_TCF_ENCAP_IP_TOS) > - mnl_attr_put_u8(nlh, > - TCA_TUNNEL_KEY_ENC_TOS, > - encap.vxlan->ip_tos); > - if (encap.vxlan->mask & > FLOW_TCF_ENCAP_VXLAN_VNI) > - mnl_attr_put_u32(nlh, > - TCA_TUNNEL_KEY_ENC_KEY_ID, > - vxlan_vni_as_be32 > - (encap.vxlan->vxlan.vni)); > - mnl_attr_put_u8(nlh, TCA_TUNNEL_KEY_NO_CSUM, > 0); > - mnl_attr_nest_end(nlh, na_act); > - mnl_attr_nest_end(nlh, na_act_index); > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - break; > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: > - case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_TP_DST: > - case RTE_FLOW_ACTION_TYPE_SET_TTL: > - case RTE_FLOW_ACTION_TYPE_DEC_TTL: > - case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: > - case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: > - na_act_index =3D > - mnl_attr_nest_start(nlh, > na_act_index_cur++); > - flow_tcf_create_pedit_mnl_msg(nlh, > - &actions, item_flags); > - mnl_attr_nest_end(nlh, na_act_index); > - break; > - default: > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "action not supported"); > - } > - } > - assert(na_flower); > - assert(na_flower_act); > - mnl_attr_nest_end(nlh, na_flower_act); > - dev_flow->tcf.ptc_flags =3D mnl_attr_get_payload > - (mnl_nlmsg_get_payload_tail(nlh)); > - mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, decap.vxlan ? > - 0 : > TCA_CLS_FLAGS_SKIP_SW); > - mnl_attr_nest_end(nlh, na_flower); > - if (dev_flow->tcf.tunnel && dev_flow->tcf.tunnel->ifindex_ptr) > - dev_flow->tcf.tunnel->ifindex_org =3D > - *dev_flow->tcf.tunnel->ifindex_ptr; > - assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > - return 0; > -} > - > -/** > - * Send Netlink message with acknowledgment. > - * > - * @param tcf > - * Flow context to use. > - * @param nlh > - * Message to send. This function always raises the NLM_F_ACK flag > before > - * sending. > - * @param[in] cb > - * Callback handler for received message. > - * @param[in] arg > - * Context pointer for callback handler. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_nl_ack(struct mlx5_flow_tcf_context *tcf, > - struct nlmsghdr *nlh, > - mnl_cb_t cb, void *arg) > -{ > - unsigned int portid =3D mnl_socket_get_portid(tcf->nl); > - uint32_t seq =3D tcf->seq++; > - int ret, err =3D 0; > - > - assert(tcf->nl); > - assert(tcf->buf); > - if (!seq) { > - /* seq 0 is reserved for kernel event-driven notifications. */ > - seq =3D tcf->seq++; > - } > - nlh->nlmsg_seq =3D seq; > - nlh->nlmsg_flags |=3D NLM_F_ACK; > - ret =3D mnl_socket_sendto(tcf->nl, nlh, nlh->nlmsg_len); > - if (ret <=3D 0) { > - /* Message send error occurred. */ > - rte_errno =3D errno; > - return -rte_errno; > - } > - nlh =3D (struct nlmsghdr *)(tcf->buf); > - /* > - * The following loop postpones non-fatal errors until multipart > - * messages are complete. > - */ > - while (true) { > - ret =3D mnl_socket_recvfrom(tcf->nl, tcf->buf, tcf->buf_size); > - if (ret < 0) { > - err =3D errno; > - /* > - * In case of overflow Will receive till > - * end of multipart message. We may lost part > - * of reply messages but mark and return an error. > - */ > - if (err !=3D ENOSPC || > - !(nlh->nlmsg_flags & NLM_F_MULTI) || > - nlh->nlmsg_type =3D=3D NLMSG_DONE) > - break; > - } else { > - ret =3D mnl_cb_run(nlh, ret, seq, portid, cb, arg); > - if (!ret) { > - /* > - * libmnl returns 0 if DONE or > - * success ACK message found. > - */ > - break; > - } > - if (ret < 0) { > - /* > - * ACK message with error found > - * or some error occurred. > - */ > - err =3D errno; > - break; > - } > - /* We should continue receiving. */ > - } > - } > - if (!err) > - return 0; > - rte_errno =3D err; > - return -err; > -} > - > -#define MNL_BUF_EXTRA_SPACE 16 > -#define MNL_REQUEST_SIZE_MIN 256 > -#define MNL_REQUEST_SIZE_MAX 2048 > -#define MNL_REQUEST_SIZE RTE_MIN(RTE_MAX(sysconf(_SC_PAGESIZE), \ > - MNL_REQUEST_SIZE_MIN), > MNL_REQUEST_SIZE_MAX) > - > -/* Data structures used by flow_tcf_xxx_cb() routines. */ > -struct tcf_nlcb_buf { > - LIST_ENTRY(tcf_nlcb_buf) next; > - uint32_t size; > - alignas(struct nlmsghdr) > - uint8_t msg[]; /**< Netlink message data. */ > -}; > - > -struct tcf_nlcb_context { > - unsigned int ifindex; /**< Base interface index. */ > - uint32_t bufsize; > - LIST_HEAD(, tcf_nlcb_buf) nlbuf; > -}; > - > -/** > - * Allocate space for netlink command in buffer list > - * > - * @param[in, out] ctx > - * Pointer to callback context with command buffers list. > - * @param[in] size > - * Required size of data buffer to be allocated. > - * > - * @return > - * Pointer to allocated memory, aligned as message header. > - * NULL if some error occurred. > - */ > -static struct nlmsghdr * > -flow_tcf_alloc_nlcmd(struct tcf_nlcb_context *ctx, uint32_t size) > -{ > - struct tcf_nlcb_buf *buf; > - struct nlmsghdr *nlh; > - > - size =3D NLMSG_ALIGN(size); > - buf =3D LIST_FIRST(&ctx->nlbuf); > - if (buf && (buf->size + size) <=3D ctx->bufsize) { > - nlh =3D (struct nlmsghdr *)&buf->msg[buf->size]; > - buf->size +=3D size; > - return nlh; > - } > - if (size > ctx->bufsize) { > - DRV_LOG(WARNING, "netlink: too long command buffer > requested"); > - return NULL; > - } > - buf =3D rte_malloc(__func__, > - ctx->bufsize + sizeof(struct tcf_nlcb_buf), > - alignof(struct tcf_nlcb_buf)); > - if (!buf) { > - DRV_LOG(WARNING, "netlink: no memory for command > buffer"); > - return NULL; > - } > - LIST_INSERT_HEAD(&ctx->nlbuf, buf, next); > - buf->size =3D size; > - nlh =3D (struct nlmsghdr *)&buf->msg[0]; > - return nlh; > -} > - > -/** > - * Send the buffers with prepared netlink commands. Scans the list and > - * sends all found buffers. Buffers are sent and freed anyway in order > - * to prevent memory leakage if some every message in received packet. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in, out] ctx > - * Pointer to callback context with command buffers list. > - * > - * @return > - * Zero value on success, negative errno value otherwise > - * and rte_errno is set. > - */ > -static int > -flow_tcf_send_nlcmd(struct mlx5_flow_tcf_context *tcf, > - struct tcf_nlcb_context *ctx) > -{ > - struct tcf_nlcb_buf *bc =3D LIST_FIRST(&ctx->nlbuf); > - int ret =3D 0; > - > - while (bc) { > - struct tcf_nlcb_buf *bn =3D LIST_NEXT(bc, next); > - struct nlmsghdr *nlh; > - uint32_t msg =3D 0; > - int rc; > - > - while (msg < bc->size) { > - /* > - * Send Netlink commands from buffer in one by one > - * fashion. If we send multiple rule deletion > commands > - * in one Netlink message and some error occurs it > may > - * cause multiple ACK error messages and break > sequence > - * numbers of Netlink communication, because we > expect > - * the only one ACK reply. > - */ > - assert((bc->size - msg) >=3D sizeof(struct nlmsghdr)); > - nlh =3D (struct nlmsghdr *)&bc->msg[msg]; > - assert((bc->size - msg) >=3D nlh->nlmsg_len); > - msg +=3D nlh->nlmsg_len; > - rc =3D flow_tcf_nl_ack(tcf, nlh, NULL, NULL); > - if (rc) { > - DRV_LOG(WARNING, > - "netlink: cleanup error %d", rc); > - if (!ret) > - ret =3D rc; > - } > - } > - rte_free(bc); > - bc =3D bn; > - } > - LIST_INIT(&ctx->nlbuf); > - return ret; > -} > - > -/** > - * Collect local IP address rules with scope link attribute on specifie= d > - * network device. This is callback routine called by libmnl mnl_cb_run(= ) > - * in loop for every message in received packet. > - * > - * @param[in] nlh > - * Pointer to reply header. > - * @param[in, out] arg > - * Opaque data pointer for this callback. > - * > - * @return > - * A positive, nonzero value on success, negative errno value otherwis= e > - * and rte_errno is set. > - */ > -static int > -flow_tcf_collect_local_cb(const struct nlmsghdr *nlh, void *arg) > -{ > - struct tcf_nlcb_context *ctx =3D arg; > - struct nlmsghdr *cmd; > - struct ifaddrmsg *ifa; > - struct nlattr *na; > - struct nlattr *na_local =3D NULL; > - struct nlattr *na_peer =3D NULL; > - unsigned char family; > - uint32_t size; > - > - if (nlh->nlmsg_type !=3D RTM_NEWADDR) { > - rte_errno =3D EINVAL; > - return -rte_errno; > - } > - ifa =3D mnl_nlmsg_get_payload(nlh); > - family =3D ifa->ifa_family; > - if (ifa->ifa_index !=3D ctx->ifindex || > - ifa->ifa_scope !=3D RT_SCOPE_LINK || > - !(ifa->ifa_flags & IFA_F_PERMANENT) || > - (family !=3D AF_INET && family !=3D AF_INET6)) > - return 1; > - mnl_attr_for_each(na, nlh, sizeof(*ifa)) { > - switch (mnl_attr_get_type(na)) { > - case IFA_LOCAL: > - na_local =3D na; > - break; > - case IFA_ADDRESS: > - na_peer =3D na; > - break; > - } > - if (na_local && na_peer) > - break; > - } > - if (!na_local || !na_peer) > - return 1; > - /* Local rule found with scope link, permanent and assigned peer. */ > - size =3D MNL_ALIGN(sizeof(struct nlmsghdr)) + > - MNL_ALIGN(sizeof(struct ifaddrmsg)) + > - (family =3D=3D AF_INET6 ? 2 * > SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) > - : 2 * SZ_NLATTR_TYPE_OF(uint32_t)); > - cmd =3D flow_tcf_alloc_nlcmd(ctx, size); > - if (!cmd) { > - rte_errno =3D ENOMEM; > - return -rte_errno; > - } > - cmd =3D mnl_nlmsg_put_header(cmd); > - cmd->nlmsg_type =3D RTM_DELADDR; > - cmd->nlmsg_flags =3D NLM_F_REQUEST; > - ifa =3D mnl_nlmsg_put_extra_header(cmd, sizeof(*ifa)); > - ifa->ifa_flags =3D IFA_F_PERMANENT; > - ifa->ifa_scope =3D RT_SCOPE_LINK; > - ifa->ifa_index =3D ctx->ifindex; > - if (family =3D=3D AF_INET) { > - ifa->ifa_family =3D AF_INET; > - ifa->ifa_prefixlen =3D 32; > - mnl_attr_put_u32(cmd, IFA_LOCAL, > mnl_attr_get_u32(na_local)); > - mnl_attr_put_u32(cmd, IFA_ADDRESS, > mnl_attr_get_u32(na_peer)); > - } else { > - ifa->ifa_family =3D AF_INET6; > - ifa->ifa_prefixlen =3D 128; > - mnl_attr_put(cmd, IFA_LOCAL, IPV6_ADDR_LEN, > - mnl_attr_get_payload(na_local)); > - mnl_attr_put(cmd, IFA_ADDRESS, IPV6_ADDR_LEN, > - mnl_attr_get_payload(na_peer)); > - } > - assert(size =3D=3D cmd->nlmsg_len); > - return 1; > -} > - > -/** > - * Cleanup the local IP addresses on outer interface. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifindex > - * Network interface index to perform cleanup. > - */ > -static void > -flow_tcf_encap_local_cleanup(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifindex) > -{ > - struct nlmsghdr *nlh; > - struct ifaddrmsg *ifa; > - struct tcf_nlcb_context ctx =3D { > - .ifindex =3D ifindex, > - .bufsize =3D MNL_REQUEST_SIZE, > - .nlbuf =3D LIST_HEAD_INITIALIZER(), > - }; > - int ret; > - > - assert(ifindex); > - /* > - * Seek and destroy leftovers of local IP addresses with > - * matching properties "scope link". > - */ > - nlh =3D mnl_nlmsg_put_header(tcf->buf); > - nlh->nlmsg_type =3D RTM_GETADDR; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_DUMP; > - ifa =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifa)); > - ifa->ifa_family =3D AF_UNSPEC; > - ifa->ifa_index =3D ifindex; > - ifa->ifa_scope =3D RT_SCOPE_LINK; > - ret =3D flow_tcf_nl_ack(tcf, nlh, flow_tcf_collect_local_cb, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: query device list error %d", > ret); > - ret =3D flow_tcf_send_nlcmd(tcf, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: device delete error %d", ret); > -} > - > -/** > - * Collect neigh permanent rules on specified network device. > - * This is callback routine called by libmnl mnl_cb_run() in loop for > - * every message in received packet. > - * > - * @param[in] nlh > - * Pointer to reply header. > - * @param[in, out] arg > - * Opaque data pointer for this callback. > - * > - * @return > - * A positive, nonzero value on success, negative errno value otherwis= e > - * and rte_errno is set. > - */ > -static int > -flow_tcf_collect_neigh_cb(const struct nlmsghdr *nlh, void *arg) > -{ > - struct tcf_nlcb_context *ctx =3D arg; > - struct nlmsghdr *cmd; > - struct ndmsg *ndm; > - struct nlattr *na; > - struct nlattr *na_ip =3D NULL; > - struct nlattr *na_mac =3D NULL; > - unsigned char family; > - uint32_t size; > - > - if (nlh->nlmsg_type !=3D RTM_NEWNEIGH) { > - rte_errno =3D EINVAL; > - return -rte_errno; > - } > - ndm =3D mnl_nlmsg_get_payload(nlh); > - family =3D ndm->ndm_family; > - if (ndm->ndm_ifindex !=3D (int)ctx->ifindex || > - !(ndm->ndm_state & NUD_PERMANENT) || > - (family !=3D AF_INET && family !=3D AF_INET6)) > - return 1; > - mnl_attr_for_each(na, nlh, sizeof(*ndm)) { > - switch (mnl_attr_get_type(na)) { > - case NDA_DST: > - na_ip =3D na; > - break; > - case NDA_LLADDR: > - na_mac =3D na; > - break; > - } > - if (na_mac && na_ip) > - break; > - } > - if (!na_mac || !na_ip) > - return 1; > - /* Neigh rule with permanent attribute found. */ > - size =3D MNL_ALIGN(sizeof(struct nlmsghdr)) + > - MNL_ALIGN(sizeof(struct ndmsg)) + > - SZ_NLATTR_DATA_OF(RTE_ETHER_ADDR_LEN) + > - (family =3D=3D AF_INET6 ? SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) > - : SZ_NLATTR_TYPE_OF(uint32_t)); > - cmd =3D flow_tcf_alloc_nlcmd(ctx, size); > - if (!cmd) { > - rte_errno =3D ENOMEM; > - return -rte_errno; > - } > - cmd =3D mnl_nlmsg_put_header(cmd); > - cmd->nlmsg_type =3D RTM_DELNEIGH; > - cmd->nlmsg_flags =3D NLM_F_REQUEST; > - ndm =3D mnl_nlmsg_put_extra_header(cmd, sizeof(*ndm)); > - ndm->ndm_ifindex =3D ctx->ifindex; > - ndm->ndm_state =3D NUD_PERMANENT; > - ndm->ndm_flags =3D 0; > - ndm->ndm_type =3D 0; > - if (family =3D=3D AF_INET) { > - ndm->ndm_family =3D AF_INET; > - mnl_attr_put_u32(cmd, NDA_DST, > mnl_attr_get_u32(na_ip)); > - } else { > - ndm->ndm_family =3D AF_INET6; > - mnl_attr_put(cmd, NDA_DST, IPV6_ADDR_LEN, > - mnl_attr_get_payload(na_ip)); > - } > - mnl_attr_put(cmd, NDA_LLADDR, RTE_ETHER_ADDR_LEN, > - mnl_attr_get_payload(na_mac)); > - assert(size =3D=3D cmd->nlmsg_len); > - return 1; > -} > - > -/** > - * Cleanup the neigh rules on outer interface. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifindex > - * Network interface index to perform cleanup. > - */ > -static void > -flow_tcf_encap_neigh_cleanup(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifindex) > -{ > - struct nlmsghdr *nlh; > - struct ndmsg *ndm; > - struct tcf_nlcb_context ctx =3D { > - .ifindex =3D ifindex, > - .bufsize =3D MNL_REQUEST_SIZE, > - .nlbuf =3D LIST_HEAD_INITIALIZER(), > - }; > - int ret; > - > - assert(ifindex); > - /* Seek and destroy leftovers of neigh rules. */ > - nlh =3D mnl_nlmsg_put_header(tcf->buf); > - nlh->nlmsg_type =3D RTM_GETNEIGH; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_DUMP; > - ndm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ndm)); > - ndm->ndm_family =3D AF_UNSPEC; > - ndm->ndm_ifindex =3D ifindex; > - ndm->ndm_state =3D NUD_PERMANENT; > - ret =3D flow_tcf_nl_ack(tcf, nlh, flow_tcf_collect_neigh_cb, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: query device list error %d", > ret); > - ret =3D flow_tcf_send_nlcmd(tcf, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: device delete error %d", ret); > -} > - > -/** > - * Collect indices of VXLAN encap/decap interfaces associated with devic= e. > - * This is callback routine called by libmnl mnl_cb_run() in loop for > - * every message in received packet. > - * > - * @param[in] nlh > - * Pointer to reply header. > - * @param[in, out] arg > - * Opaque data pointer for this callback. > - * > - * @return > - * A positive, nonzero value on success, negative errno value otherwis= e > - * and rte_errno is set. > - */ > -static int > -flow_tcf_collect_vxlan_cb(const struct nlmsghdr *nlh, void *arg) > -{ > - struct tcf_nlcb_context *ctx =3D arg; > - struct nlmsghdr *cmd; > - struct ifinfomsg *ifm; > - struct nlattr *na; > - struct nlattr *na_info =3D NULL; > - struct nlattr *na_vxlan =3D NULL; > - bool found =3D false; > - unsigned int vxindex; > - uint32_t size; > - > - if (nlh->nlmsg_type !=3D RTM_NEWLINK) { > - rte_errno =3D EINVAL; > - return -rte_errno; > - } > - ifm =3D mnl_nlmsg_get_payload(nlh); > - if (!ifm->ifi_index) { > - rte_errno =3D EINVAL; > - return -rte_errno; > - } > - mnl_attr_for_each(na, nlh, sizeof(*ifm)) > - if (mnl_attr_get_type(na) =3D=3D IFLA_LINKINFO) { > - na_info =3D na; > - break; > - } > - if (!na_info) > - return 1; > - mnl_attr_for_each_nested(na, na_info) { > - switch (mnl_attr_get_type(na)) { > - case IFLA_INFO_KIND: > - if (!strncmp("vxlan", mnl_attr_get_str(na), > - mnl_attr_get_len(na))) > - found =3D true; > - break; > - case IFLA_INFO_DATA: > - na_vxlan =3D na; > - break; > - } > - if (found && na_vxlan) > - break; > - } > - if (!found || !na_vxlan) > - return 1; > - found =3D false; > - mnl_attr_for_each_nested(na, na_vxlan) { > - if (mnl_attr_get_type(na) =3D=3D IFLA_VXLAN_LINK && > - mnl_attr_get_u32(na) =3D=3D ctx->ifindex) { > - found =3D true; > - break; > - } > - } > - if (!found) > - return 1; > - /* Attached VXLAN device found, store the command to delete. */ > - vxindex =3D ifm->ifi_index; > - size =3D MNL_ALIGN(sizeof(struct nlmsghdr)) + > - MNL_ALIGN(sizeof(struct ifinfomsg)); > - cmd =3D flow_tcf_alloc_nlcmd(ctx, size); > - if (!cmd) { > - rte_errno =3D ENOMEM; > - return -rte_errno; > - } > - cmd =3D mnl_nlmsg_put_header(cmd); > - cmd->nlmsg_type =3D RTM_DELLINK; > - cmd->nlmsg_flags =3D NLM_F_REQUEST; > - ifm =3D mnl_nlmsg_put_extra_header(cmd, sizeof(*ifm)); > - ifm->ifi_family =3D AF_UNSPEC; > - ifm->ifi_index =3D vxindex; > - assert(size =3D=3D cmd->nlmsg_len); > - return 1; > -} > - > -/** > - * Cleanup the outer interface. Removes all found vxlan devices > - * attached to specified index, flushes the neigh and local IP > - * database. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifindex > - * Network inferface index to perform cleanup. > - */ > -static void > -flow_tcf_encap_iface_cleanup(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifindex) > -{ > - struct nlmsghdr *nlh; > - struct ifinfomsg *ifm; > - struct tcf_nlcb_context ctx =3D { > - .ifindex =3D ifindex, > - .bufsize =3D MNL_REQUEST_SIZE, > - .nlbuf =3D LIST_HEAD_INITIALIZER(), > - }; > - int ret; > - > - assert(ifindex); > - /* > - * Seek and destroy leftover VXLAN encap/decap interfaces with > - * matching properties. > - */ > - nlh =3D mnl_nlmsg_put_header(tcf->buf); > - nlh->nlmsg_type =3D RTM_GETLINK; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_DUMP; > - ifm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); > - ifm->ifi_family =3D AF_UNSPEC; > - ret =3D flow_tcf_nl_ack(tcf, nlh, flow_tcf_collect_vxlan_cb, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: query device list error %d", > ret); > - ret =3D flow_tcf_send_nlcmd(tcf, &ctx); > - if (ret) > - DRV_LOG(WARNING, "netlink: device delete error %d", ret); > -} > - > -/** > - * Emit Netlink message to add/remove local address to the outer device. > - * The address being added is visible within the link only (scope link). > - * > - * Note that an implicit route is maintained by the kernel due to the > - * presence of a peer address (IFA_ADDRESS). > - * > - * These rules are used for encapsulation only and allow to assign > - * the outer tunnel source IP address. > - * > - * @param[in] tcf > - * Libmnl socket context object. > - * @param[in] encap > - * Encapsulation properties (source address and its peer). > - * @param[in] ifindex > - * Network interface to apply rule. > - * @param[in] enable > - * Toggle between add and remove. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_rule_local(struct mlx5_flow_tcf_context *tcf, > - const struct flow_tcf_vxlan_encap *encap, > - unsigned int ifindex, > - bool enable, > - struct rte_flow_error *error) > -{ > - struct nlmsghdr *nlh; > - struct ifaddrmsg *ifa; > - alignas(struct nlmsghdr) > - uint8_t buf[mnl_nlmsg_size(sizeof(*ifa) + 128)]; > - > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D enable ? RTM_NEWADDR : RTM_DELADDR; > - nlh->nlmsg_flags =3D > - NLM_F_REQUEST | (enable ? NLM_F_CREATE | > NLM_F_REPLACE : 0); > - nlh->nlmsg_seq =3D 0; > - ifa =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifa)); > - ifa->ifa_flags =3D IFA_F_PERMANENT; > - ifa->ifa_scope =3D RT_SCOPE_LINK; > - ifa->ifa_index =3D ifindex; > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_SRC) { > - ifa->ifa_family =3D AF_INET; > - ifa->ifa_prefixlen =3D 32; > - mnl_attr_put_u32(nlh, IFA_LOCAL, encap->ipv4.src); > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_DST) > - mnl_attr_put_u32(nlh, IFA_ADDRESS, > - encap->ipv4.dst); > - } else { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_SRC); > - ifa->ifa_family =3D AF_INET6; > - ifa->ifa_prefixlen =3D 128; > - mnl_attr_put(nlh, IFA_LOCAL, > - sizeof(encap->ipv6.src), > - &encap->ipv6.src); > - if (encap->mask & FLOW_TCF_ENCAP_IPV6_DST) > - mnl_attr_put(nlh, IFA_ADDRESS, > - sizeof(encap->ipv6.dst), > - &encap->ipv6.dst); > - } > - if (!flow_tcf_nl_ack(tcf, nlh, NULL, NULL)) > - return 0; > - return rte_flow_error_set(error, rte_errno, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: cannot complete IFA request" > - " (ip addr add)"); > -} > - > -/** > - * Emit Netlink message to add/remove neighbor. > - * > - * @param[in] tcf > - * Libmnl socket context object. > - * @param[in] encap > - * Encapsulation properties (destination address). > - * @param[in] ifindex > - * Network interface. > - * @param[in] enable > - * Toggle between add and remove. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_rule_neigh(struct mlx5_flow_tcf_context *tcf, > - const struct flow_tcf_vxlan_encap *encap, > - unsigned int ifindex, > - bool enable, > - struct rte_flow_error *error) > -{ > - struct nlmsghdr *nlh; > - struct ndmsg *ndm; > - alignas(struct nlmsghdr) > - uint8_t buf[mnl_nlmsg_size(sizeof(*ndm) + 128)]; > - > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D enable ? RTM_NEWNEIGH : RTM_DELNEIGH; > - nlh->nlmsg_flags =3D > - NLM_F_REQUEST | (enable ? NLM_F_CREATE | > NLM_F_REPLACE : 0); > - nlh->nlmsg_seq =3D 0; > - ndm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ndm)); > - ndm->ndm_ifindex =3D ifindex; > - ndm->ndm_state =3D NUD_PERMANENT; > - ndm->ndm_flags =3D 0; > - ndm->ndm_type =3D 0; > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_DST) { > - ndm->ndm_family =3D AF_INET; > - mnl_attr_put_u32(nlh, NDA_DST, encap->ipv4.dst); > - } else { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_DST); > - ndm->ndm_family =3D AF_INET6; > - mnl_attr_put(nlh, NDA_DST, sizeof(encap->ipv6.dst), > - &encap->ipv6.dst); > - } > - if (encap->mask & FLOW_TCF_ENCAP_ETH_SRC && enable) > - DRV_LOG(WARNING, > - "outer ethernet source address cannot be " > - "forced for VXLAN encapsulation"); > - if (encap->mask & FLOW_TCF_ENCAP_ETH_DST) > - mnl_attr_put(nlh, NDA_LLADDR, sizeof(encap->eth.dst), > - &encap->eth.dst); > - if (!flow_tcf_nl_ack(tcf, nlh, NULL, NULL)) > - return 0; > - return rte_flow_error_set(error, rte_errno, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: cannot complete ND request" > - " (ip neigh)"); > -} > - > -/** > - * Manage the local IP addresses and their peers IP addresses on the > - * outer interface for encapsulation purposes. The kernel searches the > - * appropriate device for tunnel egress traffic using the outer source > - * IP, this IP should be assigned to the outer network device, otherwise > - * kernel rejects the rule. > - * > - * Adds or removes the addresses using the Netlink command like this: > - * ip addr add peer scope link dev > - * > - * The addresses are local to the netdev ("scope link"), this reduces > - * the risk of conflicts. Note that an implicit route is maintained by > - * the kernel due to the presence of a peer address (IFA_ADDRESS). > - * > - * @param[in] tcf > - * Libmnl socket context object. > - * @param[in] iface > - * Object, contains rule database and ifouter index. > - * @param[in] dev_flow > - * Flow object, contains the tunnel parameters (for encap only). > - * @param[in] enable > - * Toggle between add and remove. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_encap_local(struct mlx5_flow_tcf_context *tcf, > - struct tcf_irule *iface, > - struct mlx5_flow *dev_flow, > - bool enable, > - struct rte_flow_error *error) > -{ > - const struct flow_tcf_vxlan_encap *encap =3D dev_flow- > >tcf.vxlan_encap; > - struct tcf_local_rule *rule =3D NULL; > - int ret; > - > - assert(encap); > - assert(encap->hdr.type =3D=3D FLOW_TCF_TUNACT_VXLAN_ENCAP); > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_SRC) { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV4_DST); > - LIST_FOREACH(rule, &iface->local, next) { > - if (rule->mask & FLOW_TCF_ENCAP_IPV4_SRC && > - encap->ipv4.src =3D=3D rule->ipv4.src && > - encap->ipv4.dst =3D=3D rule->ipv4.dst) { > - break; > - } > - } > - } else { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_SRC); > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_DST); > - LIST_FOREACH(rule, &iface->local, next) { > - if (rule->mask & FLOW_TCF_ENCAP_IPV6_SRC && > - !memcmp(&encap->ipv6.src, &rule->ipv6.src, > - sizeof(encap->ipv6.src)) && > - !memcmp(&encap->ipv6.dst, &rule->ipv6.dst, > - sizeof(encap->ipv6.dst))) { > - break; > - } > - } > - } > - if (rule) { > - if (enable) { > - rule->refcnt++; > - return 0; > - } > - if (!rule->refcnt || !--rule->refcnt) { > - LIST_REMOVE(rule, next); > - return flow_tcf_rule_local(tcf, encap, > - iface->ifouter, false, error); > - } > - return 0; > - } > - if (!enable) { > - DRV_LOG(WARNING, "disabling not existing local rule"); > - rte_flow_error_set(error, ENOENT, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "disabling not existing local rule"); > - return -ENOENT; > - } > - rule =3D rte_zmalloc(__func__, sizeof(struct tcf_local_rule), > - alignof(struct tcf_local_rule)); > - if (!rule) { > - rte_flow_error_set(error, ENOMEM, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unable to allocate memory for local rule"); > - return -rte_errno; > - } > - *rule =3D (struct tcf_local_rule){.refcnt =3D 0, > - .mask =3D 0, > - }; > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_SRC) { > - rule->mask =3D FLOW_TCF_ENCAP_IPV4_SRC > - | FLOW_TCF_ENCAP_IPV4_DST; > - rule->ipv4.src =3D encap->ipv4.src; > - rule->ipv4.dst =3D encap->ipv4.dst; > - } else { > - rule->mask =3D FLOW_TCF_ENCAP_IPV6_SRC > - | FLOW_TCF_ENCAP_IPV6_DST; > - memcpy(&rule->ipv6.src, &encap->ipv6.src, > IPV6_ADDR_LEN); > - memcpy(&rule->ipv6.dst, &encap->ipv6.dst, > IPV6_ADDR_LEN); > - } > - ret =3D flow_tcf_rule_local(tcf, encap, iface->ifouter, true, error); > - if (ret) { > - rte_free(rule); > - return ret; > - } > - rule->refcnt++; > - LIST_INSERT_HEAD(&iface->local, rule, next); > - return 0; > -} > - > -/** > - * Manage the destination MAC/IP addresses neigh database, kernel uses > - * this one to determine the destination MAC address within encapsulatio= n > - * header. Adds or removes the entries using the Netlink command like th= is: > - * ip neigh add dev lladdr to nud permane= nt > - * > - * @param[in] tcf > - * Libmnl socket context object. > - * @param[in] iface > - * Object, contains rule database and ifouter index. > - * @param[in] dev_flow > - * Flow object, contains the tunnel parameters (for encap only). > - * @param[in] enable > - * Toggle between add and remove. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_encap_neigh(struct mlx5_flow_tcf_context *tcf, > - struct tcf_irule *iface, > - struct mlx5_flow *dev_flow, > - bool enable, > - struct rte_flow_error *error) > -{ > - const struct flow_tcf_vxlan_encap *encap =3D dev_flow- > >tcf.vxlan_encap; > - struct tcf_neigh_rule *rule =3D NULL; > - int ret; > - > - assert(encap); > - assert(encap->hdr.type =3D=3D FLOW_TCF_TUNACT_VXLAN_ENCAP); > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_DST) { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV4_SRC); > - LIST_FOREACH(rule, &iface->neigh, next) { > - if (rule->mask & FLOW_TCF_ENCAP_IPV4_DST && > - encap->ipv4.dst =3D=3D rule->ipv4.dst) { > - break; > - } > - } > - } else { > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_SRC); > - assert(encap->mask & FLOW_TCF_ENCAP_IPV6_DST); > - LIST_FOREACH(rule, &iface->neigh, next) { > - if (rule->mask & FLOW_TCF_ENCAP_IPV6_DST && > - !memcmp(&encap->ipv6.dst, &rule->ipv6.dst, > - sizeof(encap->ipv6.dst))) { > - break; > - } > - } > - } > - if (rule) { > - if (memcmp(&encap->eth.dst, &rule->eth, > - sizeof(encap->eth.dst))) { > - DRV_LOG(WARNING, "Destination MAC differs" > - " in neigh rule"); > - rte_flow_error_set(error, EEXIST, > - > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > - NULL, "Different MAC address" > - " neigh rule for the same" > - " destination IP"); > - return -EEXIST; > - } > - if (enable) { > - rule->refcnt++; > - return 0; > - } > - if (!rule->refcnt || !--rule->refcnt) { > - LIST_REMOVE(rule, next); > - return flow_tcf_rule_neigh(tcf, encap, > - iface->ifouter, > - false, error); > - } > - return 0; > - } > - if (!enable) { > - DRV_LOG(WARNING, "Disabling not existing neigh rule"); > - rte_flow_error_set(error, ENOENT, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unable to allocate memory for neigh > rule"); > - return -ENOENT; > - } > - rule =3D rte_zmalloc(__func__, sizeof(struct tcf_neigh_rule), > - alignof(struct tcf_neigh_rule)); > - if (!rule) { > - rte_flow_error_set(error, ENOMEM, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unable to allocate memory for neigh > rule"); > - return -rte_errno; > - } > - *rule =3D (struct tcf_neigh_rule){.refcnt =3D 0, > - .mask =3D 0, > - }; > - if (encap->mask & FLOW_TCF_ENCAP_IPV4_DST) { > - rule->mask =3D FLOW_TCF_ENCAP_IPV4_DST; > - rule->ipv4.dst =3D encap->ipv4.dst; > - } else { > - rule->mask =3D FLOW_TCF_ENCAP_IPV6_DST; > - memcpy(&rule->ipv6.dst, &encap->ipv6.dst, > IPV6_ADDR_LEN); > - } > - memcpy(&rule->eth, &encap->eth.dst, sizeof(rule->eth)); > - ret =3D flow_tcf_rule_neigh(tcf, encap, iface->ifouter, true, error); > - if (ret) { > - rte_free(rule); > - return ret; > - } > - rule->refcnt++; > - LIST_INSERT_HEAD(&iface->neigh, rule, next); > - return 0; > -} > - > -/* VXLAN encap rule database for outer interfaces. */ > -static LIST_HEAD(, tcf_irule) iface_list_vxlan =3D LIST_HEAD_INITIALIZE= R(); > - > -/* VTEP device list is shared between PMD port instances. */ > -static LIST_HEAD(, tcf_vtep) vtep_list_vxlan =3D LIST_HEAD_INITIALIZER()= ; > -static pthread_mutex_t vtep_list_mutex =3D PTHREAD_MUTEX_INITIALIZER; > - > -/** > - * Acquire the VXLAN encap rules container for specified interface. > - * First looks for the container in the existing ones list, creates > - * and initializes the new container if existing not found. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifouter > - * Network interface index to create VXLAN encap rules on. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * @return > - * Rule container pointer on success, > - * NULL otherwise and rte_errno is set. > - */ > -static struct tcf_irule* > -flow_tcf_encap_irule_acquire(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifouter, > - struct rte_flow_error *error) > -{ > - struct tcf_irule *iface; > - > - /* Look whether the container for encap rules is created. */ > - assert(ifouter); > - LIST_FOREACH(iface, &iface_list_vxlan, next) { > - if (iface->ifouter =3D=3D ifouter) > - break; > - } > - if (iface) { > - /* Container already exists, just increment the reference. */ > - iface->refcnt++; > - return iface; > - } > - /* Not found, we should create the new container. */ > - iface =3D rte_zmalloc(__func__, sizeof(*iface), > - alignof(struct tcf_irule)); > - if (!iface) { > - rte_flow_error_set(error, ENOMEM, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unable to allocate memory for > container"); > - return NULL; > - } > - *iface =3D (struct tcf_irule){ > - .local =3D LIST_HEAD_INITIALIZER(), > - .neigh =3D LIST_HEAD_INITIALIZER(), > - .ifouter =3D ifouter, > - .refcnt =3D 1, > - }; > - /* Interface cleanup for new container created. */ > - flow_tcf_encap_iface_cleanup(tcf, ifouter); > - flow_tcf_encap_local_cleanup(tcf, ifouter); > - flow_tcf_encap_neigh_cleanup(tcf, ifouter); > - LIST_INSERT_HEAD(&iface_list_vxlan, iface, next); > - return iface; > -} > - > -/** > - * Releases VXLAN encap rules container by pointer. Decrements the > - * reference counter and deletes the container if counter is zero. > - * > - * @param[in] irule > - * VXLAN rule container pointer to release. > - */ > -static void > -flow_tcf_encap_irule_release(struct tcf_irule *iface) > -{ > - assert(iface->refcnt); > - if (--iface->refcnt =3D=3D 0) { > - /* Reference counter is zero, delete the container. */ > - assert(LIST_EMPTY(&iface->local)); > - assert(LIST_EMPTY(&iface->neigh)); > - LIST_REMOVE(iface, next); > - rte_free(iface); > - } > -} > - > -/** > - * Deletes VTEP network device. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] vtep > - * Object representing the network device to delete. Memory > - * allocated for this object is freed by routine. > - */ > -static void > -flow_tcf_vtep_delete(struct mlx5_flow_tcf_context *tcf, > - struct tcf_vtep *vtep) > -{ > - struct nlmsghdr *nlh; > - struct ifinfomsg *ifm; > - alignas(struct nlmsghdr) > - uint8_t buf[mnl_nlmsg_size(MNL_ALIGN(sizeof(*ifm))) + > - MNL_BUF_EXTRA_SPACE]; > - int ret; > - > - assert(!vtep->refcnt); > - /* Delete only ifaces those we actually created. */ > - if (vtep->created && vtep->ifindex) { > - DRV_LOG(INFO, "VTEP delete (%d)", vtep->ifindex); > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D RTM_DELLINK; > - nlh->nlmsg_flags =3D NLM_F_REQUEST; > - ifm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); > - ifm->ifi_family =3D AF_UNSPEC; > - ifm->ifi_index =3D vtep->ifindex; > - assert(sizeof(buf) >=3D nlh->nlmsg_len); > - ret =3D flow_tcf_nl_ack(tcf, nlh, NULL, NULL); > - if (ret) > - DRV_LOG(WARNING, "netlink: error deleting vxlan" > - " encap/decap ifindex %u", > - ifm->ifi_index); > - } > - rte_free(vtep); > -} > - > -/** > - * Creates VTEP network device. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] port > - * UDP port of created VTEP device. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * Pointer to created device structure on success, > - * NULL otherwise and rte_errno is set. > - */ > -static struct tcf_vtep* > -flow_tcf_vtep_create(struct mlx5_flow_tcf_context *tcf, > - uint16_t port, struct rte_flow_error *error) > -{ > - struct tcf_vtep *vtep; > - struct nlmsghdr *nlh; > - struct ifinfomsg *ifm; > - char name[sizeof(MLX5_VXLAN_DEVICE_PFX) + 24]; > - alignas(struct nlmsghdr) > - uint8_t buf[mnl_nlmsg_size(sizeof(*ifm)) + > - SZ_NLATTR_DATA_OF(sizeof(name)) + > - SZ_NLATTR_NEST * 2 + > - SZ_NLATTR_STRZ_OF("vxlan") + > - SZ_NLATTR_DATA_OF(sizeof(uint32_t)) + > - SZ_NLATTR_DATA_OF(sizeof(uint16_t)) + > - SZ_NLATTR_DATA_OF(sizeof(uint8_t)) * 3 + > - MNL_BUF_EXTRA_SPACE]; > - struct nlattr *na_info; > - struct nlattr *na_vxlan; > - rte_be16_t vxlan_port =3D rte_cpu_to_be_16(port); > - int ret; > - > - vtep =3D rte_zmalloc(__func__, sizeof(*vtep), alignof(struct tcf_vtep))= ; > - if (!vtep) { > - rte_flow_error_set(error, ENOMEM, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unable to allocate memory for VTEP"); > - return NULL; > - } > - *vtep =3D (struct tcf_vtep){ > - .port =3D port, > - }; > - memset(buf, 0, sizeof(buf)); > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D RTM_NEWLINK; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_CREATE | > NLM_F_EXCL; > - ifm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); > - ifm->ifi_family =3D AF_UNSPEC; > - ifm->ifi_type =3D 0; > - ifm->ifi_index =3D 0; > - ifm->ifi_flags =3D IFF_UP; > - ifm->ifi_change =3D 0xffffffff; > - snprintf(name, sizeof(name), "%s%u", MLX5_VXLAN_DEVICE_PFX, > port); > - mnl_attr_put_strz(nlh, IFLA_IFNAME, name); > - na_info =3D mnl_attr_nest_start(nlh, IFLA_LINKINFO); > - assert(na_info); > - mnl_attr_put_strz(nlh, IFLA_INFO_KIND, "vxlan"); > - na_vxlan =3D mnl_attr_nest_start(nlh, IFLA_INFO_DATA); > - assert(na_vxlan); > -#ifdef HAVE_IFLA_VXLAN_COLLECT_METADATA > - /* > - * RH 7.2 does not support metadata for tunnel device. > - * It does not matter because we are going to use the > - * hardware offload by mlx5 driver. > - */ > - mnl_attr_put_u8(nlh, IFLA_VXLAN_COLLECT_METADATA, 1); > -#endif > - mnl_attr_put_u8(nlh, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 1); > - mnl_attr_put_u8(nlh, IFLA_VXLAN_LEARNING, 0); > - mnl_attr_put_u16(nlh, IFLA_VXLAN_PORT, vxlan_port); > -#ifndef HAVE_IFLA_VXLAN_COLLECT_METADATA > - /* > - * We must specify VNI explicitly if metadata not supported. > - * Note, VNI is transferred with native endianness format. > - */ > - mnl_attr_put_u16(nlh, IFLA_VXLAN_ID, > MLX5_VXLAN_DEFAULT_VNI); > -#endif > - mnl_attr_nest_end(nlh, na_vxlan); > - mnl_attr_nest_end(nlh, na_info); > - assert(sizeof(buf) >=3D nlh->nlmsg_len); > - ret =3D flow_tcf_nl_ack(tcf, nlh, NULL, NULL); > - if (ret) { > - DRV_LOG(WARNING, > - "netlink: VTEP %s create failure (%d)", > - name, rte_errno); > - if (rte_errno !=3D EEXIST) > - /* > - * Some unhandled error occurred or device is > - * for encapsulation and cannot be shared. > - */ > - goto error; > - } else { > - /* > - * Mark device we actually created. > - * We should explicitly delete > - * when we do not need it anymore. > - */ > - vtep->created =3D 1; > - vtep->waitreg =3D 1; > - } > - /* Try to get ifindex of created of pre-existing device. */ > - ret =3D if_nametoindex(name); > - if (!ret) { > - DRV_LOG(WARNING, > - "VTEP %s failed to get index (%d)", name, errno); > - rte_flow_error_set > - (error, -errno, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, > - "netlink: failed to retrieve VTEP ifindex"); > - goto error; > - } > - vtep->ifindex =3D ret; > - memset(buf, 0, sizeof(buf)); > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D RTM_NEWLINK; > - nlh->nlmsg_flags =3D NLM_F_REQUEST; > - ifm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); > - ifm->ifi_family =3D AF_UNSPEC; > - ifm->ifi_type =3D 0; > - ifm->ifi_index =3D vtep->ifindex; > - ifm->ifi_flags =3D IFF_UP; > - ifm->ifi_change =3D IFF_UP; > - ret =3D flow_tcf_nl_ack(tcf, nlh, NULL, NULL); > - if (ret) { > - rte_flow_error_set(error, -errno, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: failed to set VTEP link up"); > - DRV_LOG(WARNING, "netlink: VTEP %s set link up failure > (%d)", > - name, rte_errno); > - goto clean; > - } > - ret =3D mlx5_flow_tcf_init(tcf, vtep->ifindex, error); > - if (ret) { > - DRV_LOG(WARNING, "VTEP %s init failure (%d)", name, > rte_errno); > - goto clean; > - } > - DRV_LOG(INFO, "VTEP create (%d, %d)", vtep->port, vtep->ifindex); > - vtep->refcnt =3D 1; > - return vtep; > -clean: > - flow_tcf_vtep_delete(tcf, vtep); > - return NULL; > -error: > - rte_free(vtep); > - return NULL; > -} > - > -/** > - * Acquire target interface index for VXLAN tunneling decapsulation. > - * In order to share the UDP port within the other interfaces the > - * VXLAN device created as not attached to any interface (if created). > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] dev_flow > - * Flow tcf object with tunnel structure pointer set. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * @return > - * Interface descriptor pointer on success, > - * NULL otherwise and rte_errno is set. > - */ > -static struct tcf_vtep* > -flow_tcf_decap_vtep_acquire(struct mlx5_flow_tcf_context *tcf, > - struct mlx5_flow *dev_flow, > - struct rte_flow_error *error) > -{ > - struct tcf_vtep *vtep; > - uint16_t port =3D dev_flow->tcf.vxlan_decap->udp_port; > - > - LIST_FOREACH(vtep, &vtep_list_vxlan, next) { > - if (vtep->port =3D=3D port) > - break; > - } > - if (vtep) { > - /* Device exists, just increment the reference counter. */ > - vtep->refcnt++; > - assert(vtep->ifindex); > - return vtep; > - } > - /* No decapsulation device exists, try to create the new one. */ > - vtep =3D flow_tcf_vtep_create(tcf, port, error); > - if (vtep) > - LIST_INSERT_HEAD(&vtep_list_vxlan, vtep, next); > - return vtep; > -} > - > -/** > - * Acquire target interface index for VXLAN tunneling encapsulation. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifouter > - * Network interface index to attach VXLAN encap device to. > - * @param[in] dev_flow > - * Flow tcf object with tunnel structure pointer set. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * @return > - * Interface descriptor pointer on success, > - * NULL otherwise and rte_errno is set. > - */ > -static struct tcf_vtep* > -flow_tcf_encap_vtep_acquire(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifouter, > - struct mlx5_flow *dev_flow, > - struct rte_flow_error *error) > -{ > - static uint16_t port; > - struct tcf_vtep *vtep; > - struct tcf_irule *iface; > - int ret; > - > - assert(ifouter); > - /* Look whether the VTEP for specified port is created. */ > - port =3D rte_be_to_cpu_16(dev_flow->tcf.vxlan_encap->udp.dst); > - LIST_FOREACH(vtep, &vtep_list_vxlan, next) { > - if (vtep->port =3D=3D port) > - break; > - } > - if (vtep) { > - /* VTEP already exists, just increment the reference. */ > - vtep->refcnt++; > - } else { > - /* Not found, we should create the new VTEP. */ > - vtep =3D flow_tcf_vtep_create(tcf, port, error); > - if (!vtep) > - return NULL; > - LIST_INSERT_HEAD(&vtep_list_vxlan, vtep, next); > - } > - assert(vtep->ifindex); > - iface =3D flow_tcf_encap_irule_acquire(tcf, ifouter, error); > - if (!iface) { > - if (--vtep->refcnt =3D=3D 0) > - flow_tcf_vtep_delete(tcf, vtep); > - return NULL; > - } > - dev_flow->tcf.vxlan_encap->iface =3D iface; > - /* Create local ipaddr with peer to specify the outer IPs. */ > - ret =3D flow_tcf_encap_local(tcf, iface, dev_flow, true, error); > - if (!ret) { > - /* Create neigh rule to specify outer destination MAC. */ > - ret =3D flow_tcf_encap_neigh(tcf, iface, dev_flow, true, error); > - if (ret) > - flow_tcf_encap_local(tcf, iface, > - dev_flow, false, error); > - } > - if (ret) { > - dev_flow->tcf.vxlan_encap->iface =3D NULL; > - flow_tcf_encap_irule_release(iface); > - if (--vtep->refcnt =3D=3D 0) > - flow_tcf_vtep_delete(tcf, vtep); > - return NULL; > - } > - return vtep; > -} > - > -/** > - * Acquires target interface index for tunneling of any type. > - * Creates the new VTEP if needed. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] ifouter > - * Network interface index to create VXLAN encap rules on. > - * @param[in] dev_flow > - * Flow tcf object with tunnel structure pointer set. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * @return > - * Interface descriptor pointer on success, > - * NULL otherwise and rte_errno is set. > - */ > -static struct tcf_vtep* > -flow_tcf_vtep_acquire(struct mlx5_flow_tcf_context *tcf, > - unsigned int ifouter, > - struct mlx5_flow *dev_flow, > - struct rte_flow_error *error) > -{ > - struct tcf_vtep *vtep =3D NULL; > - > - assert(dev_flow->tcf.tunnel); > - pthread_mutex_lock(&vtep_list_mutex); > - switch (dev_flow->tcf.tunnel->type) { > - case FLOW_TCF_TUNACT_VXLAN_ENCAP: > - vtep =3D flow_tcf_encap_vtep_acquire(tcf, ifouter, > - dev_flow, error); > - break; > - case FLOW_TCF_TUNACT_VXLAN_DECAP: > - vtep =3D flow_tcf_decap_vtep_acquire(tcf, dev_flow, error); > - break; > - default: > - rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "unsupported tunnel type"); > - break; > - } > - pthread_mutex_unlock(&vtep_list_mutex); > - return vtep; > -} > - > -/** > - * Release tunneling interface by ifindex. Decrements reference > - * counter and actually removes the device if counter is zero. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] vtep > - * VTEP device descriptor structure. > - * @param[in] dev_flow > - * Flow tcf object with tunnel structure pointer set. > - */ > -static void > -flow_tcf_vtep_release(struct mlx5_flow_tcf_context *tcf, > - struct tcf_vtep *vtep, > - struct mlx5_flow *dev_flow) > -{ > - assert(dev_flow->tcf.tunnel); > - pthread_mutex_lock(&vtep_list_mutex); > - switch (dev_flow->tcf.tunnel->type) { > - case FLOW_TCF_TUNACT_VXLAN_DECAP: > - break; > - case FLOW_TCF_TUNACT_VXLAN_ENCAP: { > - struct tcf_irule *iface; > - > - /* Remove the encap ancillary rules first. */ > - iface =3D dev_flow->tcf.vxlan_encap->iface; > - assert(iface); > - flow_tcf_encap_neigh(tcf, iface, dev_flow, false, NULL); > - flow_tcf_encap_local(tcf, iface, dev_flow, false, NULL); > - flow_tcf_encap_irule_release(iface); > - dev_flow->tcf.vxlan_encap->iface =3D NULL; > - break; > - } > - default: > - assert(false); > - DRV_LOG(WARNING, "Unsupported tunnel type"); > - break; > - } > - assert(vtep->refcnt); > - if (--vtep->refcnt =3D=3D 0) { > - LIST_REMOVE(vtep, next); > - flow_tcf_vtep_delete(tcf, vtep); > - } > - pthread_mutex_unlock(&vtep_list_mutex); > -} > - > -struct tcf_nlcb_query { > - uint32_t handle; > - uint32_t tc_flags; > - uint32_t flags_valid:1; > -}; > - > -/** > - * Collect queried rule attributes. This is callback routine called by > - * libmnl mnl_cb_run() in loop for every message in received packet. > - * Current implementation collects the flower flags only. > - * > - * @param[in] nlh > - * Pointer to reply header. > - * @param[in, out] arg > - * Context pointer for this callback. > - * > - * @return > - * A positive, nonzero value on success (required by libmnl > - * to continue messages processing). > - */ > -static int > -flow_tcf_collect_query_cb(const struct nlmsghdr *nlh, void *arg) > -{ > - struct tcf_nlcb_query *query =3D arg; > - struct tcmsg *tcm =3D mnl_nlmsg_get_payload(nlh); > - struct nlattr *na, *na_opt; > - bool flower =3D false; > - > - if (nlh->nlmsg_type !=3D RTM_NEWTFILTER || > - tcm->tcm_handle !=3D query->handle) > - return 1; > - mnl_attr_for_each(na, nlh, sizeof(*tcm)) { > - switch (mnl_attr_get_type(na)) { > - case TCA_KIND: > - if (strcmp(mnl_attr_get_payload(na), "flower")) { > - /* Not flower filter, drop entire message. */ > - return 1; > - } > - flower =3D true; > - break; > - case TCA_OPTIONS: > - if (!flower) { > - /* Not flower options, drop entire message. > */ > - return 1; > - } > - /* Check nested flower options. */ > - mnl_attr_for_each_nested(na_opt, na) { > - switch (mnl_attr_get_type(na_opt)) { > - case TCA_FLOWER_FLAGS: > - query->flags_valid =3D 1; > - query->tc_flags =3D > - mnl_attr_get_u32(na_opt); > - break; > - } > - } > - break; > - } > - } > - return 1; > -} > - > -/** > - * Query a TC flower rule flags via netlink. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] dev_flow > - * Pointer to the flow. > - * @param[out] pflags > - * pointer to the data retrieved by the query. > - * > - * @return > - * 0 on success, a negative errno value otherwise. > - */ > -static int > -flow_tcf_query_flags(struct mlx5_flow_tcf_context *tcf, > - struct mlx5_flow *dev_flow, > - uint32_t *pflags) > -{ > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - struct tcf_nlcb_query query =3D { > - .handle =3D dev_flow->tcf.tcm->tcm_handle, > - }; > - > - nlh =3D mnl_nlmsg_put_header(tcf->buf); > - nlh->nlmsg_type =3D RTM_GETTFILTER; > - nlh->nlmsg_flags =3D NLM_F_REQUEST; > - tcm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm)); > - memcpy(tcm, dev_flow->tcf.tcm, sizeof(*tcm)); > - /* > - * Ignore Netlink error for filter query operations. > - * The reply length is sent by kernel as errno. > - * Just check we got the flags option. > - */ > - flow_tcf_nl_ack(tcf, nlh, flow_tcf_collect_query_cb, &query); > - if (!query.flags_valid) { > - *pflags =3D 0; > - return -ENOENT; > - } > - *pflags =3D query.tc_flags; > - return 0; > -} > - > -/** > - * Query and check the in_hw set for specified rule. > - * > - * @param[in] tcf > - * Context object initialized by mlx5_flow_tcf_context_create(). > - * @param[in] dev_flow > - * Pointer to the flow to check. > - * > - * @return > - * 0 on success, a negative errno value otherwise. > - */ > -static int > -flow_tcf_check_inhw(struct mlx5_flow_tcf_context *tcf, > - struct mlx5_flow *dev_flow) > -{ > - uint32_t flags; > - int ret; > - > - ret =3D flow_tcf_query_flags(tcf, dev_flow, &flags); > - if (ret) > - return ret; > - return (flags & TCA_CLS_FLAGS_IN_HW) ? 0 : -ENOENT; > -} > - > -/** > - * Remove flow from E-Switch by sending Netlink message. > - * > - * @param[in] dev > - * Pointer to Ethernet device. > - * @param[in, out] flow > - * Pointer to the sub flow. > - */ > -static void > -flow_tcf_remove(struct rte_eth_dev *dev, struct rte_flow *flow) > -{ > - struct mlx5_priv *priv =3D dev->data->dev_private; > - struct mlx5_flow_tcf_context *ctx =3D priv->tcf_context; > - struct mlx5_flow *dev_flow; > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - > - if (!flow) > - return; > - dev_flow =3D LIST_FIRST(&flow->dev_flows); > - if (!dev_flow) > - return; > - /* E-Switch flow can't be expanded. */ > - assert(!LIST_NEXT(dev_flow, next)); > - if (dev_flow->tcf.applied) { > - nlh =3D dev_flow->tcf.nlh; > - nlh->nlmsg_type =3D RTM_DELTFILTER; > - nlh->nlmsg_flags =3D NLM_F_REQUEST; > - flow_tcf_nl_ack(ctx, nlh, NULL, NULL); > - if (dev_flow->tcf.tunnel) { > - assert(dev_flow->tcf.tunnel->vtep); > - flow_tcf_vtep_release(ctx, > - dev_flow->tcf.tunnel->vtep, > - dev_flow); > - dev_flow->tcf.tunnel->vtep =3D NULL; > - } > - /* Cleanup the rule handle value. */ > - tcm =3D mnl_nlmsg_get_payload(nlh); > - tcm->tcm_handle =3D 0; > - dev_flow->tcf.applied =3D 0; > - } > -} > - > -/** > - * Fetch the applied rule handle. This is callback routine called by > - * libmnl mnl_cb_run() in loop for every message in received packet. > - * When the NLM_F_ECHO flag is specified the kernel sends the created > - * rule descriptor back to the application and we can retrieve the > - * actual rule handle from updated descriptor. > - * > - * @param[in] nlh > - * Pointer to reply header. > - * @param[in, out] arg > - * Context pointer for this callback. > - * > - * @return > - * A positive, nonzero value on success (required by libmnl > - * to continue messages processing). > - */ > -static int > -flow_tcf_collect_apply_cb(const struct nlmsghdr *nlh, void *arg) > -{ > - struct nlmsghdr *nlhrq =3D arg; > - struct tcmsg *tcmrq =3D mnl_nlmsg_get_payload(nlhrq); > - struct tcmsg *tcm =3D mnl_nlmsg_get_payload(nlh); > - struct nlattr *na; > - > - if (nlh->nlmsg_type !=3D RTM_NEWTFILTER || > - nlh->nlmsg_seq !=3D nlhrq->nlmsg_seq) > - return 1; > - mnl_attr_for_each(na, nlh, sizeof(*tcm)) { > - switch (mnl_attr_get_type(na)) { > - case TCA_KIND: > - if (strcmp(mnl_attr_get_payload(na), "flower")) { > - /* Not flower filter, drop entire message. */ > - return 1; > - } > - tcmrq->tcm_handle =3D tcm->tcm_handle; > - return 1; > - } > - } > - return 1; > -} > -/** > - * Apply flow to E-Switch by sending Netlink message. > - * > - * @param[in] dev > - * Pointer to Ethernet device. > - * @param[in, out] flow > - * Pointer to the sub flow. > - * @param[out] error > - * Pointer to the error structure. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_apply(struct rte_eth_dev *dev, struct rte_flow *flow, > - struct rte_flow_error *error) > -{ > - struct mlx5_priv *priv =3D dev->data->dev_private; > - struct mlx5_flow_tcf_context *ctx =3D priv->tcf_context; > - struct mlx5_flow *dev_flow; > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - uint64_t start =3D 0; > - uint64_t twait =3D 0; > - int ret; > - > - dev_flow =3D LIST_FIRST(&flow->dev_flows); > - /* E-Switch flow can't be expanded. */ > - assert(!LIST_NEXT(dev_flow, next)); > - if (dev_flow->tcf.applied) > - return 0; > - nlh =3D dev_flow->tcf.nlh; > - nlh->nlmsg_type =3D RTM_NEWTFILTER; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_CREATE | > - NLM_F_EXCL | NLM_F_ECHO; > - tcm =3D mnl_nlmsg_get_payload(nlh); > - /* Allow kernel to assign handle on its own. */ > - tcm->tcm_handle =3D 0; > - if (dev_flow->tcf.tunnel) { > - /* > - * Replace the interface index, target for > - * encapsulation, source for decapsulation. > - */ > - assert(!dev_flow->tcf.tunnel->vtep); > - assert(dev_flow->tcf.tunnel->ifindex_ptr); > - /* Acquire actual VTEP device when rule is being applied. */ > - dev_flow->tcf.tunnel->vtep =3D > - flow_tcf_vtep_acquire(ctx, > - dev_flow->tcf.tunnel->ifindex_org, > - dev_flow, error); > - if (!dev_flow->tcf.tunnel->vtep) > - return -rte_errno; > - DRV_LOG(INFO, "Replace ifindex: %d->%d", > - dev_flow->tcf.tunnel->vtep->ifindex, > - dev_flow->tcf.tunnel->ifindex_org); > - *dev_flow->tcf.tunnel->ifindex_ptr =3D > - dev_flow->tcf.tunnel->vtep->ifindex; > - if (dev_flow->tcf.tunnel->vtep->waitreg) { > - /* Clear wait flag for VXLAN port registration. */ > - dev_flow->tcf.tunnel->vtep->waitreg =3D 0; > - twait =3D rte_get_timer_hz(); > - assert(twait > MS_PER_S); > - twait =3D twait * MLX5_VXLAN_WAIT_PORT_REG_MS; > - twait =3D twait / MS_PER_S; > - start =3D rte_get_timer_cycles(); > - } > - } > - /* > - * Kernel creates the VXLAN devices and registers UDP ports to > - * be hardware offloaded within the NIC kernel drivers. The > - * registration process is being performed into context of > - * working kernel thread and the race conditions might happen. > - * The VXLAN device is created and success is returned to > - * calling application, but the UDP port registration process > - * is not completed yet. The next applied rule may be rejected > - * by the driver with ENOSUP code. We are going to wait a bit, > - * allowing registration process to be completed. The waiting > - * is performed once after device been created. > - */ > - do { > - struct timespec onems; > - > - ret =3D flow_tcf_nl_ack(ctx, nlh, > - flow_tcf_collect_apply_cb, nlh); > - if (!ret || ret !=3D -ENOTSUP || !twait) > - break; > - /* Wait one millisecond and try again till timeout. */ > - onems.tv_sec =3D 0; > - onems.tv_nsec =3D NS_PER_S / MS_PER_S; > - nanosleep(&onems, 0); > - if ((rte_get_timer_cycles() - start) > twait) { > - /* Timeout elapsed, try once more and exit. */ > - twait =3D 0; > - } > - } while (true); > - if (!ret) { > - if (!tcm->tcm_handle) { > - flow_tcf_remove(dev, flow); > - return rte_flow_error_set > - (error, ENOENT, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: rule zero handle returned"); > - } > - dev_flow->tcf.applied =3D 1; > - if (*dev_flow->tcf.ptc_flags & TCA_CLS_FLAGS_SKIP_SW) > - return 0; > - /* > - * Rule was applied without skip_sw flag set. > - * We should check whether the rule was acctually > - * accepted by hardware (have look at in_hw flag). > - */ > - if (flow_tcf_check_inhw(ctx, dev_flow)) { > - flow_tcf_remove(dev, flow); > - return rte_flow_error_set > - (error, ENOENT, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: rule has no in_hw flag set"); > - } > - return 0; > - } > - if (dev_flow->tcf.tunnel) { > - /* Rollback the VTEP configuration if rule apply failed. */ > - assert(dev_flow->tcf.tunnel->vtep); > - flow_tcf_vtep_release(ctx, dev_flow->tcf.tunnel->vtep, > - dev_flow); > - dev_flow->tcf.tunnel->vtep =3D NULL; > - } > - return rte_flow_error_set(error, rte_errno, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > NULL, > - "netlink: failed to create TC flow rule"); > -} > - > -/** > - * Remove flow from E-Switch and release resources of the device flow. > - * > - * @param[in] dev > - * Pointer to Ethernet device. > - * @param[in, out] flow > - * Pointer to the sub flow. > - */ > -static void > -flow_tcf_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) > -{ > - struct mlx5_flow *dev_flow; > - > - if (!flow) > - return; > - flow_tcf_remove(dev, flow); > - if (flow->counter) { > - if (--flow->counter->ref_cnt =3D=3D 0) { > - rte_free(flow->counter); > - flow->counter =3D NULL; > - } > - } > - dev_flow =3D LIST_FIRST(&flow->dev_flows); > - if (!dev_flow) > - return; > - /* E-Switch flow can't be expanded. */ > - assert(!LIST_NEXT(dev_flow, next)); > - LIST_REMOVE(dev_flow, next); > - rte_free(dev_flow); > -} > - > -/** > - * Helper routine for figuring the space size required for a parse buffe= r. > - * > - * @param array > - * array of values to use. > - * @param idx > - * Current location in array. > - * @param value > - * Value to compare with. > - * > - * @return > - * The maximum between the given value and the array value on index. > - */ > -static uint16_t > -flow_tcf_arr_val_max(uint16_t array[], int idx, uint16_t value) > -{ > - return idx < 0 ? (value) : RTE_MAX((array)[idx], value); > -} > - > -/** > - * Parse rtnetlink message attributes filling the attribute table with t= he info > - * retrieved. > - * > - * @param tb > - * Attribute table to be filled. > - * @param[out] max > - * Maxinum entry in the attribute table. > - * @param rte > - * The attributes section in the message to be parsed. > - * @param len > - * The length of the attributes section in the message. > - */ > -static void > -flow_tcf_nl_parse_rtattr(struct rtattr *tb[], int max, > - struct rtattr *rta, int len) > -{ > - unsigned short type; > - memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); > - while (RTA_OK(rta, len)) { > - type =3D rta->rta_type; > - if (type <=3D max && !tb[type]) > - tb[type] =3D rta; > - rta =3D RTA_NEXT(rta, len); > - } > -} > - > -/** > - * Extract flow counters from flower action. > - * > - * @param rta > - * flower action stats properties in the Netlink message received. > - * @param rta_type > - * The backward sequence of rta_types, as written in the attribute tab= le, > - * we need to traverse in order to get to the requested object. > - * @param idx > - * Current location in rta_type table. > - * @param[out] data > - * data holding the count statistics of the rte_flow retrieved from > - * the message. > - * > - * @return > - * 0 if data was found and retrieved, -1 otherwise. > - */ > -static int > -flow_tcf_nl_action_stats_parse_and_get(struct rtattr *rta, > - uint16_t rta_type[], int idx, > - struct gnet_stats_basic *data) > -{ > - int tca_stats_max =3D flow_tcf_arr_val_max(rta_type, idx, > - TCA_STATS_BASIC); > - struct rtattr *tbs[tca_stats_max + 1]; > - > - if (rta =3D=3D NULL || idx < 0) > - return -1; > - flow_tcf_nl_parse_rtattr(tbs, tca_stats_max, > - RTA_DATA(rta), RTA_PAYLOAD(rta)); > - switch (rta_type[idx]) { > - case TCA_STATS_BASIC: > - if (tbs[TCA_STATS_BASIC]) { > - memcpy(data, RTA_DATA(tbs[TCA_STATS_BASIC]), > - > RTE_MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), > - sizeof(*data))); > - return 0; > - } > - break; > - default: > - break; > - } > - return -1; > -} > - > -/** > - * Parse flower single action retrieving the requested action attribute, > - * if found. > - * > - * @param arg > - * flower action properties in the Netlink message received. > - * @param rta_type > - * The backward sequence of rta_types, as written in the attribute tab= le, > - * we need to traverse in order to get to the requested object. > - * @param idx > - * Current location in rta_type table. > - * @param[out] data > - * Count statistics retrieved from the message query. > - * > - * @return > - * 0 if data was found and retrieved, -1 otherwise. > - */ > -static int > -flow_tcf_nl_parse_one_action_and_get(struct rtattr *arg, > - uint16_t rta_type[], int idx, void *data) > -{ > - int tca_act_max =3D flow_tcf_arr_val_max(rta_type, idx, > TCA_ACT_STATS); > - struct rtattr *tb[tca_act_max + 1]; > - > - if (arg =3D=3D NULL || idx < 0) > - return -1; > - flow_tcf_nl_parse_rtattr(tb, tca_act_max, > - RTA_DATA(arg), RTA_PAYLOAD(arg)); > - if (tb[TCA_ACT_KIND] =3D=3D NULL) > - return -1; > - switch (rta_type[idx]) { > - case TCA_ACT_STATS: > - if (tb[TCA_ACT_STATS]) > - return flow_tcf_nl_action_stats_parse_and_get > - (tb[TCA_ACT_STATS], > - rta_type, --idx, > - (struct gnet_stats_basic *)data); > - break; > - default: > - break; > - } > - return -1; > -} > - > -/** > - * Parse flower action section in the message retrieving the requested > - * attribute from the first action that provides it. > - * > - * @param opt > - * flower section in the Netlink message received. > - * @param rta_type > - * The backward sequence of rta_types, as written in the attribute tab= le, > - * we need to traverse in order to get to the requested object. > - * @param idx > - * Current location in rta_type table. > - * @param[out] data > - * data retrieved from the message query. > - * > - * @return > - * 0 if data was found and retrieved, -1 otherwise. > - */ > -static int > -flow_tcf_nl_action_parse_and_get(struct rtattr *arg, > - uint16_t rta_type[], int idx, void *data) > -{ > - struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; > - int i; > - > - if (arg =3D=3D NULL || idx < 0) > - return -1; > - flow_tcf_nl_parse_rtattr(tb, TCA_ACT_MAX_PRIO, > - RTA_DATA(arg), RTA_PAYLOAD(arg)); > - switch (rta_type[idx]) { > - /* > - * flow counters are stored in the actions defined by the flow > - * and not in the flow itself, therefore we need to traverse the > - * flower chain of actions in search for them. > - * > - * Note that the index is not decremented here. > - */ > - case TCA_ACT_STATS: > - for (i =3D 0; i <=3D TCA_ACT_MAX_PRIO; i++) { > - if (tb[i] && > - !flow_tcf_nl_parse_one_action_and_get(tb[i], > - rta_type, > - idx, data)) > - return 0; > - } > - break; > - default: > - break; > - } > - return -1; > -} > - > -/** > - * Parse flower classifier options in the message, retrieving the reques= ted > - * attribute if found. > - * > - * @param opt > - * flower section in the Netlink message received. > - * @param rta_type > - * The backward sequence of rta_types, as written in the attribute tab= le, > - * we need to traverse in order to get to the requested object. > - * @param idx > - * Current location in rta_type table. > - * @param[out] data > - * data retrieved from the message query. > - * > - * @return > - * 0 if data was found and retrieved, -1 otherwise. > - */ > -static int > -flow_tcf_nl_opts_parse_and_get(struct rtattr *opt, > - uint16_t rta_type[], int idx, void *data) > -{ > - int tca_flower_max =3D flow_tcf_arr_val_max(rta_type, idx, > - TCA_FLOWER_ACT); > - struct rtattr *tb[tca_flower_max + 1]; > - > - if (!opt || idx < 0) > - return -1; > - flow_tcf_nl_parse_rtattr(tb, tca_flower_max, > - RTA_DATA(opt), RTA_PAYLOAD(opt)); > - switch (rta_type[idx]) { > - case TCA_FLOWER_ACT: > - if (tb[TCA_FLOWER_ACT]) > - return flow_tcf_nl_action_parse_and_get > - > (tb[TCA_FLOWER_ACT], > - rta_type, --idx, > data); > - break; > - default: > - break; > - } > - return -1; > -} > - > -/** > - * Parse Netlink reply on filter query, retrieving the flow counters. > - * > - * @param nlh > - * Message received from Netlink. > - * @param rta_type > - * The backward sequence of rta_types, as written in the attribute tab= le, > - * we need to traverse in order to get to the requested object. > - * @param idx > - * Current location in rta_type table. > - * @param[out] data > - * data retrieved from the message query. > - * > - * @return > - * 0 if data was found and retrieved, -1 otherwise. > - */ > -static int > -flow_tcf_nl_filter_parse_and_get(struct nlmsghdr *cnlh, > - uint16_t rta_type[], int idx, void *data) > -{ > - struct nlmsghdr *nlh =3D cnlh; > - struct tcmsg *t =3D NLMSG_DATA(nlh); > - int len =3D nlh->nlmsg_len; > - int tca_max =3D flow_tcf_arr_val_max(rta_type, idx, TCA_OPTIONS); > - struct rtattr *tb[tca_max + 1]; > - > - if (idx < 0) > - return -1; > - if (nlh->nlmsg_type !=3D RTM_NEWTFILTER && > - nlh->nlmsg_type !=3D RTM_GETTFILTER && > - nlh->nlmsg_type !=3D RTM_DELTFILTER) > - return -1; > - len -=3D NLMSG_LENGTH(sizeof(*t)); > - if (len < 0) > - return -1; > - flow_tcf_nl_parse_rtattr(tb, tca_max, TCA_RTA(t), len); > - /* Not a TC flower flow - bail out */ > - if (!tb[TCA_KIND] || > - strcmp(RTA_DATA(tb[TCA_KIND]), "flower")) > - return -1; > - switch (rta_type[idx]) { > - case TCA_OPTIONS: > - if (tb[TCA_OPTIONS]) > - return > flow_tcf_nl_opts_parse_and_get(tb[TCA_OPTIONS], > - rta_type, > - --idx, data); > - break; > - default: > - break; > - } > - return -1; > -} > - > -/** > - * A callback to parse Netlink reply on TC flower query. > - * > - * @param nlh > - * Message received from Netlink. > - * @param[out] data > - * Pointer to data area to be filled by the parsing routine. > - * assumed to be a pointer to struct flow_tcf_stats_basic. > - * > - * @return > - * MNL_CB_OK value. > - */ > -static int > -flow_tcf_nl_message_get_stats_basic(const struct nlmsghdr *nlh, void > *data) > -{ > - /* > - * The backward sequence of rta_types to pass in order to get > - * to the counters. > - */ > - uint16_t rta_type[] =3D { TCA_STATS_BASIC, TCA_ACT_STATS, > - TCA_FLOWER_ACT, TCA_OPTIONS }; > - struct flow_tcf_stats_basic *sb_data =3D data; > - union { > - const struct nlmsghdr *c; > - struct nlmsghdr *nc; > - } tnlh =3D { .c =3D nlh }; > - > - if (!flow_tcf_nl_filter_parse_and_get(tnlh.nc, rta_type, > - RTE_DIM(rta_type) - 1, > - (void *)&sb_data->counters)) > - sb_data->valid =3D true; > - return MNL_CB_OK; > -} > - > -/** > - * Query a TC flower rule for its statistics via netlink. > - * > - * @param[in] dev > - * Pointer to Ethernet device. > - * @param[in] flow > - * Pointer to the sub flow. > - * @param[out] data > - * data retrieved by the query. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -static int > -flow_tcf_query_count(struct rte_eth_dev *dev, > - struct rte_flow *flow, > - void *data, > - struct rte_flow_error *error) > -{ > - struct flow_tcf_stats_basic sb_data; > - struct rte_flow_query_count *qc =3D data; > - struct mlx5_priv *priv =3D dev->data->dev_private; > - struct mlx5_flow_tcf_context *ctx =3D priv->tcf_context; > - struct mnl_socket *nl =3D ctx->nl; > - struct mlx5_flow *dev_flow; > - struct nlmsghdr *nlh; > - uint32_t seq =3D priv->tcf_context->seq++; > - ssize_t ret; > - assert(qc); > - > - memset(&sb_data, 0, sizeof(sb_data)); > - dev_flow =3D LIST_FIRST(&flow->dev_flows); > - /* E-Switch flow can't be expanded. */ > - assert(!LIST_NEXT(dev_flow, next)); > - if (!dev_flow->flow->counter) > - goto notsup_exit; > - nlh =3D dev_flow->tcf.nlh; > - nlh->nlmsg_type =3D RTM_GETTFILTER; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_ECHO; > - nlh->nlmsg_seq =3D seq; > - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) =3D=3D -1) > - goto error_exit; > - do { > - ret =3D mnl_socket_recvfrom(nl, ctx->buf, ctx->buf_size); > - if (ret <=3D 0) > - break; > - ret =3D mnl_cb_run(ctx->buf, ret, seq, > - mnl_socket_get_portid(nl), > - flow_tcf_nl_message_get_stats_basic, > - (void *)&sb_data); > - } while (ret > 0); > - /* Return the delta from last reset. */ > - if (sb_data.valid) { > - /* Return the delta from last reset. */ > - qc->hits_set =3D 1; > - qc->bytes_set =3D 1; > - qc->hits =3D sb_data.counters.packets - flow->counter->hits; > - qc->bytes =3D sb_data.counters.bytes - flow->counter->bytes; > - if (qc->reset) { > - flow->counter->hits =3D sb_data.counters.packets; > - flow->counter->bytes =3D sb_data.counters.bytes; > - } > - return 0; > - } > - return rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > - NULL, > - "flow does not have counter"); > -error_exit: > - return rte_flow_error_set > - (error, errno, > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > - NULL, "netlink: failed to read flow rule counters"); > -notsup_exit: > - return rte_flow_error_set > - (error, ENOTSUP, > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, > - NULL, "counters are not available."); > -} > - > -/** > - * Query a flow. > - * > - * @see rte_flow_query() > - * @see rte_flow_ops > - */ > -static int > -flow_tcf_query(struct rte_eth_dev *dev, > - struct rte_flow *flow, > - const struct rte_flow_action *actions, > - void *data, > - struct rte_flow_error *error) > -{ > - int ret =3D -EINVAL; > - > - for (; actions->type !=3D RTE_FLOW_ACTION_TYPE_END; actions++) { > - switch (actions->type) { > - case RTE_FLOW_ACTION_TYPE_VOID: > - break; > - case RTE_FLOW_ACTION_TYPE_COUNT: > - ret =3D flow_tcf_query_count(dev, flow, data, error); > - break; > - default: > - return rte_flow_error_set(error, ENOTSUP, > - > RTE_FLOW_ERROR_TYPE_ACTION, > - actions, > - "action not supported"); > - } > - } > - return ret; > -} > - > -const struct mlx5_flow_driver_ops mlx5_flow_tcf_drv_ops =3D { > - .validate =3D flow_tcf_validate, > - .prepare =3D flow_tcf_prepare, > - .translate =3D flow_tcf_translate, > - .apply =3D flow_tcf_apply, > - .remove =3D flow_tcf_remove, > - .destroy =3D flow_tcf_destroy, > - .query =3D flow_tcf_query, > -}; > - > -/** > - * Create and configure a libmnl socket for Netlink flow rules. > - * > - * @return > - * A valid libmnl socket object pointer on success, NULL otherwise and > - * rte_errno is set. > - */ > -static struct mnl_socket * > -flow_tcf_mnl_socket_create(void) > -{ > - struct mnl_socket *nl =3D mnl_socket_open(NETLINK_ROUTE); > - > - if (nl) { > - mnl_socket_setsockopt(nl, NETLINK_CAP_ACK, &(int){ 1 }, > - sizeof(int)); > - if (!mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID)) > - return nl; > - } > - rte_errno =3D errno; > - if (nl) > - mnl_socket_close(nl); > - return NULL; > -} > - > -/** > - * Destroy a libmnl socket. > - * > - * @param nl > - * Libmnl socket of the @p NETLINK_ROUTE kind. > - */ > -static void > -flow_tcf_mnl_socket_destroy(struct mnl_socket *nl) > -{ > - if (nl) > - mnl_socket_close(nl); > -} > - > -/** > - * Initialize ingress qdisc of a given network interface. > - * > - * @param ctx > - * Pointer to tc-flower context to use. > - * @param ifindex > - * Index of network interface to initialize. > - * @param[out] error > - * Perform verbose error reporting if not NULL. > - * > - * @return > - * 0 on success, a negative errno value otherwise and rte_errno is set= . > - */ > -int > -mlx5_flow_tcf_init(struct mlx5_flow_tcf_context *ctx, > - unsigned int ifindex, struct rte_flow_error *error) > -{ > - struct nlmsghdr *nlh; > - struct tcmsg *tcm; > - alignas(struct nlmsghdr) > - uint8_t buf[mnl_nlmsg_size(sizeof(*tcm)) + > - SZ_NLATTR_STRZ_OF("ingress") + > - MNL_BUF_EXTRA_SPACE]; > - > - /* Destroy existing ingress qdisc and everything attached to it. */ > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D RTM_DELQDISC; > - nlh->nlmsg_flags =3D NLM_F_REQUEST; > - tcm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm)); > - tcm->tcm_family =3D AF_UNSPEC; > - tcm->tcm_ifindex =3D ifindex; > - tcm->tcm_handle =3D TC_H_MAKE(TC_H_INGRESS, 0); > - tcm->tcm_parent =3D TC_H_INGRESS; > - assert(sizeof(buf) >=3D nlh->nlmsg_len); > - /* Ignore errors when qdisc is already absent. */ > - if (flow_tcf_nl_ack(ctx, nlh, NULL, NULL) && > - rte_errno !=3D EINVAL && rte_errno !=3D ENOENT) > - return rte_flow_error_set(error, rte_errno, > - > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, > - "netlink: failed to remove ingress" > - " qdisc"); > - /* Create fresh ingress qdisc. */ > - nlh =3D mnl_nlmsg_put_header(buf); > - nlh->nlmsg_type =3D RTM_NEWQDISC; > - nlh->nlmsg_flags =3D NLM_F_REQUEST | NLM_F_CREATE | > NLM_F_EXCL; > - tcm =3D mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm)); > - tcm->tcm_family =3D AF_UNSPEC; > - tcm->tcm_ifindex =3D ifindex; > - tcm->tcm_handle =3D TC_H_MAKE(TC_H_INGRESS, 0); > - tcm->tcm_parent =3D TC_H_INGRESS; > - mnl_attr_put_strz_check(nlh, sizeof(buf), TCA_KIND, "ingress"); > - assert(sizeof(buf) >=3D nlh->nlmsg_len); > - if (flow_tcf_nl_ack(ctx, nlh, NULL, NULL)) > - return rte_flow_error_set(error, rte_errno, > - > RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, > - "netlink: failed to create ingress" > - " qdisc"); > - return 0; > -} > - > -/** > - * Create libmnl context for Netlink flow rules. > - * > - * @return > - * A valid libmnl socket object pointer on success, NULL otherwise and > - * rte_errno is set. > - */ > -struct mlx5_flow_tcf_context * > -mlx5_flow_tcf_context_create(void) > -{ > - struct mlx5_flow_tcf_context *ctx =3D rte_zmalloc(__func__, > - sizeof(*ctx), > - sizeof(uint32_t)); > - if (!ctx) > - goto error; > - ctx->nl =3D flow_tcf_mnl_socket_create(); > - if (!ctx->nl) > - goto error; > - ctx->buf_size =3D MNL_SOCKET_BUFFER_SIZE; > - ctx->buf =3D rte_zmalloc(__func__, > - ctx->buf_size, sizeof(uint32_t)); > - if (!ctx->buf) > - goto error; > - ctx->seq =3D random(); > - return ctx; > -error: > - mlx5_flow_tcf_context_destroy(ctx); > - return NULL; > -} > - > -/** > - * Destroy a libmnl context. > - * > - * @param ctx > - * Libmnl socket of the @p NETLINK_ROUTE kind. > - */ > -void > -mlx5_flow_tcf_context_destroy(struct mlx5_flow_tcf_context *ctx) > -{ > - if (!ctx) > - return; > - flow_tcf_mnl_socket_destroy(ctx->nl); > - rte_free(ctx->buf); > - rte_free(ctx); > -} > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index 7c9b4b5..05126ee 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -175,7 +175,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI) +=3D - > lrte_pmd_kni > endif > _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD) +=3D -lrte_pmd_lio > _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) +=3D -lrte_pmd_mlx4 > -_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D -lrte_pmd_mlx5 -lmnl > +_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D -lrte_pmd_mlx5 > ifeq ($(CONFIG_RTE_IBVERBS_LINK_DLOPEN),y) > _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) +=3D -ldl > _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) +=3D -ldl > -- > 1.8.3.1