1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright 2009-2016, LabN Consulting, L.L.C.
9 #include "lib/prefix.h"
10 #include "lib/agg_table.h"
12 #include "lib/memory.h"
13 #include "lib/routemap.h"
15 #include "lib/linklist.h"
16 #include "lib/command.h"
17 #include "lib/stream.h"
18 #include "lib/ringbuf.h"
19 #include "lib/lib_errors.h"
21 #include "bgpd/bgpd.h"
22 #include "bgpd/bgp_ecommunity.h"
23 #include "bgpd/bgp_attr.h"
25 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
26 #include "bgpd/rfapi/rfapi.h"
27 #include "bgpd/rfapi/rfapi_backend.h"
29 #include "bgpd/bgp_route.h"
30 #include "bgpd/bgp_mplsvpn.h"
31 #include "bgpd/bgp_aspath.h"
32 #include "bgpd/bgp_advertise.h"
33 #include "bgpd/bgp_vnc_types.h"
34 #include "bgpd/bgp_zebra.h"
36 #include "bgpd/rfapi/rfapi_import.h"
37 #include "bgpd/rfapi/rfapi_private.h"
38 #include "bgpd/rfapi/rfapi_monitor.h"
39 #include "bgpd/rfapi/rfapi_vty.h"
40 #include "bgpd/rfapi/vnc_export_bgp.h"
41 #include "bgpd/rfapi/vnc_export_bgp_p.h"
42 #include "bgpd/rfapi/vnc_zebra.h"
43 #include "bgpd/rfapi/vnc_import_bgp.h"
44 #include "bgpd/rfapi/rfapi_rib.h"
45 #include "bgpd/rfapi/rfapi_ap.h"
46 #include "bgpd/rfapi/rfapi_encap_tlv.h"
47 #include "bgpd/rfapi/vnc_debug.h"
49 #ifdef HAVE_GLIBC_BACKTRACE
50 /* for backtrace and friends */
52 #endif /* HAVE_GLIBC_BACKTRACE */
54 #define DEBUG_CLEANUP 0
56 struct ethaddr rfapi_ethaddr0
= {{0}};
58 #define DEBUG_RFAPI_STR "RF API debugging/testing command\n"
60 const char *rfapi_error_str(int code
)
66 return "BGP or VNC not configured";
70 return "Handle already open";
72 return "Incomplete configuration";
74 return "Invalid address family";
76 return "Called from within a callback procedure";
78 return "Invalid handle";
80 return "Invalid argument";
82 return "Stale descriptor";
84 return "Unknown error";
88 /*------------------------------------------
89 * rfapi_get_response_lifetime_default
91 * Returns the default lifetime for a response.
92 * rfp_start_val value returned by rfp_start or
93 * NULL (=use default instance)
100 * return value: The bgp instance default lifetime for a response.
101 --------------------------------------------*/
102 int rfapi_get_response_lifetime_default(void *rfp_start_val
)
104 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
106 return bgp
->rfapi_cfg
->default_response_lifetime
;
107 return BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
;
110 /*------------------------------------------
111 * rfapi_is_vnc_configured
113 * Returns if VNC is configured
116 * rfp_start_val value returned by rfp_start or
117 * NULL (=use default instance)
121 * return value: If VNC is configured for the bgpd instance
123 * ENXIO VNC not configured
124 --------------------------------------------*/
125 int rfapi_is_vnc_configured(void *rfp_start_val
)
127 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
128 if (bgp_rfapi_is_vnc_configured(bgp
) == 0)
134 /*------------------------------------------
137 * Get the virtual network address used by an NVE based on it's RFD
140 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
145 * vn NVE virtual network address
146 *------------------------------------------*/
147 struct rfapi_ip_addr
*rfapi_get_vn_addr(void *rfd
)
149 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
150 return &rrfd
->vn_addr
;
153 /*------------------------------------------
156 * Get the underlay network address used by an NVE based on it's RFD
159 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
164 * un NVE underlay network address
165 *------------------------------------------*/
166 struct rfapi_ip_addr
*rfapi_get_un_addr(void *rfd
)
168 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
169 return &rrfd
->un_addr
;
172 int rfapi_ip_addr_cmp(struct rfapi_ip_addr
*a1
, struct rfapi_ip_addr
*a2
)
174 if (a1
->addr_family
!= a2
->addr_family
)
175 return a1
->addr_family
- a2
->addr_family
;
177 if (a1
->addr_family
== AF_INET
) {
178 return IPV4_ADDR_CMP(&a1
->addr
.v4
, &a2
->addr
.v4
);
181 if (a1
->addr_family
== AF_INET6
) {
182 return IPV6_ADDR_CMP(&a1
->addr
.v6
, &a2
->addr
.v6
);
190 static int rfapi_find_node(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
191 struct rfapi_ip_addr
*un_addr
,
192 struct agg_node
**node
)
209 afi
= family2afi(un_addr
->addr_family
);
214 if ((rc
= rfapiRaddr2Qprefix(un_addr
, &p
)))
217 rn
= agg_node_lookup(h
->un
[afi
], &p
);
230 int rfapi_find_rfd(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
231 struct rfapi_ip_addr
*un_addr
, struct rfapi_descriptor
**rfd
)
236 rc
= rfapi_find_node(bgp
, vn_addr
, un_addr
, &rn
);
241 for (*rfd
= (struct rfapi_descriptor
*)(rn
->info
); *rfd
;
242 *rfd
= (*rfd
)->next
) {
243 if (!rfapi_ip_addr_cmp(&(*rfd
)->vn_addr
, vn_addr
))
253 /*------------------------------------------
257 * un underlay network address
258 * vn virtual network address
261 * pHandle pointer to location to store handle
265 * ENOENT no matching handle
266 * ENXIO BGP or VNC not configured
267 *------------------------------------------*/
268 static int rfapi_find_handle(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
269 struct rfapi_ip_addr
*un_addr
,
270 rfapi_handle
*handle
)
272 struct rfapi_descriptor
**rfd
;
274 rfd
= (struct rfapi_descriptor
**)handle
;
276 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
279 static int rfapi_find_handle_vty(struct vty
*vty
, struct rfapi_ip_addr
*vn_addr
,
280 struct rfapi_ip_addr
*un_addr
,
281 rfapi_handle
*handle
)
284 struct rfapi_descriptor
**rfd
;
286 bgp
= bgp_get_default(); /* assume 1 instance for now */
288 rfd
= (struct rfapi_descriptor
**)handle
;
290 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
293 static int is_valid_rfd(struct rfapi_descriptor
*rfd
)
297 if (!rfd
|| rfd
->bgp
== NULL
)
302 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
305 if (rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &hh
))
315 * check status of descriptor
317 int rfapi_check(void *handle
)
319 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
323 if (!rfd
|| rfd
->bgp
== NULL
)
328 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
331 if ((rc
= rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
,
345 void del_vnc_route(struct rfapi_descriptor
*rfd
,
346 struct peer
*peer
, /* rfd->peer for RFP regs */
347 struct bgp
*bgp
, safi_t safi
, const struct prefix
*p
,
348 struct prefix_rd
*prd
, uint8_t type
, uint8_t sub_type
,
349 struct rfapi_nexthop
*lnh
, int kill
)
351 afi_t afi
; /* of the VN address */
353 struct bgp_path_info
*bpi
;
354 struct prefix_rd prd0
;
356 afi
= family2afi(p
->family
);
357 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
359 if (safi
== SAFI_ENCAP
) {
360 memset(&prd0
, 0, sizeof(prd0
));
361 prd0
.family
= AF_UNSPEC
;
365 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
367 vnc_zlog_debug_verbose(
368 "%s: peer=%p, prefix=%pFX, prd=%pRDP afi=%d, safi=%d bn=%p, bn->info=%p",
369 __func__
, peer
, p
, prd
, afi
, safi
, bn
,
370 (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
));
372 for (bpi
= (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
); bpi
;
375 vnc_zlog_debug_verbose(
376 "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64
,
377 __func__
, bpi
, bpi
->peer
, bpi
->type
, bpi
->sub_type
,
378 (bpi
->extra
? bpi
->extra
->vnc
.export
.rfapi_handle
380 CHECK_FLAG(bpi
->attr
->flag
,
381 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)
382 ? bpi
->attr
->local_pref
: 0));
384 if (bpi
->peer
== peer
&& bpi
->type
== type
385 && bpi
->sub_type
== sub_type
&& bpi
->extra
386 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
388 vnc_zlog_debug_verbose("%s: matched it", __func__
);
396 * lnh set means to JUST delete the local nexthop from this
397 * route. Leave the route itself in place.
398 * TBD add return code reporting of success/failure
400 if (!bpi
|| !bpi
->extra
401 || !bpi
->extra
->vnc
.export
.local_nexthops
) {
405 vnc_zlog_debug_verbose(
406 "%s: lnh list already empty at prefix %pFX",
414 struct listnode
*node
;
415 struct rfapi_nexthop
*pLnh
= NULL
;
417 for (ALL_LIST_ELEMENTS_RO(bpi
->extra
->vnc
.export
.local_nexthops
,
420 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
426 listnode_delete(bpi
->extra
->vnc
.export
.local_nexthops
,
429 /* silly rabbit, listnode_delete doesn't invoke
430 * list->del on data */
431 rfapi_nexthop_free(pLnh
);
433 vnc_zlog_debug_verbose("%s: desired lnh not found %pFX",
440 * loop back to import tables
441 * Do this before removing from BGP RIB because rfapiProcessWithdraw
444 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
447 vnc_zlog_debug_verbose(
448 "%s: Found route (safi=%d) to delete at prefix %pFX",
451 if (safi
== SAFI_MPLS_VPN
) {
452 struct bgp_dest
*pdest
= NULL
;
453 struct bgp_table
*table
= NULL
;
455 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
456 (struct prefix
*)prd
);
457 table
= bgp_dest_get_bgp_table_info(pdest
);
459 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
460 bgp
, prd
, table
, p
, bpi
);
461 bgp_dest_unlock_node(pdest
);
465 * Delete local_nexthops list
467 if (bpi
->extra
&& bpi
->extra
->vnc
.export
.local_nexthops
)
468 list_delete(&bpi
->extra
->vnc
.export
.local_nexthops
);
470 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
471 bgp_path_info_delete(bn
, bpi
);
472 bgp_process(bgp
, bn
, afi
, safi
);
474 vnc_zlog_debug_verbose(
475 "%s: Couldn't find route (safi=%d) at prefix %pFX",
479 bgp_dest_unlock_node(bn
);
482 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
484 struct rfapi_nexthop
*new =
485 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
491 void rfapi_nexthop_free(void *p
)
493 struct rfapi_nexthop
*goner
= p
;
494 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
497 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
499 struct rfapi_vn_option
*p
;
500 struct rfapi_vn_option
*head
= NULL
;
501 struct rfapi_vn_option
*tail
= NULL
;
503 for (p
= existing
; p
; p
= p
->next
) {
504 struct rfapi_vn_option
*new;
506 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
507 sizeof(struct rfapi_vn_option
));
520 void rfapi_un_options_free(struct rfapi_un_option
*p
)
522 struct rfapi_un_option
*next
;
526 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
531 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
533 struct rfapi_vn_option
*next
;
537 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
542 /* Based on bgp_redistribute_add() */
543 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
544 struct bgp
*bgp
, int safi
, const struct prefix
*p
,
545 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
546 uint32_t *local_pref
,
547 uint32_t *lifetime
, /* NULL => dont send lifetime */
548 struct bgp_tea_options
*rfp_options
,
549 struct rfapi_un_option
*options_un
,
550 struct rfapi_vn_option
*options_vn
,
551 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
552 uint32_t *med
, /* NULL => don't set med */
553 uint32_t *label
, /* low order 3 bytes */
554 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
557 afi_t afi
; /* of the VN address */
558 struct bgp_path_info
*new;
559 struct bgp_path_info
*bpi
;
562 struct attr attr
= {0};
563 struct attr
*new_attr
;
566 struct bgp_attr_encap_subtlv
*encaptlv
;
567 char buf
[PREFIX_STRLEN
];
569 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
570 struct rfapi_vn_option
*vo
;
571 struct rfapi_l2address_option
*l2o
= NULL
;
572 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
574 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
575 struct bgp_redist
*red
;
577 if (safi
== SAFI_ENCAP
578 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
581 * Encap mode not enabled. UN addresses will be communicated
582 * via VNC Tunnel subtlv instead.
584 vnc_zlog_debug_verbose(
585 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
590 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
591 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
593 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
594 l2o
= NULL
; /* not MAC resolution */
596 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
597 lnh
= &vo
->v
.local_nexthop
;
604 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
606 afi
= family2afi(p
->family
);
607 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
609 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
612 /* Make default attribute. Produces already-interned attr.aspath */
613 /* Cripes, the memory management of attributes is byzantine */
615 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_INCOMPLETE
);
620 * extra: dynamically allocated, owned by attr
621 * aspath: points to interned hash from aspath hash table
626 * Route-specific un_options get added to the VPN SAFI
627 * advertisement tunnel encap attribute. (the per-NVE
628 * "default" un_options are put into the 1-per-NVE ENCAP
629 * SAFI advertisement). The VPN SAFI also gets the
630 * default un_options if there are no route-specific options.
633 struct rfapi_un_option
*uo
;
635 for (uo
= options_un
; uo
; uo
= uo
->next
) {
636 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
637 TunnelType
= rfapi_tunneltype_option_to_tlv(
638 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
645 * These are the NVE-specific "default" un_options which are
646 * put into the 1-per-NVE ENCAP advertisement.
648 if (rfd
->default_tunneltype_option
.type
) {
649 TunnelType
= rfapi_tunneltype_option_to_tlv(
650 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
652 } else /* create default for local addse */
653 if (type
== ZEBRA_ROUTE_BGP
654 && sub_type
== BGP_ROUTE_RFP
)
655 TunnelType
= rfapi_tunneltype_option_to_tlv(
656 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
659 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
660 if (safi
== SAFI_ENCAP
) {
661 /* Encap SAFI not used with MPLS */
662 vnc_zlog_debug_verbose(
663 "%s: mpls tunnel type, encap safi omitted",
665 aspath_unintern(&attr
.aspath
); /* Unintern original. */
671 attr
.local_pref
= *local_pref
;
672 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
677 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
680 /* override default weight assigned by bgp_attr_default_set() */
681 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
684 * NB: ticket 81: do not reset attr.aspath here because it would
685 * cause iBGP peers to drop route
689 * Set originator ID for routes imported from BGP directly.
690 * These routes could be synthetic, and therefore could
691 * reuse the peer pointers of the routes they are derived
692 * from. Setting the originator ID to "us" prevents the
693 * wrong originator ID from being sent when this route is
694 * sent from a route reflector.
696 if (type
== ZEBRA_ROUTE_BGP_DIRECT
697 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
698 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
699 attr
.originator_id
= bgp
->router_id
;
703 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
704 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
707 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
708 sizeof(struct bgp_attr_encap_subtlv
) + 4);
710 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
711 encaptlv
->length
= 4;
712 lt
= htonl(*lifetime
);
713 memcpy(encaptlv
->value
, <
, 4);
714 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
715 vnc_zlog_debug_verbose(
716 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
720 /* add rfp options to vnc attr */
723 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
724 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
725 bgp_attr_get_vnc_subtlvs(&attr
);
727 * this flag means we're passing a pointer to an
728 * existing encap tlv chain which we should copy.
729 * It's a hack to avoid adding yet another argument
732 encaptlv
= encap_tlv_dup(
733 (struct bgp_attr_encap_subtlv
*)rfp_options
);
735 vnc_subtlvs
->next
= encaptlv
;
737 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
739 struct bgp_tea_options
*hop
;
740 /* XXX max of one tlv present so far from above code */
741 struct bgp_attr_encap_subtlv
*tail
=
742 bgp_attr_get_vnc_subtlvs(&attr
);
744 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
751 sizeof(struct bgp_attr_encap_subtlv
) + 2
754 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
757 encaptlv
->length
= 2 + hop
->length
;
758 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
759 *((uint8_t *)(encaptlv
->value
) + 1) =
761 memcpy(((uint8_t *)encaptlv
->value
) + 2,
762 hop
->value
, hop
->length
);
765 * add to end of subtlv chain
768 tail
->next
= encaptlv
;
770 bgp_attr_set_vnc_subtlvs(&attr
,
780 * extra: dynamically allocated, owned by attr
781 * vnc_subtlvs: dynamic chain, length 1
782 * aspath: points to interned hash from aspath hash table
786 bgp_attr_set_ecommunity(&attr
, ecommunity_new());
787 assert(bgp_attr_get_ecommunity(&attr
));
789 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
790 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
792 * Add BGP Encapsulation Extended Community. Format described in
793 * section 4.5 of RFC 5512.
794 * Always include when not MPLS type, to disambiguate this case.
796 struct ecommunity_val beec
;
798 memset(&beec
, 0, sizeof(beec
));
799 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
800 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
801 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
802 beec
.val
[7] = (TunnelType
)&0xff;
803 ecommunity_add_val(bgp_attr_get_ecommunity(&attr
), &beec
, false,
808 * Add extended community attributes to match rt export list
810 if (rt_export_list
) {
811 bgp_attr_set_ecommunity(
812 &attr
, ecommunity_merge(bgp_attr_get_ecommunity(&attr
),
816 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(&attr
);
819 ecommunity_free(&ecomm
);
820 bgp_attr_set_ecommunity(&attr
, NULL
);
822 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
, ecomm
);
828 * extra: dynamically allocated, owned by attr
829 * vnc_subtlvs: dynamic chain, length 1
830 * ecommunity: dynamic 2-part
831 * aspath: points to interned hash from aspath hash table
834 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
835 switch (nexthop
->addr_family
) {
838 * set this field to prevent bgp_route.c code from setting
839 * mp_nexthop_global_in to self
841 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
843 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
844 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
848 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
849 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV6_GLOBAL
;
857 prefix2str(p
, buf
, sizeof(buf
));
863 * extra: dynamically allocated, owned by attr
864 * vnc_subtlvs: dynamic chain, length 1
865 * ecommunity: dynamic 2-part
866 * aspath: points to interned hash from aspath hash table
869 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
871 if (red
&& red
->redist_metric_flag
) {
872 attr
.med
= red
->redist_metric
;
873 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
876 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
879 * bgp_attr_intern creates a new reference to a cached
880 * attribute, but leaves the following bits of trash:
882 * - old attr->extra (free via bgp_attr_extra_free(attr))
884 * Note that it frees the original attr->extra->ecommunity
885 * but leaves the new attribute pointing to the ORIGINAL
886 * vnc options (which therefore we needn't free from the
889 new_attr
= bgp_attr_intern(&attr
);
891 aspath_unintern(&attr
.aspath
); /* Unintern original. */
897 * extra: dynamically allocated, owned by attr
898 * vnc_subtlvs: dynamic chain, length 1
899 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
901 * new_attr: an attr that is part of the hash table, distinct
902 * from attr which is static.
903 * extra: dynamically allocated, owned by new_attr (in hash table)
904 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
905 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
906 * aspath: POINTS TO interned/refcounted hashed block
908 for (bpi
= bgp_dest_get_bgp_path_info(bn
); bpi
; bpi
= bpi
->next
) {
909 /* probably only need to check
910 * bpi->extra->vnc.export.rfapi_handle */
911 if (bpi
->peer
== rfd
->peer
&& bpi
->type
== type
912 && bpi
->sub_type
== sub_type
&& bpi
->extra
913 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
922 * Adding new local_nexthop, which does not by itself change
923 * what is advertised via BGP
926 if (!bpi
->extra
->vnc
.export
.local_nexthops
) {
927 /* TBD make arrangements to free when needed */
928 bpi
->extra
->vnc
.export
.local_nexthops
=
930 bpi
->extra
->vnc
.export
.local_nexthops
->del
=
937 struct listnode
*node
;
938 struct rfapi_nexthop
*pLnh
= NULL
;
940 for (ALL_LIST_ELEMENTS_RO(
941 bpi
->extra
->vnc
.export
.local_nexthops
,
944 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
950 * Not present, add new one
953 pLnh
= rfapi_nexthop_new(lnh
);
955 bpi
->extra
->vnc
.export
.local_nexthops
,
960 if (attrhash_cmp(bpi
->attr
, new_attr
)
961 && !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
962 bgp_attr_unintern(&new_attr
);
963 bgp_dest_unlock_node(bn
);
966 "%s: Found route (safi=%d) at prefix %s, no change",
967 __func__
, safi
, buf
);
971 /* The attribute is changed. */
972 bgp_path_info_set_flag(bn
, bpi
, BGP_PATH_ATTR_CHANGED
);
974 if (safi
== SAFI_MPLS_VPN
) {
975 struct bgp_dest
*pdest
= NULL
;
976 struct bgp_table
*table
= NULL
;
978 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
979 (struct prefix
*)prd
);
980 table
= bgp_dest_get_bgp_table_info(pdest
);
982 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
983 bgp
, prd
, table
, p
, bpi
);
984 bgp_dest_unlock_node(pdest
);
987 /* Rewrite BGP route information. */
988 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
989 bgp_path_info_restore(bn
, bpi
);
991 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
992 bgp_attr_unintern(&bpi
->attr
);
993 bpi
->attr
= new_attr
;
994 bpi
->uptime
= monotime(NULL
);
997 if (safi
== SAFI_MPLS_VPN
) {
998 struct bgp_dest
*pdest
= NULL
;
999 struct bgp_table
*table
= NULL
;
1001 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
1002 (struct prefix
*)prd
);
1003 table
= bgp_dest_get_bgp_table_info(pdest
);
1005 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1006 bgp
, prd
, table
, p
, bpi
);
1007 bgp_dest_unlock_node(pdest
);
1010 /* Process change. */
1011 bgp_aggregate_increment(bgp
, p
, bpi
, afi
, safi
);
1012 bgp_process(bgp
, bn
, afi
, safi
);
1013 bgp_dest_unlock_node(bn
);
1016 "%s: Found route (safi=%d) at prefix %s, changed attr",
1017 __func__
, safi
, buf
);
1023 new = info_make(type
, sub_type
, 0, rfd
->peer
, new_attr
, NULL
);
1024 SET_FLAG(new->flags
, BGP_PATH_VALID
);
1026 /* save backref to rfapi handle */
1027 bgp_path_info_extra_get(new);
1028 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1029 encode_label(label_val
, &new->extra
->label
[0]);
1033 if (VNC_DEBUG(VERBOSE
)) {
1034 vnc_zlog_debug_verbose("%s: printing BPI", __func__
);
1035 rfapiPrintBi(NULL
, new);
1038 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1039 bgp_path_info_add(bn
, new);
1041 if (safi
== SAFI_MPLS_VPN
) {
1042 struct bgp_dest
*pdest
= NULL
;
1043 struct bgp_table
*table
= NULL
;
1045 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1046 table
= bgp_dest_get_bgp_table_info(pdest
);
1048 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1049 bgp
, prd
, table
, p
, new);
1050 bgp_dest_unlock_node(pdest
);
1051 encode_label(label_val
, &bn
->local_label
);
1054 bgp_dest_unlock_node(bn
);
1055 bgp_process(bgp
, bn
, afi
, safi
);
1058 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)",
1059 __func__
, safi2str(safi
), buf
, bn
, prd
);
1062 /* Loop back to import tables */
1063 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1064 sub_type
, &label_val
);
1065 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1069 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1074 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1075 struct rfapi_descriptor
*rfd
,
1076 uint32_t *pLifetime
)
1078 struct prefix_rd prd
;
1079 struct prefix pfx_vn
;
1081 uint32_t local_pref
= rfp_cost_to_localpref(0);
1083 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1087 * Construct route distinguisher = 0
1089 memset(&prd
, 0, sizeof(prd
));
1090 prd
.family
= AF_UNSPEC
;
1093 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1094 bgp
, /* which bgp instance */
1095 SAFI_ENCAP
, /* which SAFI */
1096 &pfx_vn
, /* prefix to advertise */
1097 &prd
, /* route distinguisher to use */
1098 &rfd
->un_addr
, /* nexthop */
1100 pLifetime
, /* max lifetime of child VPN routes */
1101 NULL
, /* no rfp options for ENCAP safi */
1102 NULL
, /* rfp un options */
1103 NULL
, /* rfp vn options */
1104 rfd
->rt_export_list
, NULL
, /* med */
1105 NULL
, /* label: default */
1106 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1110 /***********************************************************************
1111 * RFP processing behavior configuration
1112 ***********************************************************************/
1114 /*------------------------------------------
1115 * rfapi_rfp_set_configuration
1117 * This is used to change rfapi's processing behavior based on
1121 * rfp_start_val value returned by rfp_start
1122 * rfapi_rfp_cfg Pointer to configuration structure
1129 * ENXIO Unabled to locate configured BGP/VNC
1130 --------------------------------------------*/
1131 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1133 struct rfapi_rfp_cfg
*rcfg
;
1136 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1138 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1141 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1142 rcfg
->download_type
= new->download_type
;
1143 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1144 rcfg
->holddown_factor
= new->holddown_factor
;
1146 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1147 rcfg
->use_updated_response
= new->use_updated_response
;
1148 if (rcfg
->use_updated_response
)
1149 rfapiMonitorCallbacksOn(bgp
);
1151 rfapiMonitorCallbacksOff(bgp
);
1153 if (rcfg
->use_removes
!= new->use_removes
) {
1154 rcfg
->use_removes
= new->use_removes
;
1155 if (rcfg
->use_removes
)
1156 rfapiMonitorResponseRemovalOn(bgp
);
1158 rfapiMonitorResponseRemovalOff(bgp
);
1163 /*------------------------------------------
1164 * rfapi_rfp_set_cb_methods
1166 * Change registered callback functions for asynchronous notifications
1167 * from RFAPI to the RFP client.
1170 * rfp_start_val value returned by rfp_start
1171 * methods Pointer to struct rfapi_rfp_cb_methods containing
1172 * pointers to callback methods as described above
1176 * ENXIO BGP or VNC not configured
1177 *------------------------------------------*/
1178 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1179 struct rfapi_rfp_cb_methods
*methods
)
1184 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1192 h
->rfp_methods
= *methods
;
1197 /***********************************************************************
1199 ***********************************************************************/
1201 * Caller must supply an already-allocated rfd with the "caller"
1202 * fields already set (vn_addr, un_addr, callback, cookie)
1203 * The advertised_prefixes[] array elements should be NULL to
1204 * have this function set them to newly-allocated radix trees.
1206 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1207 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1211 if (h
->flags
& RFAPI_INCALLBACK
)
1215 * Fill in configured fields
1219 * If group's RD is specified as "auto", then fill in based
1220 * on NVE's VN address
1224 if (rfd
->rd
.family
== AF_UNIX
) {
1225 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1229 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1230 ? ecommunity_dup(rfg
->rt_export_list
)
1232 rfd
->response_lifetime
= rfg
->response_lifetime
;
1236 * Fill in BGP peer structure
1238 rfd
->peer
= peer_new(bgp
);
1239 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1240 bgp_sync_delete(rfd
->peer
); /* don't need these */
1243 * since this peer is not on the I/O thread, this lock is not strictly
1244 * necessary, but serves as a reminder to those who may meddle...
1246 frr_with_mutex (&rfd
->peer
->io_mtx
) {
1247 // we don't need any I/O related facilities
1248 if (rfd
->peer
->ibuf
)
1249 stream_fifo_free(rfd
->peer
->ibuf
);
1250 if (rfd
->peer
->obuf
)
1251 stream_fifo_free(rfd
->peer
->obuf
);
1253 if (rfd
->peer
->ibuf_work
)
1254 ringbuf_del(rfd
->peer
->ibuf_work
);
1255 if (rfd
->peer
->obuf_work
)
1256 stream_free(rfd
->peer
->obuf_work
);
1258 rfd
->peer
->ibuf
= NULL
;
1259 rfd
->peer
->obuf
= NULL
;
1260 rfd
->peer
->obuf_work
= NULL
;
1261 rfd
->peer
->ibuf_work
= NULL
;
1264 { /* base code assumes have valid host pointer */
1265 char buf
[INET6_ADDRSTRLEN
];
1268 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1269 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
,
1271 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1272 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
,
1275 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1277 /* Mark peer as belonging to HD */
1278 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1281 * Set min prefix lifetime to max value so it will get set
1282 * upon first rfapi_register()
1284 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1287 * Allocate response tables if needed
1289 #define RFD_RTINIT_AFI(rh, ary, afi) \
1292 ary[afi] = agg_table_init(); \
1293 agg_set_table_info(ary[afi], rh); \
1297 #define RFD_RTINIT(rh, ary) \
1299 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1300 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1301 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1304 RFD_RTINIT(rfd
, rfd
->rib
);
1305 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1306 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1309 * Link to Import Table
1311 rfd
->import_table
= rfg
->rfapi_import_table
;
1312 rfd
->import_table
->refcount
+= 1;
1314 rfapiApInit(&rfd
->advertised
);
1317 * add this NVE descriptor to the list of NVEs in the NVE group
1320 rfg
->nves
= list_new();
1322 listnode_add(rfg
->nves
, rfd
);
1324 vnc_direct_bgp_add_nve(bgp
, rfd
);
1325 vnc_zebra_add_nve(bgp
, rfd
);
1330 /* moved from rfapi_register */
1331 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1332 struct rfapi_nve_group_cfg
*rfg
)
1334 struct rfapi
*h
= bgp
->rfapi
;
1335 char buf_vn
[BUFSIZ
];
1336 char buf_un
[BUFSIZ
];
1337 afi_t afi_vn
, afi_un
;
1338 struct prefix pfx_un
;
1339 struct agg_node
*rn
;
1341 rfd
->open_time
= monotime(NULL
);
1343 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1344 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1346 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1347 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1349 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1350 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1352 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1354 listnode_add(&h
->descriptors
, rfd
);
1355 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1356 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1360 * attach to UN radix tree
1362 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1363 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1364 assert(afi_vn
&& afi_un
);
1365 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1367 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1369 rfd
->next
= rn
->info
;
1373 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1376 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1378 struct rfapi_vn_option
*head
= NULL
;
1379 struct rfapi_vn_option
*tail
= NULL
;
1380 struct rfapi_vn_option
*vo
= NULL
;
1382 for (vo
= orig
; vo
; vo
= vo
->next
) {
1383 struct rfapi_vn_option
*new;
1385 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1386 sizeof(struct rfapi_vn_option
));
1387 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1399 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1401 struct rfapi_un_option
*head
= NULL
;
1402 struct rfapi_un_option
*tail
= NULL
;
1403 struct rfapi_un_option
*uo
= NULL
;
1405 for (uo
= orig
; uo
; uo
= uo
->next
) {
1406 struct rfapi_un_option
*new;
1408 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1409 sizeof(struct rfapi_un_option
));
1410 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1422 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1424 struct bgp_tea_options
*head
= NULL
;
1425 struct bgp_tea_options
*tail
= NULL
;
1426 struct bgp_tea_options
*hop
= NULL
;
1428 for (hop
= orig
; hop
; hop
= hop
->next
) {
1429 struct bgp_tea_options
*new;
1431 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1432 sizeof(struct bgp_tea_options
));
1433 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1436 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1438 memcpy(new->value
, hop
->value
, hop
->length
);
1449 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1451 struct bgp_tea_options
*next
;
1456 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1457 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1463 void rfapiAdbFree(struct rfapi_adb
*adb
)
1465 XFREE(MTYPE_RFAPI_ADB
, adb
);
1469 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1470 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1471 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1475 struct prefix p_original
;
1476 struct agg_node
*rn
;
1477 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1478 struct bgp
*bgp
= rfd
->bgp
;
1479 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1480 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1482 int use_eth_resolution
= 0;
1483 struct rfapi_next_hop_entry
*i_nhe
;
1487 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1492 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1496 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1497 vnc_zlog_debug_verbose(
1498 "%s: Called during calback, returning EDEADLK",
1503 if (!is_valid_rfd(rfd
)) {
1504 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1509 rfd
->rsp_counter
++; /* dedup: identify this generation */
1510 rfd
->rsp_time
= monotime(NULL
); /* response content dedup */
1511 rfd
->ftd_last_allowed_time
=
1513 bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1516 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1520 /* per t/c Paul/Lou 151022 */
1521 if (!eth_is_0
|| l2o
->logical_net_id
) {
1522 use_eth_resolution
= 1;
1527 *ppNextHopEntry
= NULL
;
1530 * Save original target in prefix form. In case of L2-based queries,
1531 * p_original will be modified to reflect the L2 target
1533 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1535 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1536 /* convert query to 0/0 when full-table download is enabled */
1537 memset((char *)&p
, 0, sizeof(p
));
1538 p
.family
= target
->addr_family
;
1546 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1547 __func__
, rfd
, &p
, ppNextHopEntry
);
1549 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1550 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1551 vnc_zlog_debug_verbose(
1552 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1553 __func__
, rfd
->import_table
, s
);
1554 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1557 afi
= family2afi(p
.family
);
1560 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1561 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1562 self_vn_addr
= &rfd
->vn_addr
;
1565 if (use_eth_resolution
) {
1566 uint32_t logical_net_id
= l2o
->logical_net_id
;
1567 struct ecommunity
*l2com
;
1570 * fix up p_original to contain L2 address
1572 rfapiL2o2Qprefix(l2o
, &p_original
);
1574 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1575 bgp
, 1, logical_net_id
, l2o
->label
);
1577 uint8_t *v
= l2com
->val
;
1578 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1581 * Ethernet/L2-based lookup
1583 * Always returns IT node corresponding to route
1586 if (RFAPI_RFP_DOWNLOAD_FULL
1587 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1591 rn
= rfapiMonitorEthAdd(
1592 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1596 struct rfapi_ip_prefix rprefix
;
1598 memset(&rprefix
, 0, sizeof(rprefix
));
1599 rprefix
.prefix
.addr_family
= target
->addr_family
;
1600 if (target
->addr_family
== AF_INET
) {
1601 rprefix
.length
= IPV4_MAX_BITLEN
;
1603 rprefix
.length
= IPV6_MAX_BITLEN
;
1606 pNHE
= rfapiEthRouteTable2NextHopList(
1607 logical_net_id
, &rprefix
,
1608 rfd
->response_lifetime
, self_vn_addr
,
1609 rfd
->rib
[afi
], &p_original
);
1619 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1622 * If target address is 0, this request is special: means to
1623 * return ALL routes in the table
1625 * Monitors for All-Routes queries get put on a special list,
1626 * not in the VPN tree
1628 if (RFAPI_0_PREFIX(&p
)) {
1630 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1633 * Generate nexthop list for caller
1635 pNHE
= rfapiRouteTable2NextHopList(
1636 rfd
->import_table
->imported_vpn
[afi
],
1637 rfd
->response_lifetime
, self_vn_addr
,
1638 rfd
->rib
[afi
], &p_original
);
1643 agg_lock_node(rn
); /* so we can unlock below */
1646 * returns locked node. Don't unlock yet because the
1648 * might free it before we're done with it. This
1650 * could occur when rfapiMonitorGetAttachNode() returns
1652 * newly-created default node.
1654 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1660 agg_unlock_node(rn
);
1661 vnc_zlog_debug_verbose(
1662 "%s: VPN route not found, returning ENOENT", __func__
);
1666 if (VNC_DEBUG(RFAPI_QUERY
)) {
1667 rfapiShowImportTable(NULL
, "query",
1668 rfd
->import_table
->imported_vpn
[afi
], 1);
1671 if (use_eth_resolution
) {
1673 struct rfapi_ip_prefix rprefix
;
1675 memset(&rprefix
, 0, sizeof(rprefix
));
1676 rprefix
.prefix
.addr_family
= target
->addr_family
;
1677 if (target
->addr_family
== AF_INET
) {
1678 rprefix
.length
= IPV4_MAX_BITLEN
;
1680 rprefix
.length
= IPV6_MAX_BITLEN
;
1683 pNHE
= rfapiEthRouteNode2NextHopList(
1684 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1685 rfd
->rib
[afi
], &p_original
);
1690 * Generate answer to query
1692 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1693 self_vn_addr
, rfd
->rib
[afi
],
1697 agg_unlock_node(rn
);
1700 if (ppNextHopEntry
) {
1701 /* only count if caller gets it */
1702 ++bgp
->rfapi
->response_immediate_count
;
1706 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1712 * count nexthops for statistics
1714 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1715 ++rfd
->stat_count_nh_reachable
;
1718 if (ppNextHopEntry
) {
1719 *ppNextHopEntry
= pNHE
;
1721 rfapi_free_next_hop_list(pNHE
);
1724 vnc_zlog_debug_verbose("%s: success", __func__
);
1729 * support on-the-fly reassignment of an already-open nve to a new
1730 * nve-group in the event that its original nve-group is
1731 * administratively deleted.
1733 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1735 struct prefix pfx_vn
;
1736 struct prefix pfx_un
;
1737 struct rfapi_nve_group_cfg
*rfg
;
1739 struct rfapi_cfg
*hc
;
1746 hc
= bgp
->rfapi_cfg
;
1750 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1753 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1757 * Find the matching nve group config block
1759 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1765 * check nve group config block for required values
1767 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1772 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1778 * re-advertise registered routes, this time as part of new NVE-group
1780 rfapiApReadvertiseAll(bgp
, rfd
);
1783 * re-attach callbacks to import table
1785 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1786 rfapiMonitorAttachImportHd(rfd
);
1792 /*------------------------------------------
1795 * This function initializes a NVE record and associates it with
1796 * the specified VN and underlay network addresses
1799 * rfp_start_val value returned by rfp_start
1800 * vn NVE virtual network address
1802 * un NVE underlay network address
1804 * default_options Default options to use on registrations.
1805 * For now only tunnel type is supported.
1806 * May be overridden per-prefix in rfapi_register().
1807 * Caller owns (rfapi_open() does not free)
1809 * response_cb Pointer to next hop list update callback function or
1810 * NULL when no callbacks are desired.
1812 * userdata Passed to subsequent response_cb invocations.
1815 * response_lifetime The length of time that responses sent to this
1818 * pHandle pointer to location to store rfapi handle. The
1819 * handle must be passed on subsequent rfapi_ calls.
1824 * EEXIST NVE with this {vn,un} already open
1825 * ENOENT No matching nve group config
1826 * ENOMSG Matched nve group config was incomplete
1827 * ENXIO BGP or VNC not configured
1828 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1829 * but underlay network address is not IPv4
1830 * EDEADLK Called from within a callback procedure
1831 *------------------------------------------*/
1832 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1833 struct rfapi_ip_addr
*un
,
1834 struct rfapi_un_option
*default_options
,
1835 uint32_t *response_lifetime
,
1836 void *userdata
, /* callback cookie */
1837 rfapi_handle
*pHandle
)
1841 struct rfapi_descriptor
*rfd
;
1842 struct rfapi_cfg
*hc
;
1843 struct rfapi_nve_group_cfg
*rfg
;
1845 struct prefix pfx_vn
;
1846 struct prefix pfx_un
;
1849 rfapi_handle hh
= NULL
;
1850 int reusing_provisional
= 0;
1853 char buf
[2][INET_ADDRSTRLEN
];
1854 vnc_zlog_debug_verbose(
1855 "%s: VN=%s UN=%s", __func__
,
1856 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1857 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1863 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1871 hc
= bgp
->rfapi_cfg
;
1875 if (h
->flags
& RFAPI_INCALLBACK
)
1878 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1881 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1885 * already have a descriptor with VN and UN?
1887 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1889 * we might have set up a handle for static routes before
1890 * this NVE was opened. In that case, reuse the handle
1893 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1898 * reuse provisional descriptor
1901 reusing_provisional
= 1;
1905 * Find the matching nve group config block
1907 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1909 ++h
->stat
.count_unknown_nves
;
1911 char buf
[2][INET_ADDRSTRLEN
];
1912 zlog_notice("%s: no matching group VN=%s UN=%s",
1914 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1916 rfapiRfapiIpAddr2Str(un
, buf
[1],
1923 * check nve group config block for required values
1925 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1927 ++h
->stat
.count_unknown_nves
;
1932 * If group config specifies auto-rd assignment, check that
1933 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1934 * Check here so we don't need to unwind memory allocations, &c.
1936 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1937 && (vn
->addr_family
!= AF_INET6
)) {
1938 return EAFNOSUPPORT
;
1943 * reusing provisional rfd
1947 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1948 sizeof(struct rfapi_descriptor
));
1952 if (default_options
) {
1953 struct rfapi_un_option
*p
;
1955 for (p
= default_options
; p
; p
= p
->next
) {
1956 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1957 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1959 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1960 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1966 * Fill in caller fields
1970 rfd
->cookie
= userdata
;
1972 if (!reusing_provisional
) {
1973 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1975 * This can fail only if the VN address is IPv6 and the group
1976 * specified auto-assignment of RDs, which only works for v4,
1977 * and the check above should catch it.
1979 * Another failure possibility is that we were called
1980 * during an rfapi callback. Also checked above.
1985 if (response_lifetime
)
1986 *response_lifetime
= rfd
->response_lifetime
;
1992 * For use with debug functions
1994 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
1995 rfapi_response_cb_t
*response_cb
)
1997 if (!is_valid_rfd(rfd
))
1999 rfd
->response_cb
= response_cb
;
2006 * Does almost all the work of rfapi_close, except:
2007 * 1. preserves the descriptor (doesn't free it)
2008 * 2. preserves the prefix query list (i.e., rfd->mon list)
2009 * 3. preserves the advertised prefix list (rfd->advertised)
2010 * 4. preserves the rib and rib_pending tables
2012 * The purpose of organizing it this way is to support on-the-fly
2013 * reassignment of an already-open nve to a new nve-group in the
2014 * event that its original nve-group is administratively deleted.
2016 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2019 struct prefix pfx_vn
;
2020 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2022 if (!is_valid_rfd(rfd
))
2025 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2026 assert(!rc
); /* should never have bad AF in stored vn address */
2029 * update exported routes to reflect disappearance of this NVE as
2032 vnc_direct_bgp_del_nve(bgp
, rfd
);
2033 vnc_zebra_del_nve(bgp
, rfd
);
2036 * unlink this HD's monitors from import table
2038 rfapiMonitorDetachImportHd(rfd
);
2041 * Unlink from Import Table
2042 * NB rfd->import_table will be NULL if we are closing a stale
2045 if (rfd
->import_table
)
2046 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2047 rfd
->import_table
= NULL
;
2050 * Construct route distinguisher
2052 memset(&prd
, 0, sizeof(prd
));
2054 prd
.family
= AF_UNSPEC
;
2060 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2061 &pfx_vn
, /* prefix being advertised */
2062 &prd
, /* route distinguisher to use (0 for ENCAP) */
2063 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2066 * Construct route distinguisher for VPN routes
2069 prd
.family
= AF_UNSPEC
;
2073 * find all VPN routes associated with this rfd and delete them, too
2075 rfapiApWithdrawAll(bgp
, rfd
);
2078 * remove this nve descriptor from the list of nves
2079 * associated with the nve group
2082 listnode_delete(rfd
->rfg
->nves
, rfd
);
2083 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2086 if (rfd
->rt_export_list
)
2087 ecommunity_free(&rfd
->rt_export_list
);
2088 rfd
->rt_export_list
= NULL
;
2091 * free peer structure (possibly delayed until its
2092 * refcount reaches zero)
2095 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2096 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2097 peer_delete(rfd
->peer
);
2104 int rfapi_close(void *handle
)
2106 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2108 struct agg_node
*node
;
2112 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2114 #ifdef RFAPI_WHO_IS_CALLING_ME
2115 #ifdef HAVE_GLIBC_BACKTRACE
2116 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2118 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2123 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2124 syms
= backtrace_symbols(buf
, size
);
2125 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2127 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2143 if (!is_valid_rfd(rfd
))
2146 if (h
->flags
& RFAPI_INCALLBACK
) {
2148 * Queue these close requests for processing after callback
2151 if (!CHECK_FLAG(rfd
->flags
,
2152 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2153 work_queue_add(h
->deferred_close_q
, handle
);
2154 vnc_zlog_debug_verbose(
2155 "%s: added handle %p to deferred close queue",
2161 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2163 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2166 if (h
->rfp_methods
.close_cb
) {
2167 vnc_zlog_debug_verbose(
2168 "%s calling close callback rfd=%p", __func__
,
2172 * call the callback fairly early so that it can still
2176 * NB RFAPI_INCALLBACK is tested above, so if we reach
2178 * we are not already in the context of a callback.
2180 h
->flags
|= RFAPI_INCALLBACK
;
2181 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2182 h
->flags
&= ~RFAPI_INCALLBACK
;
2188 * Orphaned descriptors have already done this part, so do
2189 * only for non-orphaned descriptors.
2191 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2196 * Remove descriptor from UN index
2197 * (remove from chain at node)
2199 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2201 struct rfapi_descriptor
*hh
;
2203 if (node
->info
== rfd
) {
2204 node
->info
= rfd
->next
;
2207 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2208 if (hh
->next
== rfd
) {
2209 hh
->next
= rfd
->next
;
2214 agg_unlock_node(node
);
2218 * remove from descriptor list
2220 listnode_delete(&h
->descriptors
, rfd
);
2223 * Delete monitor list items and free monitor structures
2225 (void)rfapiMonitorDelHd(rfd
);
2228 * release advertised prefix data
2230 rfapiApRelease(&rfd
->advertised
);
2233 * Release RFP callback RIB
2240 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2241 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2247 * Reopen a nve descriptor. If the descriptor's NVE-group
2248 * does not exist (e.g., if it has been administratively removed),
2249 * reassignment to a new NVE-group is attempted.
2251 * If NVE-group reassignment fails, the descriptor becomes "stale"
2252 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2253 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2254 * on the descriptor will return ESTALE.
2256 * Reopening a descriptor is a potentially expensive operation, because
2257 * it involves withdrawing any routes advertised by the NVE, withdrawing
2258 * the NVE's route queries, and then re-adding them all after a new
2259 * NVE-group is assigned. There are also possible route-export affects
2260 * caused by deleting and then adding the NVE: advertised prefixes
2261 * and nexthop lists for exported routes can turn over.
2263 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2268 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2271 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2275 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2277 if (CHECK_FLAG(rfd
->flags
,
2278 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2279 && h
&& h
->rfp_methods
.close_cb
) {
2282 * NB RFAPI_INCALLBACK is tested above, so if we reach
2284 * we are not already in the context of a callback.
2286 h
->flags
|= RFAPI_INCALLBACK
;
2287 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2288 h
->flags
&= ~RFAPI_INCALLBACK
;
2295 /***********************************************************************
2297 ***********************************************************************/
2299 * Announce reachability to this prefix via the NVE
2301 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2302 uint32_t lifetime
, /* host byte order */
2303 struct rfapi_un_option
*options_un
,
2304 struct rfapi_vn_option
*options_vn
,
2305 rfapi_register_action action
)
2307 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2310 struct prefix
*pfx_ip
= NULL
;
2311 struct prefix_rd prd
;
2313 struct prefix pfx_mac_buf
;
2314 struct prefix
*pfx_mac
= NULL
;
2315 struct prefix pfx_vn_buf
;
2316 const char *action_str
= NULL
;
2317 uint32_t *label
= NULL
;
2318 struct rfapi_vn_option
*vo
;
2319 struct rfapi_l2address_option
*l2o
= NULL
;
2320 struct prefix_rd
*prd_override
= NULL
;
2323 case RFAPI_REGISTER_ADD
:
2326 case RFAPI_REGISTER_WITHDRAW
:
2327 action_str
= "withdraw";
2329 case RFAPI_REGISTER_KILL
:
2330 action_str
= "kill";
2338 * Inspect VN options
2340 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2341 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2342 l2o
= &vo
->v
.l2addr
;
2344 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2345 prd_override
= &vo
->v
.internal_rd
;
2349 /*********************************************************************
2351 *********************************************************************/
2354 * set <p> based on <prefix>
2356 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2358 afi
= family2afi(prefix
->prefix
.addr_family
);
2361 vnc_zlog_debug_verbose(
2362 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2363 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2367 * These tests come after the prefix conversion so that we can
2368 * print the prefix in a debug message before failing
2373 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2378 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2383 if (RFAPI_REGISTER_ADD
== action
) {
2384 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2386 vnc_zlog_debug_verbose(
2387 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2392 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2393 if (RFAPI_REGISTER_ADD
== action
) {
2394 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2396 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2401 if (!is_valid_rfd(rfd
)) {
2402 if (RFAPI_REGISTER_ADD
== action
) {
2403 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2405 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2411 * Is there a MAC address in this registration?
2413 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2414 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2415 pfx_mac
= &pfx_mac_buf
;
2419 * Is there an IP prefix in this registration?
2421 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2425 vnc_zlog_debug_verbose(
2426 "%s: missing mac addr that is required for host 0 pfx",
2428 if (RFAPI_REGISTER_ADD
== action
) {
2429 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2433 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2434 vnc_zlog_debug_verbose(
2435 "%s: handle has bad vn_addr: returning EBADF",
2437 if (RFAPI_REGISTER_ADD
== action
) {
2438 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2444 if (RFAPI_REGISTER_ADD
== action
) {
2445 ++bgp
->rfapi
->stat
.count_registrations
;
2449 * Figure out if this registration is missing an IP address
2453 * In RFAPI, we use prefixes in family AF_LINK to store
2454 * the MAC addresses. These prefixes are used for the
2455 * list of advertised prefixes and in the RFAPI import
2458 * In BGP proper, we use the prefix matching the NVE's
2459 * VN address with a host prefix-length (i.e., 32 or 128).
2462 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2463 && RFAPI_HOST_PREFIX(&p
)) {
2465 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2466 pfx_mac
= &pfx_mac_buf
;
2470 * Construct route distinguisher
2473 prd
= *prd_override
;
2475 memset(&prd
, 0, sizeof(prd
));
2477 prd
.family
= AF_UNSPEC
;
2479 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2480 if (l2o
->local_nve_id
2481 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2483 * If Local NVE ID is specified in message, use
2485 * (if no local default configured, also use it
2488 prd
.val
[1] = l2o
->local_nve_id
;
2490 if (rfd
->rfg
->l2rd
) {
2492 * locally-configured literal value
2494 prd
.val
[1] = rfd
->rfg
->l2rd
;
2497 * 0 means auto:vn, which means use LSB
2500 if (rfd
->vn_addr
.addr_family
2503 *(((char *)&rfd
->vn_addr
2509 *(((char *)&rfd
->vn_addr
2516 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2519 prd
.family
= AF_UNSPEC
;
2525 if (action
== RFAPI_REGISTER_WITHDRAW
2526 || action
== RFAPI_REGISTER_KILL
) {
2531 * withdraw previous advertisement
2534 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2536 : &pfx_vn_buf
, /* prefix being advertised */
2537 &prd
, /* route distinguisher (0 for ENCAP) */
2538 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2539 action
== RFAPI_REGISTER_KILL
);
2541 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2544 rfapiTunnelRouteAnnounce(
2545 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2551 uint32_t local_pref
;
2552 struct ecommunity
*rtlist
= NULL
;
2553 struct ecommunity_val ecom_value
;
2555 if (!rfapiApCount(rfd
)) {
2557 * make sure we advertise tunnel route upon adding the
2563 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2564 prefix
->cost
, l2o
)) {
2568 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2571 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2573 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2574 &rfd
->max_prefix_lifetime
);
2577 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2579 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2581 if (l2o
&& l2o
->label
)
2582 label
= &l2o
->label
;
2585 struct ecommunity
*l2com
= NULL
;
2588 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2589 bgp
, 1, l2o
->logical_net_id
, *label
);
2592 rtlist
= ecommunity_dup(l2com
);
2595 * If mac address is set, add an RT based on the
2598 memset((char *)&ecom_value
, 0,
2599 sizeof(ecom_value
));
2600 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2602 (l2o
->logical_net_id
>> 16) & 0xff;
2604 (l2o
->logical_net_id
>> 8) & 0xff;
2606 (l2o
->logical_net_id
>> 0) & 0xff;
2607 rtlist
= ecommunity_new();
2608 ecommunity_add_val(rtlist
, &ecom_value
,
2613 uint16_t val
= l2o
->tag_id
;
2614 memset((char *)&ecom_value
, 0,
2615 sizeof(ecom_value
));
2616 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2617 if (as
> BGP_AS_MAX
) {
2619 ECOMMUNITY_ENCODE_AS4
;
2620 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2621 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2622 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2623 ecom_value
.val
[5] = as
& 0xff;
2626 ECOMMUNITY_ENCODE_AS
;
2627 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2628 ecom_value
.val
[3] = as
& 0xff;
2630 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2631 ecom_value
.val
[7] = val
& 0xff;
2633 rtlist
= ecommunity_new();
2634 ecommunity_add_val(rtlist
, &ecom_value
,
2640 * advertise prefix via tunnel endpoint
2643 rfd
, /* rfapi descr, for export list & backref */
2644 bgp
, /* which bgp instance */
2645 SAFI_MPLS_VPN
, /* which SAFI */
2647 : &pfx_vn_buf
), /* prefix being advertised */
2648 &prd
, /* route distinguisher to use (0 for ENCAP) */
2649 &rfd
->vn_addr
, /* nexthop */
2651 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2652 NULL
, options_un
, /* rfapi un options */
2653 options_vn
, /* rfapi vn options */
2654 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2655 label
, /* label: default */
2656 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2659 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2662 vnc_zlog_debug_verbose("%s: success", __func__
);
2666 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2667 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2668 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2670 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2671 struct bgp
*bgp
= rfd
->bgp
;
2674 assert(ppNextHopEntry
);
2675 *ppNextHopEntry
= NULL
;
2677 if (bgp
&& bgp
->rfapi
) {
2678 bgp
->rfapi
->stat
.count_queries
++;
2682 if (bgp
&& bgp
->rfapi
)
2683 ++bgp
->rfapi
->stat
.count_queries_failed
;
2687 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2688 if (bgp
&& bgp
->rfapi
)
2689 ++bgp
->rfapi
->stat
.count_queries_failed
;
2694 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2698 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2699 struct bgp
*bgp
= rfd
->bgp
;
2705 rc
= rfapiRaddr2Qprefix(target
, &p
);
2708 if (!is_valid_rfd(rfd
))
2712 if (!bgp
|| !bgp
->rfapi
)
2715 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2718 rfapiMonitorDel(bgp
, rfd
, &p
);
2723 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2725 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2726 struct bgp
*bgp
= rfd
->bgp
;
2733 if (!is_valid_rfd(rfd
))
2737 if (!bgp
|| !bgp
->rfapi
)
2740 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2743 num
= rfapiMonitorDelHd(rfd
);
2751 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2753 struct rfapi_next_hop_entry
*nh
;
2754 struct rfapi_next_hop_entry
*next
;
2756 for (nh
= list
; nh
; nh
= next
) {
2758 rfapi_un_options_free(nh
->un_options
);
2759 nh
->un_options
= NULL
;
2760 rfapi_vn_options_free(nh
->vn_options
);
2761 nh
->vn_options
= NULL
;
2762 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2767 * NULL handle => return total count across all nves
2769 uint32_t rfapi_monitor_count(void *handle
)
2771 struct bgp
*bgp
= bgp_get_default();
2775 struct rfapi_descriptor
*rfd
=
2776 (struct rfapi_descriptor
*)handle
;
2777 count
= rfd
->monitor_count
;
2780 if (!bgp
|| !bgp
->rfapi
)
2783 count
= bgp
->rfapi
->monitor_count
;
2789 /***********************************************************************
2791 ***********************************************************************/
2793 DEFUN (debug_rfapi_show_nves
,
2794 debug_rfapi_show_nves_cmd
,
2795 "debug rfapi-dev show nves",
2799 "NVE Information\n")
2801 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2806 debug_rfapi_show_nves_vn_un
,
2807 debug_rfapi_show_nves_vn_un_cmd
,
2808 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2813 "Specify virtual network\n"
2814 "Specify underlay network interface\n"
2820 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2821 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2822 return CMD_WARNING_CONFIG_FAILED
;
2824 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2825 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2826 return CMD_WARNING_CONFIG_FAILED
;
2829 if (argv
[4]->arg
[0] == 'u') {
2830 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2832 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2838 * Note: this function does not flush vty output, so if it is called
2839 * with a stream pointing to a vty, the user will have to type something
2840 * before the callback output shows up
2842 static void test_nexthops_callback(
2843 // struct rfapi_ip_addr *target,
2844 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2846 void *stream
= userdata
;
2848 int (*fp
)(void *, const char *, ...);
2851 const char *vty_newline
;
2853 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2856 fp(out
, "Nexthops Callback, Target=(");
2857 // rfapiPrintRfapiIpAddr(stream, target);
2860 rfapiPrintNhl(stream
, next_hops
);
2864 rfapi_free_next_hop_list(next_hops
);
2867 DEFUN (debug_rfapi_open
,
2868 debug_rfapi_open_cmd
,
2869 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2873 "indicate vn addr follows\n"
2874 "virtual network interface IPv4 address\n"
2875 "virtual network interface IPv6 address\n"
2876 "indicate xt addr follows\n"
2877 "underlay network interface IPv4 address\n"
2878 "underlay network interface IPv6 address\n")
2880 struct rfapi_ip_addr vn
;
2881 struct rfapi_ip_addr un
;
2882 uint32_t lifetime
= 0;
2884 rfapi_handle handle
;
2889 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2895 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2898 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2899 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2901 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2904 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2906 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2912 DEFUN (debug_rfapi_close_vn_un
,
2913 debug_rfapi_close_vn_un_cmd
,
2914 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2918 "indicate vn addr follows\n"
2919 "virtual network interface IPv4 address\n"
2920 "virtual network interface IPv6 address\n"
2921 "indicate xt addr follows\n"
2922 "underlay network interface IPv4 address\n"
2923 "underlay network interface IPv6 address\n")
2925 struct rfapi_ip_addr vn
;
2926 struct rfapi_ip_addr un
;
2927 rfapi_handle handle
;
2933 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2940 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2944 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2945 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2946 argv
[4]->arg
, argv
[6]->arg
);
2947 return CMD_WARNING_CONFIG_FAILED
;
2950 rc
= rfapi_close(handle
);
2952 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2957 DEFUN (debug_rfapi_close_rfd
,
2958 debug_rfapi_close_rfd_cmd
,
2959 "debug rfapi-dev close rfd HANDLE",
2963 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2965 rfapi_handle handle
;
2967 char *endptr
= NULL
;
2969 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2971 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2972 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2973 return CMD_WARNING_CONFIG_FAILED
;
2976 rc
= rfapi_close(handle
);
2978 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2983 DEFUN (debug_rfapi_register_vn_un
,
2984 debug_rfapi_register_vn_un_cmd
,
2985 "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)]",
2989 "indicate vn addr follows\n"
2990 "virtual network IPv4 interface address\n"
2991 "virtual network IPv6 interface address\n"
2992 "indicate un addr follows\n"
2993 "underlay network IPv4 interface address\n"
2994 "underlay network IPv6 interface address\n"
2995 "indicate prefix follows\n"
2998 "indicate lifetime follows\n"
3000 "Cost (localpref = 255-cost)\n"
3003 struct rfapi_ip_addr vn
;
3004 struct rfapi_ip_addr un
;
3005 rfapi_handle handle
;
3008 struct rfapi_ip_prefix hpfx
;
3015 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3022 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3026 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3027 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3028 argv
[4]->arg
, argv
[6]->arg
);
3029 return CMD_WARNING_CONFIG_FAILED
;
3033 * Get prefix to advertise
3035 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3036 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3037 return CMD_WARNING_CONFIG_FAILED
;
3039 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3040 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3041 return CMD_WARNING_CONFIG_FAILED
;
3043 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3045 if (strmatch(argv
[10]->text
, "infinite")) {
3046 lifetime
= RFAPI_INFINITE_LIFETIME
;
3048 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3052 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3055 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3056 RFAPI_REGISTER_ADD
);
3058 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3065 DEFUN (debug_rfapi_register_vn_un_l2o
,
3066 debug_rfapi_register_vn_un_l2o_cmd
,
3067 "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 X:X:X:X:X:X lni (0-16777215)",
3071 "indicate vn addr follows\n"
3072 "virtual network IPv4 interface address\n"
3073 "virtual network IPv6 interface address\n"
3074 "indicate un addr follows\n"
3075 "underlay network IPv4 interface address\n"
3076 "underlay network IPv6 interface address\n"
3077 "indicate prefix follows\n"
3080 "indicate lifetime follows\n"
3081 "Seconds of lifetime\n"
3082 "indicate MAC address follows\n"
3084 "indicate lni follows\n"
3085 "lni value range\n")
3087 struct rfapi_ip_addr vn
;
3088 struct rfapi_ip_addr un
;
3089 rfapi_handle handle
;
3092 struct rfapi_ip_prefix hpfx
;
3094 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3095 struct rfapi_vn_option
*opt
= NULL
;
3101 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3108 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3112 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3113 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3114 argv
[4]->arg
, argv
[6]->arg
);
3115 return CMD_WARNING_CONFIG_FAILED
;
3119 * Get prefix to advertise
3121 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3122 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3123 return CMD_WARNING_CONFIG_FAILED
;
3125 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3126 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3127 return CMD_WARNING_CONFIG_FAILED
;
3129 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3131 if (strmatch(argv
[10]->text
, "infinite")) {
3132 lifetime
= RFAPI_INFINITE_LIFETIME
;
3134 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3137 /* L2 option parsing START */
3138 memset(optary
, 0, sizeof(optary
));
3139 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3140 strtoul(argv
[14]->arg
, NULL
, 10);
3141 if (rfapiStr2EthAddr(argv
[12]->arg
,
3142 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3143 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3144 return CMD_WARNING_CONFIG_FAILED
;
3146 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3149 /* L2 option parsing END */
3152 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3153 RFAPI_REGISTER_ADD
);
3155 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3163 DEFUN (debug_rfapi_unregister_vn_un
,
3164 debug_rfapi_unregister_vn_un_cmd
,
3165 "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]",
3168 "rfapi_unregister\n"
3169 "indicate vn addr follows\n"
3170 "virtual network interface address\n"
3171 "virtual network interface address\n"
3172 "indicate xt addr follows\n"
3173 "underlay network interface address\n"
3174 "underlay network interface address\n"
3175 "prefix to remove\n"
3176 "prefix to remove\n"
3177 "prefix to remove\n"
3178 "Remove without holddown\n")
3180 struct rfapi_ip_addr vn
;
3181 struct rfapi_ip_addr un
;
3182 rfapi_handle handle
;
3184 struct rfapi_ip_prefix hpfx
;
3190 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3196 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3200 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3201 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3202 argv
[4]->arg
, argv
[6]->arg
);
3203 return CMD_WARNING_CONFIG_FAILED
;
3207 * Get prefix to advertise
3209 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3210 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3211 return CMD_WARNING_CONFIG_FAILED
;
3213 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3214 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3215 return CMD_WARNING_CONFIG_FAILED
;
3217 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3219 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3221 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3226 DEFUN (debug_rfapi_query_vn_un
,
3227 debug_rfapi_query_vn_un_cmd
,
3228 "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>",
3232 "indicate vn addr follows\n"
3233 "virtual network interface IPv4 address\n"
3234 "virtual network interface IPv6 address\n"
3235 "indicate un addr follows\n"
3238 "indicate target follows\n"
3239 "target IPv4 address\n"
3240 "target IPv6 address\n")
3242 struct rfapi_ip_addr vn
;
3243 struct rfapi_ip_addr un
;
3244 struct rfapi_ip_addr target
;
3245 rfapi_handle handle
;
3247 struct rfapi_next_hop_entry
*pNextHopEntry
;
3252 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3259 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3266 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3270 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3271 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3272 argv
[4]->arg
, argv
[6]->arg
);
3273 return CMD_WARNING_CONFIG_FAILED
;
3277 * options parameter not used? Set to NULL for now
3279 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3282 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3286 * print nexthop list
3288 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3289 vty
); /* frees nh list! */
3296 DEFUN (debug_rfapi_query_vn_un_l2o
,
3297 debug_rfapi_query_vn_un_l2o_cmd
,
3298 "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 X:X:X:X:X:X",
3302 "indicate vn addr follows\n"
3303 "virtual network interface IPv4 address\n"
3304 "virtual network interface IPv6 address\n"
3305 "indicate xt addr follows\n"
3306 "underlay network interface IPv4 address\n"
3307 "underlay network interface IPv6 address\n"
3308 "logical network ID follows\n"
3309 "logical network ID\n"
3310 "indicate target MAC addr follows\n"
3311 "target MAC addr\n")
3313 struct rfapi_ip_addr vn
;
3314 struct rfapi_ip_addr un
;
3320 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3327 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3330 vty_out(vty
, "%% This command is broken.\n");
3331 return CMD_WARNING_CONFIG_FAILED
;
3335 DEFUN (debug_rfapi_query_done_vn_un
,
3336 debug_rfapi_query_vn_un_done_cmd
,
3337 "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>",
3340 "rfapi_query_done\n"
3341 "rfapi_query_done\n"
3342 "indicate vn addr follows\n"
3343 "virtual network interface IPv4 address\n"
3344 "virtual network interface IPv6 address\n"
3345 "indicate xt addr follows\n"
3346 "underlay network interface IPv4 address\n"
3347 "underlay network interface IPv6 address\n"
3348 "indicate target follows\n"
3349 "Target IPv4 address\n"
3350 "Target IPv6 address\n")
3352 struct rfapi_ip_addr vn
;
3353 struct rfapi_ip_addr un
;
3354 struct rfapi_ip_addr target
;
3355 rfapi_handle handle
;
3361 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3368 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3375 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3379 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3380 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3381 argv
[5]->arg
, argv
[7]->arg
);
3382 return CMD_WARNING_CONFIG_FAILED
;
3386 * options parameter not used? Set to NULL for now
3388 rc
= rfapi_query_done(handle
, &target
);
3390 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3395 DEFUN (debug_rfapi_show_import
,
3396 debug_rfapi_show_import_cmd
,
3397 "debug rfapi-dev show import",
3405 struct rfapi_import_table
*it
;
3410 * Show all import tables
3413 bgp
= bgp_get_default(); /* assume 1 instance for now */
3415 vty_out(vty
, "No BGP instance\n");
3416 return CMD_WARNING_CONFIG_FAILED
;
3421 vty_out(vty
, "No RFAPI instance\n");
3422 return CMD_WARNING_CONFIG_FAILED
;
3426 * Iterate over all import tables; do a filtered import
3427 * for the afi/safi combination
3431 for (it
= h
->imports
; it
; it
= it
->next
) {
3432 s
= ecommunity_ecom2str(it
->rt_import_list
,
3433 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3434 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3435 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3437 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3439 rfapiShowImportTable(vty
, "IP ENCAP",
3440 it
->imported_encap
[AFI_IP
], 0);
3441 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3443 rfapiShowImportTable(vty
, "IP6 ENCAP",
3444 it
->imported_encap
[AFI_IP6
], 0);
3447 if (h
->import_mac
) {
3448 void *cursor
= NULL
;
3450 uintptr_t lni_as_ptr
;
3454 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3455 (void **)&it
, &cursor
);
3457 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3458 (void **)&it
, &cursor
)) {
3460 if (it
->imported_vpn
[AFI_L2VPN
]) {
3464 "\nLNI-based Ethernet Tables:\n");
3467 snprintf(buf
, sizeof(buf
), "L2VPN LNI=%u", lni
);
3468 rfapiShowImportTable(
3469 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3475 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3476 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3481 DEFUN (debug_rfapi_show_import_vn_un
,
3482 debug_rfapi_show_import_vn_un_cmd
,
3483 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3488 "indicate vn addr follows\n"
3489 "virtual network interface IPv4 address\n"
3490 "virtual network interface IPv6 address\n"
3491 "indicate xt addr follows\n"
3492 "underlay network interface IPv4 address\n"
3493 "underlay network interface IPv6 address\n")
3495 struct rfapi_ip_addr vn
;
3496 struct rfapi_ip_addr un
;
3497 rfapi_handle handle
;
3499 struct rfapi_descriptor
*rfd
;
3504 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3511 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3515 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3516 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3517 argv
[5]->arg
, argv
[7]->arg
);
3518 return CMD_WARNING_CONFIG_FAILED
;
3521 rfd
= (struct rfapi_descriptor
*)handle
;
3523 rfapiShowImportTable(vty
, "IP VPN",
3524 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3525 rfapiShowImportTable(vty
, "IP ENCAP",
3526 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3527 rfapiShowImportTable(vty
, "IP6 VPN",
3528 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3529 rfapiShowImportTable(vty
, "IP6 ENCAP",
3530 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3535 DEFUN (debug_rfapi_response_omit_self
,
3536 debug_rfapi_response_omit_self_cmd
,
3537 "debug rfapi-dev response-omit-self <on|off>",
3540 "Omit self in RFP responses\n"
3541 "filter out self from responses\n" "leave self in responses\n")
3543 struct bgp
*bgp
= bgp_get_default();
3546 vty_out(vty
, "No BGP process is configured\n");
3547 return CMD_WARNING_CONFIG_FAILED
;
3549 if (!bgp
->rfapi_cfg
) {
3550 vty_out(vty
, "VNC not configured\n");
3551 return CMD_WARNING_CONFIG_FAILED
;
3554 if (strmatch(argv
[3]->text
, "on"))
3555 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3556 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3558 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3559 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3565 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3567 #include "lib/skiplist.h"
3568 DEFUN (skiplist_test_cli
,
3569 skiplist_test_cli_cmd
,
3571 "skiplist command\n"
3579 DEFUN (skiplist_debug_cli
,
3580 skiplist_debug_cli_cmd
,
3582 "skiplist command\n"
3585 skiplist_debug(vty
, NULL
);
3589 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3591 void rfapi_init(void)
3593 bgp_rfapi_cfg_init();
3596 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3597 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3599 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3600 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3601 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3602 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3603 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3604 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3605 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3606 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3608 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3610 /* Need the following show commands for gpz test scripts */
3611 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3612 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3613 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3615 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3616 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3617 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3624 static void rfapi_print_exported(struct bgp
*bgp
)
3626 struct bgp_dest
*destn
;
3627 struct bgp_dest
*dest
;
3628 struct bgp_path_info
*bpi
;
3633 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); destn
;
3634 destn
= bgp_route_next(destn
)) {
3635 struct bgp_table
*table
;
3637 table
= bgp_dest_get_bgp_table_info(destn
);
3640 fprintf(stderr
, "%s: vpn destn=%p\n", __func__
, destn
);
3641 for (dest
= bgp_table_top(table
); dest
;
3642 dest
= bgp_route_next(dest
)) {
3643 bpi
= bgp_dest_get_bgp_path_info(dest
);
3647 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3648 for (; bpi
; bpi
= bpi
->next
) {
3649 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3653 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); destn
;
3654 destn
= bgp_route_next(destn
)) {
3655 struct bgp_table
*table
;
3657 table
= bgp_dest_get_bgp_table_info(destn
);
3660 fprintf(stderr
, "%s: encap destn=%p\n", __func__
, destn
);
3661 for (dest
= bgp_table_top(table
); dest
;
3662 dest
= bgp_route_next(dest
)) {
3663 bpi
= bgp_dest_get_bgp_path_info(dest
);
3666 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3667 for (; bpi
; bpi
= bpi
->next
) {
3668 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3673 #endif /* defined(DEBUG_RFAPI) */
3676 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3678 void rfapi_delete(struct bgp
*bgp
)
3680 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3683 zlog_debug("%s: bgp %p", __func__
, bgp
);
3687 * This clears queries and registered routes, and closes nves
3690 rfp_clear_vnc_nve_all();
3693 * close any remaining descriptors
3695 struct rfapi
*h
= bgp
->rfapi
;
3697 if (h
&& h
->descriptors
.count
) {
3698 struct listnode
*node
, *nnode
;
3699 struct rfapi_descriptor
*rfd
;
3701 zlog_debug("%s: descriptor count %u", __func__
,
3702 h
->descriptors
.count
);
3704 for (ALL_LIST_ELEMENTS(&h
->descriptors
, node
, nnode
, rfd
)) {
3706 zlog_debug("%s: closing rfd %p", __func__
, rfd
);
3708 (void)rfapi_close(rfd
);
3712 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3713 bgp
->rfapi_cfg
= NULL
;
3714 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3718 * show what's left in the BGP MPLSVPN RIB
3720 rfapi_print_exported(bgp
);
3724 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3726 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3727 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3728 vnc_zlog_debug_verbose(
3729 "%s: can't auto-assign RD, VN addr family is not IPv4|v6",
3731 return EAFNOSUPPORT
;
3733 rd
->family
= AF_UNSPEC
;
3735 rd
->val
[1] = RD_TYPE_IP
;
3736 if (vn
->addr_family
== AF_INET
) {
3737 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3738 } else { /* is v6 */
3739 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3740 4); /* low order 4 bytes */
3742 vnc_zlog_debug_verbose("%s: auto-RD is set to %pRDP", __func__
, rd
);
3746 /*------------------------------------------
3747 * rfapi_bgp_lookup_by_rfp
3749 * Find bgp instance pointer based on value returned by rfp_start
3752 * rfp_start_val value returned by rfp_startor
3753 * NULL (=get default instance)
3759 * bgp bgp instance pointer
3762 --------------------------------------------*/
3763 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3765 struct bgp
*bgp
= NULL
;
3766 struct listnode
*node
, *nnode
;
3768 if (rfp_start_val
== NULL
)
3769 bgp
= bgp_get_default();
3771 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3772 if (bgp
->rfapi
!= NULL
3773 && bgp
->rfapi
->rfp
== rfp_start_val
)
3778 /*------------------------------------------
3779 * rfapi_get_rfp_start_val_by_bgp
3781 * Find bgp instance pointer based on value returned by rfp_start
3784 * bgp bgp instance pointer
3793 --------------------------------------------*/
3794 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3796 if (!bgp
|| !bgp
->rfapi
)
3798 return bgp
->rfapi
->rfp
;
3801 /***********************************************************************
3802 * RFP group specific configuration
3803 ***********************************************************************/
3804 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3808 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3809 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3810 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3813 return rfc
->default_rfp_cfg
;
3816 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3820 struct rfapi_nve_group_cfg
*rfg
=
3821 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3823 /* make sure group is still in list */
3824 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3825 /* Not in list anymore */
3826 vty_out(vty
, "Current NVE group no longer exists\n");
3830 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3831 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3832 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3835 return rfg
->rfp_cfg
;
3838 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3842 struct rfapi_l2_group_cfg
*rfg
=
3843 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3845 /* make sure group is still in list */
3846 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3847 /* Not in list anymore */
3848 vty_out(vty
, "Current L2 group no longer exists\n");
3851 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3852 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3853 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3856 return rfg
->rfp_cfg
;
3859 /*------------------------------------------
3860 * rfapi_rfp_init_group_config_ptr_vty
3862 * This is used to init or return a previously init'ed group specific
3863 * configuration pointer. Group is identified by vty context.
3864 * NOTE: size is ignored when a previously init'ed value is returned.
3865 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3866 * bgp restart or shutdown.
3869 * rfp_start_val value returned by rfp_start
3871 * vty quagga vty context
3872 * size number of bytes to allocation
3878 * rfp_cfg_group NULL or Pointer to configuration structure
3879 --------------------------------------------*/
3880 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3881 rfapi_rfp_cfg_group_type type
,
3882 struct vty
*vty
, uint32_t size
)
3887 if (rfp_start_val
== NULL
|| vty
== NULL
)
3890 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3891 if (!bgp
|| !bgp
->rfapi_cfg
)
3895 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3896 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3899 case RFAPI_RFP_CFG_GROUP_NVE
:
3900 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3903 case RFAPI_RFP_CFG_GROUP_L2
:
3904 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3908 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3910 /* should never happen */
3911 assert("Unknown type" == NULL
);
3917 /*------------------------------------------
3918 * rfapi_rfp_get_group_config_ptr_vty
3920 * This is used to get group specific configuration pointer.
3921 * Group is identified by type and vty context.
3922 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3923 * bgp restart or shutdown.
3926 * rfp_start_val value returned by rfp_start
3928 * vty quagga vty context
3934 * rfp_cfg_group Pointer to configuration structure
3935 --------------------------------------------*/
3936 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3937 rfapi_rfp_cfg_group_type type
,
3940 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3944 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3946 rfp_group_config_search_cb_t
*search_cb
)
3948 struct rfapi_nve_group_cfg
*rfg
;
3949 struct listnode
*node
;
3951 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3952 if (!strcmp(rfg
->name
, name
) && /* name match */
3953 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3954 return rfg
->rfp_cfg
;
3960 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3962 rfp_group_config_search_cb_t
*search_cb
)
3964 struct rfapi_l2_group_cfg
*rfg
;
3965 struct listnode
*node
;
3967 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3968 if (!strcmp(rfg
->name
, name
) && /* name match */
3969 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3970 return rfg
->rfp_cfg
;
3975 /*------------------------------------------
3976 * rfapi_rfp_get_group_config_ptr_name
3978 * This is used to get group specific configuration pointer.
3979 * Group is identified by type and name context.
3980 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3981 * bgp restart or shutdown.
3984 * rfp_start_val value returned by rfp_start
3987 * criteria RFAPI caller provided search criteria
3988 * search_cb optional rfp_group_config_search_cb_t
3994 * rfp_cfg_group Pointer to configuration structure
3995 --------------------------------------------*/
3996 void *rfapi_rfp_get_group_config_ptr_name(
3997 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3998 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
4003 if (rfp_start_val
== NULL
|| name
== NULL
)
4006 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4007 if (!bgp
|| !bgp
->rfapi_cfg
)
4011 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4012 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4014 case RFAPI_RFP_CFG_GROUP_NVE
:
4015 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4016 criteria
, search_cb
);
4018 case RFAPI_RFP_CFG_GROUP_L2
:
4019 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4020 criteria
, search_cb
);
4023 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4025 /* should never happen */
4026 assert("Unknown type" == NULL
);
4032 /*------------------------------------------
4033 * rfapi_rfp_get_l2_group_config_ptr_lni
4035 * This is used to get group specific configuration pointer.
4036 * Group is identified by type and logical network identifier.
4037 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4038 * bgp restart or shutdown.
4041 * rfp_start_val value returned by rfp_start
4043 * logical_net_id group logical network identifier
4044 * criteria RFAPI caller provided search criteria
4045 * search_cb optional rfp_group_config_search_cb_t
4051 * rfp_cfg_group Pointer to configuration structure
4052 --------------------------------------------*/
4054 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4055 uint32_t logical_net_id
, void *criteria
,
4056 rfp_group_config_search_cb_t
*search_cb
)
4059 struct rfapi_l2_group_cfg
*rfg
;
4060 struct listnode
*node
;
4062 if (rfp_start_val
== NULL
)
4065 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4066 if (!bgp
|| !bgp
->rfapi_cfg
)
4069 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4070 if (rfg
->logical_net_id
== logical_net_id
4071 && (search_cb
== NULL
4072 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4073 if (rfg
->rfp_cfg
== NULL
)
4074 vnc_zlog_debug_verbose(
4075 "%s: returning rfp group config for lni=0",
4077 return rfg
->rfp_cfg
;