From patchwork Sat May 8 13:14:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasu Dasari X-Patchwork-Id: 1475868 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.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=DjgT3d5x; dkim-atps=neutral Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FcnqJ0Vf8z9vF7 for ; Sat, 8 May 2021 23:15:06 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8A6774040A; Sat, 8 May 2021 13:15:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZHwDwP4acb3W; Sat, 8 May 2021 13:15:02 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTP id 8AEAB4012B; Sat, 8 May 2021 13:15:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 66EE5C000E; Sat, 8 May 2021 13:15:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 07348C0001 for ; Sat, 8 May 2021 13:15:00 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id DE10883DC2 for ; Sat, 8 May 2021 13:14:59 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9P6B_JzzQr4D for ; Sat, 8 May 2021 13:14:58 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 Received: from mail-qk1-x735.google.com (mail-qk1-x735.google.com [IPv6:2607:f8b0:4864:20::735]) by smtp1.osuosl.org (Postfix) with ESMTPS id A6EEB83B6A for ; Sat, 8 May 2021 13:14:58 +0000 (UTC) Received: by mail-qk1-x735.google.com with SMTP id a22so10721061qkl.10 for ; Sat, 08 May 2021 06:14:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=bN4zNzE9wjdn0S4K24TOu7tUYLLcOPcvYYfQ39HXooY=; b=DjgT3d5x+q/WuzsmXw/7Z0VkDrskYp7u/n8CDqa/ELUJRI9yePkO58i8lAuOUfv1Rs Ybpj8vao1ZEdfhQ/gIES9GmWj0q7+S5UhRMX+Wq7XLfQ5Q9T4V1NN3q39dEM+Qqzn1pa SG+1b8aCsQWbKuR11meDOlRjEpesOG8jWj+xp7JQRcGZDXqHMOAXizWrG7iaoFnnrzWA Hoc8HQ8EI25mLk3FB58vfcIWsCgCZ5Yg0NvFyD1iGaNdaIWWz0dhL6ZyWY6WLtugPlT7 OT9xYVnRzkvTqgnOgVMdJKS1B9vddqlcjuOi6zQQPlXuJvlH/5rRRCasMg/K4jjfsnRb ti7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=bN4zNzE9wjdn0S4K24TOu7tUYLLcOPcvYYfQ39HXooY=; b=LWj0lDkMZjs4PNRGnCQ3loiZFsD68wkIlaFOYbO7kW9/1v+8F37a200pjJUutbVQmZ NQJKGcRM9j9g/d4VMupvpdCKzyLhje06TguxUmJMr7rm3T4WwVkG0KWcp9Ai++cNFaEu xMOuSld06cZellf9CD/BV1fY4R8QfmusuTOoz3vM2sH2GQz26NhPWp16Ugb777rOAdru IWic613rh27Fpy4z5IYc7zsU8czq2ULpXoQdcokCXgFI88qHge29aPfDr6S64+KQlsU9 CtbpyDn8hdMwYXvzvwdHzlyFpECQAo35q/z0Dqi8W0MzrhvjDNPzCN+D4IQIm9oLyji2 ioRA== X-Gm-Message-State: AOAM53208Kn0mYoF+rp44Q05uKCgsSgjD0LUzVfcW7vSPGUihVUYFeRb ZgQhf38BJ8I7+uUOhJ/Fh93jP4Y03tcFq4Ey X-Google-Smtp-Source: ABdhPJx5r3/T/lVFXaVqQPOBPXJYzl+C+UQIO1btffUC7aupIEyeUhrCui3x8Cfmg5a7Fpulo2vO1A== X-Received: by 2002:a37:6850:: with SMTP id d77mr14889454qkc.57.1620479696987; Sat, 08 May 2021 06:14:56 -0700 (PDT) Received: from vdasari-mac.cinci.rr.com (cpe-98-28-205-172.cinci.res.rr.com. [98.28.205.172]) by smtp.gmail.com with ESMTPSA id g6sm7361262qkm.120.2021.05.08.06.14.55 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 08 May 2021 06:14:56 -0700 (PDT) From: Vasu Dasari To: dev@openvswitch.org Date: Sat, 8 May 2021 09:14:48 -0400 Message-Id: <20210508131448.83705-1-vdasari@gmail.com> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 Subject: [ovs-dev] [PATCH] ofproto-dpif: APIs and CLI option to add/delete static fdb entry 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" Currently there is an option to add/flush/show ARP/ND neighbor. This covers L3 side. For L2 side, there is only fdb show command. This patch gives an option to add/del an fdb entry via CLI. CLI command looks like: To add: ovs-appctl fdb/add ovs-appctl fdb/add br0 p1 0 50:54:00:00:00:05 To del: ovs-appctl fdb/del ovs-appctl fdb/del br0 p1 0 50:54:00:00:00:05 Static entry should not age. To indicate that entry being programmed is a static entry, 'expires' field in 'struct mac_entry' will be set to a INT_MAX. A check for this value is made while deleting mac entry as part of regular aging process. Another check as part of mac-update process, when a packet with same source mac as this entry arrives on the configured port will not modify the expires field Added two new APIs to provide convinient interfacde to add and delete static-macs void xlate_add_static_mac_entry(const struct ofproto_dpif *, ofp_port_t in_port, struct eth_addr dl_src, int vlan); void xlate_delete_static_mac_entry(const struct ofproto_dpif *, struct eth_addr dl_src, int vlan); Signed-off-by: Vasu Dasari Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2019-June/048894.html Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1597752 --- v1: - Fixed 0-day robot warnings --- lib/mac-learning.c | 26 +++++++++++++++++--- lib/mac-learning.h | 3 +++ ofproto/ofproto-dpif-xlate.c | 26 ++++++++++++++++++++ ofproto/ofproto-dpif-xlate.h | 5 ++++ ofproto/ofproto-dpif.c | 47 ++++++++++++++++++++++++++++++++++++ tests/ofproto-dpif.at | 40 ++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 3 deletions(-) diff --git a/lib/mac-learning.c b/lib/mac-learning.c index 9442858d9..ff21289e8 100644 --- a/lib/mac-learning.c +++ b/lib/mac-learning.c @@ -39,8 +39,13 @@ COVERAGE_DEFINE(mac_learning_moved); int mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e) { - time_t remaining = e->expires - time_now(); - return ml->idle_time - remaining; + /* For static fdb entries, expires would be initialized with INT_MAX */ + if (INT_MAX == e->expires) { + return -1; + } else { + time_t remaining = e->expires - time_now(); + return ml->idle_time - remaining; + } } static uint32_t @@ -282,6 +287,18 @@ mac_learning_set_idle_time(struct mac_learning *ml, unsigned int idle_time) } } +/* Changes the MAC aging timeout of a mac_entry to 'idle_time' seconds. */ +void +mac_entry_set_idle_time(struct mac_learning *ml, struct eth_addr mac, + int vlan, unsigned int idle_time) +{ + struct mac_entry *e; + e = mac_entry_lookup(ml, mac, vlan); + if (e) { + e->expires = idle_time; + } +} + /* Sets the maximum number of entries in 'ml' to 'max_entries', adjusting it * to be within a reasonable range. */ void @@ -348,7 +365,10 @@ mac_learning_insert(struct mac_learning *ml, ovs_list_remove(&e->port_lru_node); ovs_list_push_back(&e->mlport->port_lrus, &e->port_lru_node); } - e->expires = time_now() + ml->idle_time; + /* Do not update 'expires' for static mac entry */ + if (e->expires != INT_MAX) { + e->expires = time_now() + ml->idle_time; + } return e; } diff --git a/lib/mac-learning.h b/lib/mac-learning.h index 0ddab06cb..1137aae63 100644 --- a/lib/mac-learning.h +++ b/lib/mac-learning.h @@ -202,6 +202,9 @@ bool mac_learning_set_flood_vlans(struct mac_learning *ml, void mac_learning_set_idle_time(struct mac_learning *ml, unsigned int idle_time) OVS_REQ_WRLOCK(ml->rwlock); +void mac_entry_set_idle_time(struct mac_learning *ml, struct eth_addr src, + int vlan, unsigned int idle_time) + OVS_REQ_WRLOCK(ml->rwlock); void mac_learning_set_max_entries(struct mac_learning *ml, size_t max_entries) OVS_REQ_WRLOCK(ml->rwlock); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 7108c8a30..8580b39f4 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -8011,6 +8011,32 @@ xlate_mac_learning_update(const struct ofproto_dpif *ofproto, update_learning_table__(xbridge, xbundle, dl_src, vlan, is_grat_arp); } +void +xlate_add_static_mac_entry(const struct ofproto_dpif *ofproto, + ofp_port_t in_port, + struct eth_addr dl_src, int vlan) +{ + xlate_mac_learning_update(ofproto, in_port, dl_src, vlan, false); + + ovs_rwlock_wrlock(&ofproto->ml->rwlock); + mac_entry_set_idle_time(ofproto->ml, dl_src, vlan, INT_MAX); + ovs_rwlock_unlock(&ofproto->ml->rwlock); +} + +void +xlate_delete_static_mac_entry(const struct ofproto_dpif *ofproto, + struct eth_addr dl_src, int vlan) +{ + struct mac_entry *e = NULL; + + ovs_rwlock_wrlock(&ofproto->ml->rwlock); + e = mac_learning_lookup(ofproto->ml, dl_src, vlan); + if (e) { + mac_learning_expire(ofproto->ml, e); + } + ovs_rwlock_unlock(&ofproto->ml->rwlock); +} + void xlate_set_support(const struct ofproto_dpif *ofproto, const struct dpif_backer_support *support) diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 3426a27b2..9e6e95756 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -225,6 +225,11 @@ int xlate_send_packet(const struct ofport_dpif *, bool oam, struct dp_packet *); void xlate_mac_learning_update(const struct ofproto_dpif *ofproto, ofp_port_t in_port, struct eth_addr dl_src, int vlan, bool is_grat_arp); +void xlate_add_static_mac_entry(const struct ofproto_dpif *, + ofp_port_t in_port, + struct eth_addr dl_src, int vlan); +void xlate_delete_static_mac_entry(const struct ofproto_dpif *, + struct eth_addr dl_src, int vlan); void xlate_set_support(const struct ofproto_dpif *, const struct dpif_backer_support *); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index fd0b2fdea..2d2c60c0b 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5864,6 +5864,49 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_destroy(&ds); } +static void +ofproto_unixctl_fdb_update(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) +{ + const char *br_name = argv[1]; + const char *name = argv[2]; + struct eth_addr mac; + uint16_t vlan = atoi(argv[3]); + const char *op = (const char *) aux; + const struct ofproto_dpif *ofproto; + ofp_port_t in_port = OFPP_NONE; + struct ofproto_port ofproto_port; + + ofproto = ofproto_dpif_lookup_by_name(br_name); + if (!ofproto) { + unixctl_command_reply_error(conn, "no such bridge"); + return; + } + + if (!eth_addr_from_string(argv[4], &mac)) { + unixctl_command_reply_error(conn, "bad MAC address"); + return; + } + + if (ofproto_port_query_by_name(&ofproto->up, name, &ofproto_port)) { + unixctl_command_reply_error(conn, + "software error, odp port is present but no ofp port"); + return; + } + in_port = ofproto_port.ofp_port; + ofproto_port_destroy(&ofproto_port); + + if (!strcmp(op, "add")) { + xlate_add_static_mac_entry(ofproto, in_port, mac, vlan); + unixctl_command_reply(conn, "OK"); + } else if (!strcmp(op, "del")) { + xlate_delete_static_mac_entry(ofproto, mac, vlan); + unixctl_command_reply(conn, "OK"); + } else { + unixctl_command_reply_error(conn, "software error, unknown op"); + } +} + static void ofproto_unixctl_fdb_stats_clear(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) @@ -6415,6 +6458,10 @@ ofproto_unixctl_init(void) } registered = true; + unixctl_command_register("fdb/add", "[bridge port vlan mac]", 4, 4, + ofproto_unixctl_fdb_update, "add"); + unixctl_command_register("fdb/del", "[bridge port vlan mac]", 4, 4, + ofproto_unixctl_fdb_update, "del"); unixctl_command_register("fdb/flush", "[bridge]", 0, 1, ofproto_unixctl_fdb_flush, NULL); unixctl_command_register("fdb/show", "bridge", 1, 1, diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 24bbd884c..95b8dd7ce 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -6753,6 +6753,46 @@ PORTNAME portName=p2 ])]) +AT_SETUP([ofproto-dpif - static MAC programming]) +OVS_VSWITCHD_START([set bridge br0 fail-mode=standalone]) +add_of_ports br0 1 2 + +arp='eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' + +AT_CHECK([ovs-appctl fdb/add br0 p1 0 50:54:00:00:00:05], [0], [OK +]) + +dnl Check for the static MAC entry is programmed +AT_CHECK([ovs-appctl fdb/show br0], [0], [dnl + port VLAN MAC Age + 1 0 50:54:00:00:00:05 -1 +]) + +dnl Trace an ARP packet arriving on p1 +OFPROTO_TRACE( + [ovs-dummy], + [in_port(1),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),$arp], + [-generate], + [2,100]) + +dnl Check that age on static MAC entry is not altered because of above learning event +AT_CHECK([ovs-appctl fdb/show br0], [0], [dnl + port VLAN MAC Age + 1 0 50:54:00:00:00:05 -1 +]) + +dnl Remove static mac entry +AT_CHECK([ovs-appctl fdb/del br0 p1 0 50:54:00:00:00:05], [0], [OK +]) + +dnl Check that entry is removed +AT_CHECK([ovs-appctl fdb/show br0], [0], [dnl + port VLAN MAC Age +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - basic truncate action]) OVS_VSWITCHD_START add_of_ports br0 1 2 3 4 5