From patchwork Wed Nov 25 09:59:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1405969 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.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=VGxt4JhP; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CgxG06k4Pz9s0b for ; Wed, 25 Nov 2020 21:00:08 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id C98C18754A; Wed, 25 Nov 2020 10:00:06 +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 igZbVB+FnJK4; Wed, 25 Nov 2020 10:00:01 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 886DB873E4; Wed, 25 Nov 2020 10:00:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 68A6AC163C; Wed, 25 Nov 2020 10:00:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5FF7EC1836 for ; Wed, 25 Nov 2020 10:00:00 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 20AF186DDA for ; Wed, 25 Nov 2020 10:00:00 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jI7njrq7PJQP for ; Wed, 25 Nov 2020 09:59:58 +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 [63.128.21.124]) by whitealder.osuosl.org (Postfix) with ESMTPS id A96AF86DD7 for ; Wed, 25 Nov 2020 09:59:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1606298396; 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=czOzk4PUODrRXiYHHMuX323HNDf6xC+9QuyhtdvnilE=; b=VGxt4JhPmnKtblzz/5h55IySEPvldFyFgKr8qaFJfaVXfuQrbdahNVjRyfZkycYHy1d0kG 1Odf0YXIvF2wsRyL5x5FhL3ZKjcoNirAL7Kr4L/+ZFji8dAMxEyGWfaZwyfybqJg+i9wTs X9bpSHoi3nmLNkg/X+fbxKfczT93nSc= Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-548-D1gw8cuYPpa5y13E30_X2A-1; Wed, 25 Nov 2020 04:59:53 -0500 X-MC-Unique: D1gw8cuYPpa5y13E30_X2A-1 Received: by mail-ed1-f72.google.com with SMTP id d3so846843eds.3 for ; Wed, 25 Nov 2020 01:59:53 -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=czOzk4PUODrRXiYHHMuX323HNDf6xC+9QuyhtdvnilE=; b=rHMrxEzye4Az7I/XTNSzJGwcr8Tf/5o6dcd7hZqb0vOtJN9s2f3aRjuiiXmPXMAYSq kkaoIRtKu3njX/KqgdyE/7LHql0jPpYBdomFjFnX9fQEx75AzQKh2EiqAcV8ySzjIZfx mWUzigeTLpTnW8PmznU0GM//GTDMC7+dX0MCWeZ2xGfeRMjXtReczgiI8hZazHrrX41h QkvtEaGWODsRqqCKC0FSdiJKNnzHB4EVuEpaD96M7kCfEATucOJ/M7pDj4F9jjWV8hIM qthza8ymTvMIrXdK8dPxUHer9QVdM5WUdpaPnttzSvEYmwrxwfkyDMXOoIuJcYp2FY0a bLwQ== X-Gm-Message-State: AOAM533i9z/1Z+sII+v0BC1E3XIjSW/p1yzNmx6ENLy4JRTQQrgUCimY uRGAQ1Mx6fYEQs8uxIhRZyWiGe2cLSiCM0QwZ3k6t5zdhIvmXvxkAJkgOUMv0s90YFhBePgurZS D8nsqeyLlViVLCFWSNt4BjfFDNj02laWv0nmrBrOYHX0DxCg+Pah8EnddCEFx1ljCHLN+xEH8Ke 4= X-Received: by 2002:a17:907:262d:: with SMTP id aq13mr2447721ejc.484.1606298391698; Wed, 25 Nov 2020 01:59:51 -0800 (PST) X-Google-Smtp-Source: ABdhPJzdpwY7huTqbGDDhc9J3qXZgfDSupStvSrWzVrmnM2EF6sJcWEbwlZYxE4DM73gxzuulCF7/g== X-Received: by 2002:a17:907:262d:: with SMTP id aq13mr2447690ejc.484.1606298391149; Wed, 25 Nov 2020 01:59:51 -0800 (PST) Received: from lore-desk.redhat.com ([151.66.8.153]) by smtp.gmail.com with ESMTPSA id g13sm936862edy.7.2020.11.25.01.59.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 25 Nov 2020 01:59:50 -0800 (PST) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Wed, 25 Nov 2020 10:59:38 +0100 Message-Id: <2027bdac477568be52ece9a3461453bd312f44af.1606298055.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.28.0 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 Cc: trozet@redhat.com Subject: [ovs-dev] [PATCH ovn 1/4] 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 BFD tx path in ovn-controller. introduce BFD table in nb/sb dbs in order to configure BFD tx path ovn-controller Signed-off-by: Lorenzo Bianconi --- controller/ovn-controller.c | 1 + controller/pinctrl.c | 288 +++++++++++++++++++++++++++++++++++- controller/pinctrl.h | 2 + lib/ovn-l7.h | 19 +++ northd/ovn-northd.c | 118 +++++++++++++++ ovn-nb.ovsschema | 19 ++- ovn-nb.xml | 62 ++++++++ ovn-sb.ovsschema | 23 ++- ovn-sb.xml | 74 +++++++++ 9 files changed, 601 insertions(+), 5 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index bea2c8eb6..0b55605bb 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2771,6 +2771,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 919eae4f8..0e80c00c1 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(); @@ -3037,6 +3050,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; + if (pctrl->br_int_name) { if (!br_int_name || strcmp(br_int_name, pctrl->br_int_name)) { free(br_int_name); @@ -3088,6 +3103,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); @@ -3105,6 +3121,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); @@ -3154,6 +3171,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, @@ -3184,6 +3202,8 @@ 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); + bfd_monitor_run(bfd_table, sbrec_port_binding_by_name, chassis, + active_tunnels); ovs_mutex_unlock(&pinctrl_mutex); } @@ -3727,6 +3747,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); } @@ -5516,7 +5537,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 @@ -6303,6 +6325,270 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, } +static struct hmap bfd_monitor_map; + +struct bfd_entry { + struct hmap_node node; + + /* 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 last_update; + long long int next_tx; +}; + +static void +bfd_monitor_init(void) +{ + hmap_init(&bfd_monitor_map); +} + +static void +bfd_monitor_destroy(void) +{ + 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; + + 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; + } + } +} + +#define BFD_MONITOR_STALE_TIMEOUT 180000LL +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) +{ + long long int cur_time = time_msec(); + bool changed = false; + + 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; + } + + struct bfd_entry *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; + } + + 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 (!resident && strcmp(pb->type, "l3gateway") && + pb->chassis != chassis) { + 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->last_update = cur_time; + } + + struct bfd_entry *entry, *next_entry; + HMAP_FOR_EACH_SAFE (entry, next_entry, node, &bfd_monitor_map) { + if (entry->last_update + BFD_MONITOR_STALE_TIMEOUT < cur_time) { + 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 c84a0e7a9..d00982449 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 47a177c99..d25f370ae 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -69,6 +69,7 @@ struct northd_context { struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name; struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; + struct ovsdb_idl_index *sbrec_bfd_by_logical_port; }; struct northd_state { @@ -91,6 +92,8 @@ static bool controller_event_en; static bool check_lsp_is_up; +static bool bfd_en; + /* MAC allocated for service monitor usage. Just one mac is allocated * for this purpose and ovn-controller's on each chassis will make use * of this mac when sending out the packets to monitor the services @@ -11322,6 +11325,112 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, } } +static struct ovsdb_idl_index * +bfd_index_create(struct ovsdb_idl *idl) +{ + return ovsdb_idl_index_create2(idl, &sbrec_bfd_col_logical_port, + &sbrec_bfd_col_dst_ip); +} + +static const struct sbrec_bfd * +bfd_port_lookup(struct ovsdb_idl_index *bfd_index, + const char *logical_port, const char *dst_ip) +{ + struct sbrec_bfd *target = sbrec_bfd_index_init_row(bfd_index); + sbrec_bfd_index_set_logical_port(target, logical_port); + sbrec_bfd_index_set_dst_ip(target, dst_ip); + + struct sbrec_bfd *bfd_entry = sbrec_bfd_index_find(bfd_index, target); + sbrec_bfd_index_destroy_row(target); + + return bfd_entry; +} + +struct bfd_entry { + struct hmap_node hmap_node; + + char *logical_port; + char *dst_ip; + + const struct sbrec_bfd *sb_bt; + bool found; +}; + +static void +build_bfd_table(struct northd_context *ctx) +{ + const struct nbrec_nb_global *nb = nbrec_nb_global_first(ctx->ovnnb_idl); + + bfd_en = smap_get_bool(&nb->options, "bfd", false); + if (!bfd_en) { + return; + } + + struct hmap sb_only = HMAP_INITIALIZER(&sb_only); + struct bfd_entry *bfd_e, *next_bfd_e; + const struct sbrec_bfd *sb_bt; + + SBREC_BFD_FOR_EACH (sb_bt, ctx->ovnsb_idl) { + bfd_e = xmalloc(sizeof *bfd_e); + bfd_e->logical_port = xstrdup(sb_bt->logical_port); + bfd_e->dst_ip = xstrdup(sb_bt->dst_ip); + bfd_e->sb_bt = sb_bt; + hmap_insert(&sb_only, &bfd_e->hmap_node, + hash_string(bfd_e->dst_ip, 0)); + } + + const struct nbrec_bfd *nb_bt; + NBREC_BFD_FOR_EACH (nb_bt, ctx->ovnnb_idl) { + sb_bt = bfd_port_lookup(ctx->sbrec_bfd_by_logical_port, + nb_bt->logical_port, nb_bt->dst_ip); + if (!sb_bt) { + 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()); + /* 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 = random_range(16383) + 49152; + sbrec_bfd_set_src_port(sb_bt, udp_src); + sbrec_bfd_set_status(sb_bt, "down"); + sbrec_bfd_set_min_tx(sb_bt, nb_bt->min_tx); + sbrec_bfd_set_min_rx(sb_bt, nb_bt->min_rx); + sbrec_bfd_set_detect_mult(sb_bt, nb_bt->detect_mult); + } else if (strcmp(sb_bt->status, nb_bt->status)) { + if (!strcmp(nb_bt->status, "admin_down") || + !strcmp(sb_bt->status, "admin_down")) { + sbrec_bfd_set_status(sb_bt, nb_bt->status); + } else { + nbrec_bfd_set_status(nb_bt, sb_bt->status); + } + } + HMAP_FOR_EACH_WITH_HASH (bfd_e, hmap_node, + hash_string(nb_bt->dst_ip, 0), &sb_only) { + if (!strcmp(bfd_e->logical_port, nb_bt->logical_port) && + !strcmp(bfd_e->dst_ip, nb_bt->dst_ip)) { + bfd_e->found = true; + break; + } + } + } + + HMAP_FOR_EACH_SAFE (bfd_e, next_bfd_e, hmap_node, &sb_only) { + if (!bfd_e->found && bfd_e->sb_bt) { + sbrec_bfd_delete(bfd_e->sb_bt); + } + free(bfd_e->logical_port); + free(bfd_e->dst_ip); + hmap_remove(&sb_only, &bfd_e->hmap_node); + free(bfd_e); + } + hmap_destroy(&sb_only); +} + static void sync_address_set(struct northd_context *ctx, const char *name, const char **addrs, size_t n_addrs, @@ -12117,6 +12226,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); build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups, &igmp_groups, &meter_groups, &lbs); ovn_update_ipv6_prefix(ports); @@ -13069,6 +13179,10 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_external_ids); + 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); + struct ovsdb_idl_index *sbrec_chassis_by_name = chassis_index_create(ovnsb_idl_loop.idl); @@ -13081,6 +13195,9 @@ main(int argc, char *argv[]) struct ovsdb_idl_index *sbrec_ip_mcast_by_dp = ip_mcast_index_create(ovnsb_idl_loop.idl); + struct ovsdb_idl_index *sbrec_bfd_by_logical_port + = bfd_index_create(ovnsb_idl_loop.idl); + unixctl_command_register("sb-connection-status", "", 0, 0, ovn_conn_show, ovnsb_idl_loop.idl); @@ -13113,6 +13230,7 @@ main(int argc, char *argv[]) .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name, .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp, .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp, + .sbrec_bfd_by_logical_port = sbrec_bfd_by_logical_port, }; if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 269e3a888..fef67e70e 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.28.0", - "cksum": "610359755 26847", + "version": "5.29.0", + "cksum": "3632295919 27598", "tables": { "NB_Global": { "columns": { @@ -519,5 +519,20 @@ "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"}}}, + "min_rx": {"type": {"key": {"type": "integer"}}}, + "detect_mult": {"type": {"key": {"type": "integer"}}}, + "status": { + "type": {"key": {"type": "string", + "enum": ["set", ["down", "init", "up", "admin_down"]]}}}, + "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 a457b9cee..ac5192609 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3682,4 +3682,66 @@ + + +

+ 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. + + + + 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. + + + + + +

+ BFD port logical states. Possible values are: +

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

+
+
+
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index a1ee8d8d1..6cc4e066e 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "2.11.0", - "cksum": "455413803 23814", + "version": "2.12.0", + "cksum": "164441880 24843", "tables": { "SB_Global": { "columns": { @@ -470,6 +470,25 @@ "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"]]}}}, + "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 4c6df3fef..49a0069f3 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -4211,4 +4211,78 @@ 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. + + + + + +

+ BFD port logical states. Possible values are: +

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

+
+
+