@@ -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;
}
@@ -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);
Introduce BFD state machine according to RFC880 https://tools.ietf.org/html/rfc5880 Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> --- controller/pinctrl.c | 103 ++++++++++++++++++++++++++++++++++++++++++- northd/ovn-northd.c | 9 ++++ 2 files changed, 111 insertions(+), 1 deletion(-)