From patchwork Wed Apr 17 08:35:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ophir Munk X-Patchwork-Id: 1086850 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=Mellanox.com header.i=@Mellanox.com header.b="iCIXin+8"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44kbDC4XNyz9s4Y for ; Wed, 17 Apr 2019 18:35:54 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 554DAC7F; Wed, 17 Apr 2019 08:35:52 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 6F501941 for ; Wed, 17 Apr 2019 08:35:51 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from EUR03-VE1-obe.outbound.protection.outlook.com (mail-eopbgr50060.outbound.protection.outlook.com [40.107.5.60]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E5383F4 for ; Wed, 17 Apr 2019 08:35:49 +0000 (UTC) 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=T3B2E4oBYQBBxN70TlrlhojXxlioEMsqpYIjCvIIUvs=; b=iCIXin+8DZocCF0RfzWKrUeEQoe7qvR+hEw/vve13NDXrKs1ShMEKlWRXTqIegpDQ5sk9S9AXh5nPHLQ8OH6cIIIdp3q3FGOVWRZNAfdGN8WpyNlal1/nb6sk5TPot2+PNM5/XORlyrjfLDlxK8lJYxAsSR8ESGMimKdTeZyDE0= Received: from AM0PR05MB4209.eurprd05.prod.outlook.com (52.134.95.150) by AM0PR05MB5924.eurprd05.prod.outlook.com (20.178.202.150) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1792.19; Wed, 17 Apr 2019 08:35:46 +0000 Received: from AM0PR05MB4209.eurprd05.prod.outlook.com ([fe80::e043:37:2006:3fe5]) by AM0PR05MB4209.eurprd05.prod.outlook.com ([fe80::e043:37:2006:3fe5%2]) with mapi id 15.20.1792.018; Wed, 17 Apr 2019 08:35:46 +0000 From: Ophir Munk To: "ovs-dev@openvswitch.org" Thread-Topic: [PATCH v1] netdev-rte-offloads: Reassign vport netdev functions. Thread-Index: AQHU9PiNawLNZ7fjFEWs1Rv+EUhCXA== Date: Wed, 17 Apr 2019 08:35:46 +0000 Message-ID: <1555490103-10275-1-git-send-email-ophirmu@mellanox.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: LO2P265CA0339.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:d::15) To AM0PR05MB4209.eurprd05.prod.outlook.com (2603:10a6:208:61::22) authentication-results: spf=none (sender IP is ) smtp.mailfrom=ophirmu@mellanox.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 1.8.3.1 x-originating-ip: [37.142.13.130] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: b12a0bbc-95e0-4de2-b180-08d6c30fafe3 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600140)(711020)(4605104)(4618075)(2017052603328)(7193020); SRVR:AM0PR05MB5924; x-ms-traffictypediagnostic: AM0PR05MB5924: x-microsoft-antispam-prvs: x-forefront-prvs: 0010D93EFE x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(39860400002)(366004)(376002)(346002)(396003)(136003)(199004)(189003)(3846002)(5660300002)(6436002)(8936002)(50226002)(8676002)(81166006)(26005)(4720700003)(2351001)(186003)(7736002)(305945005)(81156014)(2906002)(6512007)(97736004)(53936002)(68736007)(6916009)(256004)(14444005)(5640700003)(6486002)(316002)(478600001)(105586002)(52116002)(99286004)(54906003)(107886003)(36756003)(2501003)(30864003)(25786009)(4326008)(66066001)(14454004)(6506007)(486006)(386003)(71200400001)(71190400001)(102836004)(106356001)(6116002)(476003)(86362001)(2616005); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR05MB5924; H:AM0PR05MB4209.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-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: y0pAN5jriRjF+HkHpY69Lzd5QPiFfTpceZzNokP8TWcyaUS/Shd2hDhxC7+Ap9xHnrWM/N3E4RsshjKRaRx8JyfhGcPnMr77ryjii87cKh7E+TNYveBVaJhyRDyGRGJxUNmBYGggGjcroGpepa5FB/1XzYjbqe5Ghfvd2TR2wIJ0eWE5cKglYgMjM0VL/M399X8QryOhU+Kupt3XPkDa8TRG9NS12EW4yR3nWfDCdcO8nrCFrR1O4c4md7qYmexh8A92OW3pOxldVXh7s5PxRVL4tzFFdbVhmSvTDw7eb8nWYK7vYC0wdA2GQvAK85POJzHRyW304D/IbxsCfGVluyD97j/Lxrs1nF1Rd4YDOlctl2dqU+KLln3dYoDMH857SuxFeKle7mLjFCF3LHYI6jQFVt3B+YVY0gahoOVlCd4= MIME-Version: 1.0 X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-Network-Message-Id: b12a0bbc-95e0-4de2-b180-08d6c30fafe3 X-MS-Exchange-CrossTenant-originalarrivaltime: 17 Apr 2019 08:35:46.6687 (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-Transport-CrossTenantHeadersStamped: AM0PR05MB5924 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Ilya Maximets Subject: [ovs-dev] [PATCH v1] netdev-rte-offloads: Reassign vport netdev functions. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Roni Bar Yanai vport offloaded functions should have a different implementation for kernel based OVS versus dpdk based OVS. Currently there is an unconditional execution of a kernel based calls even if the vport was added by dpif-netdev rather than by dpif-netlink. Before this commit and in case hw-offload=true adding a netdev datapath vport resulted in an error since the vport kernel based APIs were called. In practice the API returned immediately on a get_ifindex() failure (see [1]), which caused no harm, but it is required to avoid such scenarios in advance. In case of a netdev datapath vport flow functions must be updated at runtime. This commit reassigns flow functions to NULL when such a vport is added. It uses a duplicated vport class to keep the original default kernel vport class intact. This enables using vports in a mixed environment of kernel and netdev (userspace) bridges at the same time. [1] ovs|00002|netdev_tc_offloads(dp_netdev_flow_5)|ERR|flow_put: failed to get ifindex for vxlan_sys_4789: No such device Reviewed-by: Asaf Penso Co-authored-by: Ophir Munk Signed-off-by: Ophir Munk Signed-off-by: Roni Bar Yanai --- lib/dpif-netdev.c | 2 + lib/netdev-rte-offloads.c | 47 +++++++++++ lib/netdev-rte-offloads.h | 5 ++ lib/netdev-vport.c | 211 ++++++++++++++++++++++++++++------------------ lib/netdev-vport.h | 4 + 5 files changed, 188 insertions(+), 81 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 4d6d0c3..9a48038 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -51,6 +51,7 @@ #include "latch.h" #include "netdev.h" #include "netdev-provider.h" +#include "netdev-rte-offloads.h" #include "netdev-vport.h" #include "netlink.h" #include "odp-execute.h" @@ -1865,6 +1866,7 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev, if (!error) { *port_nop = port_no; error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no); + netdev_rte_offloads_port_add(netdev); } ovs_mutex_unlock(&dp->port_mutex); diff --git a/lib/netdev-rte-offloads.c b/lib/netdev-rte-offloads.c index e9ab086..85f01e5 100644 --- a/lib/netdev-rte-offloads.c +++ b/lib/netdev-rte-offloads.c @@ -22,6 +22,7 @@ #include "cmap.h" #include "dpif-netdev.h" #include "netdev-provider.h" +#include "netdev-vport.h" #include "openvswitch/match.h" #include "openvswitch/vlog.h" #include "packets.h" @@ -731,3 +732,49 @@ netdev_rte_offloads_flow_del(struct netdev *netdev, const ovs_u128 *ufid, return netdev_rte_offloads_destroy_flow(netdev, ufid, rte_flow); } + +/* + * Vport netdev flow pointers are initialized by default to kernel calls. + * They should be nullified or be set to a valid netdev (userspace) calls. + */ +#define NULLIFY(f) (ndc->f = NULL) +static void +netdev_rte_offloads_vxlan_init(struct netdev *netdev) +{ + /* + * Clone default function pointers some + * of which may be kernel flow pointers. + */ + struct netdev_class *ndc = netdev_vport_dup_class_once(netdev); + if (!ndc) { + VLOG_DBG("Vport netdev_class offload api cannot be updated."); + return; + } + + /* Override kernel flow pointers. */ + NULLIFY(flow_put); + NULLIFY(flow_flush); + NULLIFY(flow_dump_create); + NULLIFY(flow_dump_destroy); + NULLIFY(flow_dump_next); + NULLIFY(flow_put); + NULLIFY(flow_get); + NULLIFY(flow_del); + NULLIFY(init_flow_api); + + netdev_vport_update_class(netdev, ndc); +} + +/* + * This function is called as part of adding a new dpif netdev port. + * In case of vport class of "vxlan" type we update it to match netdev + * datapath apis. + */ +void +netdev_rte_offloads_port_add(struct netdev *netdev) +{ + const char *type = netdev_get_type(netdev); + if (!strcmp("vxlan", type)) { + netdev_rte_offloads_vxlan_init(netdev); + } +} diff --git a/lib/netdev-rte-offloads.h b/lib/netdev-rte-offloads.h index 18c8a75..7fbe414 100644 --- a/lib/netdev-rte-offloads.h +++ b/lib/netdev-rte-offloads.h @@ -50,6 +50,11 @@ int netdev_rte_offloads_flow_put(struct netdev *netdev, struct match *match, int netdev_rte_offloads_flow_del(struct netdev *netdev, const ovs_u128 *ufid, struct dpif_flow_stats *stats); +/* + * Called by dpif netdev when a port is added + */ +void netdev_rte_offloads_port_add(struct netdev *netdev); + #define DPDK_FLOW_OFFLOAD_API \ .flow_put = netdev_rte_offloads_flow_put, \ .flow_del = netdev_rte_offloads_flow_del diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 808a43f..e27bc5e 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -1131,90 +1131,95 @@ netdev_vport_get_ifindex(const struct netdev *netdev_) .get_tunnel_config = get_netdev_tunnel_config, \ .get_status = tunnel_get_status +/* The name of the dpif_port should be short enough to accomodate adding + * a port number to the end if one is necessary. */ +static struct vport_class vport_classes[] = { + { "genev_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "geneve", + .build_header = netdev_geneve_build_header, + .push_header = netdev_tnl_push_udp_header, + .pop_header = netdev_geneve_pop_header, + .get_ifindex = NETDEV_VPORT_GET_IFINDEX, + }, + {{NULL, NULL, 0, 0}} + }, + { "gre_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "gre", + .build_header = netdev_gre_build_header, + .push_header = netdev_gre_push_header, + .pop_header = netdev_gre_pop_header, + .get_ifindex = NETDEV_VPORT_GET_IFINDEX, + }, + {{NULL, NULL, 0, 0}} + }, + { "vxlan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "vxlan", + .build_header = netdev_vxlan_build_header, + .push_header = netdev_tnl_push_udp_header, + .pop_header = netdev_vxlan_pop_header, + .get_ifindex = NETDEV_VPORT_GET_IFINDEX + }, + {{NULL, NULL, 0, 0}} + }, + { "lisp_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "lisp" + }, + {{NULL, NULL, 0, 0}} + }, + { "stt_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "stt" + }, + {{NULL, NULL, 0, 0}} + }, + { "erspan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "erspan", + .build_header = netdev_erspan_build_header, + .push_header = netdev_erspan_push_header, + .pop_header = netdev_erspan_pop_header + }, + {{NULL, NULL, 0, 0}} + }, + { "ip6erspan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "ip6erspan", + .build_header = netdev_erspan_build_header, + .push_header = netdev_erspan_push_header, + .pop_header = netdev_erspan_pop_header + }, + {{NULL, NULL, 0, 0}} + }, + { "ip6gre_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "ip6gre", + .build_header = netdev_gre_build_header, + .push_header = netdev_gre_push_header, + .pop_header = netdev_gre_pop_header + }, + {{NULL, NULL, 0, 0}} + }, +}; + +#define NUM_VPORT_CLASSES (sizeof vport_classes / sizeof vport_classes[0]) + +static struct vport_class dup_vport_classes[NUM_VPORT_CLASSES]; + void netdev_vport_tunnel_register(void) { - /* The name of the dpif_port should be short enough to accomodate adding - * a port number to the end if one is necessary. */ - static struct vport_class vport_classes[] = { - { "genev_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "geneve", - .build_header = netdev_geneve_build_header, - .push_header = netdev_tnl_push_udp_header, - .pop_header = netdev_geneve_pop_header, - .get_ifindex = NETDEV_VPORT_GET_IFINDEX, - }, - {{NULL, NULL, 0, 0}} - }, - { "gre_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "gre", - .build_header = netdev_gre_build_header, - .push_header = netdev_gre_push_header, - .pop_header = netdev_gre_pop_header, - .get_ifindex = NETDEV_VPORT_GET_IFINDEX, - }, - {{NULL, NULL, 0, 0}} - }, - { "vxlan_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "vxlan", - .build_header = netdev_vxlan_build_header, - .push_header = netdev_tnl_push_udp_header, - .pop_header = netdev_vxlan_pop_header, - .get_ifindex = NETDEV_VPORT_GET_IFINDEX - }, - {{NULL, NULL, 0, 0}} - }, - { "lisp_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "lisp" - }, - {{NULL, NULL, 0, 0}} - }, - { "stt_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "stt" - }, - {{NULL, NULL, 0, 0}} - }, - { "erspan_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "erspan", - .build_header = netdev_erspan_build_header, - .push_header = netdev_erspan_push_header, - .pop_header = netdev_erspan_pop_header - }, - {{NULL, NULL, 0, 0}} - }, - { "ip6erspan_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "ip6erspan", - .build_header = netdev_erspan_build_header, - .push_header = netdev_erspan_push_header, - .pop_header = netdev_erspan_pop_header - }, - {{NULL, NULL, 0, 0}} - }, - { "ip6gre_sys", - { - TUNNEL_FUNCTIONS_COMMON, - .type = "ip6gre", - .build_header = netdev_gre_build_header, - .push_header = netdev_gre_push_header, - .pop_header = netdev_gre_pop_header - }, - {{NULL, NULL, 0, 0}} - }, - }; static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; if (ovsthread_once_start(&once)) { @@ -1225,6 +1230,8 @@ netdev_vport_tunnel_register(void) netdev_register_provider(&vport_classes[i].netdev_class); } + memset(dup_vport_classes, 0, sizeof dup_vport_classes); + unixctl_command_register("tnl/egress_port_range", "min max", 0, 2, netdev_tnl_egress_port_range, NULL); @@ -1247,3 +1254,45 @@ netdev_vport_patch_register(void) simap_init(&patch_class.global_cfg_tracker); netdev_register_provider(&patch_class.netdev_class); } + +/* + * This functions receives a netdev pointer which contains default + * netdev_class fields (such as kernel flow functions pointers). + * It returns a duplicated netdev_class that can be overriden by the caller + */ +struct netdev_class * +netdev_vport_dup_class_once(struct netdev *netdev) +{ + unsigned int i; + struct vport_class *vpclass; + struct netdev_class *ndclass = NULL; + + if (!is_vport_class(netdev->netdev_class)) { + goto out; + } + + /* Get the vport_class which contains the netdev_class. */ + vpclass = vport_class_cast(netdev_get_class(netdev)); + /* Calculate vpclass entry index in the array 'vport_classes' */ + i = vpclass - &vport_classes[0]; + if (i >= NUM_VPORT_CLASSES) { + goto out; + } + /* Entry duplication should be done only once */ + if (!dup_vport_classes[i].dpif_port) { + memcpy(&dup_vport_classes[i], vpclass, sizeof *vpclass); + } + /* Get the duplicated netdev_class pointer */ + ndclass = &dup_vport_classes[i].netdev_class; +out: + return ndclass; +} + +void +netdev_vport_update_class(struct netdev *netdev, struct netdev_class *ndclass) +{ + if (is_vport_class(netdev->netdev_class)) { + netdev->netdev_class = ndclass; + } +} + diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h index 9d756a2..d100f76 100644 --- a/lib/netdev-vport.h +++ b/lib/netdev-vport.h @@ -42,6 +42,10 @@ void netdev_vport_inc_tx(const struct netdev *, bool netdev_vport_is_vport_class(const struct netdev_class *); const char *netdev_vport_class_get_dpif_port(const struct netdev_class *); +struct netdev_class *netdev_vport_dup_class_once(struct netdev *netdev); +void netdev_vport_update_class(struct netdev *netdev, + struct netdev_class *ndclass); + #ifndef _WIN32 enum { NETDEV_VPORT_NAME_BUFSIZE = 16 }; #else