From: David Lamparter <equi...@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 <equi...@opensourcerouting.org> Signed-off-by: Philippe Guibert <philippe.guib...@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