Introduce BFD state machine according to RFC880 https://tools.ietf.org/html/rfc5880
Signed-off-by: Lorenzo Bianconi <[email protected]> --- controller/pinctrl.c | 103 ++++++++++++++++++++++++++++++++++++++++++- northd/ovn-northd.c | 9 ++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index b6d68e2a5..e88193d77 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6317,6 +6317,28 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, } +enum bfd_state { + BFD_STATE_ADMIN_DOWN, + BFD_STATE_DOWN, + BFD_STATE_INIT, + BFD_STATE_UP, +}; + +static char * +bfd_get_status(enum bfd_state state) +{ + switch (state) { + case BFD_STATE_ADMIN_DOWN: + return "admin_down"; + case BFD_STATE_DOWN: + return "down"; + case BFD_STATE_INIT: + return "init"; + case BFD_STATE_UP: + return "up"; + } +} + static struct hmap bfd_monitor_map; struct bfd_entry { @@ -6341,7 +6363,12 @@ struct bfd_entry { int64_t port_key; int64_t metadata; + enum bfd_state state; + bool change_state; + + uint32_t detection_timeout; long long int last_update; + long long int last_rx; long long int next_tx; }; @@ -6369,6 +6396,18 @@ pinctrl_find_bfd_monitor_entry_by_port(uint16_t port) return NULL; } +static struct bfd_entry * +pinctrl_find_bfd_monitor_entry_by_disc(ovs_be32 disc) +{ + struct bfd_entry *entry; + HMAP_FOR_EACH (entry, node, &bfd_monitor_map) { + if (entry->disc == disc) { + return entry; + } + } + return NULL; +} + static bool bfd_monitor_should_inject(void) { @@ -6419,9 +6458,11 @@ bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet) udp->udp_dst = htons(BFD_DEST_PORT); udp->udp_len = htons(sizeof *udp + sizeof *msg); - msg = dp_packet_put_uninit(packet, sizeof *msg); + msg = dp_packet_put_zeros(packet, sizeof *msg); msg->vers_diag = (BFD_VERSION << 5); msg->length = BFD_PACKET_LEN; + msg->flags = entry->state << 6; + msg->my_disc = entry->disc; } static void @@ -6432,6 +6473,10 @@ bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time) struct bfd_entry *entry; HMAP_FOR_EACH (entry, node, &bfd_monitor_map) { + if (cur_time > entry->last_rx + entry->detection_timeout) { + entry->state = BFD_STATE_DOWN; + } + if (cur_time < entry->next_tx) { goto next; } @@ -6483,6 +6528,56 @@ pinctrl_handle_bfd_msg(struct rconn *swconn, const struct flow *ip_flow, struct dp_packet *pkt_in, const struct match *md) OVS_REQUIRES(pinctrl_mutex) { + /* XXX add sanity checks here */ + const struct bfd_msg *msg = dp_packet_get_udp_payload(pkt_in); + struct bfd_entry *entry = pinctrl_find_bfd_monitor_entry_by_disc( + msg->your_disc); + if (!entry) { + return; + } + + enum bfd_state peer_state = msg->flags >> 6; + /* bfd state machine */ + switch (entry->state) { + case BFD_STATE_DOWN: + if (peer_state == BFD_STATE_DOWN) { + entry->state = BFD_STATE_INIT; + entry->change_state = true; + } + if (peer_state == BFD_STATE_INIT) { + entry->state = BFD_STATE_UP; + entry->change_state = true; + } + entry->last_rx = time_msec(); + break; + case BFD_STATE_INIT: + if (peer_state == BFD_STATE_INIT || + peer_state == BFD_STATE_UP) { + entry->state = BFD_STATE_UP; + entry->change_state = true; + } + if (peer_state == BFD_STATE_ADMIN_DOWN) { + entry->state = BFD_STATE_DOWN; + entry->change_state = true; + } + entry->last_rx = time_msec(); + break; + case BFD_STATE_UP: + if (peer_state == BFD_STATE_ADMIN_DOWN || + peer_state == BFD_STATE_DOWN) { + entry->state = BFD_STATE_DOWN; + entry->change_state = true; + } + entry->last_rx = time_msec(); + break; + case BFD_STATE_ADMIN_DOWN: + default: + break; + } + + if (entry->change_state) { + notify_pinctrl_main(); + } } #define BFD_MONITOR_STALE_TIMEOUT 180000LL @@ -6564,12 +6659,18 @@ bfd_monitor_run(const struct sbrec_bfd_table *bfd_table, entry->udp_src = bt->src_port; entry->disc = htonl(bt->disc); entry->next_tx = cur_time; + entry->last_rx = cur_time; + entry->detection_timeout = 30000; /* XXX */ entry->metadata = pb->datapath->tunnel_key; entry->port_key = pb->tunnel_key; + entry->state = BFD_STATE_DOWN; uint32_t hash = hash_string(bt->dst_ip, 0); hmap_insert(&bfd_monitor_map, &entry->node, hash); changed = true; + } else if (entry->change_state) { + sbrec_bfd_set_status(bt, bfd_get_status(entry->state)); + entry->change_state = false; } entry->last_update = cur_time; } diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 6470d1670..91dff5979 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -91,6 +91,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 @@ -9267,6 +9269,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } + /* BFD msg handling */ + if (bfd_en) { + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100, + "udp.dst == 3784", "handle_bfd_msg;"); + } + /* Packets are allowed by default. */ ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 0, "1", "next;"); @@ -12330,6 +12338,7 @@ ovnnb_db_run(struct northd_context *ctx, controller_event_en = smap_get_bool(&nb->options, "controller_event", false); + bfd_en = smap_get_bool(&nb->options, "bfd", false); check_lsp_is_up = !smap_get_bool(&nb->options, "ignore_lsp_down", false); -- 2.26.2 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
