Mailing List Archive

[PATCH 16/23] bgpd: enable iteration of routes in VRF
From: David Lamparter <equinox@opensourcerouting.org>

This enhancement to the bgp.capnp scheme files permits bgp daemon
to handle get requests to parse a routing table. It is possible
to retrieve the next element of a table, by reusing the passed
as parameter element, then, the query will response with the
associated next element.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
---
bgpd/bgp.bcapnp.c | 23 +++++++++++++++---
bgpd/bgp.bcapnp.h | 6 ++++-
bgpd/bgp.capnp | 13 ++++++++++
bgpd/bgp_route.c | 52 +++++++++++++++++++++++++++++++++++++++
bgpd/bgpd.h | 10 +++++++-
bgpd/bgpd.ndef.i | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++----
6 files changed, 166 insertions(+), 11 deletions(-)

diff --git a/bgpd/bgp.bcapnp.c b/bgpd/bgp.bcapnp.c
index 0da76f7a492b..2bf038128cd1 100644
--- a/bgpd/bgp.bcapnp.c
+++ b/bgpd/bgp.bcapnp.c
@@ -1109,13 +1109,11 @@ void qcapn_BGPVRFRoute_set(struct bgp_api_route *s, capn_ptr p)
}


-capn_ptr qcapn_new_BGPVRFRoute(struct capn_segment *s)
+capn_ptr qcapn_new_BGPVRFRoute(struct capn_segment *s, uint8_t extend_by)
{
- return capn_new_struct(s, 8, 2);
+ return capn_new_struct(s, CAPN_BGPVRF_ROUTE_DEF_SIZE + extend_by, 2);
}

-
-
void qcapn_BGPEventVRFRoute_read(struct bgp_event_vrf *s, capn_ptr p)
{
uint64_t tmp;
@@ -1246,3 +1244,20 @@ capn_ptr qcapn_new_BGPEventShut(struct capn_segment *s)
return capn_new_struct(s, 8, 1);
}

+capn_ptr qcapn_new_BGPVRFInfoIter(struct capn_segment *s)
+{
+ return capn_new_struct(s, 8, 0);
+}
+
+void qcapn_BGPVRFInfoIter_write(const unsigned long s, capn_ptr p, int offset)
+{
+ capn_resolve(&p);
+ capn_write64(p, offset, s);
+}
+
+void qcapn_BGPVRFInfoIter_read(unsigned long *s, capn_ptr p, int offset)
+{
+ capn_resolve(&p);
+
+ *s = capn_read64(p, offset);
+}
diff --git a/bgpd/bgp.bcapnp.h b/bgpd/bgp.bcapnp.h
index fafaf6cce83a..3b8ce361f6b2 100644
--- a/bgpd/bgp.bcapnp.h
+++ b/bgpd/bgp.bcapnp.h
@@ -43,7 +43,7 @@ capn_ptr qcapn_new_BGPVRF(struct capn_segment *s);
void qcapn_BGPVRFRoute_read(struct bgp_api_route *s, capn_ptr p);
void qcapn_BGPVRFRoute_write(const struct bgp_api_route *s, capn_ptr p);
void qcapn_BGPVRFRoute_set(struct bgp_api_route *s, capn_ptr p);
-capn_ptr qcapn_new_BGPVRFRoute(struct capn_segment *s);
+capn_ptr qcapn_new_BGPVRFRoute(struct capn_segment *s, uint8_t extend_by);
void qcapn_BGPEventVRFRoute_read(struct bgp_event_vrf *s, capn_ptr p);
void qcapn_BGPEventVRFRoute_write(const struct bgp_event_vrf *s, capn_ptr p);
void qcapn_BGPEventVRFRoute_set(struct bgp_event_vrf *s, capn_ptr p);
@@ -52,5 +52,9 @@ void qcapn_BGPEventShut_read(struct bgp_event_shut *s, capn_ptr p);
void qcapn_BGPEventShut_write(const struct bgp_event_shut *s, capn_ptr p);
void qcapn_BGPEventShut_set(struct bgp_event_shut *s, capn_ptr p);
capn_ptr qcapn_new_BGPEventShut(struct capn_segment *s);
+capn_ptr qcapn_new_BGPVRFInfoIter(struct capn_segment *s);
+void qcapn_BGPVRFInfoIter_write(const unsigned long s, capn_ptr p, int offset);
+void qcapn_BGPVRFInfoIter_read(unsigned long *s, capn_ptr p, int offset);

+#define CAPN_BGPVRF_ROUTE_DEF_SIZE 8
#endif /* CAPN_C4C948A17D3B2250 */
diff --git a/bgpd/bgp.capnp b/bgpd/bgp.capnp
index da56ee4d2548..27a917ff62cd 100644
--- a/bgpd/bgp.capnp
+++ b/bgpd/bgp.capnp
@@ -40,6 +40,9 @@ struct AfiSafiKey $cgennaked $cgetfield {
afi @0 :UInt8 $ctype("afi_t");
safi @1 :UInt8 $ctype("safi_t");
}
+struct AfiKey $cgennaked $cgetfield {
+ afi @0 :UInt8 $ctype("afi_t");
+}
struct ExtCommunityList {
values @0 :List(UInt64);
}
@@ -47,6 +50,9 @@ struct PrefixV4 {
addr @0 :UInt32;
prefixlen @1 :UInt8;
}
+struct VRFTableIter $ctype("struct tbliter_v4") $cgen {
+ prefix @0 :PrefixV4;
+}

struct BGP $ctype("struct bgp") $cgen
$csetter("bgp_%%_set")
@@ -159,6 +165,13 @@ struct BGPVRF $ctype("struct bgp_vrf") $cgen
rtExport @2 :ExtCommunityList;
}

+struct BGPVRFRoute $ctype("struct bgp_api_route") $cgen
+{
+ prefix @0 :PrefixV4;
+ nexthop @1 :IPv4;
+ label @2 :UInt32;
+}
+
struct BGPEventVRFRoute $ctype("struct bgp_event_vrf") $cgen
{
announce @0 :Bool;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index d26e64256985..652c47e6274a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1543,6 +1543,58 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
return 0;
}

+bool bgp_api_route_get (struct bgp_api_route *out, struct bgp_node *bn,
+ int iter_on_multipath, void **next)
+{
+ struct bgp_info *sel, *iter;
+
+ memset(out, 0, sizeof (*out));
+ if (bn->p.family != AF_INET)
+ return false;
+ if (!bn->info)
+ return false;
+
+ prefix_copy ((struct prefix *)&out->prefix, &bn->p);
+
+ for (sel = bn->info; sel; sel = sel->next)
+ {
+ if (iter_on_multipath)
+ {
+ if (CHECK_FLAG (sel->flags, BGP_INFO_MULTIPATH))
+ break;
+ }
+ else
+ {
+ if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
+ break;
+ {
+ /* prepare sel with start of list to look for multipath entries */
+ /* Since this function should be first called with iter_on_multipath set to 0 */
+ /* sel should correspond to the start of the list */
+ sel = bn->info;
+ break;
+ }
+ }
+ }
+
+ if (!sel)
+ return false;
+
+ if (sel->attr && sel->attr->extra)
+ out->nexthop = sel->attr->extra->mp_nexthop_global_in;
+ if (sel->extra && sel->extra->nlabels)
+ out->label = sel->extra->labels[0] >> 4;
+
+ /* now that an entry with SELECTED flag was found, check for possibly MULTIPATH entries
+ in next items */
+ for (iter = sel->next; iter; iter = iter->next)
+ if (CHECK_FLAG (iter->flags, BGP_INFO_MULTIPATH))
+ {
+ *next = iter;
+ break;
+ }
+ return true;
+}

static bool rd_same (const struct prefix_rd *a, const struct prefix_rd *b)
{
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index dfc2a4e97ef2..4c79071abe2f 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -278,6 +278,11 @@ struct bgp_event_shut
uint8_t type, subtype;
};

+struct tbliter_v4
+{
+ struct prefix_ipv4 prefix;
+};
+
struct bgp_api_route
{
struct prefix_ipv4 prefix;
@@ -1120,5 +1125,8 @@ extern void bgp_vrf_rt_import_unset (struct bgp_vrf *vrf);
extern void bgp_vrf_rt_export_unset (struct bgp_vrf *vrf);
extern int bgp_vrf_static_set (struct bgp_vrf *vrf, afi_t afi, const struct bgp_api_route *route);
extern int bgp_vrf_static_unset (struct bgp_vrf *vrf, afi_t afi, const struct bgp_api_route *route);
-
+extern bool bgp_api_route_get (struct bgp_api_route *out,
+ struct bgp_node *bn,
+ int iter_on_multipath,
+ void **next);
#endif /* _QUAGGA_BGPD_H */
diff --git a/bgpd/bgpd.ndef.i b/bgpd/bgpd.ndef.i
index 54b5d185aa08..c235b557479f 100644
--- a/bgpd/bgpd.ndef.i
+++ b/bgpd/bgpd.ndef.i
@@ -524,6 +524,7 @@ _qzc_get_bgp_vrf_2(struct bgp_vrf *p,
struct tbliter_v4 iter, nextiter;
const struct tbliter_v4 *iterptr;
afi_t afi;
+ void *next = NULL;

if (req->ctxtype != 0xac25a73c3ff455c0)
/* error */
@@ -556,16 +557,75 @@ _qzc_get_bgp_vrf_2(struct bgp_vrf *p,
if (val) {
struct bgp_api_route *outptr;
struct bgp_api_route tmpval;
- if (!bgp_api_route_get(&tmpval, val))
- return;
+
+ memset(&tmpval,0, sizeof(struct bgp_api_route));
outptr = &tmpval;
- rep->data = qcapn_new_BGPVRFRoute(seg);
- qcapn_BGPVRFRoute_write(outptr, rep->data);
+ rep->data = qcapn_new_BGPVRFRoute(seg, sizeof(next));
rep->datatype = 0x8f217eb4bad6c06f;
+ qcapn_BGPVRFRoute_write(outptr, rep->data);
+ if (!bgp_api_route_get(&tmpval, val, 0, &next))
+ return;
+
+ qcapn_BGPVRFRoute_write(outptr, rep->data);
+ /* send value of pointer to next ri which has BGP_INFO_MULTIPATH flag,
+ sending 0 means there is no next element */
+ qcapn_BGPVRFInfoIter_write((unsigned long) next,
+ rep->data, CAPN_BGPVRF_ROUTE_DEF_SIZE);
+
}
}

+/* Iterated GET bgp_vrf:4 <> bgp_vrf->rib ()*/

+static void
+_qzc_get_bgp_vrf_4(struct bgp_vrf *p,
+ struct QZCGetReq *req, struct QZCGetRep *rep,
+ struct capn_segment *seg)
+{
+ unsigned long mpath_iter_ptr = 0;
+ struct bgp_node dummy;
+ void *next = NULL;
+ struct bgp_api_route *outptr;
+ struct bgp_api_route tmpval;
+
+ if (req->itertype == 0xeb8ab4f58b7753ee) {
+ qcapn_BGPVRFInfoIter_read(&mpath_iter_ptr, req->iterdata, 0);
+ } else {
+ /* error */
+ zlog_err("%s: req->itertype:%016lx != 0xeb8ab4f58b7753ee",
+ __func__, req->itertype);
+ return;
+ }
+
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.p.family = AF_INET;
+ dummy.info = (struct bgp_info*) mpath_iter_ptr;
+ rep->datatype = 0;
+ rep->itertype = 0; /* by default, no need to iterate more */
+
+ /* do not write route if bgp info has nothing, but keep next iteration */
+ memset(&tmpval,0, sizeof(struct bgp_api_route));
+ outptr = &tmpval;
+ rep->data = qcapn_new_BGPVRFRoute(seg, 0);
+ rep->datatype = 0x8f217eb4bad6c06f;
+ qcapn_BGPVRFRoute_write(outptr, rep->data);
+
+ /* do this way to look for multipath entries instead of selected */
+ if (!bgp_api_route_get(&tmpval, &dummy, 1, &next))
+ return;
+
+ qcapn_BGPVRFRoute_write(outptr, rep->data);
+ /* send value of pointer to next ri which has BGP_INFO_MULTIPATH flag,
+ sending 0 means there is no next element */
+ if ((unsigned long) next)
+ {
+ /* This way bgp_configurator can know there is something next after the
+ route transfert done above */
+ rep->itertype = 0xeb8ab4f58b7753ee;
+ rep->nextiter = qcapn_new_BGPVRFInfoIter(seg);
+ qcapn_BGPVRFInfoIter_write((unsigned long) next, rep->nextiter, 0);
+ }
+}

static struct bgp_node * qcap_iter_bgp_vrf_route(struct bgp_table *table,
const struct tbliter_v4 *prev_iter,
@@ -635,7 +695,7 @@ _qzc_get_bgp_vrf_3(struct bgp_vrf *p,
if (!bgp_api_static_get(&tmpval, val))
return;
outptr = &tmpval;
- rep->data = qcapn_new_BGPVRFRoute(seg);
+ rep->data = qcapn_new_BGPVRFRoute(seg, 0);
qcapn_BGPVRFRoute_write(outptr, rep->data);
rep->datatype = 0x8f217eb4bad6c06f;
}
@@ -734,6 +794,9 @@ _qzc_get_bgp_vrf(void *entity, struct QZCGetReq *req, struct QZCGetRep *rep,
case 3:
_qzc_get_bgp_vrf_3(p, req, rep, seg);
return;
+ case 4:
+ _qzc_get_bgp_vrf_4(p, req, rep, seg);
+ return;
default:
return;
}
--
2.1.4


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev