diff options
author | Christian Hopps <chopps@labn.net> | 2022-06-01 21:25:35 +0200 |
---|---|---|
committer | Christian Hopps <chopps@labn.net> | 2022-06-02 22:37:16 +0200 |
commit | 149491af80ceaeb666a9bf06f97e918a64c46a5c (patch) | |
tree | da50c5f09450c81a31cccd916f179bf07c1848b8 /ospfd | |
parent | ospfd: add all_rtrs route table when opaque enabled (diff) | |
download | frr-149491af80ceaeb666a9bf06f97e918a64c46a5c.tar.xz frr-149491af80ceaeb666a9bf06f97e918a64c46a5c.zip |
ospfd: api: add reachable router notifications
Reachable router information is used by OSPF opaque clients in order
to determine if the router advertising the opaque LSA data is
reachable (i.e., 2-way conectivity check).
Signed-off-by: Christian Hopps <chopps@labn.net>
Diffstat (limited to 'ospfd')
-rw-r--r-- | ospfd/ospf_api.c | 31 | ||||
-rw-r--r-- | ospfd/ospf_api.h | 16 | ||||
-rw-r--r-- | ospfd/ospf_apiserver.c | 168 | ||||
-rw-r--r-- | ospfd/ospf_apiserver.h | 12 | ||||
-rw-r--r-- | ospfd/ospf_spf.c | 2 |
5 files changed, 228 insertions, 1 deletions
diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 81de88275..99bc6c0b0 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -177,6 +177,10 @@ const char *ospf_api_typename(int msgtype) { MSG_NSM_CHANGE, "NSM change", }, + { + MSG_REACHABLE_CHANGE, + "Reachable change", + }, }; int i, n = array_size(NameTab); @@ -651,4 +655,31 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum, return msg_new(msgtype, nmsg, seqnum, len); } +struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd, + struct in_addr *add, uint16_t nremove, + struct in_addr *remove) +{ + uint8_t buf[OSPF_API_MAX_MSG_SIZE]; + struct msg_reachable_change *nmsg = (void *)buf; + const uint insz = sizeof(*nmsg->router_ids); + const uint nmax = (sizeof(buf) - sizeof(*nmsg)) / insz; + uint len; + + if (nadd > nmax) + nadd = nmax; + if (nremove > (nmax - nadd)) + nremove = (nmax - nadd); + + if (nadd) + memcpy(nmsg->router_ids, add, nadd * insz); + if (nremove) + memcpy(&nmsg->router_ids[nadd], remove, nremove * insz); + + nmsg->nadd = htons(nadd); + nmsg->nremove = htons(nremove); + len = sizeof(*nmsg) + insz * (nadd + nremove); + + return msg_new(MSG_REACHABLE_CHANGE, nmsg, seqnum, len); +} + #endif /* SUPPORT_OSPF_API */ diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index c20284aed..7ff39dc12 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -26,6 +26,9 @@ #ifndef _OSPF_API_H #define _OSPF_API_H +#include <zebra.h> +#include "ospf_lsa.h" + #define OSPF_API_VERSION 1 /* MTYPE definition is not reflected to "memory.h". */ @@ -112,6 +115,7 @@ extern void msg_fifo_free(struct msg_fifo *fifo); #define MSG_SYNC_LSDB 4 #define MSG_ORIGINATE_REQUEST 5 #define MSG_DELETE_REQUEST 6 +#define MSG_SYNC_REACHABLE 7 /* Messages from OSPF daemon. */ #define MSG_REPLY 10 @@ -122,6 +126,7 @@ extern void msg_fifo_free(struct msg_fifo *fifo); #define MSG_DEL_IF 15 #define MSG_ISM_CHANGE 16 #define MSG_NSM_CHANGE 17 +#define MSG_REACHABLE_CHANGE 18 struct msg_register_opaque_type { uint8_t lsatype; @@ -247,6 +252,12 @@ struct msg_nsm_change { uint8_t pad[3]; }; +struct msg_reachable_change { + uint16_t nadd; + uint16_t nremove; + struct in_addr router_ids[]; /* add followed by remove */ +}; + /* We make use of a union to define a structure that covers all possible API messages. This allows us to find out how much memory needs to be reserved for the largest API message. */ @@ -265,6 +276,7 @@ struct apimsg { struct msg_ism_change ism_change; struct msg_nsm_change nsm_change; struct msg_lsa_change_notify lsa_change_notify; + struct msg_reachable_change reachable_change; } u; }; @@ -320,6 +332,10 @@ extern struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum, uint8_t is_self_originated, struct lsa_header *data); +extern struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd, + struct in_addr *add, + uint16_t nremove, + struct in_addr *remove); /* string printing functions */ extern const char *ospf_api_errname(int errcode); extern const char *ospf_api_typename(int msgtype); diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index d6c1e28d4..259ba2a3f 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -726,6 +726,7 @@ static int ospf_apiserver_send_msg(struct ospf_apiserver *apiserv, case MSG_DEL_IF: case MSG_ISM_CHANGE: case MSG_NSM_CHANGE: + case MSG_REACHABLE_CHANGE: fifo = apiserv->out_async_fifo; fd = apiserv->fd_async; event = OSPF_APISERVER_ASYNC_WRITE; @@ -799,6 +800,9 @@ int ospf_apiserver_handle_msg(struct ospf_apiserver *apiserv, struct msg *msg) case MSG_DELETE_REQUEST: rc = ospf_apiserver_handle_delete_request(apiserv, msg); break; + case MSG_SYNC_REACHABLE: + rc = ospf_apiserver_handle_sync_reachable(apiserv, msg); + break; default: zlog_warn("ospf_apiserver_handle_msg: Unknown message type: %d", msg->hdr.msgtype); @@ -1343,6 +1347,59 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, return rc; } +/* ----------------------------------------------------------- + * Followings are functions for Reachability synchronization. + * ----------------------------------------------------------- + */ + +int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv, + struct msg *msg) +{ + struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + struct route_table *rt = ospf->all_rtrs; + uint32_t seqnum = msg_get_seq(msg); + struct in_addr *a, *abuf; + struct msg_reachable_change *areach; + struct msg *amsg; + uint mcount, count; + int _rc, rc = 0; + + if (!rt) + goto out; + + /* send all adds based on current reachable routers */ + a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, + sizeof(struct in_addr) * rt->count); + for (struct route_node *rn = route_top(rt); rn; rn = route_next(rn)) + if (listhead((struct list *)rn->info)) + *a++ = rn->p.u.prefix4; + + assert((a - abuf) <= (long)rt->count); + count = (a - abuf); + + a = abuf; + while (count && !rc) { + amsg = new_msg_reachable_change(seqnum, count, a, 0, NULL); + areach = (struct msg_reachable_change *)STREAM_DATA(amsg->s); + mcount = ntohs(areach->nadd) + ntohs(areach->nremove); + assert(mcount <= count); + a = a + mcount; + count -= mcount; + rc = ospf_apiserver_send_msg(apiserv, amsg); + msg_free(amsg); + } + XFREE(MTYPE_OSPF_APISERVER, abuf); + +out: + zlog_info("ospf_apiserver_handle_sync_reachable: rc %d", rc); + /* Send a reply back to client with return code */ + _rc = ospf_apiserver_send_reply(apiserv, seqnum, rc); + zlog_info("ospf_apiserver_handle_sync_reachable: _rc %d", _rc); + rc = rc ? rc : _rc; + apiserv->reachable_sync = !rc; + return rc; +} + /* ----------------------------------------------------------- * Following are functions to originate or update LSA @@ -2471,4 +2528,115 @@ int ospf_apiserver_lsa_delete(struct ospf_lsa *lsa) return apiserver_notify_clients_lsa(MSG_LSA_DELETE_NOTIFY, lsa); } +/* ------------------------------------------------------------- + * Reachable functions + * ------------------------------------------------------------- + */ + +static inline int cmp_route_nodes(struct route_node *orn, + struct route_node *nrn) +{ + if (!orn) + return 1; + else if (!nrn) + return -1; + else if (orn->p.u.prefix4.s_addr < nrn->p.u.prefix4.s_addr) + return -1; + else if (orn->p.u.prefix4.s_addr > nrn->p.u.prefix4.s_addr) + return 1; + else + return 0; +} + +void ospf_apiserver_notify_reachable(struct route_table *ort, + struct route_table *nrt) +{ + struct msg *msg; + struct msg_reachable_change *areach; + struct route_node *orn, *nrn; + const uint insz = sizeof(struct in_addr); + struct in_addr *abuf = NULL, *dbuf = NULL; + struct in_addr *a = NULL, *d = NULL; + uint nadd, nremove; + int cmp; + + if (!ort && !nrt) { + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug("%s: no routing tables", __func__); + return; + } + if (nrt && nrt->count) + a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * nrt->count); + if (ort && ort->count) + d = dbuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * ort->count); + + /* walk both tables */ + orn = ort ? route_top(ort) : NULL; + nrn = nrt ? route_top(nrt) : NULL; + while (orn || nrn) { + if (orn && !listhead((struct list *)orn->info)) { + orn = route_next(orn); + continue; + } + if (nrn && !listhead((struct list *)nrn->info)) { + nrn = route_next(nrn); + continue; + } + cmp = cmp_route_nodes(orn, nrn); + if (!cmp) { + /* if old == new advance old and new */ + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug("keeping router id: %pI4", + &orn->p.u.prefix4); + orn = route_next(orn); + nrn = route_next(nrn); + } else if (cmp < 0) { + assert(d != NULL); /* Silence SA warning */ + + /* if old < new, delete old, advance old */ + *d++ = orn->p.u.prefix4; + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug("removing router id: %pI4", + &orn->p.u.prefix4); + orn = route_next(orn); + } else { + assert(a != NULL); /* Silence SA warning */ + + /* if new < old, add new, advance new */ + *a++ = nrn->p.u.prefix4; + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug("adding router id: %pI4", + &nrn->p.u.prefix4); + nrn = route_next(nrn); + } + } + + nadd = abuf ? (a - abuf) : 0; + nremove = dbuf ? (d - dbuf) : 0; + a = abuf; + d = dbuf; + + while (nadd + nremove) { + msg = new_msg_reachable_change(0, nadd, a, nremove, d); + areach = (struct msg_reachable_change *)STREAM_DATA(msg->s); + + a += ntohs(areach->nadd); + nadd = nadd - ntohs(areach->nadd); + + d += ntohs(areach->nremove); + nremove = nremove - ntohs(areach->nremove); + + if (IS_DEBUG_OSPF_CLIENT_API) + zlog_debug("%s: adding %d removing %d", __func__, + ntohs(areach->nadd), ntohs(areach->nremove)); + ospf_apiserver_clients_notify_all(msg); + msg_free(msg); + } + if (abuf) + XFREE(MTYPE_OSPF_APISERVER, abuf); + if (dbuf) + XFREE(MTYPE_OSPF_APISERVER, dbuf); +} + + #endif /* SUPPORT_OSPF_API */ diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index b4d8bb2f5..8a756e9c3 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -22,6 +22,10 @@ #ifndef _OSPF_APISERVER_H #define _OSPF_APISERVER_H +#include <zebra.h> +#include "ospf_api.h" +#include "ospf_lsdb.h" + /* MTYPE definition is not reflected to "memory.h". */ #define MTYPE_OSPF_APISERVER MTYPE_TMP #define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP @@ -52,6 +56,9 @@ struct ospf_apiserver { /* Temporary storage for LSA instances to be refreshed. */ struct ospf_lsdb reserve; + /* Sync reachable routers */ + bool reachable_sync; + /* filter for LSA update/delete notifies */ struct lsa_filter_type *filter; @@ -144,8 +151,11 @@ extern int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, struct msg *msg); +extern int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv, + struct msg *msg); - +extern void ospf_apiserver_notify_reachable(struct route_table *ort, + struct route_table *nrt); /* ----------------------------------------------------------- * Following are functions for LSA origination/deletion * ----------------------------------------------------------- diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 1974a42f5..44549b980 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -48,6 +48,7 @@ #include "ospfd/ospf_sr.h" #include "ospfd/ospf_ti_lfa.h" #include "ospfd/ospf_errors.h" +#include "ospfd/ospf_apiserver.h" /* Variables to ensure a SPF scheduled log message is printed only once */ @@ -1891,6 +1892,7 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread) /* Update all routers routing table */ ospf->oall_rtrs = ospf->all_rtrs; ospf->all_rtrs = all_rtrs; + ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs); /* Free old ABR/ASBR routing table */ if (ospf->old_rtrs) |