From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR03-VE1-obe.outbound.protection.outlook.com (mail-eopbgr50083.outbound.protection.outlook.com [40.107.5.83]) by dpdk.org (Postfix) with ESMTP id 3A2FD1B19A for ; Tue, 23 Oct 2018 12:06:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SgIaqgm8+aPFFSeqHb9okwj0wd0HBWCLQboU5dTS9xU=; b=YosCD3/6RkaL/OvZS/8M2uNNBFUmaSU/In3auJUfcbcUANx2RqPdOXlH0WSHzxUe/+CWPC1Zt+U/XubR6f6KNYUvJ2l507//jMmoQxIhh77URx8OzIcvUBOkCjj/NAjXdLkfqeMfvMaaBCdn+imDrMRjo8e8YWggYVN2w+gcUs0= Received: from DB3PR0502MB3980.eurprd05.prod.outlook.com (52.134.72.27) by DB3PR0502MB3961.eurprd05.prod.outlook.com (52.134.70.142) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1250.30; Tue, 23 Oct 2018 10:06:28 +0000 Received: from DB3PR0502MB3980.eurprd05.prod.outlook.com ([fe80::f8a1:fcab:94f0:97cc]) by DB3PR0502MB3980.eurprd05.prod.outlook.com ([fe80::f8a1:fcab:94f0:97cc%4]) with mapi id 15.20.1250.028; Tue, 23 Oct 2018 10:06:28 +0000 From: Yongseok Koh To: Slava Ovsiienko CC: Shahaf Shuler , "dev@dpdk.org" Thread-Topic: [PATCH v2 3/7] net/mlx5: e-switch VXLAN flow translation routine Thread-Index: AQHUZJFZmoxzpCFrNk+Iuvz4Vcwsm6UspvYA Date: Tue, 23 Oct 2018 10:06:28 +0000 Message-ID: <20181023100621.GC14792@mtidpdk.mti.labs.mlnx> References: <1538461807-37507-1-git-send-email-viacheslavo@mellanox.com> <1539612815-47199-1-git-send-email-viacheslavo@mellanox.com> <1539612815-47199-4-git-send-email-viacheslavo@mellanox.com> In-Reply-To: <1539612815-47199-4-git-send-email-viacheslavo@mellanox.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: BYAPR02CA0001.namprd02.prod.outlook.com (2603:10b6:a02:ee::14) To DB3PR0502MB3980.eurprd05.prod.outlook.com (2603:10a6:8:10::27) authentication-results: spf=none (sender IP is ) smtp.mailfrom=yskoh@mellanox.com; x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [209.116.155.178] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DB3PR0502MB3961; 6:R5rmVVVd+g2H7xyBYfZc7A95yUM6Bb1aMzNiVLfQaAkN2xWyhkay+J4ve1wZqFlla4kSdBHGLXonrT8fxUCEaN5dHMXfVY8ayJAX0MfPqXAndLhLuQB+NoI5w4jBwLkwlz48XFDrrFs36dhxGPS2qclxOJAxbtPa7BXe5L4Op77BJe3pmBfXu7PsapxYjldMZqjKXGfkDUDfshJeUSKQ2wnXgTcQ8Z8ssW5Wm88ijz89kFL+72g0VeA3hbmXwgs7rgmvcbN89Fj+2GmBPUpvdcMG6t0lqDnrL8s9lsiHKvNagRdSOyUMhqx78LARHNxw2Pgd8+UsrX5Q77o1Cmw+cBTFTbMaoOVHs64hZQotfHGPIksFDdzYdpnAdwpqUkzDyccinK9z9sydez+2JBb7cNYYQ372c48vvxoFUES0mhz2iNZ0Td5+x6P6/hAJCXoSWOS1XmnoelTt+PnW1DSBuA==; 5:CGgMzonxaIVvlSIFRoTb6OShbe8lWu5Kmw9CJt7E2LdQzWyB6SdJiWiZ9t+MT0OkcEvD3lSidN+VXVVJY0ShEbNHUQmVrgQDkG4i/G+6n3mX/sR8enXcgvGqWTzQZA1dWJRkEYJB7dIcKB5RVVbV8HnT8uADoapiT9SyEXSuP4c=; 7:VKgS7GzP5qozBj9O08IKpheXHPb5M38XyqGghMADMwTlNxTfqv7IwiMQjE3MH3d281Qddi3Vd+ELo7Nkj5rkdjKgNLDzCn+1KTtt++mcCYW6YI2yESXknlLrqcKkLL+UyeMt5dtxnutjDkA1+rKrl26QwISsb7vy3oE3+gFhU+fHEi2QCXr4b4V7aTZOCEZ8teNRUh8LYNWDZd5PIkkfjUGVAIukpoIJxs+Fblaw+EJxFfIDTV03qoGj58uYM+kf x-ms-office365-filtering-correlation-id: 11b77a29-d8b8-45de-a432-08d638cf32a8 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(5600074)(711020)(4618075)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020); SRVR:DB3PR0502MB3961; x-ms-traffictypediagnostic: DB3PR0502MB3961: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(93006095)(93001095)(10201501046)(3002001)(3231355)(944501410)(52105095)(6055026)(148016)(149066)(150057)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123558120)(20161123564045)(20161123560045)(20161123562045)(201708071742011)(7699051)(76991095); SRVR:DB3PR0502MB3961; BCL:0; PCL:0; RULEID:; SRVR:DB3PR0502MB3961; x-forefront-prvs: 0834BAF534 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(39860400002)(376002)(366004)(346002)(396003)(136003)(199004)(189003)(52314003)(6116002)(76176011)(446003)(3846002)(66066001)(14454004)(486006)(6246003)(6862004)(4326008)(52116002)(33896004)(476003)(53946003)(86362001)(68736007)(6486002)(99286004)(229853002)(186003)(575784001)(81166006)(81156014)(11346002)(6512007)(9686003)(54906003)(316002)(105586002)(16200700003)(6636002)(106356001)(71190400001)(1076002)(4744004)(5660300001)(305945005)(71200400001)(53936002)(26005)(33656002)(478600001)(5250100002)(25786009)(2900100001)(14444005)(256004)(8936002)(6436002)(2906002)(6506007)(97736004)(386003)(8676002)(7736002)(102836004)(579004)(559001)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:DB3PR0502MB3961; H:DB3PR0502MB3980.eurprd05.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: mellanox.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: u5xgbK30DRXhPsFbLILvb0oWBAxPsG2J+mULQ6/k2SgKVxRyN/6NmonXbpj5Gyb4t4h+CUUFj0C8ek+9osXkSxz7Amte1CGP6DiucBeWUy4NsxQKeu7MGfzzefM1T6tAH7vacF7OUG19W8YllxjVoAU36d0MeejO6QIWSCAsaeXkzc/AWsZc23w5DRp9HqlT4B7NQx5yP1heHKB38RqbEcolf6TpOarKXi8RZKf5FXpj2rFYJLHd7YImtTlVArylx+LuuRnWKiRTG+G5VNKO78QXpjZg+8AZG1HNHq8KK3XaiuSDkL3lyR7/n8Mqvd7Lkf9ckI5jKcL0PUhX4NwZVzS40RRZMQCVcnC1bU2w4CA= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM Content-Type: text/plain; charset="us-ascii" Content-ID: <7F853FB0A296DD43A104565C15AEA376@eurprd05.prod.outlook.com> Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-Network-Message-Id: 11b77a29-d8b8-45de-a432-08d638cf32a8 X-MS-Exchange-CrossTenant-originalarrivaltime: 23 Oct 2018 10:06:28.4426 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB3PR0502MB3961 Subject: Re: [dpdk-dev] [PATCH v2 3/7] net/mlx5: e-switch VXLAN flow translation routine 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: , X-List-Received-Date: Tue, 23 Oct 2018 10:06:30 -0000 On Mon, Oct 15, 2018 at 02:13:31PM +0000, Viacheslav Ovsiienko wrote: > This part of patchset adds support of VXLAN-related items and > actions to the flow translation routine. If some of them are > specified in the rule, the extra space for tunnel description > structure is allocated. Later some tunnel types, other than > VXLAN can be addedd (GRE). No VTEP devices are created at this > point, the flow rule is just translated, not applied yet. >=20 > Suggested-by: Adrien Mazarguil > Signed-off-by: Viacheslav Ovsiienko > --- > drivers/net/mlx5/mlx5_flow_tcf.c | 641 +++++++++++++++++++++++++++++++++= ++---- > 1 file changed, 578 insertions(+), 63 deletions(-) >=20 > diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c b/drivers/net/mlx5/mlx5_flo= w_tcf.c > index 0055417..660d45e 100644 > --- a/drivers/net/mlx5/mlx5_flow_tcf.c > +++ b/drivers/net/mlx5/mlx5_flow_tcf.c > @@ -2094,6 +2094,265 @@ struct pedit_parser { > } > =20 > /** > + * Helper function to process RTE_FLOW_ITEM_TYPE_ETH entry in configurat= ion > + * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the MAC address fie= lds > + * 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. > + * > + * @return > + * The size needed the Netlink message tunnel_key > + * parameter buffer to store the item attributes. > + */ > +static int > +flow_tcf_parse_vxlan_encap_eth(const struct rte_flow_item_eth *spec, > + const struct rte_flow_item_eth *mask, > + struct mlx5_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 MLX5_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 MLX5_FLOW_TCF_ENCAP_ETH_SRC; > + } > + /* > + * No space allocated for ethernet addresses within Netlink > + * message tunnel_key record - these ones are not > + * supported by tc. > + */ > + return 0; > +} > + > +/** > + * Helper function to process RTE_FLOW_ITEM_TYPE_IPV4 entry in configura= tion > + * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the IPV4 address fi= elds > + * 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[out] encap > + * Structure to fill the gathered IPV4 address data. > + * > + * @return > + * The size needed the Netlink message tunnel_key > + * parameter buffer to store the item attributes. > + */ > +static int > +flow_tcf_parse_vxlan_encap_ipv4(const struct rte_flow_item_ipv4 *spec, > + struct mlx5_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 MLX5_FLOW_TCF_ENCAP_IPV4_SRC | > + MLX5_FLOW_TCF_ENCAP_IPV4_DST; > + return 2 * SZ_NLATTR_TYPE_OF(uint32_t); > +} > + > +/** > + * Helper function to process RTE_FLOW_ITEM_TYPE_IPV6 entry in configura= tion > + * of action RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP. Fills the IPV6 address fi= elds > + * 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[out] encap > + * Structure to fill the gathered IPV6 address data. > + * > + * @return > + * The size needed the Netlink message tunnel_key > + * parameter buffer to store the item attributes. > + */ > +static int > +flow_tcf_parse_vxlan_encap_ipv6(const struct rte_flow_item_ipv6 *spec, > + struct mlx5_flow_tcf_vxlan_encap *encap) > +{ > + /* Item must be validated before. No redundant checks. */ > + assert(spec); > + memcpy(encap->ipv6.dst, spec->hdr.dst_addr, sizeof(encap->ipv6.dst)); > + memcpy(encap->ipv6.src, spec->hdr.src_addr, sizeof(encap->ipv6.src)); > + encap->mask |=3D MLX5_FLOW_TCF_ENCAP_IPV6_SRC | > + MLX5_FLOW_TCF_ENCAP_IPV6_DST; > + return SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) * 2; > +} > + > +/** > + * Helper function to process RTE_FLOW_ITEM_TYPE_UDP entry in configurat= ion > + * 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. > + * > + * @return > + * The size needed the Netlink message tunnel_key > + * parameter buffer to store the item attributes. > + */ > +static int > +flow_tcf_parse_vxlan_encap_udp(const struct rte_flow_item_udp *spec, > + const struct rte_flow_item_udp *mask, > + struct mlx5_flow_tcf_vxlan_encap *encap) > +{ > + int size =3D SZ_NLATTR_TYPE_OF(uint16_t); > + > + assert(spec); > + encap->udp.dst =3D spec->hdr.dst_port; > + encap->mask |=3D MLX5_FLOW_TCF_ENCAP_UDP_DST; > + if (!mask || mask->hdr.src_port !=3D RTE_BE16(0x0000)) { > + encap->udp.src =3D spec->hdr.src_port; > + size +=3D SZ_NLATTR_TYPE_OF(uint16_t); > + encap->mask |=3D MLX5_FLOW_TCF_ENCAP_IPV4_SRC; > + } > + return size; > +} > + > +/** > + * Helper function to process RTE_FLOW_ITEM_TYPE_VXLAN entry in configur= ation > + * 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. > + * > + * @return > + * The size needed the Netlink message tunnel_key > + * parameter buffer to store the item attributes. > + */ > +static int > +flow_tcf_parse_vxlan_encap_vni(const struct rte_flow_item_vxlan *spec, > + struct mlx5_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 MLX5_FLOW_TCF_ENCAP_VXLAN_VNI; > + return SZ_NLATTR_TYPE_OF(uint32_t); > +} > + > +/** > + * 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. > + * > + * @return > + * The size the part of Netlink message buffer to store the item > + * attributes on success, zero otherwise. The mask field in > + * result structure reflects correctly parsed items. > + */ > +static int > +flow_tcf_vxlan_encap_parse(const struct rte_flow_action *action, > + struct mlx5_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; > + 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: > + mask.eth =3D items->mask; > + spec.eth =3D items->spec; > + size +=3D flow_tcf_parse_vxlan_encap_eth(spec.eth, > + mask.eth, > + encap); > + break; > + case RTE_FLOW_ITEM_TYPE_IPV4: > + spec.ipv4 =3D items->spec; > + size +=3D flow_tcf_parse_vxlan_encap_ipv4(spec.ipv4, > + encap); > + break; > + case RTE_FLOW_ITEM_TYPE_IPV6: > + spec.ipv6 =3D items->spec; > + size +=3D flow_tcf_parse_vxlan_encap_ipv6(spec.ipv6, > + encap); > + break; > + case RTE_FLOW_ITEM_TYPE_UDP: > + mask.udp =3D items->mask; > + spec.udp =3D items->spec; > + size +=3D flow_tcf_parse_vxlan_encap_udp(spec.udp, > + mask.udp, > + encap); > + break; > + case RTE_FLOW_ITEM_TYPE_VXLAN: > + spec.vxlan =3D items->spec; > + size +=3D 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 0; > + } > + } > + return size; > +} > + > +/** > * Calculate maximum size of memory for flow items of Linux TC flower an= d > * extract specified items. > * > @@ -2148,7 +2407,7 @@ struct pedit_parser { > case RTE_FLOW_ITEM_TYPE_IPV6: > size +=3D SZ_NLATTR_TYPE_OF(uint16_t) + /* Ether type. */ > SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. */ > - SZ_NLATTR_TYPE_OF(IPV6_ADDR_LEN) * 4; > + SZ_NLATTR_DATA_OF(IPV6_ADDR_LEN) * 4; > /* dst/src IP addr and mask. */ > flags |=3D MLX5_FLOW_LAYER_OUTER_L3_IPV6; > break; > @@ -2164,6 +2423,10 @@ struct pedit_parser { > /* dst/src port and mask. */ > flags |=3D MLX5_FLOW_LAYER_OUTER_L4_TCP; > break; > + case RTE_FLOW_ITEM_TYPE_VXLAN: > + size +=3D SZ_NLATTR_TYPE_OF(uint32_t); > + flags |=3D MLX5_FLOW_LAYER_VXLAN; > + break; > default: > DRV_LOG(WARNING, > "unsupported item %p type %d," > @@ -2184,13 +2447,16 @@ struct pedit_parser { > * Pointer to the list of actions. > * @param[out] action_flags > * Pointer to the detected actions. > + * @param[out] tunnel > + * Pointer to tunnel encapsulation parameters structure to fill. > * > * @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) > + uint64_t *action_flags, > + void *tunnel) This func is to get actions and size but you are parsing and filling tunnel= info here. It would be better to move parsing to translate() because it anyway h= as multiple if conditions (same as switch/case) to set TCA_TUNNEL_KEY_ENC_* th= ere. > { > int size =3D 0; > uint64_t flags =3D 0; > @@ -2246,6 +2512,29 @@ struct pedit_parser { > 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_parse(actions, tunnel) + > + RTE_ALIGN_CEIL /* preceding encap params. */ > + (sizeof(struct mlx5_flow_tcf_vxlan_encap), > + MNL_ALIGNTO); Is it different from SZ_NLATTR_TYPE_OF(struct mlx5_flow_tcf_vxlan_encap)? O= r, use __rte_aligned(MNL_ALIGNTO) instead. > + flags |=3D MLX5_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 mlx5_flow_tcf_vxlan_decap), > + MNL_ALIGNTO); Same here. > + flags |=3D MLX5_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: > @@ -2289,6 +2578,26 @@ struct pedit_parser { > } > =20 > /** > + * 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 endian. > + */ > +static rte_be32_t make it inline. > +vxlan_vni_as_be32(const uint8_t vni[3]) > +{ > + rte_be32_t ret; Defining ret as rte_be32_t? The return value of this func which is bswap(re= t) is also rte_be32_t?? > + > + ret =3D vni[0]; > + ret =3D (ret << 8) | vni[1]; > + ret =3D (ret << 8) | vni[2]; > + return RTE_BE32(ret); Use rte_cpu_to_be_*() instead. But I still don't understand why you shuffle bytes twice. One with shift and or and other by bswap(). { union { uint8_t vni[4]; rte_be32_t dword; } ret =3D { .vni =3D { 0, vni[0], vni[1], vni[2] }, }; return ret.dword; } This will have the same result without extra cost. > +} > + > +/** > * Prepare a flow object for Linux TC flower. It calculates the maximum = size of > * memory required, allocates the memory, initializes Netlink message he= aders > * and set unique TC message handle. > @@ -2323,22 +2632,54 @@ struct pedit_parser { > struct mlx5_flow *dev_flow; > struct nlmsghdr *nlh; > struct tcmsg *tcm; > + struct mlx5_flow_tcf_vxlan_encap encap =3D {.mask =3D 0}; > + uint8_t *sp, *tun =3D NULL; > =20 > size +=3D flow_tcf_get_items_and_size(attr, items, item_flags); > - size +=3D flow_tcf_get_actions_and_size(actions, action_flags); > - dev_flow =3D rte_zmalloc(__func__, size, MNL_ALIGNTO); > + size +=3D flow_tcf_get_actions_and_size(actions, action_flags, &encap); > + dev_flow =3D rte_zmalloc(__func__, size, > + RTE_MAX(alignof(struct mlx5_flow_tcf_tunnel_hdr), > + (size_t)MNL_ALIGNTO)); Why RTE_MAX between the two? Note that it is alignment for start address of= the memory and the minimum alignment is cacheline size. On x86, non-zero value = less than 64 will have same result as 64. > 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; > } > - nlh =3D mnl_nlmsg_put_header((void *)(dev_flow + 1)); > + sp =3D (uint8_t *)(dev_flow + 1); > + if (*action_flags & MLX5_ACTION_VXLAN_ENCAP) { > + tun =3D sp; > + sp +=3D RTE_ALIGN_CEIL > + (sizeof(struct mlx5_flow_tcf_vxlan_encap), > + MNL_ALIGNTO); And why should it be aligned? As the size of dev_flow might not be aligned,= it is meaningless, isn't it? If you think it must be aligned for better performance (not much anyway), you can use __rte_aligned(MNL_ALIGNTO) on th= e struct definition but not for mlx5_flow (it's not only for tcf, have to do = it manually). > + size -=3D RTE_ALIGN_CEIL > + (sizeof(struct mlx5_flow_tcf_vxlan_encap), > + MNL_ALIGNTO); Don't you have to subtract sizeof(struct mlx5_flow) as well? But like I mentioned, if '.nlsize' below isn't needed, you don't need to have this calculation either. > + encap.hdr.type =3D MLX5_FLOW_TCF_TUNACT_VXLAN_ENCAP; > + memcpy(tun, &encap, > + sizeof(struct mlx5_flow_tcf_vxlan_encap)); > + } else if (*action_flags & MLX5_ACTION_VXLAN_DECAP) { > + tun =3D sp; > + sp +=3D RTE_ALIGN_CEIL > + (sizeof(struct mlx5_flow_tcf_vxlan_decap), > + MNL_ALIGNTO); > + size -=3D RTE_ALIGN_CEIL > + (sizeof(struct mlx5_flow_tcf_vxlan_decap), > + MNL_ALIGNTO); > + encap.hdr.type =3D MLX5_FLOW_TCF_TUNACT_VXLAN_DECAP; > + memcpy(tun, &encap, > + sizeof(struct mlx5_flow_tcf_vxlan_decap)); > + } > + 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){ > + .nlsize =3D size, > .nlh =3D nlh, > .tcm =3D tcm, > + .tunnel =3D (struct mlx5_flow_tcf_tunnel_hdr *)tun, > + .item_flags =3D *item_flags, > + .action_flags =3D *action_flags, > }, > }; > /* > @@ -2392,6 +2733,7 @@ struct pedit_parser { > 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; > @@ -2402,6 +2744,14 @@ struct pedit_parser { > const struct rte_flow_action_of_set_vlan_pcp * > of_set_vlan_pcp; > } conf; > + union { > + struct mlx5_flow_tcf_tunnel_hdr *hdr; > + struct mlx5_flow_tcf_vxlan_decap *vxlan; > + } decap; > + union { > + struct mlx5_flow_tcf_tunnel_hdr *hdr; > + struct mlx5_flow_tcf_vxlan_encap *vxlan; > + } encap; > 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; > @@ -2418,6 +2768,12 @@ struct pedit_parser { > =20 > claim_nonzero(flow_tcf_build_ptoi_table(dev, ptoi, > PTOI_TABLE_SZ_MAX(dev))); > + encap.hdr =3D NULL; > + decap.hdr =3D NULL; > + if (dev_flow->tcf.action_flags & MLX5_ACTION_VXLAN_ENCAP) dev_flow->flow->actions already has it. > + encap.vxlan =3D dev_flow->tcf.vxlan_encap; > + if (dev_flow->tcf.action_flags & MLX5_ACTION_VXLAN_DECAP) > + decap.vxlan =3D dev_flow->tcf.vxlan_decap; > nlh =3D dev_flow->tcf.nlh; > tcm =3D dev_flow->tcf.tcm; > /* Prepare API must have been called beforehand. */ > @@ -2435,7 +2791,6 @@ struct pedit_parser { > 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); > - mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, TCA_CLS_FLAGS_SKIP_SW); Why do you move it? You anyway can know if it is vxlan decap at this point. > for (; items->type !=3D RTE_FLOW_ITEM_TYPE_END; items++) { > unsigned int i; > =20 > @@ -2479,6 +2834,12 @@ struct pedit_parser { > spec.eth->type); > eth_type_set =3D 1; > } > + /* > + * L2 addresses/masks should be sent anyway, > + * including VXLAN encap/decap cases, sometimes "sometimes" sounds like a bug. Did you figure out why it is inconsistent? > + * kernel returns an error if no L2 address > + * provided and skip_sw flag is set > + */ > if (!is_zero_ether_addr(&mask.eth->dst)) { > mnl_attr_put(nlh, TCA_FLOWER_KEY_ETH_DST, > ETHER_ADDR_LEN, > @@ -2495,8 +2856,19 @@ struct pedit_parser { > ETHER_ADDR_LEN, > mask.eth->src.addr_bytes); > } > - break; > + if (decap.hdr) { > + DRV_LOG(INFO, > + "ethernet addresses are treated " > + "as inner ones for tunnel decapsulation"); > + } I know there's no enc_[src|dst]_mac in tc flower command but can you clarif= y more about this? Let me take an example. flow create 1 ingress transfer pattern eth src is 66:77:88:99:aa:bb dst is 00:11:22:33:44:55 / ipv4 src is 2.2.2.2 dst is 1.1.1.1 / udp src is 4789 dst is 4242 / vxlan vni is 0x112233 / end actions vxlan_decap / port_id id 2 / end In this case, will the mac addrs specified above be regarded as inner mac a= ddrs? That sounds very weird. If inner mac addrs have to be specified it should b= e: flow create 1 ingress transfer pattern eth / ipv4 src is 2.2.2.2 dst is 1.1.1.1 / udp src is 4789 dst is 4242 / vxlan vni is 0x112233 / eth src is 66:77:88:99:aa:bb dst is 00:11:22:33:44:55 / end actions vxlan_decap / port_id id 2 / end Isn't it? Also, I hope it to be in validate() as well. > + assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > + break; > case RTE_FLOW_ITEM_TYPE_VLAN: > + if (encap.hdr || decap.hdr) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ITEM, NULL, > + "outer VLAN is not " > + "supported for tunnels"); This should be moved to validate(). And the error message sounds like inner= vlan is allowed, doesn't it? Even if it is moved to validate(), there's no way t= o distinguish between outer vlan and inner vlan in your code. A bit confusing= . Please clarify. > item_flags |=3D MLX5_FLOW_LAYER_OUTER_VLAN; > mask.vlan =3D flow_tcf_item_mask > (items, &rte_flow_item_vlan_mask, > @@ -2528,6 +2900,7 @@ struct pedit_parser { > 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 MLX5_FLOW_LAYER_OUTER_L3_IPV4; > @@ -2538,36 +2911,53 @@ struct pedit_parser { > sizeof(flow_tcf_mask_supported.ipv4), > error); > assert(mask.ipv4); > - vlan_present ? > - TCA_FLOWER_KEY_VLAN_ETH_TYPE : > - TCA_FLOWER_KEY_ETH_TYPE, > - RTE_BE16(ETH_P_IP)); > - eth_type_set =3D 1; > - vlan_eth_type_set =3D 1; > - if (mask.ipv4 =3D=3D &flow_tcf_mask_empty.ipv4) > - break; > spec.ipv4 =3D items->spec; > - if (mask.ipv4->hdr.next_proto_id) { > - mnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO, > + if (!decap.vxlan) { > + if (!eth_type_set || !vlan_eth_type_set) { > + mnl_attr_put_u16(nlh, > + vlan_present ? > + TCA_FLOWER_KEY_VLAN_ETH_TYPE : > + TCA_FLOWER_KEY_ETH_TYPE, > + RTE_BE16(ETH_P_IP)); > + } > + eth_type_set =3D 1; > + vlan_eth_type_set =3D 1; > + if (mask.ipv4 =3D=3D &flow_tcf_mask_empty.ipv4) > + break; > + if (mask.ipv4->hdr.next_proto_id) { > + mnl_attr_put_u8 > + (nlh, TCA_FLOWER_KEY_IP_PROTO, > spec.ipv4->hdr.next_proto_id); > - ip_proto_set =3D 1; > + ip_proto_set =3D 1; > + } > + } else { > + assert(mask.ipv4 !=3D &flow_tcf_mask_empty.ipv4); > } > if (mask.ipv4->hdr.src_addr) { > - mnl_attr_put_u32(nlh, TCA_FLOWER_KEY_IPV4_SRC, > - spec.ipv4->hdr.src_addr); > - mnl_attr_put_u32(nlh, > - TCA_FLOWER_KEY_IPV4_SRC_MASK, > - mask.ipv4->hdr.src_addr); > + mnl_attr_put_u32 > + (nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV4_SRC : > + TCA_FLOWER_KEY_IPV4_SRC, > + spec.ipv4->hdr.src_addr); > + mnl_attr_put_u32 > + (nlh, decap.vxlan ? > + 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, TCA_FLOWER_KEY_IPV4_DST, > - spec.ipv4->hdr.dst_addr); > - mnl_attr_put_u32(nlh, > - TCA_FLOWER_KEY_IPV4_DST_MASK, > - mask.ipv4->hdr.dst_addr); > + mnl_attr_put_u32 > + (nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV4_DST : > + TCA_FLOWER_KEY_IPV4_DST, > + spec.ipv4->hdr.dst_addr); > + mnl_attr_put_u32 > + (nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV4_DST_MASK : > + TCA_FLOWER_KEY_IPV4_DST_MASK, > + mask.ipv4->hdr.dst_addr); > } > + assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > break; > case RTE_FLOW_ITEM_TYPE_IPV6: > item_flags |=3D MLX5_FLOW_LAYER_OUTER_L3_IPV6; > @@ -2578,38 +2968,53 @@ struct pedit_parser { > sizeof(flow_tcf_mask_supported.ipv6), > error); > assert(mask.ipv6); > - if (!eth_type_set || !vlan_eth_type_set) > - mnl_attr_put_u16(nlh, > - vlan_present ? > - TCA_FLOWER_KEY_VLAN_ETH_TYPE : > - TCA_FLOWER_KEY_ETH_TYPE, > - RTE_BE16(ETH_P_IPV6)); > - eth_type_set =3D 1; > - vlan_eth_type_set =3D 1; > - if (mask.ipv6 =3D=3D &flow_tcf_mask_empty.ipv6) > - break; > spec.ipv6 =3D items->spec; > - if (mask.ipv6->hdr.proto) { > - mnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO, > - spec.ipv6->hdr.proto); > - ip_proto_set =3D 1; > + if (!decap.vxlan) { > + if (!eth_type_set || !vlan_eth_type_set) { > + mnl_attr_put_u16(nlh, > + vlan_present ? > + TCA_FLOWER_KEY_VLAN_ETH_TYPE : > + TCA_FLOWER_KEY_ETH_TYPE, > + RTE_BE16(ETH_P_IPV6)); > + } > + eth_type_set =3D 1; > + vlan_eth_type_set =3D 1; > + if (mask.ipv6 =3D=3D &flow_tcf_mask_empty.ipv6) > + break; > + if (mask.ipv6->hdr.proto) { > + mnl_attr_put_u8 > + (nlh, TCA_FLOWER_KEY_IP_PROTO, > + spec.ipv6->hdr.proto); > + ip_proto_set =3D 1; > + } > + } else { > + assert(mask.ipv6 !=3D &flow_tcf_mask_empty.ipv6); > } > if (!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.src_addr)) { > - mnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_SRC, > + mnl_attr_put(nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV6_SRC : > + TCA_FLOWER_KEY_IPV6_SRC, > sizeof(spec.ipv6->hdr.src_addr), > spec.ipv6->hdr.src_addr); > - mnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_SRC_MASK, > + mnl_attr_put(nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK : > + TCA_FLOWER_KEY_IPV6_SRC_MASK, > sizeof(mask.ipv6->hdr.src_addr), > mask.ipv6->hdr.src_addr); > } > if (!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.dst_addr)) { > - mnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_DST, > + mnl_attr_put(nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV6_DST : > + TCA_FLOWER_KEY_IPV6_DST, > sizeof(spec.ipv6->hdr.dst_addr), > spec.ipv6->hdr.dst_addr); > - mnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_DST_MASK, > + mnl_attr_put(nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_IPV6_DST_MASK : > + TCA_FLOWER_KEY_IPV6_DST_MASK, > sizeof(mask.ipv6->hdr.dst_addr), > mask.ipv6->hdr.dst_addr); > } > + assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > break; > case RTE_FLOW_ITEM_TYPE_UDP: > item_flags |=3D MLX5_FLOW_LAYER_OUTER_L4_UDP; > @@ -2620,26 +3025,44 @@ struct pedit_parser { > sizeof(flow_tcf_mask_supported.udp), > error); > assert(mask.udp); > - 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; > spec.udp =3D items->spec; > + if (!decap.vxlan) { > + 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_BE16(spec.udp->hdr.dst_port); Use rte_cpu_to_be_*() instead. And (=3D) sign has to be moved up. > + } > if (mask.udp->hdr.src_port) { > - mnl_attr_put_u16(nlh, TCA_FLOWER_KEY_UDP_SRC, > - spec.udp->hdr.src_port); > - mnl_attr_put_u16(nlh, > - TCA_FLOWER_KEY_UDP_SRC_MASK, > - mask.udp->hdr.src_port); > + mnl_attr_put_u16 > + (nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_UDP_SRC_PORT : > + TCA_FLOWER_KEY_UDP_SRC, > + spec.udp->hdr.src_port); > + mnl_attr_put_u16 > + (nlh, decap.vxlan ? > + 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, TCA_FLOWER_KEY_UDP_DST, > - spec.udp->hdr.dst_port); > - mnl_attr_put_u16(nlh, > - TCA_FLOWER_KEY_UDP_DST_MASK, > - mask.udp->hdr.dst_port); > + mnl_attr_put_u16 > + (nlh, decap.vxlan ? > + TCA_FLOWER_KEY_ENC_UDP_DST_PORT : > + TCA_FLOWER_KEY_UDP_DST, > + spec.udp->hdr.dst_port); > + mnl_attr_put_u16 > + (nlh, decap.vxlan ? > + 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 MLX5_FLOW_LAYER_OUTER_L4_TCP; > @@ -2682,7 +3105,15 @@ struct pedit_parser { > 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); > + 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); > default: > return rte_flow_error_set(error, ENOTSUP, > RTE_FLOW_ERROR_TYPE_ITEM, > @@ -2715,6 +3146,14 @@ struct pedit_parser { > 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; > + } > mnl_attr_put(nlh, TCA_MIRRED_PARMS, > sizeof(struct tc_mirred), > &(struct tc_mirred){ > @@ -2724,6 +3163,7 @@ struct pedit_parser { > }); > 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_JUMP: > conf.jump =3D actions->conf; > @@ -2741,6 +3181,7 @@ struct pedit_parser { > }); > 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_DROP: > na_act_index =3D > @@ -2827,6 +3268,76 @@ struct pedit_parser { > (na_vlan_priority) =3D > conf.of_set_vlan_pcp->vlan_pcp; > } > + assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > + 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); > + 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 & MLX5_FLOW_TCF_ENCAP_UDP_DST) > + mnl_attr_put_u16(nlh, > + TCA_TUNNEL_KEY_ENC_DST_PORT, > + encap.vxlan->udp.dst); > + if (encap.vxlan->mask & MLX5_FLOW_TCF_ENCAP_IPV4_SRC) > + mnl_attr_put_u32(nlh, > + TCA_TUNNEL_KEY_ENC_IPV4_SRC, > + encap.vxlan->ipv4.src); > + if (encap.vxlan->mask & MLX5_FLOW_TCF_ENCAP_IPV4_DST) > + mnl_attr_put_u32(nlh, > + TCA_TUNNEL_KEY_ENC_IPV4_DST, > + encap.vxlan->ipv4.dst); > + if (encap.vxlan->mask & MLX5_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 & MLX5_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 & MLX5_FLOW_TCF_ENCAP_VXLAN_VNI) > + mnl_attr_put_u32(nlh, > + TCA_TUNNEL_KEY_ENC_KEY_ID, > + vxlan_vni_as_be32 > + (encap.vxlan->vxlan.vni)); > +#ifdef TCA_TUNNEL_KEY_NO_CSUM > + mnl_attr_put_u8(nlh, TCA_TUNNEL_KEY_NO_CSUM, 0); > +#endif TCA_TUNNEL_KEY_NO_CSUM is anyway defined like others, then why do you treat= it differently with #ifdef/#endif? > + 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: > @@ -2850,7 +3361,11 @@ struct pedit_parser { > assert(na_flower); > assert(na_flower_act); > mnl_attr_nest_end(nlh, na_flower_act); > + mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, > + dev_flow->tcf.action_flags & MLX5_ACTION_VXLAN_DECAP > + ? 0 : TCA_CLS_FLAGS_SKIP_SW); > mnl_attr_nest_end(nlh, na_flower); > + assert(dev_flow->tcf.nlsize >=3D nlh->nlmsg_len); > return 0; > }