From patchwork Thu Sep 19 17:08:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1987524 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fMdNmZfe; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4X8hnR2Jjpz1y1m for ; Fri, 20 Sep 2024 03:08:59 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 041BA4143A; Thu, 19 Sep 2024 17:08:55 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 9xaHL9-FPfKZ; Thu, 19 Sep 2024 17:08:52 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org D273641351 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fMdNmZfe Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id D273641351; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 73D1BC0013; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id E2964C0011 for ; Thu, 19 Sep 2024 17:08:48 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id D279A84B21 for ; Thu, 19 Sep 2024 17:08:48 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id MMFV5wjtbat8 for ; Thu, 19 Sep 2024 17:08:47 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=lorenzo.bianconi@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 8120884B1F Authentication-Results: smtp1.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8120884B1F Authentication-Results: smtp1.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fMdNmZfe Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id 8120884B1F for ; Thu, 19 Sep 2024 17:08:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1726765726; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZaDPXaGsEwFfqR+h7zxLUwwGzfkj1P6H0Dbw1aCljAw=; b=fMdNmZfe9Ws5pQAPDwV1Q6tKYxSKyWsMKTN45dNlbcEttnvp81br14JJ26G1/Kp7pJYi9G zVwmYvhxrR9Lcu7MHMVEHxQWP4LEkUMhKDY6I3+4N3H2vUKhGRhXl4+y2EHAq8hyozEc1T 6g8Awe2yG35n4JDqf2OyvEkRj0i22gQ= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-589-frDYbETWMMWw7ktDrzyVFw-1; Thu, 19 Sep 2024 13:08:45 -0400 X-MC-Unique: frDYbETWMMWw7ktDrzyVFw-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-42caf073db8so8557535e9.3 for ; Thu, 19 Sep 2024 10:08:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726765724; x=1727370524; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZaDPXaGsEwFfqR+h7zxLUwwGzfkj1P6H0Dbw1aCljAw=; b=F9/PbkiCh7xPjdEWIybDh0lTv9GJ1Nc9gRcqnNVqnaNZIY13CxUo4MTBNL+Y9UEdhA aHF6yw/++uGwoV49Xk49xwvCk0YP0ckqDM3r5h5GzV6LUQeExCn8MMSGKZJJg3C4VRci F+tmv0faQ9GSNlcmUAlJz2WlPCS4Tq4QO+yg6AmzCxjg93xqzSxgbfrDqcEdiz7szpHh ZXoGhCHSlrZ0F7Wg39O5uncFA5g2uFETuJFUBV0xz6CguHrVMc3tMHSOyw4fxZjFBoKt Ga1K6f1ZDY63mJGgN6P2pZXyWDWxQapybppaSUdNDmFSRs/ieHYqp+jl8BFY5xzTXcem HUtA== X-Gm-Message-State: AOJu0Yw68DNKxmmZ98hqxN00OhOrEyXyq7/vQp46zi3+JWShDcsjIWl1 /y+h2snjewSaSSTnrEHVTKm/KmAlUC+7rb0oYSoUXxWaSGGtTWsLAr2jJdUw5tsKLIBbuTWl8La 24nD9dukppHhum5NK4dxYCBJcX5n3mqsSN6XCU0eHb7oA9+c6kkNrwssMpIA+8WPjznm9bWRO97 Hnk/ssuGeUftK3lFPct+fjf7Qe68U4+NyOwM1ooYH17rFUHKuLWg== X-Received: by 2002:a05:600c:1da0:b0:42c:b750:1a1e with SMTP id 5b1f17b1804b1-42e7ab43460mr1201675e9.0.1726765723523; Thu, 19 Sep 2024 10:08:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH5tNnMdYyuimG5HZRTePVimuQkZUJpKUfg++YQKpTXDWJeIvzOQEb5riRNouif9HtZdvwYzA== X-Received: by 2002:a05:600c:1da0:b0:42c:b750:1a1e with SMTP id 5b1f17b1804b1-42e7ab43460mr1201405e9.0.1726765722945; Thu, 19 Sep 2024 10:08:42 -0700 (PDT) Received: from localhost (net-37-182-8-79.cust.vodafonedsl.it. [37.182.8.79]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-378e71f060bsm15744507f8f.1.2024.09.19.10.08.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Sep 2024 10:08:42 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 19 Sep 2024 19:08:26 +0200 Message-ID: <118aa9e58fd50d37755086a67105f2c2c52a5e56.1726765502.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.46.1 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [RFC v2 ovn 1/4] northd: Introduce ECMP_Nexthop table in SB db. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dceara@redhat.com Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce ECMP_Nexthop table in the SB db in order to track active ecmp-symmetric-reply connections and flush stale ones. ECMP_Nexthop table contains ip and mac address for each active nexthop. Signed-off-by: Lorenzo Bianconi --- northd/en-northd.c | 27 ++++++++++++++++++++ northd/en-northd.h | 4 +++ northd/inc-proc-northd.c | 8 +++++- northd/northd.c | 53 +++++++++++++++++++++++++++++++++++++++- northd/northd.h | 4 +++ ovn-sb.ovsschema | 17 +++++++++++-- ovn-sb.xml | 34 ++++++++++++++++++++++++++ tests/ovn-northd.at | 18 ++++++++------ 8 files changed, 154 insertions(+), 11 deletions(-) diff --git a/northd/en-northd.c b/northd/en-northd.c index 24ed31517..b8227617b 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -404,6 +404,21 @@ en_bfd_sync_run(struct engine_node *node, void *data) engine_set_node_state(node, EN_UPDATED); } +void +en_ecmp_nexthop_run(struct engine_node *node, void *data OVS_UNUSED) +{ + const struct engine_context *eng_ctx = engine_get_context(); + struct static_routes_data *static_routes_data = + engine_get_input_data("static_routes", node); + const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table = + EN_OVSDB_GET(engine_get_input("SB_ecmp_nexthop", node)); + + build_ecmp_nexthop_table(eng_ctx->ovnsb_idl_txn, + &static_routes_data->parsed_routes, + sbrec_ecmp_nexthop_table); + engine_set_node_state(node, EN_UPDATED); +} + void *en_northd_init(struct engine_node *node OVS_UNUSED, struct engine_arg *arg OVS_UNUSED) @@ -454,6 +469,13 @@ void return data; } +void +*en_ecmp_nexthop_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + void en_northd_cleanup(void *data) { @@ -526,3 +548,8 @@ en_bfd_sync_cleanup(void *data) { bfd_sync_destroy(data); } + +void +en_ecmp_nexthop_cleanup(void *data OVS_UNUSED) +{ +} diff --git a/northd/en-northd.h b/northd/en-northd.h index 631a7c17a..2666cc67e 100644 --- a/northd/en-northd.h +++ b/northd/en-northd.h @@ -42,5 +42,9 @@ bool bfd_sync_northd_change_handler(struct engine_node *node, void *data OVS_UNUSED); void en_bfd_sync_run(struct engine_node *node, void *data); void en_bfd_sync_cleanup(void *data OVS_UNUSED); +void en_ecmp_nexthop_run(struct engine_node *node, void *data); +void *en_ecmp_nexthop_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED); +void en_ecmp_nexthop_cleanup(void *data); #endif /* EN_NORTHD_H */ diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 1f79916a5..cdc080ef0 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -103,7 +103,8 @@ static unixctl_cb_func chassis_features_list; SB_NODE(fdb, "fdb") \ SB_NODE(static_mac_binding, "static_mac_binding") \ SB_NODE(chassis_template_var, "chassis_template_var") \ - SB_NODE(logical_dp_group, "logical_dp_group") + SB_NODE(logical_dp_group, "logical_dp_group") \ + SB_NODE(ecmp_nexthop, "ecmp_nexthop") enum sb_engine_node { #define SB_NODE(NAME, NAME_STR) SB_##NAME, @@ -162,6 +163,7 @@ static ENGINE_NODE(route_policies, "route_policies"); static ENGINE_NODE(static_routes, "static_routes"); static ENGINE_NODE(bfd, "bfd"); static ENGINE_NODE(bfd_sync, "bfd_sync"); +static ENGINE_NODE(ecmp_nexthop, "ecmp_nexthop"); void inc_proc_northd_init(struct ovsdb_idl_loop *nb, struct ovsdb_idl_loop *sb) @@ -264,6 +266,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_bfd_sync, &en_route_policies, NULL); engine_add_input(&en_bfd_sync, &en_northd, bfd_sync_northd_change_handler); + engine_add_input(&en_ecmp_nexthop, &en_sb_ecmp_nexthop, NULL); + engine_add_input(&en_ecmp_nexthop, &en_static_routes, NULL); + engine_add_input(&en_sync_meters, &en_nb_acl, NULL); engine_add_input(&en_sync_meters, &en_nb_meter, NULL); engine_add_input(&en_sync_meters, &en_sb_meter, NULL); @@ -334,6 +339,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_sync_from_sb, &en_sb_port_binding, NULL); engine_add_input(&en_sync_from_sb, &en_sb_ha_chassis_group, NULL); + engine_add_input(&en_northd_output, &en_ecmp_nexthop, NULL); engine_add_input(&en_northd_output, &en_sync_from_sb, NULL); engine_add_input(&en_northd_output, &en_sync_to_sb, northd_output_sync_to_sb_handler); diff --git a/northd/northd.c b/northd/northd.c index a267cd5f8..3e3bb84ef 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -10665,6 +10665,55 @@ build_bfd_map(const struct nbrec_bfd_table *nbrec_bfd_table, } } +void +build_ecmp_nexthop_table( + struct ovsdb_idl_txn *ovnsb_txn, + struct hmap *routes, + const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table) +{ + if (!ovnsb_txn) { + return; + } + + struct sset nb_nexthops_sset = SSET_INITIALIZER(&nb_nexthops_sset); + struct sset sb_nexthops_sset = SSET_INITIALIZER(&sb_nexthops_sset); + + const struct sbrec_ecmp_nexthop *sb_ecmp_nexthop; + SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sb_ecmp_nexthop, + sbrec_ecmp_nexthop_table) { + sset_add(&sb_nexthops_sset, sb_ecmp_nexthop->nexthop); + } + + struct parsed_route *pr; + HMAP_FOR_EACH (pr, key_node, routes) { + if (!pr->ecmp_symmetric_reply) { + continue; + } + + if (!pr->out_port) { + continue; + } + + const struct nbrec_logical_router_static_route *r = pr->route; + if (!sset_contains(&sb_nexthops_sset, r->nexthop)) { + sb_ecmp_nexthop = sbrec_ecmp_nexthop_insert(ovnsb_txn); + sbrec_ecmp_nexthop_set_nexthop(sb_ecmp_nexthop, r->nexthop); + sbrec_ecmp_nexthop_set_port(sb_ecmp_nexthop, pr->out_port->key); + } + sset_add(&nb_nexthops_sset, r->nexthop); + } + + SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH_SAFE (sb_ecmp_nexthop, + sbrec_ecmp_nexthop_table) { + if (!sset_contains(&nb_nexthops_sset, sb_ecmp_nexthop->nexthop)) { + sbrec_ecmp_nexthop_delete(sb_ecmp_nexthop); + } + } + + sset_destroy(&nb_nexthops_sset); + sset_destroy(&sb_nexthops_sset); +} + /* Returns a string of the IP address of the router port 'op' that * overlaps with 'ip_s". If one is not found, returns NULL. * @@ -11105,10 +11154,11 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, } /* Verify that ip_prefix and nexthop are on the same network. */ + struct ovn_port *out_port = NULL; if (!is_discard_route && !find_static_route_outport(od, lr_ports, route, IN6_IS_ADDR_V4MAPPED(&prefix), - NULL, NULL)) { + NULL, &out_port)) { return; } @@ -11151,6 +11201,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, new_pr->hash = route_hash(new_pr); new_pr->route = route; new_pr->nbr = od->nbr; + new_pr->out_port = out_port; new_pr->ecmp_symmetric_reply = smap_get_bool(&route->options, "ecmp_symmetric_reply", false); diff --git a/northd/northd.h b/northd/northd.h index 8f76d642d..c4c2a5d7e 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -703,6 +703,7 @@ struct parsed_route { uint32_t route_table_id; uint32_t hash; const struct nbrec_logical_router_static_route *route; + struct ovn_port *out_port; bool ecmp_symmetric_reply; bool is_discard_route; const struct nbrec_logical_router *nbr; @@ -745,6 +746,9 @@ void bfd_destroy(struct bfd_data *); void bfd_sync_init(struct bfd_sync_data *); void bfd_sync_destroy(struct bfd_sync_data *); +void build_ecmp_nexthop_table(struct ovsdb_idl_txn *, struct hmap *, + const struct sbrec_ecmp_nexthop_table *); + struct lflow_table; struct lr_stateful_tracked_data; struct ls_stateful_tracked_data; diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 73abf2c8d..870ee256b 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.37.0", - "cksum": "1950136776 31493", + "version": "20.38.0", + "cksum": "3311058931 32061", "tables": { "SB_Global": { "columns": { @@ -610,6 +610,19 @@ "refTable": "Datapath_Binding"}}}}, "indexes": [["logical_port", "ip"]], "isRoot": true}, + "ECMP_Nexthop": { + "columns": { + "nexthop": {"type": "string"}, + "port": {"type": "string"}, + "mac": {"type": "string"}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, + "options": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["nexthop"]], + "isRoot": true}, "Chassis_Template_Var": { "columns": { "chassis": {"type": "string"}, diff --git a/ovn-sb.xml b/ovn-sb.xml index 746cc6308..b5dc34012 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -5178,4 +5178,38 @@ tcp.flags = RST; The set of variable values for a given chassis. + + +

+ Each record in this table represents an active ECMP route committed by + ovn-northd to ovs connection-tracking table. + ECMP_Nexthop table is used by ovn-controller + to track active ct entries and to flush stale ones. +

+ +

+ Nexthop IP address for this ECMP route. Nexthop IP address should + be the IP address of a connected router port or the IP address of + an external device used as nexthop for the given destination. +

+
+ +

+ Logical port used to connect to the configured next-hop. +

+
+ +

+ Nexthop mac address. +

+
+ + + Reserved for future use. + + + + See External IDs at the beginning of this document. + +
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index dcc3dbbc3..9923243fa 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -3878,7 +3878,7 @@ wait_row_count bfd 1 logical_port=r0-sw3 detect_mult=5 dst_ip=192.168.3.2 \ check_engine_stats northd norecompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +#check_engine_stats northd_output norecompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3893,7 +3893,7 @@ wait_row_count bfd 1 logical_port=r0-sw1 min_rx=1000 min_tx=1000 detect_mult=100 check_engine_stats northd norecompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3905,7 +3905,7 @@ check_engine_stats northd recompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats static_routes recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3921,7 +3921,7 @@ check_engine_stats northd recompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats static_routes recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3933,7 +3933,7 @@ check_engine_stats northd recompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats route_policies recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3968,7 +3968,7 @@ check_engine_stats northd recompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats static_routes recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -3983,7 +3983,7 @@ check_engine_stats northd recompute nocompute check_engine_stats bfd recompute nocompute check_engine_stats route_policies recompute nocompute check_engine_stats lflow recompute nocompute -check_engine_stats northd_output norecompute compute +check_engine_stats northd_output recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats @@ -6800,6 +6800,7 @@ check ovn-nbctl lsp-set-addresses public-lr0 router check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.10 +check_row_count ECMP_Nexthop 1 ovn-sbctl dump-flows lr0 > lr0flows @@ -6817,6 +6818,7 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dn ]) check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.20 +check_row_count ECMP_Nexthop 2 ovn-sbctl dump-flows lr0 > lr0flows AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl @@ -6846,6 +6848,7 @@ AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | ovn_strip_lflows], [0], [ # add ecmp route with wrong nexthop check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20 +check_row_count ECMP_Nexthop 2 ovn-sbctl dump-flows lr0 > lr0flows AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl @@ -6865,6 +6868,7 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192. check ovn-nbctl lr-route-del lr0 wait_row_count nb:Logical_Router_Static_Route 0 +check_row_count ECMP_Nexthop 0 check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10 ovn-sbctl dump-flows lr0 > lr0flows From patchwork Thu Sep 19 17:08:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1987526 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=E+LDTUMz; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4X8hnT5fsJz1y27 for ; Fri, 20 Sep 2024 03:09:01 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 4027341461; Thu, 19 Sep 2024 17:08:56 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id YiD4Db4ZqT4X; Thu, 19 Sep 2024 17:08:53 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 24C9D41353 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=E+LDTUMz Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 24C9D41353; Thu, 19 Sep 2024 17:08:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C0C05C0013; Thu, 19 Sep 2024 17:08:52 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 9DA4AC0016 for ; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 622C3615FF for ; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id zGVYlIUxkCzc for ; Thu, 19 Sep 2024 17:08:50 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=lorenzo.bianconi@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org BCD8F615E3 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org BCD8F615E3 Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=E+LDTUMz Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id BCD8F615E3 for ; Thu, 19 Sep 2024 17:08:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1726765728; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WrFruXEgB8fBEImdmVi0ZqTh6Ze5e+5DJBsk7VzhpL8=; b=E+LDTUMz9Ul5BekhPBGey874KaU/gQUQvAG4wSw0i2Nv4qpwXMjOwYhhOIE60/kAmVxHYo 5CWSaDG6ZawI+jbCzmyfl8T1wzhsqw2wf7kZnWJxMRkCj0EfTbzSKjZ/wuF1PgFYX+DAv4 80z6EWZnH9WjKhNdfZmCcRn0lhTDMmw= Received: from mail-lj1-f199.google.com (mail-lj1-f199.google.com [209.85.208.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-653-TK64i5VAOWyFm3en5Z32yQ-1; Thu, 19 Sep 2024 13:08:47 -0400 X-MC-Unique: TK64i5VAOWyFm3en5Z32yQ-1 Received: by mail-lj1-f199.google.com with SMTP id 38308e7fff4ca-2f77ca80fe1so9953241fa.0 for ; Thu, 19 Sep 2024 10:08:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726765725; x=1727370525; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WrFruXEgB8fBEImdmVi0ZqTh6Ze5e+5DJBsk7VzhpL8=; b=OG+XI/qC3IEUofq3s5sUe82oZMq7WeaHoo6/N7jDWfsDvc0Utq9v82LZkqSvf452iE g9cowkwxMDzHj/HCK2D6bU44lwCjh3+VgVD35H48Cd4Djnj8WWu64103yxdjuPGw2p9K 31L6SMkpFY63/2SsQZYj05nIazg3kCy5Lmv3x7nlpYuqlpwYfjmymSQjZn1ludmTpYN0 +0AUzlF+/fZrSlF72bPKZBVdh7UgwAZvUkhxwhMZRr4EuZAmPoiSR9n2qlOqOF0XdffX k/mE3Um20rJ+O1ip1PDsohwi5nbuDls5prukqej319MR+tA4pisARxOfI96SdUbgPnh7 Pfkw== X-Gm-Message-State: AOJu0YwohZo2ioJXiTGyp+jCmSnbr8sGtv0gY+yqYUgUz8OvzigKcLHM we/xnz0YXE5YeUB29MZTYR8k/ywLQToJJHypRPJBgAo9rNW4gkMVpivu/jpkuyC+yBY19990883 bT8sWSilnJ2psVQjQbgSZnD5HGh+bltXUnfnMpcCiS+FViLF0bWQdyDMohc45O5SVqFpzTanZGA OAwZ3SMqmbnzn7gaRNP07V1osWD6jMQklB4pc+JLidUkyG9m+aBg== X-Received: by 2002:a2e:be03:0:b0:2ef:26dc:efb3 with SMTP id 38308e7fff4ca-2f7cb30131fmr2380581fa.2.1726765724994; Thu, 19 Sep 2024 10:08:44 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE4B8RqxPqYm+gfMUq5wDmFcHqj3+ZAbLVO1aCp7hqWm2muFTlMOms7iIJ4xcUOzw8JEotdPQ== X-Received: by 2002:a2e:be03:0:b0:2ef:26dc:efb3 with SMTP id 38308e7fff4ca-2f7cb30131fmr2380211fa.2.1726765724255; Thu, 19 Sep 2024 10:08:44 -0700 (PDT) Received: from localhost (net-37-182-8-79.cust.vodafonedsl.it. [37.182.8.79]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42e7ae5fc1bsm572975e9.8.2024.09.19.10.08.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Sep 2024 10:08:43 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 19 Sep 2024 19:08:27 +0200 Message-ID: <6b8ae1e72ade79c9901e638de570034a8402e512.1726765502.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.46.1 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [RFC v2 ovn 2/4] pinctrl: Send periodic arp/nd to ecmp next-hops. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dceara@redhat.com Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce the capbility to periodically send ARP/ND packets for ECMP nexthops in order to resolve their L2 address. This is a preliminary patch to introduce the capability to flush stale ECMP CT entries. Signed-off-by: Lorenzo Bianconi --- controller/ovn-controller.8.xml | 11 ++ controller/ovn-controller.c | 2 + controller/pinctrl.c | 269 +++++++++++++++++++++++++++++--- controller/pinctrl.h | 2 + 4 files changed, 261 insertions(+), 23 deletions(-) diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml index aeaa374c1..c7fcad1fa 100644 --- a/controller/ovn-controller.8.xml +++ b/controller/ovn-controller.8.xml @@ -385,6 +385,17 @@ cap for the exponential backoff used by ovn-controller to send GARPs packets. +
external_ids:arp-nd-max-timeout-sec
+
+ When used, this configuration value specifies the maximum timeout + (in seconds) between two consecutive ARP/ND packets sent by + ovn-controller to resolve ECMP nexthop mac address. + ovn-controller by default sends just 4 ARP/ND packets + with an exponential backoff timeout. + Setting external_ids:arp-nd-max-timeout-sec allows to + cap for the exponential backoff used by ovn-controller + to send ARPs/NDs packets. +
external_ids:ovn-bridge-remote

diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 64be08ce3..e72d28731 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -5653,6 +5653,8 @@ main(int argc, char *argv[]) sbrec_mac_binding_table_get( ovnsb_idl_loop.idl), sbrec_bfd_table_get(ovnsb_idl_loop.idl), + sbrec_ecmp_nexthop_table_get( + ovnsb_idl_loop.idl), br_int, chassis, &runtime_data->local_datapaths, &runtime_data->active_tunnels, diff --git a/controller/pinctrl.c b/controller/pinctrl.c index c86b4f940..daf0bfa41 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -170,6 +170,9 @@ static struct seq *pinctrl_main_seq; static long long int garp_rarp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT; static bool garp_rarp_continuous; +static long long int arp_nd_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT; +static bool arp_nd_continuous; + static void *pinctrl_handler(void *arg); struct pinctrl { @@ -229,13 +232,17 @@ static void run_activated_ports( const struct sbrec_chassis *chassis); static void init_send_garps_rarps(void); +static void init_send_arps_nds(void); static void destroy_send_garps_rarps(void); +static void destroy_send_arps_nds(void); static void send_garp_rarp_wait(long long int send_garp_rarp_time); +static void send_arp_nd_wait(long long int send_arp_nd_time); static void send_garp_rarp_prepare( struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_port_binding_by_datapath, struct ovsdb_idl_index *sbrec_port_binding_by_name, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + const struct sbrec_ecmp_nexthop_table *ecmp_nh_table, const struct ovsrec_bridge *, const struct sbrec_chassis *, const struct hmap *local_datapaths, @@ -245,6 +252,9 @@ static void send_garp_rarp_prepare( static void send_garp_rarp_run(struct rconn *swconn, long long int *send_garp_rarp_time) OVS_REQUIRES(pinctrl_mutex); +static void send_arp_nd_run(struct rconn *swconn, + long long int *send_arp_nd_time) + OVS_REQUIRES(pinctrl_mutex); static void pinctrl_handle_nd_na(struct rconn *swconn, const struct flow *ip_flow, const struct match *md, @@ -554,6 +564,7 @@ pinctrl_init(void) { init_put_mac_bindings(); init_send_garps_rarps(); + init_send_arps_nds(); init_ipv6_ras(); init_ipv6_prefixd(); init_buffered_packets_ctx(); @@ -4000,6 +4011,7 @@ pinctrl_handler(void *arg_) static long long int send_ipv6_ra_time = LLONG_MAX; /* Next GARP/RARP announcement in ms. */ static long long int send_garp_rarp_time = LLONG_MAX; + static long long int send_arp_nd_time = LLONG_MAX; /* Next multicast query (IGMP) in ms. */ static long long int send_mcast_query_time = LLONG_MAX; static long long int svc_monitors_next_run_time = LLONG_MAX; @@ -4037,6 +4049,7 @@ pinctrl_handler(void *arg_) if (may_inject_pkts()) { ovs_mutex_lock(&pinctrl_mutex); send_garp_rarp_run(swconn, &send_garp_rarp_time); + send_arp_nd_run(swconn, &send_arp_nd_time); send_ipv6_ras(swconn, &send_ipv6_ra_time); send_ipv6_prefixd(swconn, &send_prefixd_time); send_mac_binding_buffered_pkts(swconn); @@ -4055,6 +4068,7 @@ pinctrl_handler(void *arg_) rconn_recv_wait(swconn); if (rconn_is_connected(swconn)) { send_garp_rarp_wait(send_garp_rarp_time); + send_arp_nd_wait(send_arp_nd_time); ipv6_ra_wait(send_ipv6_ra_time); ip_mcast_querier_wait(send_mcast_query_time); svc_monitors_wait(svc_monitors_next_run_time); @@ -4151,6 +4165,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_service_monitor_table *svc_mon_table, const struct sbrec_mac_binding_table *mac_binding_table, const struct sbrec_bfd_table *bfd_table, + const struct sbrec_ecmp_nexthop_table *ecmp_nh_table, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *chassis, const struct hmap *local_datapaths, @@ -4167,8 +4182,9 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, sbrec_port_binding_by_key, chassis); send_garp_rarp_prepare(ovnsb_idl_txn, sbrec_port_binding_by_datapath, sbrec_port_binding_by_name, - sbrec_mac_binding_by_lport_ip, br_int, chassis, - local_datapaths, active_tunnels, ovs_table); + sbrec_mac_binding_by_lport_ip, ecmp_nh_table, + br_int, chassis, local_datapaths, active_tunnels, + ovs_table); prepare_ipv6_ras(local_active_ports_ras, sbrec_port_binding_by_name); prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name, local_active_ports_ipv6_pd, chassis, @@ -4702,6 +4718,7 @@ pinctrl_destroy(void) latch_destroy(&pinctrl.pinctrl_thread_exit); rconn_destroy(pinctrl.swconn); destroy_send_garps_rarps(); + destroy_send_arps_nds(); destroy_ipv6_ras(); destroy_ipv6_prefixd(); destroy_buffered_packets_ctx(); @@ -5029,7 +5046,8 @@ wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn) */ struct garp_rarp_data { struct eth_addr ea; /* Ethernet address of port. */ - ovs_be32 ipv4; /* Ipv4 address of port. */ + struct in6_addr src_ip; /* IP address of port. */ + struct in6_addr dst_ip; /* Destination IP address */ long long int announce_time; /* Next announcement in ms. */ int backoff; /* Backoff timeout for the next * announcement (in msecs). */ @@ -5052,19 +5070,37 @@ destroy_send_garps_rarps(void) shash_destroy_free_data(&send_garp_rarp_data); } +/* Contains ARPs data to be sent to track ECMP next-hop mac address. Protected + * by pinctrl_mutex. */ +static struct shash send_arp_nd_data; + +static void +init_send_arps_nds(void) +{ + shash_init(&send_arp_nd_data); +} + +static void +destroy_send_arps_nds(void) +{ + shash_destroy_free_data(&send_arp_nd_data); +} + /* Runs with in the main ovn-controller thread context. */ static void -add_garp_rarp(const char *name, const struct eth_addr ea, ovs_be32 ip, - uint32_t dp_key, uint32_t port_key) +add_garp_rarp(const char *name, const struct eth_addr ea, + struct in6_addr src_ip, struct in6_addr dst_ip, + uint32_t dp_key, uint32_t port_key, struct shash *shash) { struct garp_rarp_data *garp_rarp = xmalloc(sizeof *garp_rarp); garp_rarp->ea = ea; - garp_rarp->ipv4 = ip; + garp_rarp->src_ip = src_ip; + garp_rarp->dst_ip = dst_ip; garp_rarp->announce_time = time_msec() + 1000; garp_rarp->backoff = 1000; /* msec. */ garp_rarp->dp_key = dp_key; garp_rarp->port_key = port_key; - shash_add(&send_garp_rarp_data, name, garp_rarp); + shash_add(shash, name, garp_rarp); /* Notify pinctrl_handler so that it can wakeup and process * these GARP/RARP requests. */ @@ -5113,9 +5149,10 @@ send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn, } } else if (ovnsb_idl_txn) { add_garp_rarp(name, laddrs->ea, - laddrs->ipv4_addrs[i].addr, - binding_rec->datapath->tunnel_key, - binding_rec->tunnel_key); + in6_addr_mapped_ipv4(laddrs->ipv4_addrs[i].addr), + in6_addr_mapped_ipv4(laddrs->ipv4_addrs[i].addr), + binding_rec->datapath->tunnel_key, + binding_rec->tunnel_key, &send_garp_rarp_data); send_garp_locally(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, local_datapaths, binding_rec, laddrs->ea, @@ -5142,9 +5179,11 @@ send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn, garp_rarp->backoff = 1000; /* msec. */ } } else { - add_garp_rarp(name, laddrs->ea, - 0, binding_rec->datapath->tunnel_key, - binding_rec->tunnel_key); + struct in6_addr ip = {}; + add_garp_rarp(name, laddrs->ea, ip, ip, + binding_rec->datapath->tunnel_key, + binding_rec->tunnel_key, + &send_garp_rarp_data); } free(name); } @@ -5182,10 +5221,10 @@ send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn, ip = laddrs.ipv4_addrs[0].addr; } - add_garp_rarp(binding_rec->logical_port, - laddrs.ea, ip, + add_garp_rarp(binding_rec->logical_port, laddrs.ea, + in6_addr_mapped_ipv4(ip), in6_addr_mapped_ipv4(ip), binding_rec->datapath->tunnel_key, - binding_rec->tunnel_key); + binding_rec->tunnel_key, &send_garp_rarp_data); if (ip) { send_garp_locally(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, local_datapaths, binding_rec, laddrs.ea, ip); @@ -5196,12 +5235,52 @@ send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn, } } +/* Add or update a vif for which ARPs need to be announced. */ +static void +send_arp_nd_update(const struct sbrec_port_binding *pb, const char *nexthop, + long long int max_arp_timeout, bool continuous_arp_nd) +{ + volatile struct garp_rarp_data *e = shash_find_data(&send_arp_nd_data, + nexthop); + if (e) { + e->dp_key = pb->datapath->tunnel_key; + e->port_key = pb->tunnel_key; + if (max_arp_timeout != arp_nd_max_timeout || + continuous_arp_nd != arp_nd_continuous) { + /* reset backoff */ + e->announce_time = time_msec() + 1000; + e->backoff = 1000; /* msec. */ + } + } else { + struct lport_addresses laddrs; + if (!extract_lsp_addresses(pb->mac[0], &laddrs)) { + return; + } + + if (laddrs.n_ipv4_addrs) { + ovs_be32 dst_ip; + inet_pton(AF_INET, nexthop, &dst_ip); + add_garp_rarp(nexthop, laddrs.ea, + in6_addr_mapped_ipv4(laddrs.ipv4_addrs[0].addr), + in6_addr_mapped_ipv4(dst_ip), + pb->datapath->tunnel_key, pb->tunnel_key, + &send_arp_nd_data); + } else if (laddrs.n_ipv6_addrs) { + struct in6_addr dst_ip; + inet_pton(AF_INET6, nexthop, &dst_ip); + add_garp_rarp(nexthop, laddrs.ea, laddrs.ipv6_addrs[0].addr, + dst_ip, pb->datapath->tunnel_key, pb->tunnel_key, + &send_arp_nd_data); + } + destroy_lport_addresses(&laddrs); + } +} + /* Remove a vif from GARP announcements. */ static void -send_garp_rarp_delete(const char *lport) +send_garp_rarp_delete(struct shash *shash, const char *lport) { - struct garp_rarp_data *garp_rarp = shash_find_and_delete - (&send_garp_rarp_data, lport); + struct garp_rarp_data *garp_rarp = shash_find_and_delete(shash, lport); free(garp_rarp); notify_pinctrl_handler(); } @@ -5220,9 +5299,11 @@ send_garp_rarp(struct rconn *swconn, struct garp_rarp_data *garp_rarp, uint64_t packet_stub[128 / 8]; struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); - if (garp_rarp->ipv4) { + ovs_be32 src_ipv4 = in6_addr_get_mapped_ipv4(&garp_rarp->src_ip); + if (src_ipv4) { compose_arp(&packet, ARP_OP_REQUEST, garp_rarp->ea, eth_addr_zero, - true, garp_rarp->ipv4, garp_rarp->ipv4); + true, src_ipv4, + in6_addr_get_mapped_ipv4(&garp_rarp->dst_ip)); } else { compose_rarp(&packet, garp_rarp->ea); } @@ -6524,6 +6605,25 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_port_binding_by_name, } } +static void +get_local_ecmp_nexthop_map( + const struct sbrec_ecmp_nexthop_table *ecmp_nh_table, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + const struct sbrec_chassis *chassis, + struct smap *local_ecmp_nexthop_map) +{ + const struct sbrec_ecmp_nexthop *sb_ecmp_nexthop; + SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sb_ecmp_nexthop, ecmp_nh_table) { + const struct sbrec_port_binding *pb = + lport_lookup_by_name(sbrec_port_binding_by_name, + sb_ecmp_nexthop->port); + if (pb && !strcmp(pb->type, "l3gateway") && pb->chassis == chassis) { + smap_add_once(local_ecmp_nexthop_map, sb_ecmp_nexthop->nexthop, + sb_ecmp_nexthop->port); + } + } +} + static void send_garp_rarp_wait(long long int send_garp_rarp_time) { @@ -6534,6 +6634,16 @@ send_garp_rarp_wait(long long int send_garp_rarp_time) } } +static void +send_arp_nd_wait(long long int send_arp_nd_time) +{ + /* Set the poll timer for next arp packet only if there is data to + * be sent. */ + if (!shash_is_empty(&send_arp_nd_data)) { + poll_timer_wait_until(send_arp_nd_time); + } +} + /* Called with in the pinctrl_handler thread context. */ static void send_garp_rarp_run(struct rconn *swconn, long long int *send_garp_rarp_time) @@ -6556,6 +6666,86 @@ send_garp_rarp_run(struct rconn *swconn, long long int *send_garp_rarp_time) } } +static long long int +send_arp_nd(struct rconn *swconn, struct garp_rarp_data *garp_rarp, + long long int current_time) + OVS_REQUIRES(pinctrl_mutex) +{ + if (current_time < garp_rarp->announce_time) { + return garp_rarp->announce_time; + } + + /* Compose a ARP request packet. */ + uint64_t packet_stub[128 / 8]; + struct dp_packet packet; + dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); + if (IN6_IS_ADDR_V4MAPPED(&garp_rarp->src_ip)) { + compose_arp(&packet, ARP_OP_REQUEST, garp_rarp->ea, eth_addr_zero, + true, in6_addr_get_mapped_ipv4(&garp_rarp->src_ip), + in6_addr_get_mapped_ipv4(&garp_rarp->dst_ip)); + } else { + compose_nd_ns(&packet, garp_rarp->ea, &garp_rarp->src_ip, + &garp_rarp->dst_ip); + } + + /* Inject ARP request. */ + uint64_t ofpacts_stub[4096 / 8]; + struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); + enum ofp_version version = rconn_get_version(swconn); + put_load(garp_rarp->dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); + put_load(garp_rarp->port_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); + struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); + resubmit->in_port = OFPP_CONTROLLER; + resubmit->table_id = OFTABLE_LOCAL_OUTPUT; + + struct ofputil_packet_out po = { + .packet = dp_packet_data(&packet), + .packet_len = dp_packet_size(&packet), + .buffer_id = UINT32_MAX, + .ofpacts = ofpacts.data, + .ofpacts_len = ofpacts.size, + }; + match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER); + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); + queue_msg(swconn, ofputil_encode_packet_out(&po, proto)); + dp_packet_uninit(&packet); + ofpbuf_uninit(&ofpacts); + + /* Set the next announcement. At most 5 announcements are sent for a + * vif if arp_nd_max_timeout is not specified otherwise cap the max + * timeout to arp_nd_max_timeout. */ + if (arp_nd_continuous || garp_rarp->backoff < arp_nd_max_timeout) { + garp_rarp->announce_time = current_time + garp_rarp->backoff; + } else { + garp_rarp->announce_time = LLONG_MAX; + } + garp_rarp->backoff = MIN(arp_nd_max_timeout, garp_rarp->backoff * 2); + + return garp_rarp->announce_time; +} + +static void +send_arp_nd_run(struct rconn *swconn, long long int *send_arp_nd_time) + OVS_REQUIRES(pinctrl_mutex) +{ + if (shash_is_empty(&send_arp_nd_data)) { + return; + } + + /* Send ARPs, and update the next announcement. */ + long long int current_time = time_msec(); + *send_arp_nd_time = LLONG_MAX; + + struct shash_node *iter; + SHASH_FOR_EACH (iter, &send_arp_nd_data) { + long long int next_announce = send_arp_nd(swconn, iter->data, + current_time); + if (*send_arp_nd_time > next_announce) { + *send_arp_nd_time = next_announce; + } + } +} + /* Called by pinctrl_run(). Runs with in the main ovn-controller * thread context. */ static void @@ -6563,6 +6753,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_port_binding_by_datapath, struct ovsdb_idl_index *sbrec_port_binding_by_name, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + const struct sbrec_ecmp_nexthop_table *ecmp_nh_table, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *chassis, const struct hmap *local_datapaths, @@ -6572,10 +6763,13 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, { struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs); struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports); + struct smap local_ecmp_nexthop_map = + SMAP_INITIALIZER(&local_ecmp_nexthop_map); struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys); struct shash nat_addresses; unsigned long long garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT; - bool garp_continuous = false; + unsigned long long max_arp_nd_timeout = GARP_RARP_DEF_MAX_TIMEOUT; + bool garp_continuous = false, continuous_arp_nd = true; const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_table_first(ovs_table); if (cfg) { @@ -6585,6 +6779,11 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, if (!garp_max_timeout) { garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT; } + + max_arp_nd_timeout = smap_get_ullong( + &cfg->external_ids, "arp-nd-max-timeout-sec", + GARP_RARP_DEF_MAX_TIMEOUT / 1000) * 1000; + continuous_arp_nd = !!max_arp_nd_timeout; } shash_init(&nat_addresses); @@ -6598,13 +6797,23 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, &nat_ip_keys, &local_l3gw_ports, chassis, active_tunnels, &nat_addresses); + + get_local_ecmp_nexthop_map(ecmp_nh_table, sbrec_port_binding_by_name, + chassis, &local_ecmp_nexthop_map); + /* For deleted ports and deleted nat ips, remove from * send_garp_rarp_data. */ struct shash_node *iter; SHASH_FOR_EACH_SAFE (iter, &send_garp_rarp_data) { if (!sset_contains(&localnet_vifs, iter->name) && !sset_contains(&nat_ip_keys, iter->name)) { - send_garp_rarp_delete(iter->name); + send_garp_rarp_delete(&send_garp_rarp_data, iter->name); + } + } + + SHASH_FOR_EACH_SAFE (iter, &send_arp_nd_data) { + if (!smap_get(&local_ecmp_nexthop_map, iter->name)) { + send_garp_rarp_delete(&send_arp_nd_data, iter->name); } } @@ -6633,10 +6842,21 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, } } + struct smap_node *node; + SMAP_FOR_EACH (node, &local_ecmp_nexthop_map) { + const struct sbrec_port_binding *pb = lport_lookup_by_name( + sbrec_port_binding_by_name, node->value); + if (pb) { + send_arp_nd_update(pb, node->key, max_arp_nd_timeout, + continuous_arp_nd); + } + } + /* pinctrl_handler thread will send the GARPs. */ sset_destroy(&localnet_vifs); sset_destroy(&local_l3gw_ports); + smap_destroy(&local_ecmp_nexthop_map); SHASH_FOR_EACH_SAFE (iter, &nat_addresses) { struct lport_addresses *laddrs = iter->data; @@ -6650,6 +6870,9 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, garp_rarp_max_timeout = garp_max_timeout; garp_rarp_continuous = garp_continuous; + + arp_nd_max_timeout = max_arp_nd_timeout; + arp_nd_continuous = continuous_arp_nd; } static bool diff --git a/controller/pinctrl.h b/controller/pinctrl.h index 3462b670c..5c8ea7aea 100644 --- a/controller/pinctrl.h +++ b/controller/pinctrl.h @@ -36,6 +36,7 @@ struct sbrec_dns_table; struct sbrec_controller_event_table; struct sbrec_service_monitor_table; struct sbrec_bfd_table; +struct sbrec_ecmp_nexthop_table; struct sbrec_port_binding; struct sbrec_mac_binding_table; @@ -54,6 +55,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_service_monitor_table *, const struct sbrec_mac_binding_table *, const struct sbrec_bfd_table *, + const struct sbrec_ecmp_nexthop_table *, const struct ovsrec_bridge *, const struct sbrec_chassis *, const struct hmap *local_datapaths, const struct sset *active_tunnels, From patchwork Thu Sep 19 17:08:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1987527 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=g/E7dGbC; dkim-atps=neutral Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4X8hnX36qGz1y1m for ; Fri, 20 Sep 2024 03:09:04 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 92AA74143E; Thu, 19 Sep 2024 17:08:59 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id alppZjdAAFcG; Thu, 19 Sep 2024 17:08:55 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org E53B641439 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=g/E7dGbC Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id E53B641439; Thu, 19 Sep 2024 17:08:54 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 337DEC0014; Thu, 19 Sep 2024 17:08:54 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id A2888C0017 for ; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7328742A84 for ; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id lzrnjFS51cNP for ; Thu, 19 Sep 2024 17:08:50 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=lorenzo.bianconi@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org CD9D142A80 Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org CD9D142A80 Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=g/E7dGbC Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id CD9D142A80 for ; Thu, 19 Sep 2024 17:08:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1726765728; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nms1bT0cgagjAajUw1wn0JmOiwrS0+juf25elYfgsf0=; b=g/E7dGbCBHw3fv6tW4zJ45PwMZjEuNef61j8U4hOg8XNXHUNeqZkSNaRuk2NhsRxaK3deI y4h9E9X9DV+buMdXOlaYtmhq4rZx3lrhhj4kdi0b3kLXk35Azka2VQFrBvzthxQaT/dqg9 Jc0+kE3epn9UF1+edZmOSsUubhIXdrA= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-633-gSXZQIMbP06p666_W_m_ZA-1; Thu, 19 Sep 2024 13:08:47 -0400 X-MC-Unique: gSXZQIMbP06p666_W_m_ZA-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-42cae209243so6490045e9.1 for ; Thu, 19 Sep 2024 10:08:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726765726; x=1727370526; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=nms1bT0cgagjAajUw1wn0JmOiwrS0+juf25elYfgsf0=; b=kxxAs7aau2Y2NFuaFLTUq07PhPtiQQJqktizstExztUKUH5bVY7Ffn43LK/GBirIhP vFv/XWu3YPlZxLmM5VzZs/9i0k90exIJJ4jyGaIOAcUhZks7RyFNZ3NYyXNifqcqt20S w99yiQj2BGxCfXbZCX1aIQkUiG4ogxpl6xYNh9FxC41QplYkdMqOpiR9fyTCmfvxmaay HjXZmbNxEgn6PmJWcxRvOmcnn42R66KVyoxPBBdNor2QabyO3DMRCmMBuqHDdG7Kpqh+ t3y5ig2yNFIpv48uxMaJMuHbNWFI009LvrDhxwBaBgwUSKd9cQh38sSRNLEKHmYmcCEF vV7A== X-Gm-Message-State: AOJu0YygKa43lo6aePMXBbhur28NCuW5Qjz9vj5xlvmm/6Z97fVB9FGx OH2nRPUv3dlaktND3UcdwbnGK5I3BHb8RjOcvfnUUgXe77qJgIUBBAgOiNWUvB8ATgcSG81Jm2L nd1TWegH+b3DsOGKQsS60ly3R8ysmBIJkvngMfaewej3d5sR9wFkPfgukyuzPNIILXWx/ZOW4+4 rMvIfjMm3wSJsP2n0tCzacgEKwwOYuoQlgdwvix3N4IHKq8GmU4g== X-Received: by 2002:a05:600c:3b21:b0:426:5440:8541 with SMTP id 5b1f17b1804b1-42e7ad970dbmr241375e9.27.1726765726065; Thu, 19 Sep 2024 10:08:46 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGtorytCt7CgjRpUQVz+s9kG82sArRtac8DPWh8UNbq6LS3YkpWBC2lepDXvZZX85gXSH6CeQ== X-Received: by 2002:a05:600c:3b21:b0:426:5440:8541 with SMTP id 5b1f17b1804b1-42e7ad970dbmr241185e9.27.1726765725524; Thu, 19 Sep 2024 10:08:45 -0700 (PDT) Received: from localhost (net-37-182-8-79.cust.vodafonedsl.it. [37.182.8.79]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-378e73f9cd3sm15764227f8f.62.2024.09.19.10.08.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Sep 2024 10:08:45 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 19 Sep 2024 19:08:28 +0200 Message-ID: X-Mailer: git-send-email 2.46.1 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [RFC v2 ovn 3/4] pinctrl: Update ecmp-nexthop mac resolving L2 address. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dceara@redhat.com Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Set the mac address column in the ECMP_Nexthop table updating sb MAC_Binding table. This is a preliminary patch to introduce the capability to flush stale ECMP CT entries. Signed-off-by: Lorenzo Bianconi --- controller/ovn-controller.c | 4 +++ controller/pinctrl.c | 50 +++++++++++++++++++++++++++++-------- controller/pinctrl.h | 1 + northd/en-northd.c | 4 +++ northd/inc-proc-northd.c | 6 +++++ northd/northd.c | 17 +++++++++++++ northd/northd.h | 1 + 7 files changed, 72 insertions(+), 11 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index e72d28731..4dc9bc8cb 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -4939,6 +4939,9 @@ main(int argc, char *argv[]) = ovsdb_idl_index_create2(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac, &sbrec_fdb_col_dp_key); + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop + = ovsdb_idl_index_create1(ovnsb_idl_loop.idl, + &sbrec_ecmp_nexthop_col_nexthop); struct ovsdb_idl_index *sbrec_mac_binding_by_datapath = mac_binding_by_datapath_index_create(ovnsb_idl_loop.idl); struct ovsdb_idl_index *sbrec_static_mac_binding_by_datapath @@ -5645,6 +5648,7 @@ main(int argc, char *argv[]) sbrec_igmp_group, sbrec_ip_multicast, sbrec_fdb_by_dp_key_mac, + sbrec_ecmp_by_nexthop, sbrec_dns_table_get(ovnsb_idl_loop.idl), sbrec_controller_event_table_get( ovnsb_idl_loop.idl), diff --git a/controller/pinctrl.c b/controller/pinctrl.c index daf0bfa41..092613c4a 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -206,11 +206,15 @@ static void pinctrl_handle_put_mac_binding(const struct flow *md, OVS_REQUIRES(pinctrl_mutex); static void init_put_mac_bindings(void); static void destroy_put_mac_bindings(void); +const struct sbrec_ecmp_nexthop *ecmp_nexthop_lookup( + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop, + const char *nexthop); static void run_put_mac_bindings( struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_datapath_binding_by_key, struct ovsdb_idl_index *sbrec_port_binding_by_key, - struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip) + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop) OVS_REQUIRES(pinctrl_mutex); static void wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn); static void send_mac_binding_buffered_pkts(struct rconn *swconn) @@ -4160,6 +4164,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_igmp_groups, struct ovsdb_idl_index *sbrec_ip_multicast_opts, struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop, const struct sbrec_dns_table *dns_table, const struct sbrec_controller_event_table *ce_table, const struct sbrec_service_monitor_table *svc_mon_table, @@ -4177,7 +4182,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, ovs_mutex_lock(&pinctrl_mutex); run_put_mac_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, - sbrec_mac_binding_by_lport_ip); + sbrec_mac_binding_by_lport_ip, + sbrec_ecmp_by_nexthop); run_put_vport_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, chassis); send_garp_rarp_prepare(ovnsb_idl_txn, sbrec_port_binding_by_datapath, @@ -4831,13 +4837,9 @@ mac_binding_add_to_sb(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, const char *logical_port, const struct sbrec_datapath_binding *dp, - struct eth_addr ea, const char *ip, + char *mac_string, const char *ip, bool update_only) { - /* Convert ethernet argument to string form for database. */ - char mac_string[ETH_ADDR_STRLEN + 1]; - snprintf(mac_string, sizeof mac_string, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea)); - const struct sbrec_mac_binding *b = mac_binding_lookup(sbrec_mac_binding_by_lport_ip, logical_port, ip); @@ -4896,18 +4898,37 @@ send_garp_locally(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ds ip_s = DS_EMPTY_INITIALIZER; ip_format_masked(ip, OVS_BE32_MAX, &ip_s); + /* Convert ethernet argument to string form for database. */ + char mac_string[ETH_ADDR_STRLEN + 1]; + snprintf(mac_string, sizeof mac_string, ETH_ADDR_FMT, + ETH_ADDR_ARGS(ea)); mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, remote->logical_port, remote->datapath, - ea, ds_cstr(&ip_s), update_only); + mac_string, ds_cstr(&ip_s), update_only); ds_destroy(&ip_s); } } +const struct sbrec_ecmp_nexthop * +ecmp_nexthop_lookup(struct ovsdb_idl_index *sbrec_ecmp_by_nexthop, + const char *nexthop) +{ + struct sbrec_ecmp_nexthop *ecmp_nh = + sbrec_ecmp_nexthop_index_init_row(sbrec_ecmp_by_nexthop); + sbrec_ecmp_nexthop_set_nexthop(ecmp_nh, nexthop); + const struct sbrec_ecmp_nexthop *retval = + sbrec_ecmp_nexthop_index_find(sbrec_ecmp_by_nexthop, ecmp_nh); + sbrec_ecmp_nexthop_index_destroy_row(ecmp_nh); + + return retval; +} + static void run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_datapath_binding_by_key, struct ovsdb_idl_index *sbrec_port_binding_by_key, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop, const struct mac_binding *mb) { /* Convert logical datapath and logical port key into lport. */ @@ -4930,8 +4951,13 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ds ip_s = DS_EMPTY_INITIALIZER; ipv6_format_mapped(&mb->data.ip, &ip_s); mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, - pb->logical_port, pb->datapath, mb->data.mac, + pb->logical_port, pb->datapath, mac_string, ds_cstr(&ip_s), false); + const struct sbrec_ecmp_nexthop *ecmp_nh = + ecmp_nexthop_lookup(sbrec_ecmp_by_nexthop, ds_cstr(&ip_s)); + if (ecmp_nh) { + sbrec_ecmp_nexthop_set_mac(ecmp_nh, mac_string); + } ds_destroy(&ip_s); } @@ -4941,7 +4967,8 @@ static void run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_datapath_binding_by_key, struct ovsdb_idl_index *sbrec_port_binding_by_key, - struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip) + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop) OVS_REQUIRES(pinctrl_mutex) { if (!ovnsb_idl_txn) { @@ -4956,7 +4983,8 @@ run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn, run_put_mac_binding(ovnsb_idl_txn, sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, - sbrec_mac_binding_by_lport_ip, mb); + sbrec_mac_binding_by_lport_ip, + sbrec_ecmp_by_nexthop, mb); mac_binding_remove(&put_mac_bindings, mb); } } diff --git a/controller/pinctrl.h b/controller/pinctrl.h index 5c8ea7aea..f1968f31c 100644 --- a/controller/pinctrl.h +++ b/controller/pinctrl.h @@ -50,6 +50,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_igmp_groups, struct ovsdb_idl_index *sbrec_ip_multicast_opts, struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, + struct ovsdb_idl_index *sbrec_ecmp_by_nexthop, const struct sbrec_dns_table *, const struct sbrec_controller_event_table *, const struct sbrec_service_monitor_table *, diff --git a/northd/en-northd.c b/northd/en-northd.c index b8227617b..b3e612958 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -412,9 +412,13 @@ en_ecmp_nexthop_run(struct engine_node *node, void *data OVS_UNUSED) engine_get_input_data("static_routes", node); const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table = EN_OVSDB_GET(engine_get_input("SB_ecmp_nexthop", node)); + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip = + engine_ovsdb_node_get_index(engine_get_input("SB_mac_binding", node), + "sbrec_mac_binding_by_lport_ip"); build_ecmp_nexthop_table(eng_ctx->ovnsb_idl_txn, &static_routes_data->parsed_routes, + sbrec_mac_binding_by_lport_ip, sbrec_ecmp_nexthop_table); engine_set_node_state(node, EN_UPDATED); } diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index cdc080ef0..d29bdca3e 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -266,6 +266,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_bfd_sync, &en_route_policies, NULL); engine_add_input(&en_bfd_sync, &en_northd, bfd_sync_northd_change_handler); + engine_add_input(&en_ecmp_nexthop, &en_sb_mac_binding, NULL); engine_add_input(&en_ecmp_nexthop, &en_sb_ecmp_nexthop, NULL); engine_add_input(&en_ecmp_nexthop, &en_static_routes, NULL); @@ -369,6 +370,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, = static_mac_binding_index_create(sb->idl); struct ovsdb_idl_index *sbrec_mac_binding_by_datapath = mac_binding_by_datapath_index_create(sb->idl); + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip + = mac_binding_by_lport_ip_index_create(sb->idl); struct ovsdb_idl_index *fdb_by_dp_key = ovsdb_idl_index_create1(sb->idl, &sbrec_fdb_col_dp_key); @@ -395,6 +398,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_ovsdb_node_add_index(&en_sb_mac_binding, "sbrec_mac_binding_by_datapath", sbrec_mac_binding_by_datapath); + engine_ovsdb_node_add_index(&en_sb_mac_binding, + "sbrec_mac_binding_by_lport_ip", + sbrec_mac_binding_by_lport_ip); engine_ovsdb_node_add_index(&en_sb_fdb, "fdb_by_dp_key", fdb_by_dp_key); diff --git a/northd/northd.c b/northd/northd.c index 3e3bb84ef..4e99e2687 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -10669,6 +10669,7 @@ void build_ecmp_nexthop_table( struct ovsdb_idl_txn *ovnsb_txn, struct hmap *routes, + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table) { if (!ovnsb_txn) { @@ -10699,6 +10700,22 @@ build_ecmp_nexthop_table( sb_ecmp_nexthop = sbrec_ecmp_nexthop_insert(ovnsb_txn); sbrec_ecmp_nexthop_set_nexthop(sb_ecmp_nexthop, r->nexthop); sbrec_ecmp_nexthop_set_port(sb_ecmp_nexthop, pr->out_port->key); + + struct sbrec_mac_binding *mb_index_row = + sbrec_mac_binding_index_init_row( + sbrec_mac_binding_by_lport_ip); + sbrec_mac_binding_index_set_ip(mb_index_row, r->nexthop); + sbrec_mac_binding_index_set_logical_port(mb_index_row, + pr->out_port->key); + + const struct sbrec_mac_binding *mb = + sbrec_mac_binding_index_find(sbrec_mac_binding_by_lport_ip, + mb_index_row); + if (mb) { + sbrec_ecmp_nexthop_set_mac(sb_ecmp_nexthop, mb->mac); + } + + sbrec_mac_binding_index_destroy_row(mb_index_row); } sset_add(&nb_nexthops_sset, r->nexthop); } diff --git a/northd/northd.h b/northd/northd.h index c4c2a5d7e..83239197f 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -747,6 +747,7 @@ void bfd_sync_init(struct bfd_sync_data *); void bfd_sync_destroy(struct bfd_sync_data *); void build_ecmp_nexthop_table(struct ovsdb_idl_txn *, struct hmap *, + struct ovsdb_idl_index *, const struct sbrec_ecmp_nexthop_table *); struct lflow_table; From patchwork Thu Sep 19 17:08:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1987525 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=cu6FtyEL; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4X8hnT1CzXz1y1m for ; Fri, 20 Sep 2024 03:09:01 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 30FB442ACB; Thu, 19 Sep 2024 17:08:59 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id wLc-41V548bs; Thu, 19 Sep 2024 17:08:56 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org AFB6842A94 Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=cu6FtyEL Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id AFB6842A94; Thu, 19 Sep 2024 17:08:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 020EDC0014; Thu, 19 Sep 2024 17:08:56 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id E7918C0013 for ; Thu, 19 Sep 2024 17:08:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D7495615FB for ; Thu, 19 Sep 2024 17:08:53 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 9nRxm-avbOPw for ; Thu, 19 Sep 2024 17:08:52 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=lorenzo.bianconi@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org BF78B615FF Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org BF78B615FF Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=cu6FtyEL Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id BF78B615FF for ; Thu, 19 Sep 2024 17:08:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1726765730; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=z+Wz5zEDfN9wv7XFTesl22rHjR3P1G6NF8XmmeuubI0=; b=cu6FtyELpBGbeOAMSZhZiiAmrSlxu4khZYF2Tw9L7OMCDGc1vYIpQ9Y2UNiby7krRQ/tZn HloA8fktsvQl6NX+GzQv20bC40Mpa2sjQEv2IFMUd05ERHGCb7XNiHcWd1kiRbG+LgIEXq baUkpZ4UDtLjuyKTrIJ5Ar1Er6p0/Kk= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-404-a5vjp2n1PVm6_iRcAChUcg-1; Thu, 19 Sep 2024 13:08:49 -0400 X-MC-Unique: a5vjp2n1PVm6_iRcAChUcg-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-374b9617ab0so457938f8f.3 for ; Thu, 19 Sep 2024 10:08:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726765728; x=1727370528; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=z+Wz5zEDfN9wv7XFTesl22rHjR3P1G6NF8XmmeuubI0=; b=VZYHKfB6HZDP9HezyhCJ4YMcFWJ1a87IxK4vEpeb98fRNgYKlrkwvfsmI59T2+rV+r y5f6y5ryJMDc7ok2rTNi/f4q4mcr6chdFzB8VKqpTDuac12+fQSuPKYheQQpteVe2TjH LJQ/6ce9tpLmAS+z/CTgnHkIahdHLgZ8e2Eh8j2aY3s5MywRKMeDM91Sfhgb7gwGyxMT btfh3ZqOYueYsypdgqYQfAq6ti3ya3aKonkkO9TCXsg56DpxM8kb2K+W+51Dwf0AB4lA fdxBpVzxfhJQZN2zE4ssUCkgNYaP8pf7eazLkOQmdmtm9VTTda2Ho2eGV+qfaCYLwAos BZwA== X-Gm-Message-State: AOJu0YyGiaX+Eiwvu5h6BjFKAeAMEeSJKQWQp13BONCTuSkJhq4G9VtH oflMar+8q+oFXfxPoOPTAWAaee1slFLK3Fr2/khXXblEHvcjMHJAAxJnGcuCQZ7k6jVrKdCJjwJ G5xHGuoOSHnNVsqaxOVUiufF63G7bqlbm7W7us7ms9FmFtJhq6iqwUk4AHDqFMV/70wZLLC+Q2t z07rkT28ulMSdqDnvGvdyNOCWSGSmv0nuTUnjUzUCs8VkrX+heKw== X-Received: by 2002:a5d:5306:0:b0:374:bb32:6560 with SMTP id ffacd0b85a97d-378c2d5965dmr13957012f8f.58.1726765727352; Thu, 19 Sep 2024 10:08:47 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHhCtNNCSfBV48WUFq9VgVxdBufQYGJpNbjwo0Q39A/a8/s1ECJfSiz+iVSGwoaj1JibRCuvQ== X-Received: by 2002:a5d:5306:0:b0:374:bb32:6560 with SMTP id ffacd0b85a97d-378c2d5965dmr13956995f8f.58.1726765726660; Thu, 19 Sep 2024 10:08:46 -0700 (PDT) Received: from localhost (net-37-182-8-79.cust.vodafonedsl.it. [37.182.8.79]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-378e71f0622sm15631871f8f.18.2024.09.19.10.08.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Sep 2024 10:08:46 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 19 Sep 2024 19:08:29 +0200 Message-ID: <924500581c8278d640a0e8e06189bae25366fa73.1726765502.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.46.1 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [RFC v2 ovn 4/4] ofctrl: Introduce ecmp_nexthop_monitor. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dceara@redhat.com Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce ecmp_nexthop_monitor in ovn-controller in order to track and flush ecmp-symmetric reply ct entires when requested by the CMS (e.g removing the related static ecmp routes). CT entries are flushed using the ethernet mac address stored in ct_label. Signed-off-by: Lorenzo Bianconi --- controller/ofctrl.c | 73 +++++++ controller/ofctrl.h | 2 + controller/ovn-controller.c | 2 + tests/system-ovn.at | 378 ++++++++++++++++++++++++++++++++++++ 4 files changed, 455 insertions(+) diff --git a/controller/ofctrl.c b/controller/ofctrl.c index f9387d375..5987e9be3 100644 --- a/controller/ofctrl.c +++ b/controller/ofctrl.c @@ -45,6 +45,7 @@ #include "ovn/actions.h" #include "lib/extend-table.h" #include "lib/lb.h" +#include "lib/ovn-util.h" #include "openvswitch/poll-loop.h" #include "physical.h" #include "openvswitch/rconn.h" @@ -392,6 +393,11 @@ static struct shash meter_bands; static void ofctrl_meter_bands_destroy(void); static void ofctrl_meter_bands_clear(void); +static struct smap ecmp_nexthop; +static void ecmp_nexthop_monitor_run( + const struct sbrec_ecmp_nexthop_table *enh_table, + struct ovs_list *msgs); + /* MFF_* field ID for our Geneve option. In S_TLV_TABLE_MOD_SENT, this is * the option we requested (we don't know whether we obtained it yet). In * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */ @@ -425,6 +431,7 @@ ofctrl_init(struct ovn_extend_table *group_table, tx_counter = rconn_packet_counter_create(); hmap_init(&installed_lflows); hmap_init(&installed_pflows); + smap_init(&ecmp_nexthop); ovs_list_init(&flow_updates); ovn_init_symtab(&symtab); groups = group_table; @@ -877,6 +884,7 @@ ofctrl_destroy(void) expr_symtab_destroy(&symtab); shash_destroy(&symtab); ofctrl_meter_bands_destroy(); + smap_destroy(&ecmp_nexthop); } uint64_t @@ -2306,6 +2314,68 @@ add_meter(struct ovn_extend_table_info *m_desired, ofctrl_meter_bands_alloc(sb_meter, m_desired, msgs); } +static void +ecmp_nexthop_monitor_flush_ct_entry(const char *mac, struct ovs_list *msgs) +{ + struct eth_addr ea; + if (!ovs_scan(mac, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { + return; + } + + ovs_u128 mask = { + /* ct_label.ecmp_reply_eth BITS[32-79] */ + .u64.hi = 0x000000000000ffff, + .u64.lo = 0xffffffff00000000, + }; + + ovs_be32 lo = get_unaligned_be32((void *)&ea.be16[1]); + ovs_u128 nexthop = { + .u64.hi = ntohs(ea.be16[0]), + .u64.lo = (uint64_t) ntohl(lo) << 32, + }; + + struct ofp_ct_match match = { + .labels = nexthop, + .labels_mask = mask, + }; + struct ofpbuf *msg = ofp_ct_match_encode(&match, NULL, + rconn_get_version(swconn)); + ovs_list_push_back(msgs, &msg->list_node); +} + +static void +ecmp_nexthop_monitor_run(const struct sbrec_ecmp_nexthop_table *enh_table, + struct ovs_list *msgs) +{ + struct sset ecmp_sb_only = SSET_INITIALIZER(&ecmp_sb_only); + struct simap mac_count = SIMAP_INITIALIZER(&mac_count); + + struct smap_node *node; + SMAP_FOR_EACH_SAFE (node, &ecmp_nexthop) { + simap_increase(&mac_count, node->value, 1); + } + + const struct sbrec_ecmp_nexthop *sbrec_ecmp_nexthop; + SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sbrec_ecmp_nexthop, enh_table) { + smap_replace(&ecmp_nexthop, sbrec_ecmp_nexthop->nexthop, + sbrec_ecmp_nexthop->mac); + sset_add(&ecmp_sb_only, sbrec_ecmp_nexthop->nexthop); + } + + SMAP_FOR_EACH_SAFE (node, &ecmp_nexthop) { + /* Do not flush CT entries if the share the same mac address. */ + if (!sset_contains(&ecmp_sb_only, node->key)) { + if (simap_get(&mac_count, node->value) == 1) { + ecmp_nexthop_monitor_flush_ct_entry(node->value, msgs); + } + smap_remove_node(&ecmp_nexthop, node); + } + } + + sset_destroy(&ecmp_sb_only); + simap_destroy(&mac_count); +} + static void installed_flow_add(struct ovn_flow *d, struct ofputil_bundle_ctrl_msg *bc, @@ -2664,6 +2734,7 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, struct shash *pending_ct_zones, struct hmap *pending_lb_tuples, struct ovsdb_idl_index *sbrec_meter_by_name, + const struct sbrec_ecmp_nexthop_table *enh_table, uint64_t req_cfg, bool lflows_changed, bool pflows_changed) @@ -2704,6 +2775,8 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, /* OpenFlow messages to send to the switch to bring it up-to-date. */ struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs); + ecmp_nexthop_monitor_run(enh_table, &msgs); + /* Iterate through ct zones that need to be flushed. */ struct shash_node *iter; SHASH_FOR_EACH(iter, pending_ct_zones) { diff --git a/controller/ofctrl.h b/controller/ofctrl.h index 129e3b6ad..33953a8a4 100644 --- a/controller/ofctrl.h +++ b/controller/ofctrl.h @@ -31,6 +31,7 @@ struct ofpbuf; struct ovsrec_bridge; struct ovsrec_open_vswitch_table; struct sbrec_meter_table; +struct sbrec_ecmp_nexthop_table; struct shash; struct ovn_desired_flow_table { @@ -59,6 +60,7 @@ void ofctrl_put(struct ovn_desired_flow_table *lflow_table, struct shash *pending_ct_zones, struct hmap *pending_lb_tuples, struct ovsdb_idl_index *sbrec_meter_by_name, + const struct sbrec_ecmp_nexthop_table *enh_table, uint64_t nb_cfg, bool lflow_changed, bool pflow_changed); diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 4dc9bc8cb..7203cda42 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -5731,6 +5731,8 @@ main(int argc, char *argv[]) &ct_zones_data->ctx.pending, &lb_data->removed_tuples, sbrec_meter_by_name, + sbrec_ecmp_nexthop_table_get( + ovnsb_idl_loop.idl), ofctrl_seqno_get_req_cfg(), engine_node_changed(&en_lflow_output), engine_node_changed(&en_pflow_output)); diff --git a/tests/system-ovn.at b/tests/system-ovn.at index e065b1079..01008b899 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -13884,3 +13884,381 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d /.*terminating with signal 15.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ECMP Flush CT entries - IPv4]) +AT_KEYWORDS([ecmp]) +ovn_start +OVS_TRAFFIC_VSWITCHD_START() + +ADD_BR([br-int]) +ADD_BR([br-ext]) +ADD_BR([br-ecmp]) + +ovs-ofctl add-flow br-ext action=normal +ovs-ofctl add-flow br-ecmp action=normal +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller +ovs-vsctl set Open_vSwitch . external-ids:arp-max-timeout-sec=1 + +check ovn-nbctl lr-add R1 +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 +check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 + +ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +ADD_NAMESPACES(alice) +ADD_VETH(alice, alice, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ + "192.168.1.1") +check ovn-nbctl lsp-add sw0 alice \ + -- lsp-set-addresses alice "f0:00:00:01:02:03 192.168.1.2" + +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +ADD_NAMESPACES(ecmp-path0) +ADD_VETH(ecmp-p01, ecmp-path0, br-ext, "172.16.1.2/24", "f0:00:00:01:02:04", "172.16.1.1") +ADD_VETH(ecmp-p02, ecmp-path0, br-ecmp, "172.16.2.2/24", "f0:00:00:01:03:04") + +ADD_NAMESPACES(ecmp-path1) +ADD_VETH(ecmp-p11, ecmp-path1, br-ext, "172.16.1.3/24", "f0:00:00:01:02:05", "172.16.1.1") +ADD_VETH(ecmp-p12, ecmp-path1, br-ecmp, "172.16.2.3/24", "f0:00:00:01:03:05") + +ADD_NAMESPACES(bob) +ADD_VETH(bob, bob, br-ecmp, "172.16.2.10/24", "f0:00:00:01:02:06", "172.16.2.2") + +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 172.16.2.0/24 172.16.1.2 +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 172.16.2.0/24 172.16.1.3 + +ovn-nbctl --wait=hv sync +NETNS_DAEMONIZE([alice], [nc -l -k 80], [alice.pid]) + +NS_CHECK_EXEC([bob], [ping -q -c 3 -i 0.3 -w 2 192.168.1.2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +NS_CHECK_EXEC([bob], [nc -z 192.168.1.2 80], [0]) + +wait_row_count ECMP_Nexthop 2 +wait_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='172.16.1.2' +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='172.16.1.3' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020400000000 +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020400000000,protoinfo=(state=) +]) + +# Change bob default IP address +NS_CHECK_EXEC([bob], [ip route del 0.0.0.0/0 via 172.16.2.2]) +NS_CHECK_EXEC([bob], [ip route add 0.0.0.0/0 via 172.16.2.3]) + +NS_CHECK_EXEC([bob], [ping -q -c 3 -i 0.3 -w 2 192.168.1.2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +NS_CHECK_EXEC([bob], [nc -z 192.168.1.2 80], [0]) + +wait_row_count ECMP_Nexthop 2 +check_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='172.16.1.2' +check_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='172.16.1.3' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020400000000 +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020400000000,protoinfo=(state=) +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove first ECMP route +check ovn-nbctl lr-route-del R1 172.16.2.0/24 172.16.1.2 +wait_row_count ECMP_Nexthop 1 +check_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='172.16.1.3' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Add the route back and verify we do not flush if we have multiple next-hops with the same mac address +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 172.16.2.0/24 172.16.1.2 +wait_row_count ECMP_Nexthop 2 +wait_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='172.16.1.2' +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='172.16.1.3' + +NS_CHECK_EXEC([ecmp-path0], [ip link set dev ecmp-p01 address f0:00:00:01:02:05]) +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='172.16.1.2' + +# Change bob default IP address +NS_CHECK_EXEC([bob], [ip route del 0.0.0.0/0 via 172.16.2.3]) +NS_CHECK_EXEC([bob], [ip route add 0.0.0.0/0 via 172.16.2.2]) + +NS_CHECK_EXEC([bob], [ping -q -c 3 -i 0.3 -w 2 192.168.1.2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +NS_CHECK_EXEC([bob], [nc -z 192.168.1.2 80], [0]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove first ECMP route +check ovn-nbctl lr-route-del R1 172.16.2.0/24 172.16.1.2 +wait_row_count ECMP_Nexthop 1 + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmp,orig=(src=172.16.2.10,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.2.10,id=,type=0,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=172.16.2.10,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.2.10,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove second ECMP route +check ovn-nbctl lr-route-del R1 +wait_row_count ECMP_Nexthop 0 + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.2.10) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +]) + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ECMP Flush CT entries - IPv6]) +AT_KEYWORDS([ecmp]) +ovn_start +OVS_TRAFFIC_VSWITCHD_START() + +ADD_BR([br-int]) +ADD_BR([br-ext]) +ADD_BR([br-ecmp]) + +ovs-ofctl add-flow br-ext action=normal +ovs-ofctl add-flow br-ecmp action=normal +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller +ovs-vsctl set Open_vSwitch . external-ids:arp-max-timeout-sec=1 + +check ovn-nbctl lr-add R1 +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 fd11::1/64 +check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 fd12::1/64 + +ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +ADD_NAMESPACES(alice) +ADD_VETH(alice, alice, br-int, "fd11::2/64", "f0:00:00:01:02:03", "fd11::1", "nodad") +check ovn-nbctl lsp-add sw0 alice -- lsp-set-addresses alice "f0:00:00:01:02:03 fd11::2" + +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +ADD_NAMESPACES(ecmp-path0) +ADD_VETH(ecmp-p01, ecmp-path0, br-ext, "fd12::2/64", "f0:00:00:01:02:04", "fd12::1", "nodad") +ADD_VETH(ecmp-p02, ecmp-path0, br-ecmp, "fd13::2/64", "f0:00:00:01:03:04") +OVS_WAIT_UNTIL([NS_EXEC([ecmp-path0], [ip a show dev ecmp-p02 | grep "fe80::" | grep -v tentative])]) + +ADD_NAMESPACES(ecmp-path1) +ADD_VETH(ecmp-p11, ecmp-path1, br-ext, "fd12::3/64", "f0:00:00:01:02:05", "fd12::1", "nodad") +ADD_VETH(ecmp-p12, ecmp-path1, br-ecmp, "fd13::3/64", "f0:00:00:01:03:05") +OVS_WAIT_UNTIL([NS_EXEC([ecmp-path1], [ip a show dev ecmp-p12 | grep "fe80::" | grep -v tentative])]) + +ADD_NAMESPACES(bob) +ADD_VETH(bob, bob, br-ecmp, "fd13::a/64", "f0:00:00:01:02:06", "fd13::2", "nodad") + +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 fd13::/64 fd12::2 +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 fd13::/64 fd12::3 + +NS_CHECK_EXEC([ecmp-path0], [sysctl -w net.ipv6.conf.all.forwarding=1],[0], [dnl +net.ipv6.conf.all.forwarding = 1 +]) +NS_CHECK_EXEC([ecmp-path1], [sysctl -w net.ipv6.conf.all.forwarding=1],[0], [dnl +net.ipv6.conf.all.forwarding = 1 +]) + +ovn-nbctl --wait=hv sync +NETNS_DAEMONIZE([alice], [nc -6 -l -k 80], [alice.pid]) + +NS_CHECK_EXEC([bob], [ping6 -q -c 3 -i 0.3 -w 2 fd11::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +NS_CHECK_EXEC([bob], [nc -6 -z fd11::2 80], [0]) + +wait_row_count ECMP_Nexthop 2 +wait_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='"fd12::2"' +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='"fd12::3"' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020400000000 +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020400000000,protoinfo=(state=) +]) + +# Change bob default IP address +NS_CHECK_EXEC([bob], [ip -6 route del ::/0 via fd13::2]) +NS_CHECK_EXEC([bob], [ip -6 route add ::/0 via fd13::3]) + +NS_CHECK_EXEC([bob], [ping -6 -q -c 3 -i 0.3 -w 2 fd11::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +NS_CHECK_EXEC([bob], [nc -6 -z fd11::2 80], [0]) + +wait_row_count ECMP_Nexthop 2 +check_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='"fd12::2"' +check_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='"fd12::3"' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020400000000 +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020400000000,protoinfo=(state=) +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove first ECMP route +check ovn-nbctl lr-route-del R1 fd13::/64 fd12::2 +wait_row_count ECMP_Nexthop 1 +check_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='"fd12::3"' + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + + Add the route back and verify we do not flush if we have multiple next-hops with the same mac address +check ovn-nbctl --ecmp-symmetric-reply lr-route-add R1 fd13::/64 fd12::2 +wait_row_count ECMP_Nexthop 2 +wait_column 'f0:00:00:01:02:04' ECMP_Nexthop mac nexthop='"fd12::2"' +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='"fd12::3"' +# +NS_CHECK_EXEC([ecmp-path0], [ip link set dev ecmp-p01 address f0:00:00:01:02:05]) +wait_column 'f0:00:00:01:02:05' ECMP_Nexthop mac nexthop='"fd12::2"' + +# Change bob default IP address +NS_CHECK_EXEC([bob], [ip -6 route del ::/0 via fd13::3]) +NS_CHECK_EXEC([bob], [ip -6 route add ::/0 via fd13::2]) + +NS_CHECK_EXEC([bob], [ping -6 -q -c 3 -i 0.3 -w 2 fd11::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +NS_CHECK_EXEC([bob], [nc -6 -z fd11::2 80], [0]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove first ECMP route +check ovn-nbctl lr-route-del R1 fd13::/64 fd12::2 +wait_row_count ECMP_Nexthop 1 + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +icmpv6,orig=(src=fd13::a,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd13::a,id=,type=129,code=0),zone=,mark=,labels=0xf0000001020500000000 +tcp,orig=(src=fd13::a,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd13::a,sport=,dport=),zone=,mark=,labels=0xf0000001020500000000,protoinfo=(state=) +]) + +# Remove second ECMP route +check ovn-nbctl lr-route-del R1 +wait_row_count ECMP_Nexthop 0 + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd13::a) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | +sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl +]) + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP +])