From patchwork Fri Jan 8 16:36:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1423874 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: 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=S05cnH/K; dkim-atps=neutral Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DC7zX1PWCz9sWs for ; Sat, 9 Jan 2021 03:36:56 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id BD67186E2B; Fri, 8 Jan 2021 16:36:54 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1UssP5RSoyzs; Fri, 8 Jan 2021 16:36:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 2354B86DC4; Fri, 8 Jan 2021 16:36:50 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0323FC0891; Fri, 8 Jan 2021 16:36:50 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 27949C0FA8 for ; Fri, 8 Jan 2021 16:36:49 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 134AF872D3 for ; Fri, 8 Jan 2021 16:36:49 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3chP42RIp+cB for ; Fri, 8 Jan 2021 16:36:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by hemlock.osuosl.org (Postfix) with ESMTPS id 7F9A986FE6 for ; Fri, 8 Jan 2021 16:36:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1610123805; 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=ZnRMQL8CYlw97lxoaVtdF9EyEB630Toe4NPDEJE63VM=; b=S05cnH/KhrtxfzpNjmM2OyNK1xds4WuZYOlPO9isor1wciLvGYbh+hsPrpvTb5GlKJj7FB D3F6owB9OxgzvW0a4vyt9MwXNfj6VSuCg4sYpMundqLvjBhWIfjL1+ErAYrpKAp3jQ8ica JYOEkLry4sH9S2p4Gz11B9veL552gHA= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-589-tqOu1KyXN2Se00iMCuvlBw-1; Fri, 08 Jan 2021 11:36:41 -0500 X-MC-Unique: tqOu1KyXN2Se00iMCuvlBw-1 Received: by mail-ej1-f72.google.com with SMTP id u25so3808655ejf.3 for ; Fri, 08 Jan 2021 08:36:40 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZnRMQL8CYlw97lxoaVtdF9EyEB630Toe4NPDEJE63VM=; b=TD7QnRr5dU7r8GPOTeyVsbJ4xAXd0bEVXbYMVd58tTQKZK0JptMlr4GWHoVpuWxC7h vTlvsrlLY1M5XAEcqa4BYEJB9KB8NlgguNocPNKT3GHp9A31LvoYMOSAZcL27mk535/m zkUu4oSZ60KrKt3BJmiJLZVAvg/6Gbddzxfa19QZsNk8M29V6DMSxJ3NklLr5JoT8T35 Vby6l1wjZMKUE5jmJUBpYu7c9kcmaqP1pSXhcX1OP8eoU+66h0zjJkpG9KCLJFESP37/ h0fCvXrp6ulTLJq1KM0FrdXgJWR+8qLbXLLtq5YPNZfQoV+w5Um6SnPjDrjOlHwTfr9I kMVg== X-Gm-Message-State: AOAM5335hck3yCYU5natngJMtAQaJyB+BuHeDX7h9BGT6R+ci3ekK8Yy B3BTQJAFmTZqGa6uz8YsAu+O/v7M6BaTrZgknrovrfdwGxydQmR7KO+itsdc/5PnxxA2W7hye7j NCbo9jYdSHMesRj7kTAbONIrd2aW7P1brr7OBlUxex5h/tPdt3ot38B3MmlXJkebYUeWKHj5OBm Q= X-Received: by 2002:a05:6402:1a52:: with SMTP id bf18mr5740308edb.143.1610123799301; Fri, 08 Jan 2021 08:36:39 -0800 (PST) X-Google-Smtp-Source: ABdhPJzVJh17NIsoJz0Oay52Ux+GTfVTMyw/4rOpsjj1UO8oyLRQW7H41/TFGk4uyOSwnZPYzsfG/Q== X-Received: by 2002:a05:6402:1a52:: with SMTP id bf18mr5740289edb.143.1610123798907; Fri, 08 Jan 2021 08:36:38 -0800 (PST) Received: from lore-desk.redhat.com ([151.66.42.92]) by smtp.gmail.com with ESMTPSA id ak17sm3745496ejc.103.2021.01.08.08.36.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 08:36:38 -0800 (PST) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Fri, 8 Jan 2021 17:36:20 +0100 Message-Id: <21c8042b76ff7adb21e21b68221c05080950b184.1610123623.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v9 ovn 1/5] controller: introduce BFD tx path in ovn-controller X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce the capability to transmit BFD packets in ovn-controller. Introduce BFD tables in nb/sb dbs in order to configure BFD parameters (e.g. min_tx, min_rx, ..) for ovn-controller. Signed-off-by: Lorenzo Bianconi --- controller/ovn-controller.c | 1 + controller/pinctrl.c | 298 +++++++++++++++++++++++++++++++++++- controller/pinctrl.h | 2 + lib/ovn-l7.h | 19 +++ northd/ovn-northd.c | 202 ++++++++++++++++++++++++ ovn-nb.ovsschema | 29 +++- ovn-nb.xml | 67 ++++++++ ovn-sb.ovsschema | 27 +++- ovn-sb.xml | 78 ++++++++++ 9 files changed, 718 insertions(+), 5 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 366fc9c06..75512871b 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2837,6 +2837,7 @@ main(int argc, char *argv[]) ovnsb_idl_loop.idl), sbrec_service_monitor_table_get( ovnsb_idl_loop.idl), + sbrec_bfd_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 e957b75a5..6b934ed16 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -323,6 +323,18 @@ put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, static void notify_pinctrl_main(void); static void notify_pinctrl_handler(void); +static bool bfd_monitor_should_inject(void); +static void bfd_monitor_wait(long long int timeout); +static void bfd_monitor_init(void); +static void bfd_monitor_destroy(void); +static void bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time) + OVS_REQUIRES(pinctrl_mutex); +static void bfd_monitor_run(const struct sbrec_bfd_table *bfd_table, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + const struct sbrec_chassis *chassis, + const struct sset *active_tunnels) + OVS_REQUIRES(pinctrl_mutex); + COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); COVERAGE_DEFINE(pinctrl_drop_controller_event); @@ -487,6 +499,7 @@ pinctrl_init(void) ip_mcast_snoop_init(); init_put_vport_bindings(); init_svc_monitors(); + bfd_monitor_init(); pinctrl.br_int_name = NULL; pinctrl_handler_seq = seq_create(); pinctrl_main_seq = seq_create(); @@ -3053,6 +3066,8 @@ pinctrl_handler(void *arg_) swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP15_VERSION); while (!latch_is_set(&pctrl->pinctrl_thread_exit)) { + long long int bfd_time = LLONG_MAX; + ovs_mutex_lock(&pinctrl_mutex); pinctrl_rconn_setup(swconn, pctrl->br_int_name); ip_mcast_snoop_run(); @@ -3085,6 +3100,7 @@ pinctrl_handler(void *arg_) send_ipv6_ras(swconn, &send_ipv6_ra_time); send_ipv6_prefixd(swconn, &send_prefixd_time); send_mac_binding_buffered_pkts(swconn); + bfd_monitor_send_msg(swconn, &bfd_time); ovs_mutex_unlock(&pinctrl_mutex); ip_mcast_querier_run(swconn, &send_mcast_query_time); @@ -3102,6 +3118,7 @@ pinctrl_handler(void *arg_) ip_mcast_querier_wait(send_mcast_query_time); svc_monitors_wait(svc_monitors_next_run_time); ipv6_prefixd_wait(send_prefixd_time); + bfd_monitor_wait(bfd_time); new_seq = seq_read(pinctrl_handler_seq); seq_wait(pinctrl_handler_seq, new_seq); @@ -3149,6 +3166,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_dns_table *dns_table, const struct sbrec_controller_event_table *ce_table, const struct sbrec_service_monitor_table *svc_mon_table, + const struct sbrec_bfd_table *bfd_table, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *chassis, const struct hmap *local_datapaths, @@ -3179,6 +3197,10 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, local_datapaths); sync_svc_monitors(ovnsb_idl_txn, svc_mon_table, sbrec_port_binding_by_name, chassis); + if (ovnsb_idl_txn) { + bfd_monitor_run(bfd_table, sbrec_port_binding_by_name, chassis, + active_tunnels); + } ovs_mutex_unlock(&pinctrl_mutex); } @@ -3722,6 +3744,7 @@ pinctrl_destroy(void) destroy_dns_cache(); ip_mcast_snoop_destroy(); destroy_svc_monitors(); + bfd_monitor_destroy(); seq_destroy(pinctrl_main_seq); seq_destroy(pinctrl_handler_seq); } @@ -5558,7 +5581,8 @@ may_inject_pkts(void) !shash_is_empty(&send_garp_rarp_data) || ipv6_prefixd_should_inject() || !ovs_list_is_empty(&mcast_query_list) || - !ovs_list_is_empty(&buffered_mac_bindings)); + !ovs_list_is_empty(&buffered_mac_bindings) || + bfd_monitor_should_inject()); } static void @@ -6345,6 +6369,278 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, } +static struct hmap bfd_monitor_map; + +struct bfd_entry { + struct hmap_node node; + bool erase; + + /* L2 source address */ + struct eth_addr src_mac; + /* IPv4 source address */ + ovs_be32 ip_src; + /* IPv4 destination address */ + ovs_be32 ip_dst; + /* RFC 5881 section 4 + * The source port MUST be in the range 49152 through 65535. + * The same UDP source port number MUST be used for all BFD + * Control packets associated with a particular session. + * The source port number SHOULD be unique among all BFD + * sessions on the system + */ + uint16_t udp_src; + ovs_be32 disc; + + int64_t port_key; + int64_t metadata; + + long long int next_tx; +}; + +static void +bfd_monitor_init(void) +{ + hmap_init(&bfd_monitor_map); +} + +static void +bfd_monitor_destroy(void) +{ + struct bfd_entry *entry; + HMAP_FOR_EACH_POP (entry, node, &bfd_monitor_map) { + free(entry); + } + hmap_destroy(&bfd_monitor_map); +} + +static struct bfd_entry * +pinctrl_find_bfd_monitor_entry_by_port(char *ip, uint16_t port) +{ + struct bfd_entry *entry; + HMAP_FOR_EACH_WITH_HASH (entry, node, hash_string(ip, 0), + &bfd_monitor_map) { + if (entry->udp_src == port) { + return entry; + } + } + return NULL; +} + +static bool +bfd_monitor_should_inject(void) +{ + long long int cur_time = time_msec(); + struct bfd_entry *entry; + + HMAP_FOR_EACH (entry, node, &bfd_monitor_map) { + if (entry->next_tx < cur_time) { + return true; + } + } + return false; +} + +static void +bfd_monitor_wait(long long int timeout) +{ + if (!hmap_is_empty(&bfd_monitor_map)) { + poll_timer_wait_until(timeout); + } +} + +static void +bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet) +{ + struct udp_header *udp; + struct bfd_msg *msg; + + /* Properly align after the ethernet header */ + dp_packet_reserve(packet, 2); + struct eth_header *eth = dp_packet_put_uninit(packet, sizeof *eth); + eth->eth_dst = eth_addr_broadcast; + eth->eth_src = entry->src_mac; + eth->eth_type = htons(ETH_TYPE_IP); + + struct ip_header *ip = dp_packet_put_zeros(packet, sizeof *ip); + ip->ip_ihl_ver = IP_IHL_VER(5, 4); + ip->ip_tot_len = htons(sizeof *ip + sizeof *udp + sizeof *msg); + ip->ip_ttl = MAXTTL; + ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; + ip->ip_proto = IPPROTO_UDP; + put_16aligned_be32(&ip->ip_src, entry->ip_src); + put_16aligned_be32(&ip->ip_dst, entry->ip_dst); + /* Checksum has already been zeroed by put_zeros call. */ + ip->ip_csum = csum(ip, sizeof *ip); + + udp = dp_packet_put_zeros(packet, sizeof *udp); + udp->udp_src = htons(entry->udp_src); + udp->udp_dst = htons(BFD_DEST_PORT); + udp->udp_len = htons(sizeof *udp + sizeof *msg); + + msg = dp_packet_put_uninit(packet, sizeof *msg); + msg->vers_diag = (BFD_VERSION << 5); + msg->length = BFD_PACKET_LEN; +} + +static void +bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time) + OVS_REQUIRES(pinctrl_mutex) +{ + long long int cur_time = time_msec(); + struct bfd_entry *entry; + + HMAP_FOR_EACH (entry, node, &bfd_monitor_map) { + if (cur_time < entry->next_tx) { + goto next; + } + + uint64_t packet_stub[256 / 8]; + struct dp_packet packet; + dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); + bfd_monitor_put_bfd_msg(entry, &packet); + + uint64_t ofpacts_stub[4096 / 8]; + struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); + + /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */ + uint32_t dp_key = entry->metadata; + uint32_t port_key = entry->port_key; + put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); + put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts); + put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY_BIT, 1, &ofpacts); + struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); + resubmit->in_port = OFPP_CONTROLLER; + resubmit->table_id = OFTABLE_LOG_INGRESS_PIPELINE; + + 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 ofp_version version = rconn_get_version(swconn); + 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); + + entry->next_tx = cur_time + 5000; +next: + if (*bfd_time > entry->next_tx) { + *bfd_time = entry->next_tx; + } + } +} + +static void +bfd_monitor_run(const struct sbrec_bfd_table *bfd_table, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + const struct sbrec_chassis *chassis, + const struct sset *active_tunnels) + OVS_REQUIRES(pinctrl_mutex) +{ + struct bfd_entry *entry, *next_entry; + long long int cur_time = time_msec(); + bool changed = false; + + HMAP_FOR_EACH (entry, node, &bfd_monitor_map) { + entry->erase = true; + } + + const struct sbrec_bfd *bt; + SBREC_BFD_TABLE_FOR_EACH (bt, bfd_table) { + const struct sbrec_port_binding *pb + = lport_lookup_by_name(sbrec_port_binding_by_name, + bt->logical_port); + if (!pb) { + continue; + } + + const char *peer_s = smap_get(&pb->options, "peer"); + if (!peer_s) { + continue; + } + + const struct sbrec_port_binding *peer + = lport_lookup_by_name(sbrec_port_binding_by_name, peer_s); + if (!peer) { + continue; + } + + char *redirect_name = xasprintf("cr-%s", pb->logical_port); + bool resident = lport_is_chassis_resident( + sbrec_port_binding_by_name, chassis, active_tunnels, + redirect_name); + free(redirect_name); + if ((strcmp(pb->type, "l3gateway") || pb->chassis != chassis) && + !resident) { + continue; + } + + entry = pinctrl_find_bfd_monitor_entry_by_port( + bt->dst_ip, bt->src_port); + if (!entry) { + ovs_be32 ip_dst, ip_src = htonl(BFD_DEFAULT_SRC_IP); + struct eth_addr ea = eth_addr_zero; + int i; + + if (!ip_parse(bt->dst_ip, &ip_dst)) { + continue; + } + + for (i = 0; i < pb->n_mac; i++) { + struct lport_addresses laddrs; + + if (!extract_lsp_addresses(pb->mac[i], &laddrs)) { + continue; + } + + ea = laddrs.ea; + if (laddrs.n_ipv4_addrs > 0) { + ip_src = laddrs.ipv4_addrs[0].addr; + destroy_lport_addresses(&laddrs); + break; + } + destroy_lport_addresses(&laddrs); + } + + if (eth_addr_is_zero(ea)) { + continue; + } + + entry = xzalloc(sizeof *entry); + entry->src_mac = ea; + entry->ip_src = ip_src; + entry->ip_dst = ip_dst; + entry->udp_src = bt->src_port; + entry->disc = htonl(bt->disc); + entry->next_tx = cur_time; + entry->metadata = pb->datapath->tunnel_key; + entry->port_key = pb->tunnel_key; + + uint32_t hash = hash_string(bt->dst_ip, 0); + hmap_insert(&bfd_monitor_map, &entry->node, hash); + changed = true; + } + entry->erase = false; + } + + HMAP_FOR_EACH_SAFE (entry, next_entry, node, &bfd_monitor_map) { + if (entry->erase) { + hmap_remove(&bfd_monitor_map, &entry->node); + free(entry); + } + } + + if (changed) { + notify_pinctrl_handler(); + } +} + static uint16_t get_random_src_port(void) { diff --git a/controller/pinctrl.h b/controller/pinctrl.h index 4b101ec92..8555d983d 100644 --- a/controller/pinctrl.h +++ b/controller/pinctrl.h @@ -31,6 +31,7 @@ struct sbrec_chassis; struct sbrec_dns_table; struct sbrec_controller_event_table; struct sbrec_service_monitor_table; +struct sbrec_bfd_table; void pinctrl_init(void); void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, @@ -44,6 +45,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_dns_table *, const struct sbrec_controller_event_table *, const struct sbrec_service_monitor_table *, + const struct sbrec_bfd_table *, const struct ovsrec_bridge *, const struct sbrec_chassis *, const struct hmap *local_datapaths, const struct sset *active_tunnels); diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h index cdcb8d754..40b00643b 100644 --- a/lib/ovn-l7.h +++ b/lib/ovn-l7.h @@ -26,6 +26,25 @@ #include "hash.h" #include "ovn/logical-fields.h" +#define BFD_PACKET_LEN 24 +#define BFD_DEST_PORT 3784 +#define BFD_VERSION 1 +#define BFD_DEFAULT_SRC_IP 0xA9FE0101 /* 169.254.1.1 */ +#define BFD_DEFAULT_DST_IP 0xA9FE0100 /* 169.254.1.0 */ + +struct bfd_msg { + uint8_t vers_diag; + uint8_t flags; + uint8_t mult; + uint8_t length; + ovs_be32 my_disc; + ovs_be32 your_disc; + ovs_be32 min_tx; + ovs_be32 min_rx; + ovs_be32 min_rx_echo; +}; +BUILD_ASSERT_DECL(BFD_PACKET_LEN == sizeof(struct bfd_msg)); + /* Generic options map which is used to store dhcpv4 opts and dhcpv6 opts. */ struct gen_opts_map { struct hmap_node hmap_node; diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 15d859dbd..f8b2b04aa 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -7487,6 +7487,191 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, } } +struct bfd_entry { + struct hmap_node hmap_node; + + const struct sbrec_bfd *sb_bt; + + bool ref; +}; + +static struct bfd_entry * +bfd_port_lookup(struct hmap *bfd_map, const char *logical_port, + const char *dst_ip) +{ + struct bfd_entry *bfd_e; + uint32_t hash; + + hash = hash_string(dst_ip, 0); + hash = hash_string(logical_port, hash); + HMAP_FOR_EACH_WITH_HASH (bfd_e, hmap_node, hash, bfd_map) { + if (!strcmp(bfd_e->sb_bt->logical_port, logical_port) && + !strcmp(bfd_e->sb_bt->dst_ip, dst_ip)) { + return bfd_e; + } + } + return NULL; +} + +static void +bfd_cleanup_connections(struct northd_context *ctx, struct hmap *bfd_map) +{ + const struct nbrec_bfd *nb_bt; + struct bfd_entry *bfd_e; + + NBREC_BFD_FOR_EACH (nb_bt, ctx->ovnnb_idl) { + bfd_e = bfd_port_lookup(bfd_map, nb_bt->logical_port, nb_bt->dst_ip); + if (!bfd_e) { + continue; + } + + if (!bfd_e->ref && strcmp(nb_bt->status, "admin_down")) { + /* no user for this bfd connection */ + nbrec_bfd_set_status(nb_bt, "admin_down"); + } + } + + HMAP_FOR_EACH_POP (bfd_e, hmap_node, bfd_map) { + free(bfd_e); + } +} + +#define BFD_DEF_MINTX 1000 /* 1s */ +#define BFD_DEF_MINRX 1000 /* 1s */ +#define BFD_DEF_DETECT_MULT 5 + +static void +build_bfd_update_sb_conf(const struct nbrec_bfd *nb_bt, + const struct sbrec_bfd *sb_bt) +{ + if (strcmp(nb_bt->dst_ip, sb_bt->dst_ip)) { + sbrec_bfd_set_dst_ip(sb_bt, nb_bt->dst_ip); + } + + if (strcmp(nb_bt->logical_port, sb_bt->logical_port)) { + sbrec_bfd_set_logical_port(sb_bt, nb_bt->logical_port); + } + + if (strcmp(nb_bt->status, sb_bt->status)) { + sbrec_bfd_set_status(sb_bt, nb_bt->status); + } + + int detect_mult = nb_bt->n_detect_mult ? nb_bt->detect_mult[0] + : BFD_DEF_DETECT_MULT; + if (detect_mult != sb_bt->detect_mult) { + sbrec_bfd_set_detect_mult(sb_bt, detect_mult); + } + + int min_tx = nb_bt->n_min_tx ? nb_bt->min_tx[0] : BFD_DEF_MINTX; + if (min_tx != sb_bt->min_tx) { + sbrec_bfd_set_min_tx(sb_bt, min_tx); + } + + int min_rx = nb_bt->n_min_rx ? nb_bt->min_rx[0] : BFD_DEF_MINRX; + if (min_rx != sb_bt->min_rx) { + sbrec_bfd_set_min_rx(sb_bt, min_rx); + } +} + +/* RFC 5881 section 4 + * The source port MUST be in the range 49152 through 65535. + * The same UDP source port number MUST be used for all BFD + * Control packets associated with a particular session. + * The source port number SHOULD be unique among all BFD + * sessions on the system + */ +#define BFD_UDP_SRC_PORT_START 49152 +#define BFD_UDP_SRC_PORT_LEN (65535 - BFD_UDP_SRC_PORT_START) + +static int bfd_get_unused_port(unsigned long *bfd_src_ports) +{ + int port; + + port = bitmap_scan(bfd_src_ports, 0, 0, BFD_UDP_SRC_PORT_LEN); + if (port == BFD_UDP_SRC_PORT_LEN) { + return -ENOSPC; + } + bitmap_set1(bfd_src_ports, port); + + return port + BFD_UDP_SRC_PORT_START; +} + +static void +build_bfd_table(struct northd_context *ctx, struct hmap *bfd_connections) +{ + struct hmap sb_only = HMAP_INITIALIZER(&sb_only); + const struct sbrec_bfd *sb_bt; + unsigned long *bfd_src_ports; + struct bfd_entry *bfd_e; + uint32_t hash; + + bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN); + + SBREC_BFD_FOR_EACH (sb_bt, ctx->ovnsb_idl) { + bfd_e = xmalloc(sizeof *bfd_e); + bfd_e->sb_bt = sb_bt; + hash = hash_string(sb_bt->dst_ip, 0); + hash = hash_string(sb_bt->logical_port, hash); + hmap_insert(&sb_only, &bfd_e->hmap_node, hash); + bitmap_set1(bfd_src_ports, sb_bt->src_port - BFD_UDP_SRC_PORT_START); + } + + const struct nbrec_bfd *nb_bt; + NBREC_BFD_FOR_EACH (nb_bt, ctx->ovnnb_idl) { + if (!nb_bt->status) { + /* default state is admin_down */ + nbrec_bfd_set_status(nb_bt, "admin_down"); + } + + bfd_e = bfd_port_lookup(&sb_only, nb_bt->logical_port, nb_bt->dst_ip); + if (!bfd_e) { + int udp_src = bfd_get_unused_port(bfd_src_ports); + if (udp_src < 0) { + continue; + } + + sb_bt = sbrec_bfd_insert(ctx->ovnsb_txn); + sbrec_bfd_set_logical_port(sb_bt, nb_bt->logical_port); + sbrec_bfd_set_dst_ip(sb_bt, nb_bt->dst_ip); + sbrec_bfd_set_disc(sb_bt, 1 + random_uint32()); + sbrec_bfd_set_src_port(sb_bt, udp_src); + sbrec_bfd_set_status(sb_bt, nb_bt->status); + + int min_tx = nb_bt->n_min_tx ? nb_bt->min_tx[0] : BFD_DEF_MINTX; + sbrec_bfd_set_min_tx(sb_bt, min_tx); + int min_rx = nb_bt->n_min_rx ? nb_bt->min_rx[0] : BFD_DEF_MINRX; + sbrec_bfd_set_min_rx(sb_bt, min_rx); + int d_mult = nb_bt->n_detect_mult ? nb_bt->detect_mult[0] + : BFD_DEF_DETECT_MULT; + sbrec_bfd_set_detect_mult(sb_bt, d_mult); + } else if (strcmp(bfd_e->sb_bt->status, nb_bt->status)) { + if (!strcmp(nb_bt->status, "admin_down") || + !strcmp(bfd_e->sb_bt->status, "admin_down")) { + sbrec_bfd_set_status(bfd_e->sb_bt, nb_bt->status); + } else { + nbrec_bfd_set_status(nb_bt, bfd_e->sb_bt->status); + } + } + if (bfd_e) { + build_bfd_update_sb_conf(nb_bt, bfd_e->sb_bt); + + hmap_remove(&sb_only, &bfd_e->hmap_node); + bfd_e->ref = false; + hash = hash_string(bfd_e->sb_bt->dst_ip, 0); + hash = hash_string(bfd_e->sb_bt->logical_port, hash); + hmap_insert(bfd_connections, &bfd_e->hmap_node, hash); + } + } + + HMAP_FOR_EACH_POP (bfd_e, hmap_node, &sb_only) { + sbrec_bfd_delete(bfd_e->sb_bt); + free(bfd_e); + } + hmap_destroy(&sb_only); + + bitmap_free(bfd_src_ports); +} + /* Returns a string of the IP address of the router port 'op' that * overlaps with 'ip_s". If one is not found, returns NULL. * @@ -12444,6 +12629,7 @@ ovnnb_db_run(struct northd_context *ctx, struct hmap igmp_groups; struct shash meter_groups = SHASH_INITIALIZER(&meter_groups); struct hmap lbs; + struct hmap bfd_connections = HMAP_INITIALIZER(&bfd_connections); /* Sync ipsec configuration. * Copy nb_cfg from northbound to southbound database. @@ -12538,6 +12724,7 @@ ovnnb_db_run(struct northd_context *ctx, build_ip_mcast(ctx, datapaths); build_mcast_groups(ctx, datapaths, ports, &mcast_groups, &igmp_groups); build_meter_groups(ctx, &meter_groups); + build_bfd_table(ctx, &bfd_connections); build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups, &igmp_groups, &meter_groups, &lbs); ovn_update_ipv6_prefix(ports); @@ -12563,9 +12750,13 @@ ovnnb_db_run(struct northd_context *ctx, HMAP_FOR_EACH_SAFE (pg, next_pg, key_node, &port_groups) { ovn_port_group_destroy(&port_groups, pg); } + + bfd_cleanup_connections(ctx, &bfd_connections); + hmap_destroy(&igmp_groups); hmap_destroy(&mcast_groups); hmap_destroy(&port_groups); + hmap_destroy(&bfd_connections); struct shash_node *node, *next; SHASH_FOR_EACH_SAFE (node, next, &meter_groups) { @@ -13499,6 +13690,16 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_external_ids); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_bfd); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_logical_port); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_dst_ip); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_status); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_tx); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_rx); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_detect_mult); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port); + struct ovsdb_idl_index *sbrec_chassis_by_name = chassis_index_create(ovnsb_idl_loop.idl); @@ -13621,6 +13822,7 @@ main(int argc, char *argv[]) } } + free(ovn_internal_version); unixctl_server_destroy(unixctl); ovsdb_idl_loop_destroy(&ovnnb_idl_loop); diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index b77a2308c..aea932f55 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.30.0", - "cksum": "3273824429 27172", + "version": "5.31.0", + "cksum": "1511492848 28473", "tables": { "NB_Global": { "columns": { @@ -526,5 +526,30 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "indexes": [["name"]], + "isRoot": true}, + "BFD": { + "columns": { + "logical_port": {"type": "string"}, + "dst_ip": {"type": "string"}, + "min_tx": {"type": {"key": {"type": "integer", + "minInteger": 1}, + "min": 0, "max": 1}}, + "min_rx": {"type": {"key": {"type": "integer"}, + "min": 0, "max": 1}}, + "detect_mult": {"type": {"key": {"type": "integer", + "minInteger": 1}, + "min": 0, "max": 1}}, + "status": { + "type": {"key": {"type": "string", + "enum": ["set", ["down", "init", "up", + "admin_down"]]}, + "min": 0, "max": 1}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, + "options": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["logical_port", "dst_ip"]], "isRoot": true}} } diff --git a/ovn-nb.xml b/ovn-nb.xml index ec6405ff5..2637c73a6 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3741,4 +3741,71 @@ + + +

+ Contains BFD parameter for ovn-controller bfd configuration. +

+ + + + OVN logical port when BFD engine is running. + + + + BFD peer IP address. + + + + This is the minimum interval, in milliseconds, that the local + system would like to use when transmitting BFD Control packets, + less any jitter applied. The value zero is reserved. Default + value is 1s. + + + + This is the minimum interval, in milliseconds, between received + BFD Control packets that this system is capable of supporting, + less any jitter applied by the sender. If this value is zero, + the transmitting system does not want the remote system to send + any periodic BFD Control packets. + + + + Detection time multiplier. The negotiated transmit interval, + multiplied by this value, provides the Detection Time for the + receiving system in Asynchronous mode. Default value is 5. + + + + Reserved for future use. + + + + See External IDs at the beginning of this document. + + + + + +

+ BFD port logical states. Possible values are: +

    +
  • + admin_down +
  • +
  • + down +
  • +
  • + init +
  • +
  • + up +
  • +
+

+
+
+
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 5228839b8..97db6de39 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.12.0", - "cksum": "3969471120 24441", + "version": "20.13.0", + "cksum": "3035725595 25676", "tables": { "SB_Global": { "columns": { @@ -484,6 +484,29 @@ "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, + "isRoot": true}, + "BFD": { + "columns": { + "src_port": {"type": {"key": {"type": "integer", + "minInteger": 49152, + "maxInteger": 65535}}}, + "disc": {"type": {"key": {"type": "integer"}}}, + "logical_port": {"type": "string"}, + "dst_ip": {"type": "string"}, + "min_tx": {"type": {"key": {"type": "integer"}}}, + "min_rx": {"type": {"key": {"type": "integer"}}}, + "detect_mult": {"type": {"key": {"type": "integer"}}}, + "status": { + "type": {"key": {"type": "string", + "enum": ["set", ["down", "init", "up", + "admin_down"]]}}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, + "options": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["logical_port", "dst_ip", "src_port", "disc"]], "isRoot": true} } } diff --git a/ovn-sb.xml b/ovn-sb.xml index c13994848..eb440e492 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -4231,4 +4231,82 @@ tcp.flags = RST; + + +

+ Contains BFD parameter for ovn-controller bfd configuration. +

+ + + + udp source port used in bfd control packets. + The source port MUST be in the range 49152 through 65535 + (RFC5881 section 4). + + + + A unique, nonzero discriminator value generated by the transmitting + system, used to demultiplex multiple BFD sessions between the same pair + of systems. + + + + OVN logical port when BFD engine is running. + + + + BFD peer IP address. + + + + This is the minimum interval, in milliseconds, that the local + system would like to use when transmitting BFD Control packets, + less any jitter applied. The value zero is reserved. + + + + This is the minimum interval, in milliseconds, between received + BFD Control packets that this system is capable of supporting, + less any jitter applied by the sender. If this value is zero, + the transmitting system does not want the remote system to send + any periodic BFD Control packets. + + + + Detection time multiplier. The negotiated transmit interval, + multiplied by this value, provides the Detection Time for the + receiving system in Asynchronous mode. + + + + Reserved for future use. + + + + See External IDs at the beginning of this document. + + + + + +

+ BFD port logical states. Possible values are: +

    +
  • + admin_down +
  • +
  • + down +
  • +
  • + init +
  • +
  • + up +
  • +
+

+
+
+