diff options
| author | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2020-08-18 13:06:48 -0300 |
|---|---|---|
| committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2020-11-24 07:54:07 -0300 |
| commit | efd04d60caa237de5c564355089c59794057ff1d (patch) | |
| tree | cbb188f206626edacf5618a409799ebf7a2a08e6 /bfdd/dplane.c | |
| parent | 29397ec1abb6068b5cb847a7d7a18b0c5a699b59 (diff) | |
bfdd: integrate distributed BFD
Add hooks in the correct places so the BFD daemon uses the data plane
instead of the software packet sending implementation to monitor the
session.
This code also adds some handlers to support fallback to FRR BFD session
handling, however since this complicates the code it won't work at the
moment (the BFD sockets are disabled by default when using data plane).
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
Diffstat (limited to 'bfdd/dplane.c')
| -rw-r--r-- | bfdd/dplane.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 452ee3adf0..5785c349c1 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -90,6 +90,8 @@ struct bfd_dplane_ctx { typedef void (*bfd_dplane_expect_cb)(struct bfddp_message *msg, void *arg); static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc); +static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc, + struct bfd_session *bs); /* * BFD data plane helper functions. @@ -580,6 +582,21 @@ static int bfd_dplane_read(struct thread *t) return 0; } +static void _bfd_session_register_dplane(struct hash_bucket *hb, void *arg) +{ + struct bfd_session *bs = hb->data; + struct bfd_dplane_ctx *bdc = arg; + + if (bs->bdc != NULL) + return; + + /* Disable software session. */ + bfd_session_disable(bs); + + /* Move session to data plane. */ + _bfd_dplane_add_session(bdc, bs); +} + static struct bfd_dplane_ctx *bfd_dplane_ctx_new(int sock) { struct bfd_dplane_ctx *bdc; @@ -593,6 +610,9 @@ static struct bfd_dplane_ctx *bfd_dplane_ctx_new(int sock) bdc->outbuf = stream_new(BFD_DPLANE_CLIENT_BUF_SIZE); thread_add_read(master, bfd_dplane_read, bdc, sock, &bdc->inbufev); + /* Register all unattached sessions. */ + bfd_key_iterate(_bfd_session_register_dplane, bdc); + return bdc; } @@ -605,6 +625,9 @@ static void _bfd_session_unregister_dplane(struct hash_bucket *hb, void *arg) return; bs->bdc = NULL; + + /* Fallback to software. */ + bfd_session_enable(bs); } static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc) @@ -629,6 +652,71 @@ static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc) XFREE(MTYPE_BFDD_DPLANE_CTX, bdc); } +static void _bfd_dplane_session_fill(const struct bfd_session *bs, + struct bfddp_message *msg) +{ + uint16_t msglen = sizeof(msg->header) + sizeof(msg->data.session); + + /* Message header. */ + msg->header.version = BFD_DP_VERSION; + msg->header.length = ntohs(msglen); + msg->header.type = ntohs(DP_ADD_SESSION); + + /* Message payload. */ + msg->data.session.dst = bs->key.peer; + msg->data.session.src = bs->key.local; + msg->data.session.detect_mult = bs->detect_mult; + + if (bs->ifp) { + msg->data.session.ifindex = htonl(bs->ifp->ifindex); + strlcpy(msg->data.session.ifname, bs->ifp->name, + sizeof(msg->data.session.ifname)); + } + if (bs->flags & BFD_SESS_FLAG_MH) { + msg->data.session.flags |= SESSION_MULTIHOP; + msg->data.session.ttl = bs->mh_ttl; + } else + msg->data.session.ttl = BFD_TTL_VAL; + + if (bs->flags & BFD_SESS_FLAG_IPV6) + msg->data.session.flags |= SESSION_IPV6; + if (bs->flags & BFD_SESS_FLAG_ECHO) + msg->data.session.flags |= SESSION_ECHO; + if (bs->flags & BFD_SESS_FLAG_CBIT) + msg->data.session.flags |= SESSION_CBIT; + if (bs->flags & BFD_SESS_FLAG_PASSIVE) + msg->data.session.flags |= SESSION_PASSIVE; + if (bs->flags & BFD_SESS_FLAG_SHUTDOWN) + msg->data.session.flags |= SESSION_SHUTDOWN; + + msg->data.session.flags = htonl(msg->data.session.flags); + msg->data.session.lid = htonl(bs->discrs.my_discr); + msg->data.session.min_tx = htonl(bs->timers.desired_min_tx); + msg->data.session.min_rx = htonl(bs->timers.required_min_rx); + msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo); +} + +static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc, + struct bfd_session *bs) +{ + int rv; + + /* Associate session. */ + bs->bdc = bdc; + + /* Reset previous state. */ + bs->remote_diag = 0; + bs->local_diag = 0; + bs->ses_state = PTM_BFD_DOWN; + + /* Enqueue message to data plane client. */ + rv = bfd_dplane_update_session(bs); + if (rv != 0) + bs->bdc = NULL; + + return rv; +} + /* * Data plane listening socket. */ @@ -738,3 +826,53 @@ void bfd_dplane_init(const struct sockaddr *sa, socklen_t salen) /* Observe shutdown events. */ hook_register(frr_fini, bfd_dplane_finish_late); } + +int bfd_dplane_add_session(struct bfd_session *bs) +{ + struct bfd_dplane_ctx *bdc; + + /* Select a data plane client to install session. */ + TAILQ_FOREACH (bdc, &bglobal.bg_dplaneq, entry) { + if (_bfd_dplane_add_session(bdc, bs) == 0) + return 0; + } + + return -1; +} + +int bfd_dplane_update_session(const struct bfd_session *bs) +{ + struct bfddp_message msg = {}; + + if (bs->bdc == NULL) + return 0; + + _bfd_dplane_session_fill(bs, &msg); + + /* Enqueue message to data plane client. */ + return bfd_dplane_enqueue(bs->bdc, &msg, ntohs(msg.header.length)); +} + +int bfd_dplane_delete_session(struct bfd_session *bs) +{ + struct bfddp_message msg = {}; + int rv; + + /* Not using data plane, just return success. */ + if (bs->bdc == NULL) + return 0; + + /* Fill most of the common fields. */ + _bfd_dplane_session_fill(bs, &msg); + + /* Change the message type. */ + msg.header.type = ntohs(DP_DELETE_SESSION); + + /* Enqueue message to data plane client. */ + rv = bfd_dplane_enqueue(bs->bdc, &msg, ntohs(msg.header.length)); + + /* Remove association. */ + bs->bdc = NULL; + + return rv; +} |
