From patchwork Sat Jan 11 00:40:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manoj Sharma X-Patchwork-Id: 1221507 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nutanix.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=nutanix.com header.i=@nutanix.com header.a=rsa-sha256 header.s=proofpoint20171006 header.b=EMIxHWiI; dkim-atps=neutral Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vgy73tTPz9sR0 for ; Sat, 11 Jan 2020 11:41:03 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 997CB86C6A; Sat, 11 Jan 2020 00:41:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lcAb5073L3AW; Sat, 11 Jan 2020 00:40:56 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 5198E86C6D; Sat, 11 Jan 2020 00:40:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 43234C1D8B; Sat, 11 Jan 2020 00:40:55 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3B12AC0881 for ; Sat, 11 Jan 2020 00:40:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 2A07985413 for ; Sat, 11 Jan 2020 00:40:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gEMn5_UX4HuO for ; Sat, 11 Jan 2020 00:40:51 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx0a-002c1b01.pphosted.com (mx0a-002c1b01.pphosted.com [148.163.151.68]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 1810A8521D for ; Sat, 11 Jan 2020 00:40:50 +0000 (UTC) Received: from pps.filterd (m0127840.ppops.net [127.0.0.1]) by mx0a-002c1b01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B0Qg7Y002859 for ; Fri, 10 Jan 2020 16:40:49 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nutanix.com; h=from : to : cc : subject : date : message-id : references : in-reply-to : content-type : content-transfer-encoding : mime-version; s=proofpoint20171006; bh=RM2+CYdltLBDJ6/5DLCMaMaE9ZKAOrg431P06mT9fp4=; b=EMIxHWiIGLu/HBA9/ud4YMtTJFdxKf7lDvYftblsUP/D8q75yQkfo/hjOA+zFkTE496D kObC4954hrDYf5jxRl0OT26fUAHjAjRlc2r1UTMW88q+hrlNISUcDs5833FyFs+6mnfs dPyI76sARghwf+SvaYKXYP1CcIDwHb0k4cWLoy6Ble0PFDXr71LhLeVFp23Ghi4N7h8g o1wLB+lcydTebFqLoU5GoRcPdgoEZ7pxN47b77Jr/xfC1luRuvSvLfd/dMSwl2FfqNOy wtiLCokAOOkVwhpeBsO25r83nNk+Nuf3Uib9iMc85wkbHnq9tUB5gpur43TXj/aT98+Q pw== Received: from nam10-dm6-obe.outbound.protection.outlook.com (mail-dm6nam10lp2100.outbound.protection.outlook.com [104.47.58.100]) by mx0a-002c1b01.pphosted.com with ESMTP id 2xex13rptg-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 10 Jan 2020 16:40:49 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CoUXjdZHowU+RmyJ2WYPL0D2rZ/qz07aw0QCyQvYzLIHLSDEzBpRAWgHezvmb3xZBM+F0+0YiG6/SX6WE+iEuyvqL6hIihvmwayOHmW47eawGBz2dzoDyyMyrzZCa1wzSwGypyR9nDeDLkFvn4oeMeNUeoBJV+dk7A8PdxI4BEoNW7h+YaG/hB84r/Acq1zSiY+nly9644xpS80WdNSC1O9JEeguN+d4cQHHx3jZWlNdqJNeYTAd+FnK0aIC4ZBEevUM4agaoumMFVktcPqKHuWbKeuSfHYmGvE0Rvd2g3QY1BbkYSvA3WHcoqvdySbmdoWUsoeF83EiOQSWW9Iulw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RM2+CYdltLBDJ6/5DLCMaMaE9ZKAOrg431P06mT9fp4=; b=Z2KAnA8rk/8S6zkDbnquDZadZB/9DGRD9Kin+c1k8cZ/JQ5O3kFufLOx+Jzvk1BoJkJpDIxs3TBe82/YnlcQ256ETPvmMJhymiEXYdv7elyNbIAaU9tUvgXNJXwe42STm3kc5aEHlGHLVm6spPSp2twcRepBDRgqJwg1OP/g6hMxoRbicHJw2KZF9M3dEdCfFkq7lM78hyGHA2Z2ylQPLNzH+BYXKYvQ7dL8BE1gHxsoJN6E+QSpOp3RVv7uUqzYLVUP+q25tJERbnVwdtYPgsKGRTXpJt++gb1XlvZwxwSSOwGASL+Vosy6tfckZdKC/kUj0gxOY0yvzYNABNwzuQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nutanix.com; dmarc=pass action=none header.from=nutanix.com; dkim=pass header.d=nutanix.com; arc=none Received: from BYAPR02MB4614.namprd02.prod.outlook.com (52.135.238.212) by BYAPR02MB5608.namprd02.prod.outlook.com (20.177.229.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2602.11; Sat, 11 Jan 2020 00:40:48 +0000 Received: from BYAPR02MB4614.namprd02.prod.outlook.com ([fe80::c08e:617f:5b69:a4d3]) by BYAPR02MB4614.namprd02.prod.outlook.com ([fe80::c08e:617f:5b69:a4d3%6]) with mapi id 15.20.2602.019; Sat, 11 Jan 2020 00:40:48 +0000 Received: from localhost.localdomain (192.146.154.3) by BY5PR04CA0016.namprd04.prod.outlook.com (2603:10b6:a03:1d0::26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.2623.9 via Frontend Transport; Sat, 11 Jan 2020 00:40:47 +0000 From: Manoj Sharma To: "ovs-dev@openvswitch.org" Thread-Topic: [PATCH v2 ovn 1/3] Forwarding group to load balance l2 traffic with liveness detection Thread-Index: AQHVyBfE0xJgBQNOFEqkZZubLaKOWg== Date: Sat, 11 Jan 2020 00:40:48 +0000 Message-ID: <20200111004027.21707-2-manoj.sharma@nutanix.com> References: <20200111004027.21707-1-manoj.sharma@nutanix.com> In-Reply-To: <20200111004027.21707-1-manoj.sharma@nutanix.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: BY5PR04CA0016.namprd04.prod.outlook.com (2603:10b6:a03:1d0::26) To BYAPR02MB4614.namprd02.prod.outlook.com (2603:10b6:a03:5b::20) x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.17.2 (Apple Git-113) x-originating-ip: [192.146.154.3] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 45b6041a-5b41-413e-1a18-08d7962ee665 x-ms-traffictypediagnostic: BYAPR02MB5608: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-proofpoint-crosstenant: true x-ms-oob-tlc-oobclassifiers: OLM:2733; x-forefront-prvs: 0279B3DD0D x-forefront-antispam-report: SFV:SPM; SFS:(10019020)(346002)(136003)(366004)(39860400002)(396003)(376002)(199004)(189003)(66574012)(6506007)(5660300002)(52116002)(71200400001)(6916009)(2616005)(8676002)(86362001)(1076003)(8936002)(186003)(26005)(316002)(16526019)(81156014)(81166006)(30864003)(44832011)(478600001)(4326008)(66446008)(66946007)(64756008)(956004)(66476007)(6512007)(6486002)(69590400006)(36756003)(2906002)(66556008)(107886003)(64030200002); DIR:OUT; SFP:1501; SCL:5; SRVR:BYAPR02MB5608; H:BYAPR02MB4614.namprd02.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: nutanix.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: hP3FYyKcr4gYUBvAS9P3B7QWb/L7d1KgOfTt+t+XR/biCQ4MnPr3y3BUW40ca89W7pl4Dhyu5AaoSu8pG5XIYlDNTCSXfIAaEruYWrpkvphlfYYiwuyX66+SWEwZcd8nWl9h+Jh1/txcmKdPu0YG70SmosdJGdqpkz5LjTQroskhJ/ZX+Q5FmKQHc+mPt8qVy+hUYpuSRLPOTdTRuPRRXqKJrqQzJPYLcJ7Ke+p5V891baKR7USGn4IVabXS5dneKQsv9oDdD87XOUH9myOL3Oqk5ogrFYi+QUocJNythgJ2FPBJIXF8eS/kPpDw/l1Aqjkwk0PVA9xY++zQzOYUJq4zlwPiLhs6rNLPxQg5ShjXC1SegCSUDi5V09j6rRB5JfNkvZS3VrabkccCYmpOhsjbwbfPBZZzdpjDWp2Fi9WZ4tNWBQCjaPA3j2DzeJfoEleJosdbGFgNIwa9kto9TgK88MW6VfLIcI1bBoG7eKlmt+Ja5SW9ECSha7chz+cLrYCwYNPuBpjS/aHrNsq/XdaOxwyU/T0CTbILBHfYNZ1O3GmyY8zti+FMRXPvsflQ8ABhKlCyfCQs3OMi2JFX1oCwcTPF8VY3YvfeMYOAXKcAs7YmQn8zY366/HxlzfEpjUF/LHb4Ld1wa42H+NlydeJe4ABCEL6J8WCHCqUAqBwA79xlDv9y2PoeQPe87r2dUn5mGNIkC8pt3PTZi7gJxVDtmOmtE8wqHeYkfGtUpPTK9HPbXZzR5ioGUbB60fd80aqZIR9fhqULz/FykTCAohqZs9d/FZ6GiQiyfWwCIw86MpAroLpV3DVz2SSoCLBk MIME-Version: 1.0 X-OriginatorOrg: nutanix.com X-MS-Exchange-CrossTenant-Network-Message-Id: 45b6041a-5b41-413e-1a18-08d7962ee665 X-MS-Exchange-CrossTenant-originalarrivaltime: 11 Jan 2020 00:40:48.1507 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: bb047546-786f-4de1-bd75-24e5b6f79043 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: V/9dRR4wnbBslWEiBmN1xuOai5oisOhNcMbKOZvlk5vbrKo97HBj8izQX2O3ghML6ba5OSJKVRrQ+RkdoqEKfZt6WPXp1ue/76y6zKqT04o= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB5608 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Reason: safe Subject: [ovs-dev] [PATCH v2 ovn 1/3] Forwarding group to load balance l2 traffic with liveness detection X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Add a forwarding group table and a reference to the logical switch it is configured on. The forwarding group is configured with a virtual IP, virtual MAC and a number of logical switch ports from a logical switch. Signed-off-by: Manoj Sharma Signed-off-by: Manoj Sharma > --- ovn-nb.ovsschema | 18 +++- ovn-nb.xml | 35 +++++++ utilities/ovn-nbctl.8.xml | 37 +++++++ utilities/ovn-nbctl.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 341 insertions(+), 2 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 12999a4..99b6285 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", "version": "5.18.0", - "cksum": "2806349485 24196", + "cksum": "63300136 24879", "tables": { "NB_Global": { "columns": { @@ -59,7 +59,12 @@ "min": 0, "max": "unlimited"}}, "external_ids": { "type": {"key": "string", "value": "string", - "min": 0, "max": "unlimited"}}}, + "min": 0, "max": "unlimited"}}, + "forwarding_groups": { + "type": {"key": {"type": "uuid", + "refTable": "Forwarding_Group", + "refType": "strong"}, + "min": 0, "max": "unlimited"}}}, "isRoot": true}, "Logical_Switch_Port": { "columns": { @@ -113,6 +118,15 @@ "min": 0, "max": "unlimited"}}}, "indexes": [["name"]], "isRoot": false}, + "Forwarding_Group": { + "columns": { + "name": {"type": "string"}, + "vip": {"type": "string"}, + "vmac": {"type": "string"}, + "liveness": {"type": "boolean"}, + "child_port": {"type": {"key": "string", + "min": 1, "max": "unlimited"}}}, + "isRoot": false}, "Address_Set": { "columns": { "name": {"type": "string"}, diff --git a/ovn-nb.xml b/ovn-nb.xml index 5ae52bb..decb4ae 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -197,6 +197,11 @@ Please see the table. + + Groups a set of logical port endpoints for traffic going out of the + logical switch. + +

These columns provide names for the logical switch. From OVN's @@ -1152,6 +1157,36 @@ + +

+ Each row represents one forwarding group. +

+ + + A name for the forwarding group. This name has no special meaning or + purpose other than to provide convenience for human interaction with + the ovn-nb database. + + + + The virtual IP address assigned to the forwarding group. It will respond + with vmac when an ARP request is sent for vip. + + + + The virtual MAC address assigned to the forwarding group. + + + + If set to true, liveness is enabled for child ports + otherwise it is disabled. + + + + List of child ports in the forwarding group. + +
+

Each row in this table represents a named set of addresses. diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 88ebd13..2f3badd 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -483,6 +483,43 @@ +

Forwarding Group Commands

+ +
+
[--liveness]fwd-group-add group switch vip vmac ports
+
+

+ Creates a new forwarding group named group as the name + with the provided vip and vmac. vip + should be a virtual IP address and vmac should be a + virtual MAC address to access the forwarding group. ports + are the logical switch port names that are put in the forwarding + group. Example for ports is lsp1 lsp2 ... + Traffic destined to virtual IP of the forwarding group will be load + balanced to all the child ports. +

+

+ When --liveness is specified then child ports are + expected to be bound to external devices like routers. BFD should + be configured between hypervisors and the external devices. + The child port selection will become dependent on BFD status with + its external device. +

+
+ +
[--if-exists] fwd-group-del group
+
+ Deletes group. It is an error if group does + not exist, unless --if-exists is specified. +
+ +
fwd-group-list [switch]
+
+ Lists all existing forwarding groups, If switch is specified + then only the forwarding groups configured for switch will + be listed. +
+

Logical Router Commands

diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 46ba3a9..39f53da 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -648,6 +648,13 @@ Logical switch port commands:\n\ lsp-get-dhcpv6-options PORT get the dhcpv6 options for PORT\n\ lsp-get-ls PORT get the logical switch which the port belongs to\n\ \n\ +Forwarding group commands:\n\ + [--liveness]\n\ + fwd-group-add GROUP SWITCH VIP VMAC PORTS...\n\ + add a forwarding group on SWITCH\n\ + fwd-group-del GROUP delete a forwarding group\n\ + fwd-group-list [SWITCH] print forwarding groups\n\ +\n\ Logical router commands:\n\ lr-add [ROUTER] create a logical router named ROUTER\n\ lr-del ROUTER delete ROUTER and all its ports\n\ @@ -4720,6 +4727,244 @@ nbctl_lrp_get_redirect_type(struct ctl_context *ctx) !redirect_type ? "overlay": redirect_type); } +static const struct nbrec_forwarding_group * +fwd_group_by_name_or_uuid(struct ctl_context *ctx, const char *id) +{ + const struct nbrec_forwarding_group *fwd_group = NULL; + struct uuid fwd_uuid; + + bool is_uuid = uuid_from_string(&fwd_uuid, id); + if (is_uuid) { + fwd_group = nbrec_forwarding_group_get_for_uuid(ctx->idl, &fwd_uuid); + } + + if (!fwd_group) { + NBREC_FORWARDING_GROUP_FOR_EACH(fwd_group, ctx->idl) { + if (!strcmp(fwd_group->name, id)) { + break; + } + } + } + + return fwd_group; +} + +static const struct nbrec_logical_switch * +fwd_group_to_logical_switch(struct ctl_context *ctx, + const struct nbrec_forwarding_group *fwd_group) +{ + if (!fwd_group) { + return NULL; + } + + const struct nbrec_logical_switch_port *lsp; + char *error = lsp_by_name_or_uuid(ctx, fwd_group->child_port[0], + false, &lsp); + if (error) { + ctx->error = error; + return NULL; + } + if (!lsp) { + return NULL; + } + + const struct nbrec_logical_switch *ls; + error = lsp_to_ls(ctx->idl, lsp, &ls); + if (error) { + ctx->error = error; + return NULL; + } + + if (!ls) { + return NULL; + } + + return ls; +} + +static void +nbctl_fwd_group_add(struct ctl_context *ctx) +{ + if (ctx->argc <= 5) { + ctl_error(ctx, "Usage : ovn-nbctl fwd-group-add group switch vip vmac " + "child_ports..."); + return; + } + + /* Check if the forwarding group already exists */ + const char *fwd_group_name = ctx->argv[1]; + if (fwd_group_by_name_or_uuid(ctx, fwd_group_name)) { + ctl_error(ctx, "%s: a forwarding group by this name already exists", + fwd_group_name); + return; + } + + /* Check if the logical switch exists */ + const char *ls_name = ctx->argv[2]; + const struct nbrec_logical_switch *ls = NULL; + char *error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); + if (error) { + ctx->error = error; + return; + } + + /* Virtual IP for the group */ + ovs_be32 ipv4 = 0; + const char *fwd_group_vip = ctx->argv[3]; + if (!ip_parse(fwd_group_vip, &ipv4)) { + ctl_error(ctx, "invalid ip address %s", fwd_group_vip); + return; + } + + /* Virtual MAC for the group */ + const char *fwd_group_vmac = ctx->argv[4]; + struct eth_addr ea; + if (!eth_addr_from_string(fwd_group_vmac, &ea)) { + ctl_error(ctx, "invalid mac address %s", fwd_group_vmac); + return; + } + + /* Create the forwarding group */ + struct nbrec_forwarding_group *fwd_group = NULL; + fwd_group = nbrec_forwarding_group_insert(ctx->txn); + nbrec_forwarding_group_set_name(fwd_group, fwd_group_name); + nbrec_forwarding_group_set_vip(fwd_group, fwd_group_vip); + nbrec_forwarding_group_set_vmac(fwd_group, fwd_group_vmac); + + int n_child_port = ctx->argc - 5; + const char **child_port = (const char **)&ctx->argv[5]; + + /* Verify that child ports belong to the logical switch specified */ + for (int i = 5; i < ctx->argc; ++i) { + const struct nbrec_logical_switch_port *lsp; + const char *lsp_name = ctx->argv[i]; + error = lsp_by_name_or_uuid(ctx, lsp_name, false, &lsp); + if (error) { + ctx->error = error; + return; + } + if (lsp) { + error = lsp_to_ls(ctx->idl, lsp, &ls); + if (error) { + ctx->error = error; + return; + } + if (strcmp(ls->name, ls_name)) { + ctl_error(ctx, "%s: port already exists but in logical " + "switch %s", lsp_name, ls->name); + return; + } + } else { + ctl_error(ctx, "%s: logical switch port does not exist", lsp_name); + return; + } + } + nbrec_forwarding_group_set_child_port(fwd_group, child_port, n_child_port); + + /* Liveness option */ + bool liveness = shash_find(&ctx->options, "--liveness") != NULL; + if (liveness) { + nbrec_forwarding_group_set_liveness(fwd_group, true); + } + + struct nbrec_forwarding_group **new_fwd_groups = + xmalloc(sizeof(*new_fwd_groups) * (ls->n_forwarding_groups + 1)); + memcpy(new_fwd_groups, ls->forwarding_groups, + sizeof *new_fwd_groups * ls->n_forwarding_groups); + new_fwd_groups[ls->n_forwarding_groups] = fwd_group; + nbrec_logical_switch_set_forwarding_groups(ls, new_fwd_groups, + (ls->n_forwarding_groups + 1)); + free(new_fwd_groups); + +} + +static void +nbctl_fwd_group_del(struct ctl_context *ctx) +{ + const char *id = ctx->argv[1]; + const struct nbrec_forwarding_group *fwd_group = NULL; + + fwd_group = fwd_group_by_name_or_uuid(ctx, id); + if (!fwd_group) { + return; + } + + const struct nbrec_logical_switch *ls = NULL; + ls = fwd_group_to_logical_switch(ctx, fwd_group); + if (!ls) { + return; + } + + for (int i = 0; i < ls->n_forwarding_groups; ++i) { + if (!strcmp(ls->forwarding_groups[i]->name, fwd_group->name)) { + struct nbrec_forwarding_group **new_fwd_groups = + xmemdup(ls->forwarding_groups, + sizeof *new_fwd_groups * ls->n_forwarding_groups); + new_fwd_groups[i] = + ls->forwarding_groups[ls->n_forwarding_groups - 1]; + nbrec_logical_switch_set_forwarding_groups(ls, new_fwd_groups, + (ls->n_forwarding_groups - 1)); + free(new_fwd_groups); + nbrec_forwarding_group_delete(fwd_group); + return; + } + } +} + +static void +fwd_group_list_all(struct ctl_context *ctx, const char *ls_name) +{ + const struct nbrec_logical_switch *ls; + struct ds *s = &ctx->output; + const struct nbrec_forwarding_group *fwd_group = NULL; + + if (ls_name) { + char *error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); + if (error) { + ctx->error = error; + return; + } + if (!ls) { + ctl_error( + ctx, "%s: a logical switch with this name does not exist", + ls_name); + return; + } + } + + ds_put_format(s, "%-16.16s%-14.16s%-16.7s%-22.21s%s\n", + "FWD_GROUP", "LS", "VIP", "VMAC", "CHILD_PORTS"); + + NBREC_FORWARDING_GROUP_FOR_EACH(fwd_group, ctx->idl) { + ls = fwd_group_to_logical_switch(ctx, fwd_group); + if (!ls) { + continue; + } + + if (ls_name && (strcmp(ls->name, ls_name))) { + continue; + } + + ds_put_format(s, "%-16.16s%-14.18s%-15.16s%-9.18s ", + fwd_group->name, ls->name, + fwd_group->vip, fwd_group->vmac); + for (int i = 0; i < fwd_group->n_child_port; ++i) { + ds_put_format(s, " %s", fwd_group->child_port[i]); + } + ds_put_char(s, '\n'); + } +} + +static void +nbctl_fwd_group_list(struct ctl_context *ctx) +{ + if (ctx->argc == 1) { + fwd_group_list_all(ctx, NULL); + } else if (ctx->argc == 2) { + fwd_group_list_all(ctx, ctx->argv[1]); + } +} + struct ipv4_route { int priority; @@ -5704,6 +5949,14 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_lsp_get_dhcpv6_options, NULL, "", RO }, { "lsp-get-ls", 1, 1, "PORT", NULL, nbctl_lsp_get_ls, NULL, "", RO }, + /* forwarding group commands. */ + { "fwd-group-add", 4, INT_MAX, "SWITCH GROUP VIP VMAC PORT...", + NULL, nbctl_fwd_group_add, NULL, "--liveness", RW }, + { "fwd-group-del", 1, 1, "GROUP", NULL, nbctl_fwd_group_del, NULL, + "--if-exists", RW }, + { "fwd-group-list", 0, 1, "[GROUP]", NULL, nbctl_fwd_group_list, NULL, + "", RO }, + /* logical router commands. */ { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL, "--may-exist,--add-duplicate", RW },