3 * Copyright 2009-2016, LabN Consulting, L.L.C.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "lib/zebra.h"
22 #include "lib/prefix.h"
23 #include "lib/agg_table.h"
25 #include "lib/memory.h"
26 #include "lib/routemap.h"
28 #include "lib/linklist.h"
29 #include "lib/command.h"
30 #include "lib/stream.h"
31 #include "lib/ringbuf.h"
32 #include "lib/lib_errors.h"
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_ecommunity.h"
36 #include "bgpd/bgp_attr.h"
38 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
39 #include "bgpd/rfapi/rfapi.h"
40 #include "bgpd/rfapi/rfapi_backend.h"
42 #include "bgpd/bgp_route.h"
43 #include "bgpd/bgp_mplsvpn.h"
44 #include "bgpd/bgp_aspath.h"
45 #include "bgpd/bgp_advertise.h"
46 #include "bgpd/bgp_vnc_types.h"
47 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/rfapi/rfapi_import.h"
50 #include "bgpd/rfapi/rfapi_private.h"
51 #include "bgpd/rfapi/rfapi_monitor.h"
52 #include "bgpd/rfapi/rfapi_vty.h"
53 #include "bgpd/rfapi/vnc_export_bgp.h"
54 #include "bgpd/rfapi/vnc_export_bgp_p.h"
55 #include "bgpd/rfapi/vnc_zebra.h"
56 #include "bgpd/rfapi/vnc_import_bgp.h"
57 #include "bgpd/rfapi/rfapi_rib.h"
58 #include "bgpd/rfapi/rfapi_ap.h"
59 #include "bgpd/rfapi/rfapi_encap_tlv.h"
60 #include "bgpd/rfapi/vnc_debug.h"
62 #ifdef HAVE_GLIBC_BACKTRACE
63 /* for backtrace and friends */
65 #endif /* HAVE_GLIBC_BACKTRACE */
67 struct ethaddr rfapi_ethaddr0
= {{0}};
69 #define DEBUG_RFAPI_STR "RF API debugging/testing command\n"
71 const char *rfapi_error_str(int code
)
77 return "BGP or VNC not configured";
81 return "Handle already open";
83 return "Incomplete configuration";
85 return "Invalid address family";
87 return "Called from within a callback procedure";
89 return "Invalid handle";
91 return "Invalid argument";
93 return "Stale descriptor";
95 return "Unknown error";
99 /*------------------------------------------
100 * rfapi_get_response_lifetime_default
102 * Returns the default lifetime for a response.
103 * rfp_start_val value returned by rfp_start or
104 * NULL (=use default instance)
111 * return value: The bgp instance default lifetime for a response.
112 --------------------------------------------*/
113 int rfapi_get_response_lifetime_default(void *rfp_start_val
)
115 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
117 return bgp
->rfapi_cfg
->default_response_lifetime
;
118 return BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
;
121 /*------------------------------------------
122 * rfapi_is_vnc_configured
124 * Returns if VNC is configured
127 * rfp_start_val value returned by rfp_start or
128 * NULL (=use default instance)
132 * return value: If VNC is configured for the bgpd instance
134 * ENXIO VNC not configured
135 --------------------------------------------*/
136 int rfapi_is_vnc_configured(void *rfp_start_val
)
138 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
139 if (bgp_rfapi_is_vnc_configured(bgp
) == 0)
145 /*------------------------------------------
148 * Get the virtual network address used by an NVE based on it's RFD
151 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
156 * vn NVE virtual network address
157 *------------------------------------------*/
158 struct rfapi_ip_addr
*rfapi_get_vn_addr(void *rfd
)
160 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
161 return &rrfd
->vn_addr
;
164 /*------------------------------------------
167 * Get the underlay network address used by an NVE based on it's RFD
170 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
175 * un NVE underlay network address
176 *------------------------------------------*/
177 struct rfapi_ip_addr
*rfapi_get_un_addr(void *rfd
)
179 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
180 return &rrfd
->un_addr
;
183 int rfapi_ip_addr_cmp(struct rfapi_ip_addr
*a1
, struct rfapi_ip_addr
*a2
)
185 if (a1
->addr_family
!= a2
->addr_family
)
186 return a1
->addr_family
- a2
->addr_family
;
188 if (a1
->addr_family
== AF_INET
) {
189 return IPV4_ADDR_CMP(&a1
->addr
.v4
, &a2
->addr
.v4
);
192 if (a1
->addr_family
== AF_INET6
) {
193 return IPV6_ADDR_CMP(&a1
->addr
.v6
, &a2
->addr
.v6
);
201 static int rfapi_find_node(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
202 struct rfapi_ip_addr
*un_addr
,
203 struct agg_node
**node
)
220 afi
= family2afi(un_addr
->addr_family
);
225 if ((rc
= rfapiRaddr2Qprefix(un_addr
, &p
)))
228 rn
= agg_node_lookup(h
->un
[afi
], &p
);
241 int rfapi_find_rfd(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
242 struct rfapi_ip_addr
*un_addr
, struct rfapi_descriptor
**rfd
)
247 rc
= rfapi_find_node(bgp
, vn_addr
, un_addr
, &rn
);
252 for (*rfd
= (struct rfapi_descriptor
*)(rn
->info
); *rfd
;
253 *rfd
= (*rfd
)->next
) {
254 if (!rfapi_ip_addr_cmp(&(*rfd
)->vn_addr
, vn_addr
))
264 /*------------------------------------------
268 * un underlay network address
269 * vn virtual network address
272 * pHandle pointer to location to store handle
276 * ENOENT no matching handle
277 * ENXIO BGP or VNC not configured
278 *------------------------------------------*/
279 static int rfapi_find_handle(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
280 struct rfapi_ip_addr
*un_addr
,
281 rfapi_handle
*handle
)
283 struct rfapi_descriptor
**rfd
;
285 rfd
= (struct rfapi_descriptor
**)handle
;
287 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
290 static int rfapi_find_handle_vty(struct vty
*vty
, struct rfapi_ip_addr
*vn_addr
,
291 struct rfapi_ip_addr
*un_addr
,
292 rfapi_handle
*handle
)
295 struct rfapi_descriptor
**rfd
;
297 bgp
= bgp_get_default(); /* assume 1 instance for now */
299 rfd
= (struct rfapi_descriptor
**)handle
;
301 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
304 static int is_valid_rfd(struct rfapi_descriptor
*rfd
)
308 if (!rfd
|| rfd
->bgp
== NULL
)
313 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
316 if (rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &hh
))
326 * check status of descriptor
328 int rfapi_check(void *handle
)
330 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
334 if (!rfd
|| rfd
->bgp
== NULL
)
339 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
342 if ((rc
= rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
,
356 void del_vnc_route(struct rfapi_descriptor
*rfd
,
357 struct peer
*peer
, /* rfd->peer for RFP regs */
358 struct bgp
*bgp
, safi_t safi
, struct prefix
*p
,
359 struct prefix_rd
*prd
, uint8_t type
, uint8_t sub_type
,
360 struct rfapi_nexthop
*lnh
, int kill
)
362 afi_t afi
; /* of the VN address */
365 char buf
[PREFIX_STRLEN
];
366 char buf2
[RD_ADDRSTRLEN
];
367 struct prefix_rd prd0
;
369 prefix2str(p
, buf
, sizeof(buf
));
371 afi
= family2afi(p
->family
);
372 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
374 if (safi
== SAFI_ENCAP
) {
375 memset(&prd0
, 0, sizeof(prd0
));
376 prd0
.family
= AF_UNSPEC
;
380 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
382 vnc_zlog_debug_verbose(
383 "%s: peer=%p, prefix=%s, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
384 __func__
, peer
, buf
, prefix_rd2str(prd
, buf2
, sizeof(buf2
)),
385 afi
, safi
, bn
, (bn
? bn
->info
: NULL
));
387 for (bi
= (bn
? bn
->info
: NULL
); bi
; bi
= bi
->next
) {
389 vnc_zlog_debug_verbose(
390 "%s: trying bi=%p, bi->peer=%p, bi->type=%d, bi->sub_type=%d, bi->extra->vnc.export.rfapi_handle=%p, local_pref=%u",
391 __func__
, bi
, bi
->peer
, bi
->type
, bi
->sub_type
,
392 (bi
->extra
? bi
->extra
->vnc
.export
.rfapi_handle
: NULL
),
394 && CHECK_FLAG(bi
->attr
->flag
,
395 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
396 ? bi
->attr
->local_pref
399 if (bi
->peer
== peer
&& bi
->type
== type
400 && bi
->sub_type
== sub_type
&& bi
->extra
401 && bi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
403 vnc_zlog_debug_verbose("%s: matched it", __func__
);
411 * lnh set means to JUST delete the local nexthop from this
412 * route. Leave the route itself in place.
413 * TBD add return code reporting of success/failure
415 if (!bi
|| !bi
->extra
416 || !bi
->extra
->vnc
.export
.local_nexthops
) {
420 vnc_zlog_debug_verbose(
421 "%s: lnh list already empty at prefix %s",
429 struct listnode
*node
;
430 struct rfapi_nexthop
*pLnh
= NULL
;
432 for (ALL_LIST_ELEMENTS_RO(bi
->extra
->vnc
.export
.local_nexthops
,
435 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
441 listnode_delete(bi
->extra
->vnc
.export
.local_nexthops
,
444 /* silly rabbit, listnode_delete doesn't invoke
445 * list->del on data */
446 rfapi_nexthop_free(pLnh
);
448 vnc_zlog_debug_verbose("%s: desired lnh not found %s",
455 * loop back to import tables
456 * Do this before removing from BGP RIB because rfapiProcessWithdraw
459 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
462 prefix2str(p
, buf
, sizeof(buf
));
463 vnc_zlog_debug_verbose(
464 "%s: Found route (safi=%d) to delete at prefix %s",
465 __func__
, safi
, buf
);
467 if (safi
== SAFI_MPLS_VPN
) {
468 struct bgp_node
*prn
= NULL
;
469 struct bgp_table
*table
= NULL
;
471 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
472 (struct prefix
*)prd
);
474 table
= (struct bgp_table
*)(prn
->info
);
476 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
477 bgp
, prd
, table
, p
, bi
);
479 bgp_unlock_node(prn
);
483 * Delete local_nexthops list
485 if (bi
->extra
&& bi
->extra
->vnc
.export
.local_nexthops
) {
487 &bi
->extra
->vnc
.export
.local_nexthops
);
490 bgp_aggregate_decrement(bgp
, p
, bi
, afi
, safi
);
491 bgp_info_delete(bn
, bi
);
492 bgp_process(bgp
, bn
, afi
, safi
);
494 vnc_zlog_debug_verbose(
495 "%s: Couldn't find route (safi=%d) at prefix %s",
496 __func__
, safi
, buf
);
502 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
504 struct rfapi_nexthop
*new =
505 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
511 void rfapi_nexthop_free(void *p
)
513 struct rfapi_nexthop
*goner
= p
;
514 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
517 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
519 struct rfapi_vn_option
*p
;
520 struct rfapi_vn_option
*head
= NULL
;
521 struct rfapi_vn_option
*tail
= NULL
;
523 for (p
= existing
; p
; p
= p
->next
) {
524 struct rfapi_vn_option
*new;
526 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
527 sizeof(struct rfapi_vn_option
));
540 void rfapi_un_options_free(struct rfapi_un_option
*p
)
542 struct rfapi_un_option
*next
;
546 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
551 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
553 struct rfapi_vn_option
*next
;
557 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
562 /* Based on bgp_redistribute_add() */
563 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
564 struct bgp
*bgp
, int safi
, struct prefix
*p
,
565 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
566 uint32_t *local_pref
,
567 uint32_t *lifetime
, /* NULL => dont send lifetime */
568 struct bgp_tea_options
*rfp_options
,
569 struct rfapi_un_option
*options_un
,
570 struct rfapi_vn_option
*options_vn
,
571 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
572 uint32_t *med
, /* NULL => don't set med */
573 uint32_t *label
, /* low order 3 bytes */
574 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
577 afi_t afi
; /* of the VN address */
578 struct bgp_info
*new;
582 struct attr attr
= {0};
583 struct attr
*new_attr
;
586 struct bgp_attr_encap_subtlv
*encaptlv
;
587 char buf
[PREFIX_STRLEN
];
588 char buf2
[RD_ADDRSTRLEN
];
590 struct prefix pfx_buf
;
593 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
594 struct rfapi_vn_option
*vo
;
595 struct rfapi_l2address_option
*l2o
= NULL
;
596 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
598 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
599 struct bgp_redist
*red
;
601 if (safi
== SAFI_ENCAP
602 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
605 * Encap mode not enabled. UN addresses will be communicated
606 * via VNC Tunnel subtlv instead.
608 vnc_zlog_debug_verbose(
609 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
615 if ((safi
== SAFI_MPLS_VPN
) && (flags
& RFAPI_AHR_SET_PFX_TO_NEXTHOP
))
618 if (rfapiRaddr2Qprefix (nexthop
, &pfx_buf
))
620 vnc_zlog_debug_verbose
621 ("%s: can't set pfx to vn addr, not adding SAFI_MPLS_VPN route",
628 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
629 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
631 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
632 l2o
= NULL
; /* not MAC resolution */
634 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
635 lnh
= &vo
->v
.local_nexthop
;
642 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
644 prefix_rd2str(prd
, buf2
, sizeof(buf2
));
646 afi
= family2afi(p
->family
);
647 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
649 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
652 /* Make default attribute. Produces already-interned attr.aspath */
653 /* Cripes, the memory management of attributes is byzantine */
655 bgp_attr_default_set(&attr
, BGP_ORIGIN_INCOMPLETE
);
660 * extra: dynamically allocated, owned by attr
661 * aspath: points to interned hash from aspath hash table
666 * Route-specific un_options get added to the VPN SAFI
667 * advertisement tunnel encap attribute. (the per-NVE
668 * "default" un_options are put into the 1-per-NVE ENCAP
669 * SAFI advertisement). The VPN SAFI also gets the
670 * default un_options if there are no route-specific options.
673 struct rfapi_un_option
*uo
;
675 for (uo
= options_un
; uo
; uo
= uo
->next
) {
676 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
677 TunnelType
= rfapi_tunneltype_option_to_tlv(
678 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
685 * These are the NVE-specific "default" un_options which are
686 * put into the 1-per-NVE ENCAP advertisement.
688 if (rfd
->default_tunneltype_option
.type
) {
689 TunnelType
= rfapi_tunneltype_option_to_tlv(
690 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
692 } else /* create default for local addse */
693 if (type
== ZEBRA_ROUTE_BGP
694 && sub_type
== BGP_ROUTE_RFP
)
695 TunnelType
= rfapi_tunneltype_option_to_tlv(
696 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
699 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
700 if (safi
== SAFI_ENCAP
) {
701 /* Encap SAFI not used with MPLS */
702 vnc_zlog_debug_verbose(
703 "%s: mpls tunnel type, encap safi omitted",
705 aspath_unintern(&attr
.aspath
); /* Unintern original. */
711 attr
.local_pref
= *local_pref
;
712 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
717 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
720 /* override default weight assigned by bgp_attr_default_set() */
721 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
724 * NB: ticket 81: do not reset attr.aspath here because it would
725 * cause iBGP peers to drop route
729 * Set originator ID for routes imported from BGP directly.
730 * These routes could be synthetic, and therefore could
731 * reuse the peer pointers of the routes they are derived
732 * from. Setting the originator ID to "us" prevents the
733 * wrong originator ID from being sent when this route is
734 * sent from a route reflector.
736 if (type
== ZEBRA_ROUTE_BGP_DIRECT
737 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
738 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
739 attr
.originator_id
= bgp
->router_id
;
743 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
744 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
747 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
748 sizeof(struct bgp_attr_encap_subtlv
) + 4);
751 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
752 encaptlv
->length
= 4;
753 lt
= htonl(*lifetime
);
754 memcpy(encaptlv
->value
, <
, 4);
755 attr
.vnc_subtlvs
= encaptlv
;
756 vnc_zlog_debug_verbose(
757 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
761 /* add rfp options to vnc attr */
764 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
767 * this flag means we're passing a pointer to an
768 * existing encap tlv chain which we should copy.
769 * It's a hack to avoid adding yet another argument
772 encaptlv
= encap_tlv_dup(
773 (struct bgp_attr_encap_subtlv
*)rfp_options
);
774 if (attr
.vnc_subtlvs
) {
775 attr
.vnc_subtlvs
->next
= encaptlv
;
777 attr
.vnc_subtlvs
= encaptlv
;
781 struct bgp_tea_options
*hop
;
782 /* XXX max of one tlv present so far from above code */
783 struct bgp_attr_encap_subtlv
*tail
= attr
.vnc_subtlvs
;
785 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
792 sizeof(struct bgp_attr_encap_subtlv
) + 2
796 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
799 encaptlv
->length
= 2 + hop
->length
;
800 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
801 *((uint8_t *)(encaptlv
->value
) + 1) =
803 memcpy(((uint8_t *)encaptlv
->value
) + 2,
804 hop
->value
, hop
->length
);
807 * add to end of subtlv chain
810 tail
->next
= encaptlv
;
812 attr
.vnc_subtlvs
= encaptlv
;
822 * extra: dynamically allocated, owned by attr
823 * vnc_subtlvs: dynamic chain, length 1
824 * aspath: points to interned hash from aspath hash table
828 attr
.ecommunity
= ecommunity_new();
829 assert(attr
.ecommunity
);
831 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
832 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
834 * Add BGP Encapsulation Extended Community. Format described in
835 * section 4.5 of RFC 5512.
836 * Always include when not MPLS type, to disambiguate this case.
838 struct ecommunity_val beec
;
840 memset(&beec
, 0, sizeof(beec
));
841 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
842 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
843 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
844 beec
.val
[7] = (TunnelType
)&0xff;
845 ecommunity_add_val(attr
.ecommunity
, &beec
);
849 * Add extended community attributes to match rt export list
851 if (rt_export_list
) {
853 ecommunity_merge(attr
.ecommunity
, rt_export_list
);
856 if (attr
.ecommunity
->size
) {
857 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
859 ecommunity_free(&attr
.ecommunity
);
860 attr
.ecommunity
= NULL
;
862 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
,
869 * extra: dynamically allocated, owned by attr
870 * vnc_subtlvs: dynamic chain, length 1
871 * ecommunity: dynamic 2-part
872 * aspath: points to interned hash from aspath hash table
875 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
876 switch (nexthop
->addr_family
) {
879 * set this field to prevent bgp_route.c code from setting
880 * mp_nexthop_global_in to self
882 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
884 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
885 attr
.mp_nexthop_len
= 4;
889 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
890 attr
.mp_nexthop_len
= 16;
898 prefix2str(p
, buf
, sizeof(buf
));
904 * extra: dynamically allocated, owned by attr
905 * vnc_subtlvs: dynamic chain, length 1
906 * ecommunity: dynamic 2-part
907 * aspath: points to interned hash from aspath hash table
910 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
912 if (red
&& red
->redist_metric_flag
) {
913 attr
.med
= red
->redist_metric
;
914 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
917 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
920 * bgp_attr_intern creates a new reference to a cached
921 * attribute, but leaves the following bits of trash:
923 * - old attr->extra (free via bgp_attr_extra_free(attr))
925 * Note that it frees the original attr->extra->ecommunity
926 * but leaves the new attribute pointing to the ORIGINAL
927 * vnc options (which therefore we needn't free from the
930 new_attr
= bgp_attr_intern(&attr
);
932 aspath_unintern(&attr
.aspath
); /* Unintern original. */
938 * extra: dynamically allocated, owned by attr
939 * vnc_subtlvs: dynamic chain, length 1
940 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
942 * new_attr: an attr that is part of the hash table, distinct
943 * from attr which is static.
944 * extra: dynamically allocated, owned by new_attr (in hash table)
945 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
946 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
947 * aspath: POINTS TO interned/refcounted hashed block
949 for (bi
= bn
->info
; bi
; bi
= bi
->next
) {
950 /* probably only need to check
951 * bi->extra->vnc.export.rfapi_handle */
952 if (bi
->peer
== rfd
->peer
&& bi
->type
== type
953 && bi
->sub_type
== sub_type
&& bi
->extra
954 && bi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
963 * Adding new local_nexthop, which does not by itself change
964 * what is advertised via BGP
967 if (!bi
->extra
->vnc
.export
.local_nexthops
) {
968 /* TBD make arrangements to free when needed */
969 bi
->extra
->vnc
.export
.local_nexthops
=
971 bi
->extra
->vnc
.export
.local_nexthops
->del
=
978 struct listnode
*node
;
979 struct rfapi_nexthop
*pLnh
= NULL
;
981 for (ALL_LIST_ELEMENTS_RO(
982 bi
->extra
->vnc
.export
.local_nexthops
, node
,
985 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
991 * Not present, add new one
994 pLnh
= rfapi_nexthop_new(lnh
);
996 bi
->extra
->vnc
.export
.local_nexthops
,
1001 if (attrhash_cmp(bi
->attr
, new_attr
)
1002 && !CHECK_FLAG(bi
->flags
, BGP_INFO_REMOVED
)) {
1003 bgp_attr_unintern(&new_attr
);
1004 bgp_unlock_node(bn
);
1007 "%s: Found route (safi=%d) at prefix %s, no change",
1008 __func__
, safi
, buf
);
1012 /* The attribute is changed. */
1013 bgp_info_set_flag(bn
, bi
, BGP_INFO_ATTR_CHANGED
);
1015 if (safi
== SAFI_MPLS_VPN
) {
1016 struct bgp_node
*prn
= NULL
;
1017 struct bgp_table
*table
= NULL
;
1019 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
1020 (struct prefix
*)prd
);
1022 table
= (struct bgp_table
*)(prn
->info
);
1024 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
1025 bgp
, prd
, table
, p
, bi
);
1027 bgp_unlock_node(prn
);
1030 /* Rewrite BGP route information. */
1031 if (CHECK_FLAG(bi
->flags
, BGP_INFO_REMOVED
))
1032 bgp_info_restore(bn
, bi
);
1034 bgp_aggregate_decrement(bgp
, p
, bi
, afi
, safi
);
1035 bgp_attr_unintern(&bi
->attr
);
1036 bi
->attr
= new_attr
;
1037 bi
->uptime
= bgp_clock();
1040 if (safi
== SAFI_MPLS_VPN
) {
1041 struct bgp_node
*prn
= NULL
;
1042 struct bgp_table
*table
= NULL
;
1044 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
1045 (struct prefix
*)prd
);
1047 table
= (struct bgp_table
*)(prn
->info
);
1049 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1050 bgp
, prd
, table
, p
, bi
);
1052 bgp_unlock_node(prn
);
1055 /* Process change. */
1056 bgp_aggregate_increment(bgp
, p
, bi
, afi
, safi
);
1057 bgp_process(bgp
, bn
, afi
, safi
);
1058 bgp_unlock_node(bn
);
1061 "%s: Found route (safi=%d) at prefix %s, changed attr",
1062 __func__
, safi
, buf
);
1069 new = bgp_info_new();
1071 new->sub_type
= sub_type
;
1072 new->peer
= rfd
->peer
;
1073 SET_FLAG(new->flags
, BGP_INFO_VALID
);
1074 new->attr
= new_attr
;
1075 new->uptime
= bgp_clock();
1077 /* save backref to rfapi handle */
1078 assert(bgp_info_extra_get(new));
1079 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1080 encode_label(label_val
, &new->extra
->label
[0]);
1084 if (VNC_DEBUG(VERBOSE
)) {
1085 vnc_zlog_debug_verbose("%s: printing BI", __func__
);
1086 rfapiPrintBi(NULL
, new);
1089 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1090 bgp_info_add(bn
, new);
1092 if (safi
== SAFI_MPLS_VPN
) {
1093 struct bgp_node
*prn
= NULL
;
1094 struct bgp_table
*table
= NULL
;
1096 prn
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1098 table
= (struct bgp_table
*)(prn
->info
);
1100 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1101 bgp
, prd
, table
, p
, new);
1103 bgp_unlock_node(prn
);
1104 encode_label(label_val
, &bn
->local_label
);
1107 bgp_unlock_node(bn
);
1108 bgp_process(bgp
, bn
, afi
, safi
);
1111 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
1112 __func__
, safi2str(safi
), buf
, bn
, buf2
);
1115 /* Loop back to import tables */
1116 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1117 sub_type
, &label_val
);
1118 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1122 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1127 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1128 struct rfapi_descriptor
*rfd
,
1129 uint32_t *pLifetime
)
1131 struct prefix_rd prd
;
1132 struct prefix pfx_vn
;
1134 uint32_t local_pref
= rfp_cost_to_localpref(0);
1136 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1140 * Construct route distinguisher = 0
1142 memset(&prd
, 0, sizeof(prd
));
1143 prd
.family
= AF_UNSPEC
;
1146 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1147 bgp
, /* which bgp instance */
1148 SAFI_ENCAP
, /* which SAFI */
1149 &pfx_vn
, /* prefix to advertise */
1150 &prd
, /* route distinguisher to use */
1151 &rfd
->un_addr
, /* nexthop */
1153 pLifetime
, /* max lifetime of child VPN routes */
1154 NULL
, /* no rfp options for ENCAP safi */
1155 NULL
, /* rfp un options */
1156 NULL
, /* rfp vn options */
1157 rfd
->rt_export_list
, NULL
, /* med */
1158 NULL
, /* label: default */
1159 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1163 /***********************************************************************
1164 * RFP processing behavior configuration
1165 ***********************************************************************/
1167 /*------------------------------------------
1168 * rfapi_rfp_set_configuration
1170 * This is used to change rfapi's processing behavior based on
1174 * rfp_start_val value returned by rfp_start
1175 * rfapi_rfp_cfg Pointer to configuration structure
1182 * ENXIO Unabled to locate configured BGP/VNC
1183 --------------------------------------------*/
1184 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1186 struct rfapi_rfp_cfg
*rcfg
;
1189 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1191 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1194 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1195 rcfg
->download_type
= new->download_type
;
1196 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1197 rcfg
->holddown_factor
= new->holddown_factor
;
1199 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1200 rcfg
->use_updated_response
= new->use_updated_response
;
1201 if (rcfg
->use_updated_response
)
1202 rfapiMonitorCallbacksOn(bgp
);
1204 rfapiMonitorCallbacksOff(bgp
);
1206 if (rcfg
->use_removes
!= new->use_removes
) {
1207 rcfg
->use_removes
= new->use_removes
;
1208 if (rcfg
->use_removes
)
1209 rfapiMonitorResponseRemovalOn(bgp
);
1211 rfapiMonitorResponseRemovalOff(bgp
);
1216 /*------------------------------------------
1217 * rfapi_rfp_set_cb_methods
1219 * Change registered callback functions for asynchronous notifications
1220 * from RFAPI to the RFP client.
1223 * rfp_start_val value returned by rfp_start
1224 * methods Pointer to struct rfapi_rfp_cb_methods containing
1225 * pointers to callback methods as described above
1229 * ENXIO BGP or VNC not configured
1230 *------------------------------------------*/
1231 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1232 struct rfapi_rfp_cb_methods
*methods
)
1237 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1245 h
->rfp_methods
= *methods
;
1250 /***********************************************************************
1252 ***********************************************************************/
1254 * Caller must supply an already-allocated rfd with the "caller"
1255 * fields already set (vn_addr, un_addr, callback, cookie)
1256 * The advertised_prefixes[] array elements should be NULL to
1257 * have this function set them to newly-allocated radix trees.
1259 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1260 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1264 if (h
->flags
& RFAPI_INCALLBACK
)
1268 * Fill in configured fields
1272 * If group's RD is specified as "auto", then fill in based
1273 * on NVE's VN address
1277 if (rfd
->rd
.family
== AF_UNIX
) {
1278 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1282 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1283 ? ecommunity_dup(rfg
->rt_export_list
)
1285 rfd
->response_lifetime
= rfg
->response_lifetime
;
1289 * Fill in BGP peer structure
1291 rfd
->peer
= peer_new(bgp
);
1292 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1293 bgp_sync_delete(rfd
->peer
); /* don't need these */
1296 * since this peer is not on the I/O thread, this lock is not strictly
1297 * necessary, but serves as a reminder to those who may meddle...
1299 pthread_mutex_lock(&rfd
->peer
->io_mtx
);
1301 // we don't need any I/O related facilities
1302 if (rfd
->peer
->ibuf
)
1303 stream_fifo_free(rfd
->peer
->ibuf
);
1304 if (rfd
->peer
->obuf
)
1305 stream_fifo_free(rfd
->peer
->obuf
);
1307 if (rfd
->peer
->ibuf_work
)
1308 ringbuf_del(rfd
->peer
->ibuf_work
);
1309 if (rfd
->peer
->obuf_work
)
1310 stream_free(rfd
->peer
->obuf_work
);
1312 rfd
->peer
->ibuf
= NULL
;
1313 rfd
->peer
->obuf
= NULL
;
1314 rfd
->peer
->obuf_work
= NULL
;
1315 rfd
->peer
->ibuf_work
= NULL
;
1317 pthread_mutex_unlock(&rfd
->peer
->io_mtx
);
1319 { /* base code assumes have valid host pointer */
1323 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1324 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
, BUFSIZ
);
1325 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1326 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
, BUFSIZ
);
1328 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1330 /* Mark peer as belonging to HD */
1331 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1334 * Set min prefix lifetime to max value so it will get set
1335 * upon first rfapi_register()
1337 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1340 * Allocate response tables if needed
1342 #define RFD_RTINIT_AFI(rh, ary, afi) \
1345 ary[afi] = agg_table_init(); \
1346 agg_set_table_info(ary[afi], rh); \
1350 #define RFD_RTINIT(rh, ary) \
1352 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1353 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1354 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1357 RFD_RTINIT(rfd
, rfd
->rib
);
1358 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1359 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1362 * Link to Import Table
1364 rfd
->import_table
= rfg
->rfapi_import_table
;
1365 rfd
->import_table
->refcount
+= 1;
1367 rfapiApInit(&rfd
->advertised
);
1370 * add this NVE descriptor to the list of NVEs in the NVE group
1373 rfg
->nves
= list_new();
1375 listnode_add(rfg
->nves
, rfd
);
1377 vnc_direct_bgp_add_nve(bgp
, rfd
);
1378 vnc_zebra_add_nve(bgp
, rfd
);
1383 /* moved from rfapi_register */
1384 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1385 struct rfapi_nve_group_cfg
*rfg
)
1387 struct rfapi
*h
= bgp
->rfapi
;
1388 char buf_vn
[BUFSIZ
];
1389 char buf_un
[BUFSIZ
];
1390 afi_t afi_vn
, afi_un
;
1391 struct prefix pfx_un
;
1392 struct agg_node
*rn
;
1395 rfapi_time(&rfd
->open_time
);
1397 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1398 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1400 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1401 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1403 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1404 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1406 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1408 listnode_add(&h
->descriptors
, rfd
);
1409 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1410 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1414 * attach to UN radix tree
1416 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1417 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1418 assert(afi_vn
&& afi_un
);
1419 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1421 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1423 rfd
->next
= rn
->info
;
1427 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1430 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1432 struct rfapi_vn_option
*head
= NULL
;
1433 struct rfapi_vn_option
*tail
= NULL
;
1434 struct rfapi_vn_option
*vo
= NULL
;
1436 for (vo
= orig
; vo
; vo
= vo
->next
) {
1437 struct rfapi_vn_option
*new;
1439 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1440 sizeof(struct rfapi_vn_option
));
1441 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1453 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1455 struct rfapi_un_option
*head
= NULL
;
1456 struct rfapi_un_option
*tail
= NULL
;
1457 struct rfapi_un_option
*uo
= NULL
;
1459 for (uo
= orig
; uo
; uo
= uo
->next
) {
1460 struct rfapi_un_option
*new;
1462 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1463 sizeof(struct rfapi_un_option
));
1464 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1476 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1478 struct bgp_tea_options
*head
= NULL
;
1479 struct bgp_tea_options
*tail
= NULL
;
1480 struct bgp_tea_options
*hop
= NULL
;
1482 for (hop
= orig
; hop
; hop
= hop
->next
) {
1483 struct bgp_tea_options
*new;
1485 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1486 sizeof(struct bgp_tea_options
));
1487 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1490 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1492 memcpy(new->value
, hop
->value
, hop
->length
);
1503 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1505 struct bgp_tea_options
*next
;
1511 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1514 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1520 void rfapiAdbFree(struct rfapi_adb
*adb
)
1522 XFREE(MTYPE_RFAPI_ADB
, adb
);
1526 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1527 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1528 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1532 struct prefix p_original
;
1533 struct agg_node
*rn
;
1534 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1535 struct bgp
*bgp
= rfd
->bgp
;
1536 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1537 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1539 int use_eth_resolution
= 0;
1540 struct rfapi_next_hop_entry
*i_nhe
;
1544 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1549 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1553 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1554 vnc_zlog_debug_verbose(
1555 "%s: Called during calback, returning EDEADLK",
1560 if (!is_valid_rfd(rfd
)) {
1561 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1566 rfd
->rsp_counter
++; /* dedup: identify this generation */
1567 rfd
->rsp_time
= rfapi_time(NULL
); /* response content dedup */
1568 rfd
->ftd_last_allowed_time
=
1570 - bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1573 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1577 /* per t/c Paul/Lou 151022 */
1578 if (!eth_is_0
|| l2o
->logical_net_id
) {
1579 use_eth_resolution
= 1;
1584 *ppNextHopEntry
= NULL
;
1587 * Save original target in prefix form. In case of L2-based queries,
1588 * p_original will be modified to reflect the L2 target
1590 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1592 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1593 /* convert query to 0/0 when full-table download is enabled */
1594 memset((char *)&p
, 0, sizeof(p
));
1595 p
.family
= target
->addr_family
;
1601 char buf
[PREFIX_STRLEN
];
1604 prefix2str(&p
, buf
, sizeof(buf
));
1605 vnc_zlog_debug_verbose("%s(rfd=%p, target=%s, ppNextHop=%p)",
1606 __func__
, rfd
, buf
, ppNextHopEntry
);
1608 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1609 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1610 vnc_zlog_debug_verbose(
1611 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1612 __func__
, rfd
->import_table
, s
);
1613 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1616 afi
= family2afi(p
.family
);
1619 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1620 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1621 self_vn_addr
= &rfd
->vn_addr
;
1624 if (use_eth_resolution
) {
1625 uint32_t logical_net_id
= l2o
->logical_net_id
;
1626 struct ecommunity
*l2com
;
1629 * fix up p_original to contain L2 address
1631 rfapiL2o2Qprefix(l2o
, &p_original
);
1633 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1634 bgp
, 1, logical_net_id
, l2o
->label
);
1636 uint8_t *v
= l2com
->val
;
1637 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1640 * Ethernet/L2-based lookup
1642 * Always returns IT node corresponding to route
1645 if (RFAPI_RFP_DOWNLOAD_FULL
1646 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1650 rn
= rfapiMonitorEthAdd(
1651 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1655 struct rfapi_ip_prefix rprefix
;
1657 memset(&rprefix
, 0, sizeof(rprefix
));
1658 rprefix
.prefix
.addr_family
= target
->addr_family
;
1659 if (target
->addr_family
== AF_INET
) {
1660 rprefix
.length
= 32;
1662 rprefix
.length
= 128;
1665 pNHE
= rfapiEthRouteTable2NextHopList(
1666 logical_net_id
, &rprefix
,
1667 rfd
->response_lifetime
, self_vn_addr
,
1668 rfd
->rib
[afi
], &p_original
);
1678 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1681 * If target address is 0, this request is special: means to
1682 * return ALL routes in the table
1684 * Monitors for All-Routes queries get put on a special list,
1685 * not in the VPN tree
1687 if (RFAPI_0_PREFIX(&p
)) {
1689 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1692 * Generate nexthop list for caller
1694 pNHE
= rfapiRouteTable2NextHopList(
1695 rfd
->import_table
->imported_vpn
[afi
],
1696 rfd
->response_lifetime
, self_vn_addr
,
1697 rfd
->rib
[afi
], &p_original
);
1702 agg_lock_node(rn
); /* so we can unlock below */
1705 * returns locked node. Don't unlock yet because the
1707 * might free it before we're done with it. This
1709 * could occur when rfapiMonitorGetAttachNode() returns
1711 * newly-created default node.
1713 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1719 agg_unlock_node(rn
);
1720 vnc_zlog_debug_verbose(
1721 "%s: VPN route not found, returning ENOENT", __func__
);
1725 if (VNC_DEBUG(RFAPI_QUERY
)) {
1726 rfapiShowImportTable(NULL
, "query",
1727 rfd
->import_table
->imported_vpn
[afi
], 1);
1730 if (use_eth_resolution
) {
1732 struct rfapi_ip_prefix rprefix
;
1734 memset(&rprefix
, 0, sizeof(rprefix
));
1735 rprefix
.prefix
.addr_family
= target
->addr_family
;
1736 if (target
->addr_family
== AF_INET
) {
1737 rprefix
.length
= 32;
1739 rprefix
.length
= 128;
1742 pNHE
= rfapiEthRouteNode2NextHopList(
1743 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1744 rfd
->rib
[afi
], &p_original
);
1749 * Generate answer to query
1751 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1752 self_vn_addr
, rfd
->rib
[afi
],
1756 agg_unlock_node(rn
);
1759 if (ppNextHopEntry
) {
1760 /* only count if caller gets it */
1761 ++bgp
->rfapi
->response_immediate_count
;
1765 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1771 * count nexthops for statistics
1773 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1774 ++rfd
->stat_count_nh_reachable
;
1777 if (ppNextHopEntry
) {
1778 *ppNextHopEntry
= pNHE
;
1780 rfapi_free_next_hop_list(pNHE
);
1783 vnc_zlog_debug_verbose("%s: success", __func__
);
1788 * support on-the-fly reassignment of an already-open nve to a new
1789 * nve-group in the event that its original nve-group is
1790 * administratively deleted.
1792 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1794 struct prefix pfx_vn
;
1795 struct prefix pfx_un
;
1796 struct rfapi_nve_group_cfg
*rfg
;
1798 struct rfapi_cfg
*hc
;
1805 hc
= bgp
->rfapi_cfg
;
1809 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1812 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1816 * Find the matching nve group config block
1818 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1824 * check nve group config block for required values
1826 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1831 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1837 * re-advertise registered routes, this time as part of new NVE-group
1839 rfapiApReadvertiseAll(bgp
, rfd
);
1842 * re-attach callbacks to import table
1844 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1845 rfapiMonitorAttachImportHd(rfd
);
1851 /*------------------------------------------
1854 * This function initializes a NVE record and associates it with
1855 * the specified VN and underlay network addresses
1858 * rfp_start_val value returned by rfp_start
1859 * vn NVE virtual network address
1861 * un NVE underlay network address
1863 * default_options Default options to use on registrations.
1864 * For now only tunnel type is supported.
1865 * May be overridden per-prefix in rfapi_register().
1866 * Caller owns (rfapi_open() does not free)
1868 * response_cb Pointer to next hop list update callback function or
1869 * NULL when no callbacks are desired.
1871 * userdata Passed to subsequent response_cb invocations.
1874 * response_lifetime The length of time that responses sent to this
1877 * pHandle pointer to location to store rfapi handle. The
1878 * handle must be passed on subsequent rfapi_ calls.
1883 * EEXIST NVE with this {vn,un} already open
1884 * ENOENT No matching nve group config
1885 * ENOMSG Matched nve group config was incomplete
1886 * ENXIO BGP or VNC not configured
1887 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1888 * but underlay network address is not IPv4
1889 * EDEADLK Called from within a callback procedure
1890 *------------------------------------------*/
1891 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1892 struct rfapi_ip_addr
*un
,
1893 struct rfapi_un_option
*default_options
,
1894 uint32_t *response_lifetime
,
1895 void *userdata
, /* callback cookie */
1896 rfapi_handle
*pHandle
)
1900 struct rfapi_descriptor
*rfd
;
1901 struct rfapi_cfg
*hc
;
1902 struct rfapi_nve_group_cfg
*rfg
;
1904 struct prefix pfx_vn
;
1905 struct prefix pfx_un
;
1908 rfapi_handle hh
= NULL
;
1909 int reusing_provisional
= 0;
1912 char buf
[2][INET_ADDRSTRLEN
];
1913 vnc_zlog_debug_verbose(
1914 "%s: VN=%s UN=%s", __func__
,
1915 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1916 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1922 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1930 hc
= bgp
->rfapi_cfg
;
1934 if (h
->flags
& RFAPI_INCALLBACK
)
1937 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1940 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1944 * already have a descriptor with VN and UN?
1946 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1948 * we might have set up a handle for static routes before
1949 * this NVE was opened. In that case, reuse the handle
1952 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1957 * reuse provisional descriptor
1960 reusing_provisional
= 1;
1964 * Find the matching nve group config block
1966 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1968 ++h
->stat
.count_unknown_nves
;
1970 char buf
[2][INET_ADDRSTRLEN
];
1971 zlog_notice("%s: no matching group VN=%s UN=%s",
1973 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1975 rfapiRfapiIpAddr2Str(un
, buf
[1],
1982 * check nve group config block for required values
1984 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1986 ++h
->stat
.count_unknown_nves
;
1991 * If group config specifies auto-rd assignment, check that
1992 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1993 * Check here so we don't need to unwind memory allocations, &c.
1995 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1996 && (vn
->addr_family
!= AF_INET6
)) {
1997 return EAFNOSUPPORT
;
2002 * reusing provisional rfd
2006 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
2007 sizeof(struct rfapi_descriptor
));
2012 if (default_options
) {
2013 struct rfapi_un_option
*p
;
2015 for (p
= default_options
; p
; p
= p
->next
) {
2016 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
2017 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
2019 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
2020 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
2026 * Fill in caller fields
2030 rfd
->cookie
= userdata
;
2032 if (!reusing_provisional
) {
2033 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
2035 * This can fail only if the VN address is IPv6 and the group
2036 * specified auto-assignment of RDs, which only works for v4,
2037 * and the check above should catch it.
2039 * Another failure possibility is that we were called
2040 * during an rfapi callback. Also checked above.
2045 if (response_lifetime
)
2046 *response_lifetime
= rfd
->response_lifetime
;
2052 * For use with debug functions
2054 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2055 rfapi_response_cb_t
*response_cb
)
2057 if (!is_valid_rfd(rfd
))
2059 rfd
->response_cb
= response_cb
;
2066 * Does almost all the work of rfapi_close, except:
2067 * 1. preserves the descriptor (doesn't free it)
2068 * 2. preserves the prefix query list (i.e., rfd->mon list)
2069 * 3. preserves the advertised prefix list (rfd->advertised)
2070 * 4. preserves the rib and rib_pending tables
2072 * The purpose of organizing it this way is to support on-the-fly
2073 * reassignment of an already-open nve to a new nve-group in the
2074 * event that its original nve-group is administratively deleted.
2076 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2079 struct prefix pfx_vn
;
2080 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2082 if (!is_valid_rfd(rfd
))
2085 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2086 assert(!rc
); /* should never have bad AF in stored vn address */
2089 * update exported routes to reflect disappearance of this NVE as
2092 vnc_direct_bgp_del_nve(bgp
, rfd
);
2093 vnc_zebra_del_nve(bgp
, rfd
);
2096 * unlink this HD's monitors from import table
2098 rfapiMonitorDetachImportHd(rfd
);
2101 * Unlink from Import Table
2102 * NB rfd->import_table will be NULL if we are closing a stale
2105 if (rfd
->import_table
)
2106 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2107 rfd
->import_table
= NULL
;
2110 * Construct route distinguisher
2112 memset(&prd
, 0, sizeof(prd
));
2114 prd
.family
= AF_UNSPEC
;
2120 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2121 &pfx_vn
, /* prefix being advertised */
2122 &prd
, /* route distinguisher to use (0 for ENCAP) */
2123 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2126 * Construct route distinguisher for VPN routes
2129 prd
.family
= AF_UNSPEC
;
2133 * find all VPN routes associated with this rfd and delete them, too
2135 rfapiApWithdrawAll(bgp
, rfd
);
2138 * remove this nve descriptor from the list of nves
2139 * associated with the nve group
2142 listnode_delete(rfd
->rfg
->nves
, rfd
);
2143 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2146 if (rfd
->rt_export_list
)
2147 ecommunity_free(&rfd
->rt_export_list
);
2148 rfd
->rt_export_list
= NULL
;
2151 * free peer structure (possibly delayed until its
2152 * refcount reaches zero)
2155 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2156 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2157 peer_delete(rfd
->peer
);
2164 int rfapi_close(void *handle
)
2166 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2168 struct agg_node
*node
;
2172 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2174 #if RFAPI_WHO_IS_CALLING_ME
2175 #ifdef HAVE_GLIBC_BACKTRACE
2176 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2178 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2183 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2184 syms
= backtrace_symbols(buf
, size
);
2185 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2187 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2203 if (!is_valid_rfd(rfd
))
2206 if (h
->flags
& RFAPI_INCALLBACK
) {
2208 * Queue these close requests for processing after callback
2211 if (!CHECK_FLAG(rfd
->flags
,
2212 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2213 work_queue_add(h
->deferred_close_q
, handle
);
2214 vnc_zlog_debug_verbose(
2215 "%s: added handle %p to deferred close queue",
2221 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2223 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2226 if (h
&& h
->rfp_methods
.close_cb
) {
2227 vnc_zlog_debug_verbose(
2228 "%s calling close callback rfd=%p", __func__
,
2232 * call the callback fairly early so that it can still
2236 * NB RFAPI_INCALLBACK is tested above, so if we reach
2238 * we are not already in the context of a callback.
2240 h
->flags
|= RFAPI_INCALLBACK
;
2241 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2242 h
->flags
&= ~RFAPI_INCALLBACK
;
2248 * Orphaned descriptors have already done this part, so do
2249 * only for non-orphaned descriptors.
2251 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2256 * Remove descriptor from UN index
2257 * (remove from chain at node)
2259 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2261 struct rfapi_descriptor
*hh
;
2263 if (node
->info
== rfd
) {
2264 node
->info
= rfd
->next
;
2267 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2268 if (hh
->next
== rfd
) {
2269 hh
->next
= rfd
->next
;
2274 agg_unlock_node(node
);
2278 * remove from descriptor list
2280 listnode_delete(&h
->descriptors
, rfd
);
2283 * Delete monitor list items and free monitor structures
2285 (void)rfapiMonitorDelHd(rfd
);
2288 * release advertised prefix data
2290 rfapiApRelease(&rfd
->advertised
);
2293 * Release RFP callback RIB
2300 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2301 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2307 * Reopen a nve descriptor. If the descriptor's NVE-group
2308 * does not exist (e.g., if it has been administratively removed),
2309 * reassignment to a new NVE-group is attempted.
2311 * If NVE-group reassignment fails, the descriptor becomes "stale"
2312 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2313 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2314 * on the descriptor will return ESTALE.
2316 * Reopening a descriptor is a potentially expensive operation, because
2317 * it involves withdrawing any routes advertised by the NVE, withdrawing
2318 * the NVE's route queries, and then re-adding them all after a new
2319 * NVE-group is assigned. There are also possible route-export affects
2320 * caused by deleting and then adding the NVE: advertised prefixes
2321 * and nexthop lists for exported routes can turn over.
2323 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2328 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2331 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2335 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2337 if (CHECK_FLAG(rfd
->flags
,
2338 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2339 && h
&& h
->rfp_methods
.close_cb
) {
2342 * NB RFAPI_INCALLBACK is tested above, so if we reach
2344 * we are not already in the context of a callback.
2346 h
->flags
|= RFAPI_INCALLBACK
;
2347 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2348 h
->flags
&= ~RFAPI_INCALLBACK
;
2355 /***********************************************************************
2357 ***********************************************************************/
2359 * Announce reachability to this prefix via the NVE
2361 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2362 uint32_t lifetime
, /* host byte order */
2363 struct rfapi_un_option
*options_un
,
2364 struct rfapi_vn_option
*options_vn
,
2365 rfapi_register_action action
)
2367 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2370 struct prefix
*pfx_ip
= NULL
;
2371 struct prefix_rd prd
;
2373 struct prefix pfx_mac_buf
;
2374 struct prefix
*pfx_mac
= NULL
;
2375 struct prefix pfx_vn_buf
;
2376 const char *action_str
= NULL
;
2377 uint32_t *label
= NULL
;
2378 struct rfapi_vn_option
*vo
;
2379 struct rfapi_l2address_option
*l2o
= NULL
;
2380 struct prefix_rd
*prd_override
= NULL
;
2383 case RFAPI_REGISTER_ADD
:
2386 case RFAPI_REGISTER_WITHDRAW
:
2387 action_str
= "withdraw";
2389 case RFAPI_REGISTER_KILL
:
2390 action_str
= "kill";
2398 * Inspect VN options
2400 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2401 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2402 l2o
= &vo
->v
.l2addr
;
2404 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2405 prd_override
= &vo
->v
.internal_rd
;
2409 /*********************************************************************
2411 *********************************************************************/
2414 * set <p> based on <prefix>
2416 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2418 afi
= family2afi(prefix
->prefix
.addr_family
);
2423 char buf
[PREFIX_STRLEN
];
2425 prefix2str(&p
, buf
, sizeof(buf
));
2426 vnc_zlog_debug_verbose(
2427 "%s(rfd=%p, pfx=%s, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2428 __func__
, rfd
, buf
, lifetime
, options_un
, options_vn
,
2433 * These tests come after the prefix conversion so that we can
2434 * print the prefix in a debug message before failing
2439 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2444 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2449 if (RFAPI_REGISTER_ADD
== action
) {
2450 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2452 vnc_zlog_debug_verbose(
2453 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2458 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2459 if (RFAPI_REGISTER_ADD
== action
) {
2460 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2462 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2467 if (!is_valid_rfd(rfd
)) {
2468 if (RFAPI_REGISTER_ADD
== action
) {
2469 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2471 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2477 * Is there a MAC address in this registration?
2479 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2480 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2481 pfx_mac
= &pfx_mac_buf
;
2485 * Is there an IP prefix in this registration?
2487 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2491 vnc_zlog_debug_verbose(
2492 "%s: missing mac addr that is required for host 0 pfx",
2494 if (RFAPI_REGISTER_ADD
== action
) {
2495 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2499 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2500 vnc_zlog_debug_verbose(
2501 "%s: handle has bad vn_addr: returning EBADF",
2503 if (RFAPI_REGISTER_ADD
== action
) {
2504 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2510 if (RFAPI_REGISTER_ADD
== action
) {
2511 ++bgp
->rfapi
->stat
.count_registrations
;
2515 * Figure out if this registration is missing an IP address
2519 * In RFAPI, we use prefixes in family AF_LINK to store
2520 * the MAC addresses. These prefixes are used for the
2521 * list of advertised prefixes and in the RFAPI import
2524 * In BGP proper, we use the prefix matching the NVE's
2525 * VN address with a host prefix-length (i.e., 32 or 128).
2528 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2529 && RFAPI_HOST_PREFIX(&p
)) {
2531 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2532 pfx_mac
= &pfx_mac_buf
;
2536 * Construct route distinguisher
2539 prd
= *prd_override
;
2541 memset(&prd
, 0, sizeof(prd
));
2543 prd
.family
= AF_UNSPEC
;
2545 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2546 if (l2o
->local_nve_id
2547 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2549 * If Local NVE ID is specified in message, use
2551 * (if no local default configured, also use it
2554 prd
.val
[1] = l2o
->local_nve_id
;
2556 if (rfd
->rfg
->l2rd
) {
2558 * locally-configured literal value
2560 prd
.val
[1] = rfd
->rfg
->l2rd
;
2563 * 0 means auto:vn, which means use LSB
2566 if (rfd
->vn_addr
.addr_family
2569 *(((char *)&rfd
->vn_addr
2575 *(((char *)&rfd
->vn_addr
2582 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2585 prd
.family
= AF_UNSPEC
;
2591 if (action
== RFAPI_REGISTER_WITHDRAW
2592 || action
== RFAPI_REGISTER_KILL
) {
2597 * withdraw previous advertisement
2600 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2602 : &pfx_vn_buf
, /* prefix being advertised */
2603 &prd
, /* route distinguisher (0 for ENCAP) */
2604 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2605 action
== RFAPI_REGISTER_KILL
);
2607 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2610 rfapiTunnelRouteAnnounce(
2611 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2617 uint32_t local_pref
;
2618 struct ecommunity
*rtlist
= NULL
;
2619 struct ecommunity_val ecom_value
;
2621 if (!rfapiApCount(rfd
)) {
2623 * make sure we advertise tunnel route upon adding the
2629 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2630 prefix
->cost
, l2o
)) {
2634 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2637 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2639 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2640 &rfd
->max_prefix_lifetime
);
2643 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2645 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2647 if (l2o
&& l2o
->label
)
2648 label
= &l2o
->label
;
2651 struct ecommunity
*l2com
= NULL
;
2654 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2655 bgp
, 1, l2o
->logical_net_id
, *label
);
2658 rtlist
= ecommunity_dup(l2com
);
2661 * If mac address is set, add an RT based on the
2664 memset((char *)&ecom_value
, 0,
2665 sizeof(ecom_value
));
2666 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2668 (l2o
->logical_net_id
>> 16) & 0xff;
2670 (l2o
->logical_net_id
>> 8) & 0xff;
2672 (l2o
->logical_net_id
>> 0) & 0xff;
2673 rtlist
= ecommunity_new();
2674 ecommunity_add_val(rtlist
, &ecom_value
);
2678 uint16_t val
= l2o
->tag_id
;
2679 memset((char *)&ecom_value
, 0,
2680 sizeof(ecom_value
));
2681 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2682 if (as
> BGP_AS_MAX
) {
2684 ECOMMUNITY_ENCODE_AS4
;
2685 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2686 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2687 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2688 ecom_value
.val
[5] = as
& 0xff;
2691 ECOMMUNITY_ENCODE_AS
;
2692 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2693 ecom_value
.val
[3] = as
& 0xff;
2695 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2696 ecom_value
.val
[7] = val
& 0xff;
2698 rtlist
= ecommunity_new();
2699 ecommunity_add_val(rtlist
, &ecom_value
);
2704 * advertise prefix via tunnel endpoint
2707 rfd
, /* rfapi descr, for export list & backref */
2708 bgp
, /* which bgp instance */
2709 SAFI_MPLS_VPN
, /* which SAFI */
2711 : &pfx_vn_buf
), /* prefix being advertised */
2712 &prd
, /* route distinguisher to use (0 for ENCAP) */
2713 &rfd
->vn_addr
, /* nexthop */
2715 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2716 NULL
, options_un
, /* rfapi un options */
2717 options_vn
, /* rfapi vn options */
2718 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2719 label
, /* label: default */
2720 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2723 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2726 vnc_zlog_debug_verbose("%s: success", __func__
);
2730 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2731 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2732 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2734 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2735 struct bgp
*bgp
= rfd
->bgp
;
2738 assert(ppNextHopEntry
);
2739 *ppNextHopEntry
= NULL
;
2741 if (bgp
&& bgp
->rfapi
) {
2742 bgp
->rfapi
->stat
.count_queries
++;
2746 if (bgp
&& bgp
->rfapi
)
2747 ++bgp
->rfapi
->stat
.count_queries_failed
;
2751 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2752 if (bgp
&& bgp
->rfapi
)
2753 ++bgp
->rfapi
->stat
.count_queries_failed
;
2758 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2762 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2763 struct bgp
*bgp
= rfd
->bgp
;
2769 rc
= rfapiRaddr2Qprefix(target
, &p
);
2772 if (!is_valid_rfd(rfd
))
2776 if (!bgp
|| !bgp
->rfapi
)
2779 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2782 rfapiMonitorDel(bgp
, rfd
, &p
);
2787 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2789 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2790 struct bgp
*bgp
= rfd
->bgp
;
2797 if (!is_valid_rfd(rfd
))
2801 if (!bgp
|| !bgp
->rfapi
)
2804 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2807 num
= rfapiMonitorDelHd(rfd
);
2815 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2817 struct rfapi_next_hop_entry
*nh
;
2818 struct rfapi_next_hop_entry
*next
;
2820 for (nh
= list
; nh
; nh
= next
) {
2822 rfapi_un_options_free(nh
->un_options
);
2823 nh
->un_options
= NULL
;
2824 rfapi_vn_options_free(nh
->vn_options
);
2825 nh
->vn_options
= NULL
;
2826 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2831 * NULL handle => return total count across all nves
2833 uint32_t rfapi_monitor_count(void *handle
)
2835 struct bgp
*bgp
= bgp_get_default();
2839 struct rfapi_descriptor
*rfd
=
2840 (struct rfapi_descriptor
*)handle
;
2841 count
= rfd
->monitor_count
;
2844 if (!bgp
|| !bgp
->rfapi
)
2847 count
= bgp
->rfapi
->monitor_count
;
2853 /***********************************************************************
2855 ***********************************************************************/
2857 DEFUN (debug_rfapi_show_nves
,
2858 debug_rfapi_show_nves_cmd
,
2859 "debug rfapi-dev show nves",
2863 "NVE Information\n")
2865 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2870 debug_rfapi_show_nves_vn_un
,
2871 debug_rfapi_show_nves_vn_un_cmd
,
2872 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2877 "Specify virtual network\n"
2878 "Specify underlay network interface\n"
2884 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2885 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2886 return CMD_WARNING_CONFIG_FAILED
;
2888 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2889 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2890 return CMD_WARNING_CONFIG_FAILED
;
2893 if (argv
[4]->arg
[0] == 'u') {
2894 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2896 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2902 * Note: this function does not flush vty output, so if it is called
2903 * with a stream pointing to a vty, the user will have to type something
2904 * before the callback output shows up
2906 static void test_nexthops_callback(
2907 // struct rfapi_ip_addr *target,
2908 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2910 void *stream
= userdata
;
2912 int (*fp
)(void *, const char *, ...);
2915 const char *vty_newline
;
2917 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2920 fp(out
, "Nexthops Callback, Target=(");
2921 // rfapiPrintRfapiIpAddr(stream, target);
2924 rfapiPrintNhl(stream
, next_hops
);
2928 rfapi_free_next_hop_list(next_hops
);
2931 DEFUN (debug_rfapi_open
,
2932 debug_rfapi_open_cmd
,
2933 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2937 "indicate vn addr follows\n"
2938 "virtual network interface IPv4 address\n"
2939 "virtual network interface IPv6 address\n"
2940 "indicate xt addr follows\n"
2941 "underlay network interface IPv4 address\n"
2942 "underlay network interface IPv6 address\n")
2944 struct rfapi_ip_addr vn
;
2945 struct rfapi_ip_addr un
;
2948 rfapi_handle handle
;
2953 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2959 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2962 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2963 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2965 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2968 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2970 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2976 DEFUN (debug_rfapi_close_vn_un
,
2977 debug_rfapi_close_vn_un_cmd
,
2978 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2982 "indicate vn addr follows\n"
2983 "virtual network interface IPv4 address\n"
2984 "virtual network interface IPv6 address\n"
2985 "indicate xt addr follows\n"
2986 "underlay network interface IPv4 address\n"
2987 "underlay network interface IPv6 address\n")
2989 struct rfapi_ip_addr vn
;
2990 struct rfapi_ip_addr un
;
2991 rfapi_handle handle
;
2997 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3004 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3008 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3009 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3010 argv
[4]->arg
, argv
[6]->arg
);
3011 return CMD_WARNING_CONFIG_FAILED
;
3014 rc
= rfapi_close(handle
);
3016 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
3021 DEFUN (debug_rfapi_close_rfd
,
3022 debug_rfapi_close_rfd_cmd
,
3023 "debug rfapi-dev close rfd HANDLE",
3027 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
3029 rfapi_handle handle
;
3031 char *endptr
= NULL
;
3033 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
3035 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
3036 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
3037 return CMD_WARNING_CONFIG_FAILED
;
3040 rc
= rfapi_close(handle
);
3042 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
3047 DEFUN (debug_rfapi_register_vn_un
,
3048 debug_rfapi_register_vn_un_cmd
,
3049 "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS [cost (0-255)]",
3053 "indicate vn addr follows\n"
3054 "virtual network IPv4 interface address\n"
3055 "virtual network IPv6 interface address\n"
3056 "indicate un addr follows\n"
3057 "underlay network IPv4 interface address\n"
3058 "underlay network IPv6 interface address\n"
3059 "indicate prefix follows\n"
3062 "indicate lifetime follows\n"
3064 "Cost (localpref = 255-cost)\n"
3067 struct rfapi_ip_addr vn
;
3068 struct rfapi_ip_addr un
;
3069 rfapi_handle handle
;
3072 struct rfapi_ip_prefix hpfx
;
3079 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3086 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3090 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3091 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3092 argv
[4]->arg
, argv
[6]->arg
);
3093 return CMD_WARNING_CONFIG_FAILED
;
3097 * Get prefix to advertise
3099 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3100 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3101 return CMD_WARNING_CONFIG_FAILED
;
3103 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3104 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3105 return CMD_WARNING_CONFIG_FAILED
;
3107 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3109 if (strmatch(argv
[10]->text
, "infinite")) {
3110 lifetime
= RFAPI_INFINITE_LIFETIME
;
3112 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3116 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3119 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3120 RFAPI_REGISTER_ADD
);
3122 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3129 DEFUN (debug_rfapi_register_vn_un_l2o
,
3130 debug_rfapi_register_vn_un_l2o_cmd
,
3131 "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS macaddr YY:YY:YY:YY:YY:YY lni (0-16777215)",
3135 "indicate vn addr follows\n"
3136 "virtual network IPv4 interface address\n"
3137 "virtual network IPv6 interface address\n"
3138 "indicate un addr follows\n"
3139 "underlay network IPv4 interface address\n"
3140 "underlay network IPv6 interface address\n"
3141 "indicate prefix follows\n"
3144 "indicate lifetime follows\n"
3145 "Seconds of lifetime\n"
3146 "indicate MAC address follows\n"
3148 "indicate lni follows\n"
3149 "lni value range\n")
3151 struct rfapi_ip_addr vn
;
3152 struct rfapi_ip_addr un
;
3153 rfapi_handle handle
;
3156 struct rfapi_ip_prefix hpfx
;
3158 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3159 struct rfapi_vn_option
*opt
= NULL
;
3165 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3172 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3176 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3177 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3178 argv
[4]->arg
, argv
[6]->arg
);
3179 return CMD_WARNING_CONFIG_FAILED
;
3183 * Get prefix to advertise
3185 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3186 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3187 return CMD_WARNING_CONFIG_FAILED
;
3189 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3190 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3191 return CMD_WARNING_CONFIG_FAILED
;
3193 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3195 if (strmatch(argv
[10]->text
, "infinite")) {
3196 lifetime
= RFAPI_INFINITE_LIFETIME
;
3198 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3201 /* L2 option parsing START */
3202 memset(optary
, 0, sizeof(optary
));
3203 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3204 strtoul(argv
[14]->arg
, NULL
, 10);
3205 if (rfapiStr2EthAddr(argv
[12]->arg
,
3206 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3207 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3208 return CMD_WARNING_CONFIG_FAILED
;
3210 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3212 optary
[opt_next
- 1].next
= optary
+ opt_next
;
3217 /* L2 option parsing END */
3220 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3221 RFAPI_REGISTER_ADD
);
3223 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3231 DEFUN (debug_rfapi_unregister_vn_un
,
3232 debug_rfapi_unregister_vn_un_cmd
,
3233 "debug rfapi-dev unregister vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> [kill]",
3237 "indicate vn addr follows\n"
3238 "virtual network interface address\n"
3239 "indicate xt addr follows\n"
3240 "underlay network interface address\n"
3241 "prefix to remove\n"
3242 "Remove without holddown")
3244 struct rfapi_ip_addr vn
;
3245 struct rfapi_ip_addr un
;
3246 rfapi_handle handle
;
3248 struct rfapi_ip_prefix hpfx
;
3254 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3261 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3265 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3266 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3267 argv
[4]->arg
, argv
[6]->arg
);
3268 return CMD_WARNING_CONFIG_FAILED
;
3272 * Get prefix to advertise
3274 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3275 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3276 return CMD_WARNING_CONFIG_FAILED
;
3278 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3279 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3280 return CMD_WARNING_CONFIG_FAILED
;
3282 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3284 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3286 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3291 DEFUN (debug_rfapi_query_vn_un
,
3292 debug_rfapi_query_vn_un_cmd
,
3293 "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> target <A.B.C.D|X:X::X:X>",
3297 "indicate vn addr follows\n"
3298 "virtual network interface IPv4 address\n"
3299 "virtual network interface IPv6 address\n"
3300 "indicate un addr follows\n"
3303 "indicate target follows\n"
3304 "target IPv4 address\n"
3305 "target IPv6 address\n")
3307 struct rfapi_ip_addr vn
;
3308 struct rfapi_ip_addr un
;
3309 struct rfapi_ip_addr target
;
3310 rfapi_handle handle
;
3312 struct rfapi_next_hop_entry
*pNextHopEntry
;
3317 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3324 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3331 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3335 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3336 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3337 argv
[4]->arg
, argv
[6]->arg
);
3338 return CMD_WARNING_CONFIG_FAILED
;
3342 * options parameter not used? Set to NULL for now
3344 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3347 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3351 * print nexthop list
3353 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3354 vty
); /* frees nh list! */
3361 DEFUN (debug_rfapi_query_vn_un_l2o
,
3362 debug_rfapi_query_vn_un_l2o_cmd
,
3363 "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lni LNI target YY:YY:YY:YY:YY:YY",
3367 "indicate vn addr follows\n"
3368 "virtual network interface IPv4 address\n"
3369 "virtual network interface IPv6 address\n"
3370 "indicate xt addr follows\n"
3371 "underlay network interface IPv4 address\n"
3372 "underlay network interface IPv6 address\n"
3373 "logical network ID follows\n"
3374 "logical network ID\n"
3375 "indicate target MAC addr follows\n"
3376 "target MAC addr\n")
3378 struct rfapi_ip_addr vn
;
3379 struct rfapi_ip_addr un
;
3385 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3392 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3395 vty_out(vty
, "%% This command is broken.\n");
3396 return CMD_WARNING_CONFIG_FAILED
;
3400 DEFUN (debug_rfapi_query_done_vn_un
,
3401 debug_rfapi_query_vn_un_done_cmd
,
3402 "debug rfapi-dev query done vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> target <A.B.C.D|X:X::X:X>",
3405 "rfapi_query_done\n"
3406 "rfapi_query_done\n"
3407 "indicate vn addr follows\n"
3408 "virtual network interface IPv4 address\n"
3409 "virtual network interface IPv6 address\n"
3410 "indicate xt addr follows\n"
3411 "underlay network interface IPv4 address\n"
3412 "underlay network interface IPv6 address\n"
3413 "indicate target follows\n"
3414 "Target IPv4 address\n"
3415 "Target IPv6 address\n")
3417 struct rfapi_ip_addr vn
;
3418 struct rfapi_ip_addr un
;
3419 struct rfapi_ip_addr target
;
3420 rfapi_handle handle
;
3426 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3433 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3440 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3444 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3445 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3446 argv
[5]->arg
, argv
[7]->arg
);
3447 return CMD_WARNING_CONFIG_FAILED
;
3451 * options parameter not used? Set to NULL for now
3453 rc
= rfapi_query_done(handle
, &target
);
3455 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3460 DEFUN (debug_rfapi_show_import
,
3461 debug_rfapi_show_import_cmd
,
3462 "debug rfapi-dev show import",
3470 struct rfapi_import_table
*it
;
3475 * Show all import tables
3478 bgp
= bgp_get_default(); /* assume 1 instance for now */
3480 vty_out(vty
, "No BGP instance\n");
3481 return CMD_WARNING_CONFIG_FAILED
;
3486 vty_out(vty
, "No RFAPI instance\n");
3487 return CMD_WARNING_CONFIG_FAILED
;
3491 * Iterate over all import tables; do a filtered import
3492 * for the afi/safi combination
3496 for (it
= h
->imports
; it
; it
= it
->next
) {
3497 s
= ecommunity_ecom2str(it
->rt_import_list
,
3498 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3499 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3500 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3502 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3504 rfapiShowImportTable(vty
, "IP ENCAP",
3505 it
->imported_encap
[AFI_IP
], 0);
3506 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3508 rfapiShowImportTable(vty
, "IP6 ENCAP",
3509 it
->imported_encap
[AFI_IP6
], 0);
3512 if (h
->import_mac
) {
3513 void *cursor
= NULL
;
3515 uintptr_t lni_as_ptr
;
3519 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3520 (void **)&it
, &cursor
);
3522 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3523 (void **)&it
, &cursor
)) {
3525 if (it
->imported_vpn
[AFI_L2VPN
]) {
3529 "\nLNI-based Ethernet Tables:\n");
3532 snprintf(buf
, BUFSIZ
, "L2VPN LNI=%u", lni
);
3533 rfapiShowImportTable(
3534 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3540 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3541 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3546 DEFUN (debug_rfapi_show_import_vn_un
,
3547 debug_rfapi_show_import_vn_un_cmd
,
3548 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3553 "indicate vn addr follows\n"
3554 "virtual network interface IPv4 address\n"
3555 "virtual network interface IPv6 address\n"
3556 "indicate xt addr follows\n"
3557 "underlay network interface IPv4 address\n"
3558 "underlay network interface IPv6 address\n")
3560 struct rfapi_ip_addr vn
;
3561 struct rfapi_ip_addr un
;
3562 rfapi_handle handle
;
3564 struct rfapi_descriptor
*rfd
;
3569 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3576 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3580 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3581 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3582 argv
[5]->arg
, argv
[7]->arg
);
3583 return CMD_WARNING_CONFIG_FAILED
;
3586 rfd
= (struct rfapi_descriptor
*)handle
;
3588 rfapiShowImportTable(vty
, "IP VPN",
3589 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3590 rfapiShowImportTable(vty
, "IP ENCAP",
3591 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3592 rfapiShowImportTable(vty
, "IP6 VPN",
3593 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3594 rfapiShowImportTable(vty
, "IP6 ENCAP",
3595 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3600 DEFUN (debug_rfapi_response_omit_self
,
3601 debug_rfapi_response_omit_self_cmd
,
3602 "debug rfapi-dev response-omit-self <on|off>",
3605 "Omit self in RFP responses\n"
3606 "filter out self from responses\n" "leave self in responses\n")
3608 struct bgp
*bgp
= bgp_get_default();
3611 vty_out(vty
, "No BGP process is configured\n");
3612 return CMD_WARNING_CONFIG_FAILED
;
3614 if (!bgp
->rfapi_cfg
) {
3615 vty_out(vty
, "VNC not configured\n");
3616 return CMD_WARNING_CONFIG_FAILED
;
3619 if (strmatch(argv
[3]->text
, "on"))
3620 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3621 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3623 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3624 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3630 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3632 #include "lib/skiplist.h"
3633 DEFUN (skiplist_test_cli
,
3634 skiplist_test_cli_cmd
,
3636 "skiplist command\n"
3644 DEFUN (skiplist_debug_cli
,
3645 skiplist_debug_cli_cmd
,
3647 "skiplist command\n"
3650 skiplist_debug(vty
, NULL
);
3654 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3656 void rfapi_init(void)
3658 bgp_rfapi_cfg_init();
3661 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3662 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3664 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3665 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3666 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3667 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3668 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3669 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3670 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3671 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3673 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3675 /* Need the following show commands for gpz test scripts */
3676 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3677 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3678 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3680 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3681 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3682 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3689 static void rfapi_print_exported(struct bgp
*bgp
)
3691 struct bgp_node
*rdn
;
3692 struct bgp_node
*rn
;
3693 struct bgp_info
*bi
;
3698 for (rdn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); rdn
;
3699 rdn
= bgp_route_next(rdn
)) {
3702 fprintf(stderr
, "%s: vpn rdn=%p\n", __func__
, rdn
);
3703 for (rn
= bgp_table_top(rdn
->info
); rn
;
3704 rn
= bgp_route_next(rn
)) {
3707 fprintf(stderr
, "%s: rn=%p\n", __func__
, rn
);
3708 for (bi
= rn
->info
; bi
; bi
= bi
->next
) {
3709 rfapiPrintBi((void *)2, bi
); /* 2 => stderr */
3713 for (rdn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); rdn
;
3714 rdn
= bgp_route_next(rdn
)) {
3717 fprintf(stderr
, "%s: encap rdn=%p\n", __func__
, rdn
);
3718 for (rn
= bgp_table_top(rdn
->info
); rn
;
3719 rn
= bgp_route_next(rn
)) {
3722 fprintf(stderr
, "%s: rn=%p\n", __func__
, rn
);
3723 for (bi
= rn
->info
; bi
; bi
= bi
->next
) {
3724 rfapiPrintBi((void *)2, bi
); /* 2 => stderr */
3729 #endif /* defined(DEBUG_RFAPI) */
3732 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3734 void rfapi_delete(struct bgp
*bgp
)
3736 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3739 * This clears queries and registered routes, and closes nves
3742 rfp_clear_vnc_nve_all();
3743 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3744 bgp
->rfapi_cfg
= NULL
;
3745 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3749 * show what's left in the BGP MPLSVPN RIB
3751 rfapi_print_exported(bgp
);
3755 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3757 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3758 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3759 vnc_zlog_debug_verbose(
3760 "%s: can't auto-assign RD, VN addr family is not IPv4"
3763 return EAFNOSUPPORT
;
3765 rd
->family
= AF_UNSPEC
;
3767 rd
->val
[1] = RD_TYPE_IP
;
3768 if (vn
->addr_family
== AF_INET
) {
3769 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3770 } else { /* is v6 */
3771 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3772 4); /* low order 4 bytes */
3775 char buf
[RD_ADDRSTRLEN
];
3777 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3778 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3783 /*------------------------------------------
3784 * rfapi_bgp_lookup_by_rfp
3786 * Find bgp instance pointer based on value returned by rfp_start
3789 * rfp_start_val value returned by rfp_startor
3790 * NULL (=get default instance)
3796 * bgp bgp instance pointer
3799 --------------------------------------------*/
3800 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3802 struct bgp
*bgp
= NULL
;
3803 struct listnode
*node
, *nnode
;
3805 if (rfp_start_val
== NULL
)
3806 bgp
= bgp_get_default();
3808 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3809 if (bgp
->rfapi
!= NULL
3810 && bgp
->rfapi
->rfp
== rfp_start_val
)
3815 /*------------------------------------------
3816 * rfapi_get_rfp_start_val_by_bgp
3818 * Find bgp instance pointer based on value returned by rfp_start
3821 * bgp bgp instance pointer
3830 --------------------------------------------*/
3831 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3833 if (!bgp
|| !bgp
->rfapi
)
3835 return bgp
->rfapi
->rfp
;
3838 /***********************************************************************
3839 * RFP group specific configuration
3840 ***********************************************************************/
3841 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3845 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3846 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3847 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3850 return rfc
->default_rfp_cfg
;
3853 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3857 struct rfapi_nve_group_cfg
*rfg
=
3858 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3860 /* make sure group is still in list */
3861 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3862 /* Not in list anymore */
3863 vty_out(vty
, "Current NVE group no longer exists\n");
3867 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3868 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3869 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3872 return rfg
->rfp_cfg
;
3875 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3879 struct rfapi_l2_group_cfg
*rfg
=
3880 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3882 /* make sure group is still in list */
3883 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3884 /* Not in list anymore */
3885 vty_out(vty
, "Current L2 group no longer exists\n");
3888 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3889 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3890 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3893 return rfg
->rfp_cfg
;
3896 /*------------------------------------------
3897 * rfapi_rfp_init_group_config_ptr_vty
3899 * This is used to init or return a previously init'ed group specific
3900 * configuration pointer. Group is identified by vty context.
3901 * NOTE: size is ignored when a previously init'ed value is returned.
3902 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3903 * bgp restart or shutdown.
3906 * rfp_start_val value returned by rfp_start
3908 * vty quagga vty context
3909 * size number of bytes to allocation
3915 * rfp_cfg_group NULL or Pointer to configuration structure
3916 --------------------------------------------*/
3917 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3918 rfapi_rfp_cfg_group_type type
,
3919 struct vty
*vty
, uint32_t size
)
3924 if (rfp_start_val
== NULL
|| vty
== NULL
)
3927 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3928 if (!bgp
|| !bgp
->rfapi_cfg
)
3932 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3933 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3936 case RFAPI_RFP_CFG_GROUP_NVE
:
3937 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3940 case RFAPI_RFP_CFG_GROUP_L2
:
3941 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3945 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3947 /* should never happen */
3948 assert("Unknown type" == NULL
);
3954 /*------------------------------------------
3955 * rfapi_rfp_get_group_config_ptr_vty
3957 * This is used to get group specific configuration pointer.
3958 * Group is identified by type and vty context.
3959 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3960 * bgp restart or shutdown.
3963 * rfp_start_val value returned by rfp_start
3965 * vty quagga vty context
3971 * rfp_cfg_group Pointer to configuration structure
3972 --------------------------------------------*/
3973 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3974 rfapi_rfp_cfg_group_type type
,
3977 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3981 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3983 rfp_group_config_search_cb_t
*search_cb
)
3985 struct rfapi_nve_group_cfg
*rfg
;
3986 struct listnode
*node
;
3988 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3989 if (!strcmp(rfg
->name
, name
) && /* name match */
3990 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3991 return rfg
->rfp_cfg
;
3997 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3999 rfp_group_config_search_cb_t
*search_cb
)
4001 struct rfapi_l2_group_cfg
*rfg
;
4002 struct listnode
*node
;
4004 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
4005 if (!strcmp(rfg
->name
, name
) && /* name match */
4006 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
4007 return rfg
->rfp_cfg
;
4012 /*------------------------------------------
4013 * rfapi_rfp_get_group_config_ptr_name
4015 * This is used to get group specific configuration pointer.
4016 * Group is identified by type and name context.
4017 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4018 * bgp restart or shutdown.
4021 * rfp_start_val value returned by rfp_start
4024 * criteria RFAPI caller provided serach criteria
4025 * search_cb optional rfp_group_config_search_cb_t
4031 * rfp_cfg_group Pointer to configuration structure
4032 --------------------------------------------*/
4033 void *rfapi_rfp_get_group_config_ptr_name(
4034 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
4035 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
4040 if (rfp_start_val
== NULL
|| name
== NULL
)
4043 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4044 if (!bgp
|| !bgp
->rfapi_cfg
)
4048 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4049 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4051 case RFAPI_RFP_CFG_GROUP_NVE
:
4052 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4053 criteria
, search_cb
);
4055 case RFAPI_RFP_CFG_GROUP_L2
:
4056 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4057 criteria
, search_cb
);
4060 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4062 /* should never happen */
4063 assert("Unknown type" == NULL
);
4069 /*------------------------------------------
4070 * rfapi_rfp_get_l2_group_config_ptr_lni
4072 * This is used to get group specific configuration pointer.
4073 * Group is identified by type and logical network identifier.
4074 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4075 * bgp restart or shutdown.
4078 * rfp_start_val value returned by rfp_start
4080 * logical_net_id group logical network identifier
4081 * criteria RFAPI caller provided serach criteria
4082 * search_cb optional rfp_group_config_search_cb_t
4088 * rfp_cfg_group Pointer to configuration structure
4089 --------------------------------------------*/
4091 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4092 uint32_t logical_net_id
, void *criteria
,
4093 rfp_group_config_search_cb_t
*search_cb
)
4096 struct rfapi_l2_group_cfg
*rfg
;
4097 struct listnode
*node
;
4099 if (rfp_start_val
== NULL
)
4102 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4103 if (!bgp
|| !bgp
->rfapi_cfg
)
4106 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4107 if (rfg
->logical_net_id
== logical_net_id
4108 && (search_cb
== NULL
4109 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4110 if (rfg
->rfp_cfg
== NULL
)
4111 vnc_zlog_debug_verbose(
4112 "%s: returning rfp group config for lni=0",
4114 return rfg
->rfp_cfg
;