summaryrefslogtreecommitdiffstats
path: root/ospfd
diff options
context:
space:
mode:
authorChristian Hopps <chopps@labn.net>2022-06-01 21:25:35 +0200
committerChristian Hopps <chopps@labn.net>2022-06-02 22:37:16 +0200
commit149491af80ceaeb666a9bf06f97e918a64c46a5c (patch)
treeda50c5f09450c81a31cccd916f179bf07c1848b8 /ospfd
parentospfd: add all_rtrs route table when opaque enabled (diff)
downloadfrr-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.c31
-rw-r--r--ospfd/ospf_api.h16
-rw-r--r--ospfd/ospf_apiserver.c168
-rw-r--r--ospfd/ospf_apiserver.h12
-rw-r--r--ospfd/ospf_spf.c2
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)