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
24 #include "lib/zebra.h"
25 #include "lib/prefix.h"
26 #include "lib/agg_table.h"
28 #include "lib/memory.h"
29 #include "lib/routemap.h"
31 #include "lib/linklist.h"
32 #include "lib/command.h"
33 #include "lib/stream.h"
34 #include "lib/ringbuf.h"
35 #include "lib/lib_errors.h"
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_ecommunity.h"
39 #include "bgpd/bgp_attr.h"
41 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
42 #include "bgpd/rfapi/rfapi.h"
43 #include "bgpd/rfapi/rfapi_backend.h"
45 #include "bgpd/bgp_route.h"
46 #include "bgpd/bgp_mplsvpn.h"
47 #include "bgpd/bgp_aspath.h"
48 #include "bgpd/bgp_advertise.h"
49 #include "bgpd/bgp_vnc_types.h"
50 #include "bgpd/bgp_zebra.h"
52 #include "bgpd/rfapi/rfapi_import.h"
53 #include "bgpd/rfapi/rfapi_private.h"
54 #include "bgpd/rfapi/rfapi_monitor.h"
55 #include "bgpd/rfapi/rfapi_vty.h"
56 #include "bgpd/rfapi/vnc_export_bgp.h"
57 #include "bgpd/rfapi/vnc_export_bgp_p.h"
58 #include "bgpd/rfapi/vnc_zebra.h"
59 #include "bgpd/rfapi/vnc_import_bgp.h"
60 #include "bgpd/rfapi/rfapi_rib.h"
61 #include "bgpd/rfapi/rfapi_ap.h"
62 #include "bgpd/rfapi/rfapi_encap_tlv.h"
63 #include "bgpd/rfapi/vnc_debug.h"
65 #ifdef HAVE_GLIBC_BACKTRACE
66 /* for backtrace and friends */
68 #endif /* HAVE_GLIBC_BACKTRACE */
70 struct ethaddr rfapi_ethaddr0
= {{0}};
72 #define DEBUG_RFAPI_STR "RF API debugging/testing command\n"
74 const char *rfapi_error_str(int code
)
80 return "BGP or VNC not configured";
84 return "Handle already open";
86 return "Incomplete configuration";
88 return "Invalid address family";
90 return "Called from within a callback procedure";
92 return "Invalid handle";
94 return "Invalid argument";
96 return "Stale descriptor";
98 return "Unknown error";
102 /*------------------------------------------
103 * rfapi_get_response_lifetime_default
105 * Returns the default lifetime for a response.
106 * rfp_start_val value returned by rfp_start or
107 * NULL (=use default instance)
114 * return value: The bgp instance default lifetime for a response.
115 --------------------------------------------*/
116 int rfapi_get_response_lifetime_default(void *rfp_start_val
)
118 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
120 return bgp
->rfapi_cfg
->default_response_lifetime
;
121 return BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
;
124 /*------------------------------------------
125 * rfapi_is_vnc_configured
127 * Returns if VNC is configured
130 * rfp_start_val value returned by rfp_start or
131 * NULL (=use default instance)
135 * return value: If VNC is configured for the bgpd instance
137 * ENXIO VNC not configured
138 --------------------------------------------*/
139 int rfapi_is_vnc_configured(void *rfp_start_val
)
141 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
142 if (bgp_rfapi_is_vnc_configured(bgp
) == 0)
148 /*------------------------------------------
151 * Get the virtual network address used by an NVE based on it's RFD
154 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
159 * vn NVE virtual network address
160 *------------------------------------------*/
161 struct rfapi_ip_addr
*rfapi_get_vn_addr(void *rfd
)
163 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
164 return &rrfd
->vn_addr
;
167 /*------------------------------------------
170 * Get the underlay network address used by an NVE based on it's RFD
173 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
178 * un NVE underlay network address
179 *------------------------------------------*/
180 struct rfapi_ip_addr
*rfapi_get_un_addr(void *rfd
)
182 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
183 return &rrfd
->un_addr
;
186 int rfapi_ip_addr_cmp(struct rfapi_ip_addr
*a1
, struct rfapi_ip_addr
*a2
)
188 if (a1
->addr_family
!= a2
->addr_family
)
189 return a1
->addr_family
- a2
->addr_family
;
191 if (a1
->addr_family
== AF_INET
) {
192 return IPV4_ADDR_CMP(&a1
->addr
.v4
, &a2
->addr
.v4
);
195 if (a1
->addr_family
== AF_INET6
) {
196 return IPV6_ADDR_CMP(&a1
->addr
.v6
, &a2
->addr
.v6
);
204 static int rfapi_find_node(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
205 struct rfapi_ip_addr
*un_addr
,
206 struct agg_node
**node
)
223 afi
= family2afi(un_addr
->addr_family
);
228 if ((rc
= rfapiRaddr2Qprefix(un_addr
, &p
)))
231 rn
= agg_node_lookup(h
->un
[afi
], &p
);
244 int rfapi_find_rfd(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
245 struct rfapi_ip_addr
*un_addr
, struct rfapi_descriptor
**rfd
)
250 rc
= rfapi_find_node(bgp
, vn_addr
, un_addr
, &rn
);
255 for (*rfd
= (struct rfapi_descriptor
*)(rn
->info
); *rfd
;
256 *rfd
= (*rfd
)->next
) {
257 if (!rfapi_ip_addr_cmp(&(*rfd
)->vn_addr
, vn_addr
))
267 /*------------------------------------------
271 * un underlay network address
272 * vn virtual network address
275 * pHandle pointer to location to store handle
279 * ENOENT no matching handle
280 * ENXIO BGP or VNC not configured
281 *------------------------------------------*/
282 static int rfapi_find_handle(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
283 struct rfapi_ip_addr
*un_addr
,
284 rfapi_handle
*handle
)
286 struct rfapi_descriptor
**rfd
;
288 rfd
= (struct rfapi_descriptor
**)handle
;
290 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
293 static int rfapi_find_handle_vty(struct vty
*vty
, struct rfapi_ip_addr
*vn_addr
,
294 struct rfapi_ip_addr
*un_addr
,
295 rfapi_handle
*handle
)
298 struct rfapi_descriptor
**rfd
;
300 bgp
= bgp_get_default(); /* assume 1 instance for now */
302 rfd
= (struct rfapi_descriptor
**)handle
;
304 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
307 static int is_valid_rfd(struct rfapi_descriptor
*rfd
)
311 if (!rfd
|| rfd
->bgp
== NULL
)
316 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
319 if (rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &hh
))
329 * check status of descriptor
331 int rfapi_check(void *handle
)
333 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
337 if (!rfd
|| rfd
->bgp
== NULL
)
342 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
345 if ((rc
= rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
,
359 void del_vnc_route(struct rfapi_descriptor
*rfd
,
360 struct peer
*peer
, /* rfd->peer for RFP regs */
361 struct bgp
*bgp
, safi_t safi
, struct prefix
*p
,
362 struct prefix_rd
*prd
, uint8_t type
, uint8_t sub_type
,
363 struct rfapi_nexthop
*lnh
, int kill
)
365 afi_t afi
; /* of the VN address */
368 char buf
[PREFIX_STRLEN
];
369 char buf2
[RD_ADDRSTRLEN
];
370 struct prefix_rd prd0
;
372 prefix2str(p
, buf
, sizeof(buf
));
374 afi
= family2afi(p
->family
);
375 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
377 if (safi
== SAFI_ENCAP
) {
378 memset(&prd0
, 0, sizeof(prd0
));
379 prd0
.family
= AF_UNSPEC
;
383 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
385 vnc_zlog_debug_verbose(
386 "%s: peer=%p, prefix=%s, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
387 __func__
, peer
, buf
, prefix_rd2str(prd
, buf2
, sizeof(buf2
)),
388 afi
, safi
, bn
, (bn
? bn
->info
: NULL
));
390 for (bi
= (bn
? bn
->info
: NULL
); bi
; bi
= bi
->next
) {
392 vnc_zlog_debug_verbose(
393 "%s: trying bi=%p, bi->peer=%p, bi->type=%d, bi->sub_type=%d, bi->extra->vnc.export.rfapi_handle=%p, local_pref=%u",
394 __func__
, bi
, bi
->peer
, bi
->type
, bi
->sub_type
,
395 (bi
->extra
? bi
->extra
->vnc
.export
.rfapi_handle
: NULL
),
397 && CHECK_FLAG(bi
->attr
->flag
,
398 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
399 ? bi
->attr
->local_pref
402 if (bi
->peer
== peer
&& bi
->type
== type
403 && bi
->sub_type
== sub_type
&& bi
->extra
404 && bi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
406 vnc_zlog_debug_verbose("%s: matched it", __func__
);
414 * lnh set means to JUST delete the local nexthop from this
415 * route. Leave the route itself in place.
416 * TBD add return code reporting of success/failure
418 if (!bi
|| !bi
->extra
419 || !bi
->extra
->vnc
.export
.local_nexthops
) {
423 vnc_zlog_debug_verbose(
424 "%s: lnh list already empty at prefix %s",
432 struct listnode
*node
;
433 struct rfapi_nexthop
*pLnh
= NULL
;
435 for (ALL_LIST_ELEMENTS_RO(bi
->extra
->vnc
.export
.local_nexthops
,
438 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
444 listnode_delete(bi
->extra
->vnc
.export
.local_nexthops
,
447 /* silly rabbit, listnode_delete doesn't invoke
448 * list->del on data */
449 rfapi_nexthop_free(pLnh
);
451 vnc_zlog_debug_verbose("%s: desired lnh not found %s",
458 * loop back to import tables
459 * Do this before removing from BGP RIB because rfapiProcessWithdraw
462 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
465 char buf
[PREFIX_STRLEN
];
467 prefix2str(p
, buf
, sizeof(buf
));
468 vnc_zlog_debug_verbose(
469 "%s: Found route (safi=%d) to delete at prefix %s",
470 __func__
, safi
, buf
);
472 if (safi
== SAFI_MPLS_VPN
) {
473 struct bgp_node
*prn
= NULL
;
474 struct bgp_table
*table
= NULL
;
476 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
477 (struct prefix
*)prd
);
479 table
= (struct bgp_table
*)(prn
->info
);
481 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
482 bgp
, prd
, table
, p
, bi
);
484 bgp_unlock_node(prn
);
488 * Delete local_nexthops list
490 if (bi
->extra
&& bi
->extra
->vnc
.export
.local_nexthops
) {
491 list_delete_and_null(
492 &bi
->extra
->vnc
.export
.local_nexthops
);
495 bgp_aggregate_decrement(bgp
, p
, bi
, afi
, safi
);
496 bgp_info_delete(bn
, bi
);
497 bgp_process(bgp
, bn
, afi
, safi
);
499 vnc_zlog_debug_verbose(
500 "%s: Couldn't find route (safi=%d) at prefix %s",
501 __func__
, safi
, buf
);
507 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
509 struct rfapi_nexthop
*new =
510 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
516 void rfapi_nexthop_free(void *p
)
518 struct rfapi_nexthop
*goner
= p
;
519 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
522 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
524 struct rfapi_vn_option
*p
;
525 struct rfapi_vn_option
*head
= NULL
;
526 struct rfapi_vn_option
*tail
= NULL
;
528 for (p
= existing
; p
; p
= p
->next
) {
529 struct rfapi_vn_option
*new;
531 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
532 sizeof(struct rfapi_vn_option
));
545 void rfapi_un_options_free(struct rfapi_un_option
*p
)
547 struct rfapi_un_option
*next
;
551 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
556 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
558 struct rfapi_vn_option
*next
;
562 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
567 /* Based on bgp_redistribute_add() */
568 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
569 struct bgp
*bgp
, int safi
, struct prefix
*p
,
570 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
571 uint32_t *local_pref
,
572 uint32_t *lifetime
, /* NULL => dont send lifetime */
573 struct bgp_tea_options
*rfp_options
,
574 struct rfapi_un_option
*options_un
,
575 struct rfapi_vn_option
*options_vn
,
576 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
577 uint32_t *med
, /* NULL => don't set med */
578 uint32_t *label
, /* low order 3 bytes */
579 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
582 afi_t afi
; /* of the VN address */
583 struct bgp_info
*new;
587 struct attr attr
= {0};
588 struct attr
*new_attr
;
591 struct bgp_attr_encap_subtlv
*encaptlv
;
592 char buf
[PREFIX_STRLEN
];
593 char buf2
[RD_ADDRSTRLEN
];
595 struct prefix pfx_buf
;
598 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
599 struct rfapi_vn_option
*vo
;
600 struct rfapi_l2address_option
*l2o
= NULL
;
601 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
603 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
604 struct bgp_redist
*red
;
606 if (safi
== SAFI_ENCAP
607 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
610 * Encap mode not enabled. UN addresses will be communicated
611 * via VNC Tunnel subtlv instead.
613 vnc_zlog_debug_verbose(
614 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
620 if ((safi
== SAFI_MPLS_VPN
) && (flags
& RFAPI_AHR_SET_PFX_TO_NEXTHOP
))
623 if (rfapiRaddr2Qprefix (nexthop
, &pfx_buf
))
625 vnc_zlog_debug_verbose
626 ("%s: can't set pfx to vn addr, not adding SAFI_MPLS_VPN route",
633 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
634 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
636 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
637 l2o
= NULL
; /* not MAC resolution */
639 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
640 lnh
= &vo
->v
.local_nexthop
;
647 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
649 prefix_rd2str(prd
, buf2
, sizeof(buf2
));
651 afi
= family2afi(p
->family
);
652 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
654 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
657 /* Make default attribute. Produces already-interned attr.aspath */
658 /* Cripes, the memory management of attributes is byzantine */
660 bgp_attr_default_set(&attr
, BGP_ORIGIN_INCOMPLETE
);
665 * extra: dynamically allocated, owned by attr
666 * aspath: points to interned hash from aspath hash table
671 * Route-specific un_options get added to the VPN SAFI
672 * advertisement tunnel encap attribute. (the per-NVE
673 * "default" un_options are put into the 1-per-NVE ENCAP
674 * SAFI advertisement). The VPN SAFI also gets the
675 * default un_options if there are no route-specific options.
678 struct rfapi_un_option
*uo
;
680 for (uo
= options_un
; uo
; uo
= uo
->next
) {
681 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
682 TunnelType
= rfapi_tunneltype_option_to_tlv(
683 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
690 * These are the NVE-specific "default" un_options which are
691 * put into the 1-per-NVE ENCAP advertisement.
693 if (rfd
->default_tunneltype_option
.type
) {
694 TunnelType
= rfapi_tunneltype_option_to_tlv(
695 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
697 } else /* create default for local addse */
698 if (type
== ZEBRA_ROUTE_BGP
699 && sub_type
== BGP_ROUTE_RFP
)
700 TunnelType
= rfapi_tunneltype_option_to_tlv(
701 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
704 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
705 if (safi
== SAFI_ENCAP
) {
706 /* Encap SAFI not used with MPLS */
707 vnc_zlog_debug_verbose(
708 "%s: mpls tunnel type, encap safi omitted",
710 aspath_unintern(&attr
.aspath
); /* Unintern original. */
716 attr
.local_pref
= *local_pref
;
717 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
722 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
725 /* override default weight assigned by bgp_attr_default_set() */
726 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
729 * NB: ticket 81: do not reset attr.aspath here because it would
730 * cause iBGP peers to drop route
734 * Set originator ID for routes imported from BGP directly.
735 * These routes could be synthetic, and therefore could
736 * reuse the peer pointers of the routes they are derived
737 * from. Setting the originator ID to "us" prevents the
738 * wrong originator ID from being sent when this route is
739 * sent from a route reflector.
741 if (type
== ZEBRA_ROUTE_BGP_DIRECT
742 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
743 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
744 attr
.originator_id
= bgp
->router_id
;
748 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
749 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
752 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
753 sizeof(struct bgp_attr_encap_subtlv
) + 4);
756 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
757 encaptlv
->length
= 4;
758 lt
= htonl(*lifetime
);
759 memcpy(encaptlv
->value
, <
, 4);
760 attr
.vnc_subtlvs
= encaptlv
;
761 vnc_zlog_debug_verbose(
762 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
766 /* add rfp options to vnc attr */
769 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
772 * this flag means we're passing a pointer to an
773 * existing encap tlv chain which we should copy.
774 * It's a hack to avoid adding yet another argument
777 encaptlv
= encap_tlv_dup(
778 (struct bgp_attr_encap_subtlv
*)rfp_options
);
779 if (attr
.vnc_subtlvs
) {
780 attr
.vnc_subtlvs
->next
= encaptlv
;
782 attr
.vnc_subtlvs
= encaptlv
;
786 struct bgp_tea_options
*hop
;
787 /* XXX max of one tlv present so far from above code */
788 struct bgp_attr_encap_subtlv
*tail
= attr
.vnc_subtlvs
;
790 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
797 sizeof(struct bgp_attr_encap_subtlv
) + 2
801 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
804 encaptlv
->length
= 2 + hop
->length
;
805 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
806 *((uint8_t *)(encaptlv
->value
) + 1) =
808 memcpy(((uint8_t *)encaptlv
->value
) + 2,
809 hop
->value
, hop
->length
);
812 * add to end of subtlv chain
815 tail
->next
= encaptlv
;
817 attr
.vnc_subtlvs
= encaptlv
;
827 * extra: dynamically allocated, owned by attr
828 * vnc_subtlvs: dynamic chain, length 1
829 * aspath: points to interned hash from aspath hash table
833 attr
.ecommunity
= ecommunity_new();
834 assert(attr
.ecommunity
);
836 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
837 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
839 * Add BGP Encapsulation Extended Community. Format described in
840 * section 4.5 of RFC 5512.
841 * Always include when not MPLS type, to disambiguate this case.
843 struct ecommunity_val beec
;
845 memset(&beec
, 0, sizeof(beec
));
846 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
847 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
848 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
849 beec
.val
[7] = (TunnelType
)&0xff;
850 ecommunity_add_val(attr
.ecommunity
, &beec
);
854 * Add extended community attributes to match rt export list
856 if (rt_export_list
) {
858 ecommunity_merge(attr
.ecommunity
, rt_export_list
);
861 if (attr
.ecommunity
->size
) {
862 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
864 ecommunity_free(&attr
.ecommunity
);
865 attr
.ecommunity
= NULL
;
867 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
,
874 * extra: dynamically allocated, owned by attr
875 * vnc_subtlvs: dynamic chain, length 1
876 * ecommunity: dynamic 2-part
877 * aspath: points to interned hash from aspath hash table
880 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
881 switch (nexthop
->addr_family
) {
884 * set this field to prevent bgp_route.c code from setting
885 * mp_nexthop_global_in to self
887 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
889 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
890 attr
.mp_nexthop_len
= 4;
894 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
895 attr
.mp_nexthop_len
= 16;
903 prefix2str(p
, buf
, sizeof(buf
));
909 * extra: dynamically allocated, owned by attr
910 * vnc_subtlvs: dynamic chain, length 1
911 * ecommunity: dynamic 2-part
912 * aspath: points to interned hash from aspath hash table
915 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
917 if (red
&& red
->redist_metric_flag
) {
918 attr
.med
= red
->redist_metric
;
919 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
922 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
925 * bgp_attr_intern creates a new reference to a cached
926 * attribute, but leaves the following bits of trash:
928 * - old attr->extra (free via bgp_attr_extra_free(attr))
930 * Note that it frees the original attr->extra->ecommunity
931 * but leaves the new attribute pointing to the ORIGINAL
932 * vnc options (which therefore we needn't free from the
935 new_attr
= bgp_attr_intern(&attr
);
937 aspath_unintern(&attr
.aspath
); /* Unintern original. */
943 * extra: dynamically allocated, owned by attr
944 * vnc_subtlvs: dynamic chain, length 1
945 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
947 * new_attr: an attr that is part of the hash table, distinct
948 * from attr which is static.
949 * extra: dynamically allocated, owned by new_attr (in hash table)
950 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
951 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
952 * aspath: POINTS TO interned/refcounted hashed block
954 for (bi
= bn
->info
; bi
; bi
= bi
->next
) {
955 /* probably only need to check
956 * bi->extra->vnc.export.rfapi_handle */
957 if (bi
->peer
== rfd
->peer
&& bi
->type
== type
958 && bi
->sub_type
== sub_type
&& bi
->extra
959 && bi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
968 * Adding new local_nexthop, which does not by itself change
969 * what is advertised via BGP
972 if (!bi
->extra
->vnc
.export
.local_nexthops
) {
973 /* TBD make arrangements to free when needed */
974 bi
->extra
->vnc
.export
.local_nexthops
=
976 bi
->extra
->vnc
.export
.local_nexthops
->del
=
983 struct listnode
*node
;
984 struct rfapi_nexthop
*pLnh
= NULL
;
986 for (ALL_LIST_ELEMENTS_RO(
987 bi
->extra
->vnc
.export
.local_nexthops
, node
,
990 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
996 * Not present, add new one
999 pLnh
= rfapi_nexthop_new(lnh
);
1001 bi
->extra
->vnc
.export
.local_nexthops
,
1006 if (attrhash_cmp(bi
->attr
, new_attr
)
1007 && !CHECK_FLAG(bi
->flags
, BGP_INFO_REMOVED
)) {
1008 bgp_attr_unintern(&new_attr
);
1009 bgp_unlock_node(bn
);
1012 "%s: Found route (safi=%d) at prefix %s, no change",
1013 __func__
, safi
, buf
);
1017 /* The attribute is changed. */
1018 bgp_info_set_flag(bn
, bi
, BGP_INFO_ATTR_CHANGED
);
1020 if (safi
== SAFI_MPLS_VPN
) {
1021 struct bgp_node
*prn
= NULL
;
1022 struct bgp_table
*table
= NULL
;
1024 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
1025 (struct prefix
*)prd
);
1027 table
= (struct bgp_table
*)(prn
->info
);
1029 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
1030 bgp
, prd
, table
, p
, bi
);
1032 bgp_unlock_node(prn
);
1035 /* Rewrite BGP route information. */
1036 if (CHECK_FLAG(bi
->flags
, BGP_INFO_REMOVED
))
1037 bgp_info_restore(bn
, bi
);
1039 bgp_aggregate_decrement(bgp
, p
, bi
, afi
, safi
);
1040 bgp_attr_unintern(&bi
->attr
);
1041 bi
->attr
= new_attr
;
1042 bi
->uptime
= bgp_clock();
1045 if (safi
== SAFI_MPLS_VPN
) {
1046 struct bgp_node
*prn
= NULL
;
1047 struct bgp_table
*table
= NULL
;
1049 prn
= bgp_node_get(bgp
->rib
[afi
][safi
],
1050 (struct prefix
*)prd
);
1052 table
= (struct bgp_table
*)(prn
->info
);
1054 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1055 bgp
, prd
, table
, p
, bi
);
1057 bgp_unlock_node(prn
);
1060 /* Process change. */
1061 bgp_aggregate_increment(bgp
, p
, bi
, afi
, safi
);
1062 bgp_process(bgp
, bn
, afi
, safi
);
1063 bgp_unlock_node(bn
);
1066 "%s: Found route (safi=%d) at prefix %s, changed attr",
1067 __func__
, safi
, buf
);
1074 new = bgp_info_new();
1076 new->sub_type
= sub_type
;
1077 new->peer
= rfd
->peer
;
1078 SET_FLAG(new->flags
, BGP_INFO_VALID
);
1079 new->attr
= new_attr
;
1080 new->uptime
= bgp_clock();
1082 /* save backref to rfapi handle */
1083 assert(bgp_info_extra_get(new));
1084 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1085 encode_label(label_val
, &new->extra
->label
[0]);
1089 if (VNC_DEBUG(VERBOSE
)) {
1090 vnc_zlog_debug_verbose("%s: printing BI", __func__
);
1091 rfapiPrintBi(NULL
, new);
1094 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1095 bgp_info_add(bn
, new);
1097 if (safi
== SAFI_MPLS_VPN
) {
1098 struct bgp_node
*prn
= NULL
;
1099 struct bgp_table
*table
= NULL
;
1101 prn
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1103 table
= (struct bgp_table
*)(prn
->info
);
1105 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1106 bgp
, prd
, table
, p
, new);
1108 bgp_unlock_node(prn
);
1109 encode_label(label_val
, &bn
->local_label
);
1112 bgp_unlock_node(bn
);
1113 bgp_process(bgp
, bn
, afi
, safi
);
1116 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
1117 __func__
, safi2str(safi
), buf
, bn
, buf2
);
1120 /* Loop back to import tables */
1121 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1122 sub_type
, &label_val
);
1123 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1127 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1132 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1133 struct rfapi_descriptor
*rfd
,
1134 uint32_t *pLifetime
)
1136 struct prefix_rd prd
;
1137 struct prefix pfx_vn
;
1139 uint32_t local_pref
= rfp_cost_to_localpref(0);
1141 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1145 * Construct route distinguisher = 0
1147 memset(&prd
, 0, sizeof(prd
));
1148 prd
.family
= AF_UNSPEC
;
1151 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1152 bgp
, /* which bgp instance */
1153 SAFI_ENCAP
, /* which SAFI */
1154 &pfx_vn
, /* prefix to advertise */
1155 &prd
, /* route distinguisher to use */
1156 &rfd
->un_addr
, /* nexthop */
1158 pLifetime
, /* max lifetime of child VPN routes */
1159 NULL
, /* no rfp options for ENCAP safi */
1160 NULL
, /* rfp un options */
1161 NULL
, /* rfp vn options */
1162 rfd
->rt_export_list
, NULL
, /* med */
1163 NULL
, /* label: default */
1164 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1168 /***********************************************************************
1169 * RFP processing behavior configuration
1170 ***********************************************************************/
1172 /*------------------------------------------
1173 * rfapi_rfp_set_configuration
1175 * This is used to change rfapi's processing behavior based on
1179 * rfp_start_val value returned by rfp_start
1180 * rfapi_rfp_cfg Pointer to configuration structure
1187 * ENXIO Unabled to locate configured BGP/VNC
1188 --------------------------------------------*/
1189 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1191 struct rfapi_rfp_cfg
*rcfg
;
1194 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1196 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1199 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1200 rcfg
->download_type
= new->download_type
;
1201 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1202 rcfg
->holddown_factor
= new->holddown_factor
;
1204 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1205 rcfg
->use_updated_response
= new->use_updated_response
;
1206 if (rcfg
->use_updated_response
)
1207 rfapiMonitorCallbacksOn(bgp
);
1209 rfapiMonitorCallbacksOff(bgp
);
1211 if (rcfg
->use_removes
!= new->use_removes
) {
1212 rcfg
->use_removes
= new->use_removes
;
1213 if (rcfg
->use_removes
)
1214 rfapiMonitorResponseRemovalOn(bgp
);
1216 rfapiMonitorResponseRemovalOff(bgp
);
1221 /*------------------------------------------
1222 * rfapi_rfp_set_cb_methods
1224 * Change registered callback functions for asynchronous notifications
1225 * from RFAPI to the RFP client.
1228 * rfp_start_val value returned by rfp_start
1229 * methods Pointer to struct rfapi_rfp_cb_methods containing
1230 * pointers to callback methods as described above
1234 * ENXIO BGP or VNC not configured
1235 *------------------------------------------*/
1236 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1237 struct rfapi_rfp_cb_methods
*methods
)
1242 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1250 h
->rfp_methods
= *methods
;
1255 /***********************************************************************
1257 ***********************************************************************/
1259 * Caller must supply an already-allocated rfd with the "caller"
1260 * fields already set (vn_addr, un_addr, callback, cookie)
1261 * The advertised_prefixes[] array elements should be NULL to
1262 * have this function set them to newly-allocated radix trees.
1264 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1265 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1269 if (h
->flags
& RFAPI_INCALLBACK
)
1273 * Fill in configured fields
1277 * If group's RD is specified as "auto", then fill in based
1278 * on NVE's VN address
1282 if (rfd
->rd
.family
== AF_UNIX
) {
1283 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1287 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1288 ? ecommunity_dup(rfg
->rt_export_list
)
1290 rfd
->response_lifetime
= rfg
->response_lifetime
;
1294 * Fill in BGP peer structure
1296 rfd
->peer
= peer_new(bgp
);
1297 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1298 bgp_sync_delete(rfd
->peer
); /* don't need these */
1301 * since this peer is not on the I/O thread, this lock is not strictly
1302 * necessary, but serves as a reminder to those who may meddle...
1304 pthread_mutex_lock(&rfd
->peer
->io_mtx
);
1306 // we don't need any I/O related facilities
1307 if (rfd
->peer
->ibuf
)
1308 stream_fifo_free(rfd
->peer
->ibuf
);
1309 if (rfd
->peer
->obuf
)
1310 stream_fifo_free(rfd
->peer
->obuf
);
1312 if (rfd
->peer
->ibuf_work
)
1313 ringbuf_del(rfd
->peer
->ibuf_work
);
1314 if (rfd
->peer
->obuf_work
)
1315 stream_free(rfd
->peer
->obuf_work
);
1317 rfd
->peer
->ibuf
= NULL
;
1318 rfd
->peer
->obuf
= NULL
;
1319 rfd
->peer
->obuf_work
= NULL
;
1320 rfd
->peer
->ibuf_work
= NULL
;
1322 pthread_mutex_unlock(&rfd
->peer
->io_mtx
);
1324 { /* base code assumes have valid host pointer */
1328 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1329 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
, BUFSIZ
);
1330 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1331 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
, BUFSIZ
);
1333 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1335 /* Mark peer as belonging to HD */
1336 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1339 * Set min prefix lifetime to max value so it will get set
1340 * upon first rfapi_register()
1342 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1345 * Allocate response tables if needed
1347 #define RFD_RTINIT_AFI(rh, ary, afi) \
1350 ary[afi] = agg_table_init(); \
1351 agg_set_table_info(ary[afi], rh); \
1355 #define RFD_RTINIT(rh, ary) \
1357 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1358 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1359 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1362 RFD_RTINIT(rfd
, rfd
->rib
);
1363 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1364 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1367 * Link to Import Table
1369 rfd
->import_table
= rfg
->rfapi_import_table
;
1370 rfd
->import_table
->refcount
+= 1;
1372 rfapiApInit(&rfd
->advertised
);
1375 * add this NVE descriptor to the list of NVEs in the NVE group
1378 rfg
->nves
= list_new();
1380 listnode_add(rfg
->nves
, rfd
);
1382 vnc_direct_bgp_add_nve(bgp
, rfd
);
1383 vnc_zebra_add_nve(bgp
, rfd
);
1388 /* moved from rfapi_register */
1389 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1390 struct rfapi_nve_group_cfg
*rfg
)
1392 struct rfapi
*h
= bgp
->rfapi
;
1393 char buf_vn
[BUFSIZ
];
1394 char buf_un
[BUFSIZ
];
1395 afi_t afi_vn
, afi_un
;
1396 struct prefix pfx_un
;
1397 struct agg_node
*rn
;
1400 rfapi_time(&rfd
->open_time
);
1402 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1403 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1405 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1406 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1408 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1409 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1411 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1413 listnode_add(&h
->descriptors
, rfd
);
1414 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1415 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1419 * attach to UN radix tree
1421 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1422 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1423 assert(afi_vn
&& afi_un
);
1424 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1426 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1428 rfd
->next
= rn
->info
;
1432 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1435 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1437 struct rfapi_vn_option
*head
= NULL
;
1438 struct rfapi_vn_option
*tail
= NULL
;
1439 struct rfapi_vn_option
*vo
= NULL
;
1441 for (vo
= orig
; vo
; vo
= vo
->next
) {
1442 struct rfapi_vn_option
*new;
1444 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1445 sizeof(struct rfapi_vn_option
));
1446 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1458 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1460 struct rfapi_un_option
*head
= NULL
;
1461 struct rfapi_un_option
*tail
= NULL
;
1462 struct rfapi_un_option
*uo
= NULL
;
1464 for (uo
= orig
; uo
; uo
= uo
->next
) {
1465 struct rfapi_un_option
*new;
1467 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1468 sizeof(struct rfapi_un_option
));
1469 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1481 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1483 struct bgp_tea_options
*head
= NULL
;
1484 struct bgp_tea_options
*tail
= NULL
;
1485 struct bgp_tea_options
*hop
= NULL
;
1487 for (hop
= orig
; hop
; hop
= hop
->next
) {
1488 struct bgp_tea_options
*new;
1490 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1491 sizeof(struct bgp_tea_options
));
1492 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1495 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1497 memcpy(new->value
, hop
->value
, hop
->length
);
1508 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1510 struct bgp_tea_options
*next
;
1516 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1519 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1525 void rfapiAdbFree(struct rfapi_adb
*adb
)
1527 XFREE(MTYPE_RFAPI_ADB
, adb
);
1531 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1532 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1533 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1537 struct prefix p_original
;
1538 struct agg_node
*rn
;
1539 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1540 struct bgp
*bgp
= rfd
->bgp
;
1541 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1542 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1544 int use_eth_resolution
= 0;
1545 struct rfapi_next_hop_entry
*i_nhe
;
1549 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1554 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1558 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1559 vnc_zlog_debug_verbose(
1560 "%s: Called during calback, returning EDEADLK",
1565 if (!is_valid_rfd(rfd
)) {
1566 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1571 rfd
->rsp_counter
++; /* dedup: identify this generation */
1572 rfd
->rsp_time
= rfapi_time(NULL
); /* response content dedup */
1573 rfd
->ftd_last_allowed_time
=
1575 - bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1578 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1582 /* per t/c Paul/Lou 151022 */
1583 if (!eth_is_0
|| l2o
->logical_net_id
) {
1584 use_eth_resolution
= 1;
1589 *ppNextHopEntry
= NULL
;
1592 * Save original target in prefix form. In case of L2-based queries,
1593 * p_original will be modified to reflect the L2 target
1595 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1597 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1598 /* convert query to 0/0 when full-table download is enabled */
1599 memset((char *)&p
, 0, sizeof(p
));
1600 p
.family
= target
->addr_family
;
1606 char buf
[PREFIX_STRLEN
];
1609 prefix2str(&p
, buf
, sizeof(buf
));
1610 vnc_zlog_debug_verbose("%s(rfd=%p, target=%s, ppNextHop=%p)",
1611 __func__
, rfd
, buf
, ppNextHopEntry
);
1613 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1614 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1615 vnc_zlog_debug_verbose(
1616 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1617 __func__
, rfd
->import_table
, s
);
1618 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1621 afi
= family2afi(p
.family
);
1624 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1625 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1626 self_vn_addr
= &rfd
->vn_addr
;
1629 if (use_eth_resolution
) {
1630 uint32_t logical_net_id
= l2o
->logical_net_id
;
1631 struct ecommunity
*l2com
;
1634 * fix up p_original to contain L2 address
1636 rfapiL2o2Qprefix(l2o
, &p_original
);
1638 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1639 bgp
, 1, logical_net_id
, l2o
->label
);
1641 uint8_t *v
= l2com
->val
;
1642 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1645 * Ethernet/L2-based lookup
1647 * Always returns IT node corresponding to route
1650 if (RFAPI_RFP_DOWNLOAD_FULL
1651 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1655 rn
= rfapiMonitorEthAdd(
1656 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1660 struct rfapi_ip_prefix rprefix
;
1662 memset(&rprefix
, 0, sizeof(rprefix
));
1663 rprefix
.prefix
.addr_family
= target
->addr_family
;
1664 if (target
->addr_family
== AF_INET
) {
1665 rprefix
.length
= 32;
1667 rprefix
.length
= 128;
1670 pNHE
= rfapiEthRouteTable2NextHopList(
1671 logical_net_id
, &rprefix
,
1672 rfd
->response_lifetime
, self_vn_addr
,
1673 rfd
->rib
[afi
], &p_original
);
1683 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1686 * If target address is 0, this request is special: means to
1687 * return ALL routes in the table
1689 * Monitors for All-Routes queries get put on a special list,
1690 * not in the VPN tree
1692 if (RFAPI_0_PREFIX(&p
)) {
1694 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1697 * Generate nexthop list for caller
1699 pNHE
= rfapiRouteTable2NextHopList(
1700 rfd
->import_table
->imported_vpn
[afi
],
1701 rfd
->response_lifetime
, self_vn_addr
,
1702 rfd
->rib
[afi
], &p_original
);
1707 agg_lock_node(rn
); /* so we can unlock below */
1710 * returns locked node. Don't unlock yet because the
1712 * might free it before we're done with it. This
1714 * could occur when rfapiMonitorGetAttachNode() returns
1716 * newly-created default node.
1718 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1724 agg_unlock_node(rn
);
1725 vnc_zlog_debug_verbose(
1726 "%s: VPN route not found, returning ENOENT", __func__
);
1730 if (VNC_DEBUG(RFAPI_QUERY
)) {
1731 rfapiShowImportTable(NULL
, "query",
1732 rfd
->import_table
->imported_vpn
[afi
], 1);
1735 if (use_eth_resolution
) {
1737 struct rfapi_ip_prefix rprefix
;
1739 memset(&rprefix
, 0, sizeof(rprefix
));
1740 rprefix
.prefix
.addr_family
= target
->addr_family
;
1741 if (target
->addr_family
== AF_INET
) {
1742 rprefix
.length
= 32;
1744 rprefix
.length
= 128;
1747 pNHE
= rfapiEthRouteNode2NextHopList(
1748 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1749 rfd
->rib
[afi
], &p_original
);
1754 * Generate answer to query
1756 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1757 self_vn_addr
, rfd
->rib
[afi
],
1761 agg_unlock_node(rn
);
1764 if (ppNextHopEntry
) {
1765 /* only count if caller gets it */
1766 ++bgp
->rfapi
->response_immediate_count
;
1770 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1776 * count nexthops for statistics
1778 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1779 ++rfd
->stat_count_nh_reachable
;
1782 if (ppNextHopEntry
) {
1783 *ppNextHopEntry
= pNHE
;
1785 rfapi_free_next_hop_list(pNHE
);
1788 vnc_zlog_debug_verbose("%s: success", __func__
);
1793 * support on-the-fly reassignment of an already-open nve to a new
1794 * nve-group in the event that its original nve-group is
1795 * administratively deleted.
1797 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1799 struct prefix pfx_vn
;
1800 struct prefix pfx_un
;
1801 struct rfapi_nve_group_cfg
*rfg
;
1803 struct rfapi_cfg
*hc
;
1810 hc
= bgp
->rfapi_cfg
;
1814 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1817 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1821 * Find the matching nve group config block
1823 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1829 * check nve group config block for required values
1831 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1836 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1842 * re-advertise registered routes, this time as part of new NVE-group
1844 rfapiApReadvertiseAll(bgp
, rfd
);
1847 * re-attach callbacks to import table
1849 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1850 rfapiMonitorAttachImportHd(rfd
);
1856 /*------------------------------------------
1859 * This function initializes a NVE record and associates it with
1860 * the specified VN and underlay network addresses
1863 * rfp_start_val value returned by rfp_start
1864 * vn NVE virtual network address
1866 * un NVE underlay network address
1868 * default_options Default options to use on registrations.
1869 * For now only tunnel type is supported.
1870 * May be overridden per-prefix in rfapi_register().
1871 * Caller owns (rfapi_open() does not free)
1873 * response_cb Pointer to next hop list update callback function or
1874 * NULL when no callbacks are desired.
1876 * userdata Passed to subsequent response_cb invocations.
1879 * response_lifetime The length of time that responses sent to this
1882 * pHandle pointer to location to store rfapi handle. The
1883 * handle must be passed on subsequent rfapi_ calls.
1888 * EEXIST NVE with this {vn,un} already open
1889 * ENOENT No matching nve group config
1890 * ENOMSG Matched nve group config was incomplete
1891 * ENXIO BGP or VNC not configured
1892 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1893 * but underlay network address is not IPv4
1894 * EDEADLK Called from within a callback procedure
1895 *------------------------------------------*/
1896 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1897 struct rfapi_ip_addr
*un
,
1898 struct rfapi_un_option
*default_options
,
1899 uint32_t *response_lifetime
,
1900 void *userdata
, /* callback cookie */
1901 rfapi_handle
*pHandle
)
1905 struct rfapi_descriptor
*rfd
;
1906 struct rfapi_cfg
*hc
;
1907 struct rfapi_nve_group_cfg
*rfg
;
1909 struct prefix pfx_vn
;
1910 struct prefix pfx_un
;
1913 rfapi_handle hh
= NULL
;
1914 int reusing_provisional
= 0;
1917 char buf
[2][INET_ADDRSTRLEN
];
1918 vnc_zlog_debug_verbose(
1919 "%s: VN=%s UN=%s", __func__
,
1920 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1921 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1927 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1935 hc
= bgp
->rfapi_cfg
;
1939 if (h
->flags
& RFAPI_INCALLBACK
)
1942 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1945 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1949 * already have a descriptor with VN and UN?
1951 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1953 * we might have set up a handle for static routes before
1954 * this NVE was opened. In that case, reuse the handle
1957 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1962 * reuse provisional descriptor
1965 reusing_provisional
= 1;
1969 * Find the matching nve group config block
1971 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1973 ++h
->stat
.count_unknown_nves
;
1975 char buf
[2][INET_ADDRSTRLEN
];
1976 zlog_notice("%s: no matching group VN=%s UN=%s",
1978 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1980 rfapiRfapiIpAddr2Str(un
, buf
[1],
1987 * check nve group config block for required values
1989 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1991 ++h
->stat
.count_unknown_nves
;
1996 * If group config specifies auto-rd assignment, check that
1997 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1998 * Check here so we don't need to unwind memory allocations, &c.
2000 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
2001 && (vn
->addr_family
!= AF_INET6
)) {
2002 return EAFNOSUPPORT
;
2007 * reusing provisional rfd
2011 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
2012 sizeof(struct rfapi_descriptor
));
2017 if (default_options
) {
2018 struct rfapi_un_option
*p
;
2020 for (p
= default_options
; p
; p
= p
->next
) {
2021 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
2022 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
2024 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
2025 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
2031 * Fill in caller fields
2035 rfd
->cookie
= userdata
;
2037 if (!reusing_provisional
) {
2038 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
2040 * This can fail only if the VN address is IPv6 and the group
2041 * specified auto-assignment of RDs, which only works for v4,
2042 * and the check above should catch it.
2044 * Another failure possibility is that we were called
2045 * during an rfapi callback. Also checked above.
2050 if (response_lifetime
)
2051 *response_lifetime
= rfd
->response_lifetime
;
2057 * For use with debug functions
2059 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2060 rfapi_response_cb_t
*response_cb
)
2062 if (!is_valid_rfd(rfd
))
2064 rfd
->response_cb
= response_cb
;
2071 * Does almost all the work of rfapi_close, except:
2072 * 1. preserves the descriptor (doesn't free it)
2073 * 2. preserves the prefix query list (i.e., rfd->mon list)
2074 * 3. preserves the advertised prefix list (rfd->advertised)
2075 * 4. preserves the rib and rib_pending tables
2077 * The purpose of organizing it this way is to support on-the-fly
2078 * reassignment of an already-open nve to a new nve-group in the
2079 * event that its original nve-group is administratively deleted.
2081 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2084 struct prefix pfx_vn
;
2085 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2087 if (!is_valid_rfd(rfd
))
2090 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2091 assert(!rc
); /* should never have bad AF in stored vn address */
2094 * update exported routes to reflect disappearance of this NVE as
2097 vnc_direct_bgp_del_nve(bgp
, rfd
);
2098 vnc_zebra_del_nve(bgp
, rfd
);
2101 * unlink this HD's monitors from import table
2103 rfapiMonitorDetachImportHd(rfd
);
2106 * Unlink from Import Table
2107 * NB rfd->import_table will be NULL if we are closing a stale
2110 if (rfd
->import_table
)
2111 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2112 rfd
->import_table
= NULL
;
2115 * Construct route distinguisher
2117 memset(&prd
, 0, sizeof(prd
));
2119 prd
.family
= AF_UNSPEC
;
2125 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2126 &pfx_vn
, /* prefix being advertised */
2127 &prd
, /* route distinguisher to use (0 for ENCAP) */
2128 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2131 * Construct route distinguisher for VPN routes
2134 prd
.family
= AF_UNSPEC
;
2138 * find all VPN routes associated with this rfd and delete them, too
2140 rfapiApWithdrawAll(bgp
, rfd
);
2143 * remove this nve descriptor from the list of nves
2144 * associated with the nve group
2147 listnode_delete(rfd
->rfg
->nves
, rfd
);
2148 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2151 if (rfd
->rt_export_list
)
2152 ecommunity_free(&rfd
->rt_export_list
);
2153 rfd
->rt_export_list
= NULL
;
2156 * free peer structure (possibly delayed until its
2157 * refcount reaches zero)
2160 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2161 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2162 peer_delete(rfd
->peer
);
2169 int rfapi_close(void *handle
)
2171 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2173 struct agg_node
*node
;
2177 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2179 #if RFAPI_WHO_IS_CALLING_ME
2180 #ifdef HAVE_GLIBC_BACKTRACE
2181 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2183 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2188 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2189 syms
= backtrace_symbols(buf
, size
);
2190 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2192 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2208 if (!is_valid_rfd(rfd
))
2211 if (h
->flags
& RFAPI_INCALLBACK
) {
2213 * Queue these close requests for processing after callback
2216 if (!CHECK_FLAG(rfd
->flags
,
2217 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2218 work_queue_add(h
->deferred_close_q
, handle
);
2219 vnc_zlog_debug_verbose(
2220 "%s: added handle %p to deferred close queue",
2226 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2228 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2231 if (h
&& h
->rfp_methods
.close_cb
) {
2232 vnc_zlog_debug_verbose(
2233 "%s calling close callback rfd=%p", __func__
,
2237 * call the callback fairly early so that it can still
2241 * NB RFAPI_INCALLBACK is tested above, so if we reach
2243 * we are not already in the context of a callback.
2245 h
->flags
|= RFAPI_INCALLBACK
;
2246 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2247 h
->flags
&= ~RFAPI_INCALLBACK
;
2253 * Orphaned descriptors have already done this part, so do
2254 * only for non-orphaned descriptors.
2256 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2261 * Remove descriptor from UN index
2262 * (remove from chain at node)
2264 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2266 struct rfapi_descriptor
*hh
;
2268 if (node
->info
== rfd
) {
2269 node
->info
= rfd
->next
;
2272 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2273 if (hh
->next
== rfd
) {
2274 hh
->next
= rfd
->next
;
2279 agg_unlock_node(node
);
2283 * remove from descriptor list
2285 listnode_delete(&h
->descriptors
, rfd
);
2288 * Delete monitor list items and free monitor structures
2290 (void)rfapiMonitorDelHd(rfd
);
2293 * release advertised prefix data
2295 rfapiApRelease(&rfd
->advertised
);
2298 * Release RFP callback RIB
2305 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2306 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2312 * Reopen a nve descriptor. If the descriptor's NVE-group
2313 * does not exist (e.g., if it has been administratively removed),
2314 * reassignment to a new NVE-group is attempted.
2316 * If NVE-group reassignment fails, the descriptor becomes "stale"
2317 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2318 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2319 * on the descriptor will return ESTALE.
2321 * Reopening a descriptor is a potentially expensive operation, because
2322 * it involves withdrawing any routes advertised by the NVE, withdrawing
2323 * the NVE's route queries, and then re-adding them all after a new
2324 * NVE-group is assigned. There are also possible route-export affects
2325 * caused by deleting and then adding the NVE: advertised prefixes
2326 * and nexthop lists for exported routes can turn over.
2328 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2333 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2336 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2340 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2342 if (CHECK_FLAG(rfd
->flags
,
2343 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2344 && h
&& h
->rfp_methods
.close_cb
) {
2347 * NB RFAPI_INCALLBACK is tested above, so if we reach
2349 * we are not already in the context of a callback.
2351 h
->flags
|= RFAPI_INCALLBACK
;
2352 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2353 h
->flags
&= ~RFAPI_INCALLBACK
;
2360 /***********************************************************************
2362 ***********************************************************************/
2364 * Announce reachability to this prefix via the NVE
2366 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2367 uint32_t lifetime
, /* host byte order */
2368 struct rfapi_un_option
*options_un
,
2369 struct rfapi_vn_option
*options_vn
,
2370 rfapi_register_action action
)
2372 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2375 struct prefix
*pfx_ip
= NULL
;
2376 struct prefix_rd prd
;
2378 struct prefix pfx_mac_buf
;
2379 struct prefix
*pfx_mac
= NULL
;
2380 struct prefix pfx_vn_buf
;
2381 const char *action_str
= NULL
;
2382 uint32_t *label
= NULL
;
2383 struct rfapi_vn_option
*vo
;
2384 struct rfapi_l2address_option
*l2o
= NULL
;
2385 struct prefix_rd
*prd_override
= NULL
;
2388 case RFAPI_REGISTER_ADD
:
2391 case RFAPI_REGISTER_WITHDRAW
:
2392 action_str
= "withdraw";
2394 case RFAPI_REGISTER_KILL
:
2395 action_str
= "kill";
2403 * Inspect VN options
2405 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2406 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2407 l2o
= &vo
->v
.l2addr
;
2409 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2410 prd_override
= &vo
->v
.internal_rd
;
2414 /*********************************************************************
2416 *********************************************************************/
2419 * set <p> based on <prefix>
2421 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2423 afi
= family2afi(prefix
->prefix
.addr_family
);
2428 char buf
[PREFIX_STRLEN
];
2430 prefix2str(&p
, buf
, sizeof(buf
));
2431 vnc_zlog_debug_verbose(
2432 "%s(rfd=%p, pfx=%s, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2433 __func__
, rfd
, buf
, lifetime
, options_un
, options_vn
,
2438 * These tests come after the prefix conversion so that we can
2439 * print the prefix in a debug message before failing
2444 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2449 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2454 if (RFAPI_REGISTER_ADD
== action
) {
2455 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2457 vnc_zlog_debug_verbose(
2458 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2463 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2464 if (RFAPI_REGISTER_ADD
== action
) {
2465 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2467 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2472 if (!is_valid_rfd(rfd
)) {
2473 if (RFAPI_REGISTER_ADD
== action
) {
2474 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2476 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2482 * Is there a MAC address in this registration?
2484 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2485 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2486 pfx_mac
= &pfx_mac_buf
;
2490 * Is there an IP prefix in this registration?
2492 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2496 vnc_zlog_debug_verbose(
2497 "%s: missing mac addr that is required for host 0 pfx",
2499 if (RFAPI_REGISTER_ADD
== action
) {
2500 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2504 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2505 vnc_zlog_debug_verbose(
2506 "%s: handle has bad vn_addr: returning EBADF",
2508 if (RFAPI_REGISTER_ADD
== action
) {
2509 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2515 if (RFAPI_REGISTER_ADD
== action
) {
2516 ++bgp
->rfapi
->stat
.count_registrations
;
2520 * Figure out if this registration is missing an IP address
2524 * In RFAPI, we use prefixes in family AF_LINK to store
2525 * the MAC addresses. These prefixes are used for the
2526 * list of advertised prefixes and in the RFAPI import
2529 * In BGP proper, we use the prefix matching the NVE's
2530 * VN address with a host prefix-length (i.e., 32 or 128).
2533 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2534 && RFAPI_HOST_PREFIX(&p
)) {
2536 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2537 pfx_mac
= &pfx_mac_buf
;
2541 * Construct route distinguisher
2544 prd
= *prd_override
;
2546 memset(&prd
, 0, sizeof(prd
));
2548 prd
.family
= AF_UNSPEC
;
2550 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2551 if (l2o
->local_nve_id
2552 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2554 * If Local NVE ID is specified in message, use
2556 * (if no local default configured, also use it
2559 prd
.val
[1] = l2o
->local_nve_id
;
2561 if (rfd
->rfg
->l2rd
) {
2563 * locally-configured literal value
2565 prd
.val
[1] = rfd
->rfg
->l2rd
;
2568 * 0 means auto:vn, which means use LSB
2571 if (rfd
->vn_addr
.addr_family
2574 *(((char *)&rfd
->vn_addr
2580 *(((char *)&rfd
->vn_addr
2587 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2590 prd
.family
= AF_UNSPEC
;
2596 if (action
== RFAPI_REGISTER_WITHDRAW
2597 || action
== RFAPI_REGISTER_KILL
) {
2602 * withdraw previous advertisement
2605 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2607 : &pfx_vn_buf
, /* prefix being advertised */
2608 &prd
, /* route distinguisher (0 for ENCAP) */
2609 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2610 action
== RFAPI_REGISTER_KILL
);
2612 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2615 rfapiTunnelRouteAnnounce(
2616 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2622 uint32_t local_pref
;
2623 struct ecommunity
*rtlist
= NULL
;
2624 struct ecommunity_val ecom_value
;
2626 if (!rfapiApCount(rfd
)) {
2628 * make sure we advertise tunnel route upon adding the
2634 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2635 prefix
->cost
, l2o
)) {
2639 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2642 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2644 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2645 &rfd
->max_prefix_lifetime
);
2648 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2650 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2652 if (l2o
&& l2o
->label
)
2653 label
= &l2o
->label
;
2656 struct ecommunity
*l2com
= NULL
;
2659 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2660 bgp
, 1, l2o
->logical_net_id
, *label
);
2663 rtlist
= ecommunity_dup(l2com
);
2666 * If mac address is set, add an RT based on the
2669 memset((char *)&ecom_value
, 0,
2670 sizeof(ecom_value
));
2671 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2673 (l2o
->logical_net_id
>> 16) & 0xff;
2675 (l2o
->logical_net_id
>> 8) & 0xff;
2677 (l2o
->logical_net_id
>> 0) & 0xff;
2678 rtlist
= ecommunity_new();
2679 ecommunity_add_val(rtlist
, &ecom_value
);
2683 uint16_t val
= l2o
->tag_id
;
2684 memset((char *)&ecom_value
, 0,
2685 sizeof(ecom_value
));
2686 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2687 if (as
> BGP_AS_MAX
) {
2689 ECOMMUNITY_ENCODE_AS4
;
2690 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2691 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2692 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2693 ecom_value
.val
[5] = as
& 0xff;
2696 ECOMMUNITY_ENCODE_AS
;
2697 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2698 ecom_value
.val
[3] = as
& 0xff;
2700 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2701 ecom_value
.val
[7] = val
& 0xff;
2703 rtlist
= ecommunity_new();
2704 ecommunity_add_val(rtlist
, &ecom_value
);
2709 * advertise prefix via tunnel endpoint
2712 rfd
, /* rfapi descr, for export list & backref */
2713 bgp
, /* which bgp instance */
2714 SAFI_MPLS_VPN
, /* which SAFI */
2716 : &pfx_vn_buf
), /* prefix being advertised */
2717 &prd
, /* route distinguisher to use (0 for ENCAP) */
2718 &rfd
->vn_addr
, /* nexthop */
2720 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2721 NULL
, options_un
, /* rfapi un options */
2722 options_vn
, /* rfapi vn options */
2723 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2724 label
, /* label: default */
2725 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2728 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2731 vnc_zlog_debug_verbose("%s: success", __func__
);
2735 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2736 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2737 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2739 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2740 struct bgp
*bgp
= rfd
->bgp
;
2743 assert(ppNextHopEntry
);
2744 *ppNextHopEntry
= NULL
;
2746 if (bgp
&& bgp
->rfapi
) {
2747 bgp
->rfapi
->stat
.count_queries
++;
2751 if (bgp
&& bgp
->rfapi
)
2752 ++bgp
->rfapi
->stat
.count_queries_failed
;
2756 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2757 if (bgp
&& bgp
->rfapi
)
2758 ++bgp
->rfapi
->stat
.count_queries_failed
;
2763 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2767 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2768 struct bgp
*bgp
= rfd
->bgp
;
2774 rc
= rfapiRaddr2Qprefix(target
, &p
);
2777 if (!is_valid_rfd(rfd
))
2781 if (!bgp
|| !bgp
->rfapi
)
2784 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2787 rfapiMonitorDel(bgp
, rfd
, &p
);
2792 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2794 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2795 struct bgp
*bgp
= rfd
->bgp
;
2802 if (!is_valid_rfd(rfd
))
2806 if (!bgp
|| !bgp
->rfapi
)
2809 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2812 num
= rfapiMonitorDelHd(rfd
);
2820 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2822 struct rfapi_next_hop_entry
*nh
;
2823 struct rfapi_next_hop_entry
*next
;
2825 for (nh
= list
; nh
; nh
= next
) {
2827 rfapi_un_options_free(nh
->un_options
);
2828 nh
->un_options
= NULL
;
2829 rfapi_vn_options_free(nh
->vn_options
);
2830 nh
->vn_options
= NULL
;
2831 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2836 * NULL handle => return total count across all nves
2838 uint32_t rfapi_monitor_count(void *handle
)
2840 struct bgp
*bgp
= bgp_get_default();
2844 struct rfapi_descriptor
*rfd
=
2845 (struct rfapi_descriptor
*)handle
;
2846 count
= rfd
->monitor_count
;
2849 if (!bgp
|| !bgp
->rfapi
)
2852 count
= bgp
->rfapi
->monitor_count
;
2858 /***********************************************************************
2860 ***********************************************************************/
2862 DEFUN (debug_rfapi_show_nves
,
2863 debug_rfapi_show_nves_cmd
,
2864 "debug rfapi-dev show nves",
2868 "NVE Information\n")
2870 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2875 debug_rfapi_show_nves_vn_un
,
2876 debug_rfapi_show_nves_vn_un_cmd
,
2877 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2882 "Specify virtual network\n"
2883 "Specify underlay network interface\n"
2889 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2890 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2891 return CMD_WARNING_CONFIG_FAILED
;
2893 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2894 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2895 return CMD_WARNING_CONFIG_FAILED
;
2898 if (argv
[4]->arg
[0] == 'u') {
2899 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2901 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2907 * Note: this function does not flush vty output, so if it is called
2908 * with a stream pointing to a vty, the user will have to type something
2909 * before the callback output shows up
2911 static void test_nexthops_callback(
2912 // struct rfapi_ip_addr *target,
2913 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2915 void *stream
= userdata
;
2917 int (*fp
)(void *, const char *, ...);
2920 const char *vty_newline
;
2922 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2925 fp(out
, "Nexthops Callback, Target=(");
2926 // rfapiPrintRfapiIpAddr(stream, target);
2929 rfapiPrintNhl(stream
, next_hops
);
2933 rfapi_free_next_hop_list(next_hops
);
2936 DEFUN (debug_rfapi_open
,
2937 debug_rfapi_open_cmd
,
2938 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2942 "indicate vn addr follows\n"
2943 "virtual network interface IPv4 address\n"
2944 "virtual network interface IPv6 address\n"
2945 "indicate xt addr follows\n"
2946 "underlay network interface IPv4 address\n"
2947 "underlay network interface IPv6 address\n")
2949 struct rfapi_ip_addr vn
;
2950 struct rfapi_ip_addr un
;
2953 rfapi_handle handle
;
2958 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2964 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2967 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2968 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2970 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2973 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2975 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2981 DEFUN (debug_rfapi_close_vn_un
,
2982 debug_rfapi_close_vn_un_cmd
,
2983 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2987 "indicate vn addr follows\n"
2988 "virtual network interface IPv4 address\n"
2989 "virtual network interface IPv6 address\n"
2990 "indicate xt addr follows\n"
2991 "underlay network interface IPv4 address\n"
2992 "underlay network interface IPv6 address\n")
2994 struct rfapi_ip_addr vn
;
2995 struct rfapi_ip_addr un
;
2996 rfapi_handle handle
;
3002 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3009 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3013 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3014 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3015 argv
[4]->arg
, argv
[6]->arg
);
3016 return CMD_WARNING_CONFIG_FAILED
;
3019 rc
= rfapi_close(handle
);
3021 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
3026 DEFUN (debug_rfapi_close_rfd
,
3027 debug_rfapi_close_rfd_cmd
,
3028 "debug rfapi-dev close rfd HANDLE",
3032 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
3034 rfapi_handle handle
;
3036 char *endptr
= NULL
;
3038 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
3040 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
3041 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
3042 return CMD_WARNING_CONFIG_FAILED
;
3045 rc
= rfapi_close(handle
);
3047 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
3052 DEFUN (debug_rfapi_register_vn_un
,
3053 debug_rfapi_register_vn_un_cmd
,
3054 "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)]",
3058 "indicate vn addr follows\n"
3059 "virtual network IPv4 interface address\n"
3060 "virtual network IPv6 interface address\n"
3061 "indicate un addr follows\n"
3062 "underlay network IPv4 interface address\n"
3063 "underlay network IPv6 interface address\n"
3064 "indicate prefix follows\n"
3067 "indicate lifetime follows\n"
3069 "Cost (localpref = 255-cost)\n"
3072 struct rfapi_ip_addr vn
;
3073 struct rfapi_ip_addr un
;
3074 rfapi_handle handle
;
3077 struct rfapi_ip_prefix hpfx
;
3084 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3091 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3095 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3096 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3097 argv
[4]->arg
, argv
[6]->arg
);
3098 return CMD_WARNING_CONFIG_FAILED
;
3102 * Get prefix to advertise
3104 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3105 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3106 return CMD_WARNING_CONFIG_FAILED
;
3108 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3109 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3110 return CMD_WARNING_CONFIG_FAILED
;
3112 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3114 if (strmatch(argv
[10]->text
, "infinite")) {
3115 lifetime
= RFAPI_INFINITE_LIFETIME
;
3117 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3121 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3124 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3125 RFAPI_REGISTER_ADD
);
3127 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3134 DEFUN (debug_rfapi_register_vn_un_l2o
,
3135 debug_rfapi_register_vn_un_l2o_cmd
,
3136 "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)",
3140 "indicate vn addr follows\n"
3141 "virtual network IPv4 interface address\n"
3142 "virtual network IPv6 interface address\n"
3143 "indicate un addr follows\n"
3144 "underlay network IPv4 interface address\n"
3145 "underlay network IPv6 interface address\n"
3146 "indicate prefix follows\n"
3149 "indicate lifetime follows\n"
3150 "Seconds of lifetime\n"
3151 "indicate MAC address follows\n"
3153 "indicate lni follows\n"
3154 "lni value range\n")
3156 struct rfapi_ip_addr vn
;
3157 struct rfapi_ip_addr un
;
3158 rfapi_handle handle
;
3161 struct rfapi_ip_prefix hpfx
;
3163 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3164 struct rfapi_vn_option
*opt
= NULL
;
3170 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3177 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3181 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3182 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3183 argv
[4]->arg
, argv
[6]->arg
);
3184 return CMD_WARNING_CONFIG_FAILED
;
3188 * Get prefix to advertise
3190 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3191 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3192 return CMD_WARNING_CONFIG_FAILED
;
3194 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3195 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3196 return CMD_WARNING_CONFIG_FAILED
;
3198 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3200 if (strmatch(argv
[10]->text
, "infinite")) {
3201 lifetime
= RFAPI_INFINITE_LIFETIME
;
3203 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3206 /* L2 option parsing START */
3207 memset(optary
, 0, sizeof(optary
));
3208 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3209 strtoul(argv
[14]->arg
, NULL
, 10);
3210 if (rfapiStr2EthAddr(argv
[12]->arg
,
3211 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3212 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3213 return CMD_WARNING_CONFIG_FAILED
;
3215 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3217 optary
[opt_next
- 1].next
= optary
+ opt_next
;
3222 /* L2 option parsing END */
3225 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3226 RFAPI_REGISTER_ADD
);
3228 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3236 DEFUN (debug_rfapi_unregister_vn_un
,
3237 debug_rfapi_unregister_vn_un_cmd
,
3238 "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]",
3242 "indicate vn addr follows\n"
3243 "virtual network interface address\n"
3244 "indicate xt addr follows\n"
3245 "underlay network interface address\n"
3246 "prefix to remove\n"
3247 "Remove without holddown")
3249 struct rfapi_ip_addr vn
;
3250 struct rfapi_ip_addr un
;
3251 rfapi_handle handle
;
3253 struct rfapi_ip_prefix hpfx
;
3259 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3266 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
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 * Get prefix to advertise
3279 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3280 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3281 return CMD_WARNING_CONFIG_FAILED
;
3283 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3284 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3285 return CMD_WARNING_CONFIG_FAILED
;
3287 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3289 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3291 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3296 DEFUN (debug_rfapi_query_vn_un
,
3297 debug_rfapi_query_vn_un_cmd
,
3298 "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>",
3302 "indicate vn addr follows\n"
3303 "virtual network interface IPv4 address\n"
3304 "virtual network interface IPv6 address\n"
3305 "indicate un addr follows\n"
3308 "indicate target follows\n"
3309 "target IPv4 address\n"
3310 "target IPv6 address\n")
3312 struct rfapi_ip_addr vn
;
3313 struct rfapi_ip_addr un
;
3314 struct rfapi_ip_addr target
;
3315 rfapi_handle handle
;
3317 struct rfapi_next_hop_entry
*pNextHopEntry
;
3322 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3329 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3336 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3340 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3341 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3342 argv
[4]->arg
, argv
[6]->arg
);
3343 return CMD_WARNING_CONFIG_FAILED
;
3347 * options parameter not used? Set to NULL for now
3349 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3352 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3356 * print nexthop list
3358 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3359 vty
); /* frees nh list! */
3366 DEFUN (debug_rfapi_query_vn_un_l2o
,
3367 debug_rfapi_query_vn_un_l2o_cmd
,
3368 "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",
3372 "indicate vn addr follows\n"
3373 "virtual network interface IPv4 address\n"
3374 "virtual network interface IPv6 address\n"
3375 "indicate xt addr follows\n"
3376 "underlay network interface IPv4 address\n"
3377 "underlay network interface IPv6 address\n"
3378 "logical network ID follows\n"
3379 "logical network ID\n"
3380 "indicate target MAC addr follows\n"
3381 "target MAC addr\n")
3383 struct rfapi_ip_addr vn
;
3384 struct rfapi_ip_addr un
;
3390 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3397 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3400 vty_out(vty
, "%% This command is broken.\n");
3401 return CMD_WARNING_CONFIG_FAILED
;
3405 DEFUN (debug_rfapi_query_done_vn_un
,
3406 debug_rfapi_query_vn_un_done_cmd
,
3407 "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>",
3410 "rfapi_query_done\n"
3411 "rfapi_query_done\n"
3412 "indicate vn addr follows\n"
3413 "virtual network interface IPv4 address\n"
3414 "virtual network interface IPv6 address\n"
3415 "indicate xt addr follows\n"
3416 "underlay network interface IPv4 address\n"
3417 "underlay network interface IPv6 address\n"
3418 "indicate target follows\n"
3419 "Target IPv4 address\n"
3420 "Target IPv6 address\n")
3422 struct rfapi_ip_addr vn
;
3423 struct rfapi_ip_addr un
;
3424 struct rfapi_ip_addr target
;
3425 rfapi_handle handle
;
3431 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3438 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3445 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3449 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3450 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3451 argv
[5]->arg
, argv
[7]->arg
);
3452 return CMD_WARNING_CONFIG_FAILED
;
3456 * options parameter not used? Set to NULL for now
3458 rc
= rfapi_query_done(handle
, &target
);
3460 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3465 DEFUN (debug_rfapi_show_import
,
3466 debug_rfapi_show_import_cmd
,
3467 "debug rfapi-dev show import",
3475 struct rfapi_import_table
*it
;
3480 * Show all import tables
3483 bgp
= bgp_get_default(); /* assume 1 instance for now */
3485 vty_out(vty
, "No BGP instance\n");
3486 return CMD_WARNING_CONFIG_FAILED
;
3491 vty_out(vty
, "No RFAPI instance\n");
3492 return CMD_WARNING_CONFIG_FAILED
;
3496 * Iterate over all import tables; do a filtered import
3497 * for the afi/safi combination
3501 for (it
= h
->imports
; it
; it
= it
->next
) {
3502 s
= ecommunity_ecom2str(it
->rt_import_list
,
3503 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3504 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3505 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3507 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3509 rfapiShowImportTable(vty
, "IP ENCAP",
3510 it
->imported_encap
[AFI_IP
], 0);
3511 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3513 rfapiShowImportTable(vty
, "IP6 ENCAP",
3514 it
->imported_encap
[AFI_IP6
], 0);
3517 if (h
->import_mac
) {
3518 void *cursor
= NULL
;
3520 uintptr_t lni_as_ptr
;
3524 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3525 (void **)&it
, &cursor
);
3527 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3528 (void **)&it
, &cursor
)) {
3530 if (it
->imported_vpn
[AFI_L2VPN
]) {
3534 "\nLNI-based Ethernet Tables:\n");
3537 snprintf(buf
, BUFSIZ
, "L2VPN LNI=%u", lni
);
3538 rfapiShowImportTable(
3539 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3545 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3546 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3551 DEFUN (debug_rfapi_show_import_vn_un
,
3552 debug_rfapi_show_import_vn_un_cmd
,
3553 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3558 "indicate vn addr follows\n"
3559 "virtual network interface IPv4 address\n"
3560 "virtual network interface IPv6 address\n"
3561 "indicate xt addr follows\n"
3562 "underlay network interface IPv4 address\n"
3563 "underlay network interface IPv6 address\n")
3565 struct rfapi_ip_addr vn
;
3566 struct rfapi_ip_addr un
;
3567 rfapi_handle handle
;
3569 struct rfapi_descriptor
*rfd
;
3574 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3581 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3585 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3586 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3587 argv
[5]->arg
, argv
[7]->arg
);
3588 return CMD_WARNING_CONFIG_FAILED
;
3591 rfd
= (struct rfapi_descriptor
*)handle
;
3593 rfapiShowImportTable(vty
, "IP VPN",
3594 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3595 rfapiShowImportTable(vty
, "IP ENCAP",
3596 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3597 rfapiShowImportTable(vty
, "IP6 VPN",
3598 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3599 rfapiShowImportTable(vty
, "IP6 ENCAP",
3600 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3605 DEFUN (debug_rfapi_response_omit_self
,
3606 debug_rfapi_response_omit_self_cmd
,
3607 "debug rfapi-dev response-omit-self <on|off>",
3610 "Omit self in RFP responses\n"
3611 "filter out self from responses\n" "leave self in responses\n")
3613 struct bgp
*bgp
= bgp_get_default();
3616 vty_out(vty
, "No BGP process is configured\n");
3617 return CMD_WARNING_CONFIG_FAILED
;
3619 if (!bgp
->rfapi_cfg
) {
3620 vty_out(vty
, "VNC not configured\n");
3621 return CMD_WARNING_CONFIG_FAILED
;
3624 if (strmatch(argv
[3]->text
, "on"))
3625 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3626 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3628 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3629 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3635 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3637 #include "lib/skiplist.h"
3638 DEFUN (skiplist_test_cli
,
3639 skiplist_test_cli_cmd
,
3641 "skiplist command\n"
3649 DEFUN (skiplist_debug_cli
,
3650 skiplist_debug_cli_cmd
,
3652 "skiplist command\n"
3655 skiplist_debug(vty
, NULL
);
3659 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3661 void rfapi_init(void)
3663 bgp_rfapi_cfg_init();
3666 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3667 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3669 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3670 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3671 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3672 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3673 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3674 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3675 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3676 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3678 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3680 /* Need the following show commands for gpz test scripts */
3681 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3682 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3683 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3685 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3686 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3687 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3694 static void rfapi_print_exported(struct bgp
*bgp
)
3696 struct bgp_node
*rdn
;
3697 struct bgp_node
*rn
;
3698 struct bgp_info
*bi
;
3703 for (rdn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); rdn
;
3704 rdn
= bgp_route_next(rdn
)) {
3707 fprintf(stderr
, "%s: vpn rdn=%p\n", __func__
, rdn
);
3708 for (rn
= bgp_table_top(rdn
->info
); rn
;
3709 rn
= bgp_route_next(rn
)) {
3712 fprintf(stderr
, "%s: rn=%p\n", __func__
, rn
);
3713 for (bi
= rn
->info
; bi
; bi
= bi
->next
) {
3714 rfapiPrintBi((void *)2, bi
); /* 2 => stderr */
3718 for (rdn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); rdn
;
3719 rdn
= bgp_route_next(rdn
)) {
3722 fprintf(stderr
, "%s: encap rdn=%p\n", __func__
, rdn
);
3723 for (rn
= bgp_table_top(rdn
->info
); rn
;
3724 rn
= bgp_route_next(rn
)) {
3727 fprintf(stderr
, "%s: rn=%p\n", __func__
, rn
);
3728 for (bi
= rn
->info
; bi
; bi
= bi
->next
) {
3729 rfapiPrintBi((void *)2, bi
); /* 2 => stderr */
3734 #endif /* defined(DEBUG_RFAPI) */
3737 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3739 void rfapi_delete(struct bgp
*bgp
)
3741 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3744 * This clears queries and registered routes, and closes nves
3747 rfp_clear_vnc_nve_all();
3748 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3749 bgp
->rfapi_cfg
= NULL
;
3750 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3754 * show what's left in the BGP MPLSVPN RIB
3756 rfapi_print_exported(bgp
);
3760 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3762 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3763 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3764 vnc_zlog_debug_verbose(
3765 "%s: can't auto-assign RD, VN addr family is not IPv4"
3768 return EAFNOSUPPORT
;
3770 rd
->family
= AF_UNSPEC
;
3772 rd
->val
[1] = RD_TYPE_IP
;
3773 if (vn
->addr_family
== AF_INET
) {
3774 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3775 } else { /* is v6 */
3776 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3777 4); /* low order 4 bytes */
3780 char buf
[RD_ADDRSTRLEN
];
3782 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3783 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3788 /*------------------------------------------
3789 * rfapi_bgp_lookup_by_rfp
3791 * Find bgp instance pointer based on value returned by rfp_start
3794 * rfp_start_val value returned by rfp_startor
3795 * NULL (=get default instance)
3801 * bgp bgp instance pointer
3804 --------------------------------------------*/
3805 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3807 struct bgp
*bgp
= NULL
;
3808 struct listnode
*node
, *nnode
;
3810 if (rfp_start_val
== NULL
)
3811 bgp
= bgp_get_default();
3813 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3814 if (bgp
->rfapi
!= NULL
3815 && bgp
->rfapi
->rfp
== rfp_start_val
)
3820 /*------------------------------------------
3821 * rfapi_get_rfp_start_val_by_bgp
3823 * Find bgp instance pointer based on value returned by rfp_start
3826 * bgp bgp instance pointer
3835 --------------------------------------------*/
3836 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3838 if (!bgp
|| !bgp
->rfapi
)
3840 return bgp
->rfapi
->rfp
;
3843 /***********************************************************************
3844 * RFP group specific configuration
3845 ***********************************************************************/
3846 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3850 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3851 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3852 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3855 return rfc
->default_rfp_cfg
;
3858 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3862 struct rfapi_nve_group_cfg
*rfg
=
3863 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3865 /* make sure group is still in list */
3866 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3867 /* Not in list anymore */
3868 vty_out(vty
, "Current NVE group no longer exists\n");
3872 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3873 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3874 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3877 return rfg
->rfp_cfg
;
3880 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3884 struct rfapi_l2_group_cfg
*rfg
=
3885 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3887 /* make sure group is still in list */
3888 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3889 /* Not in list anymore */
3890 vty_out(vty
, "Current L2 group no longer exists\n");
3893 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3894 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3895 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3898 return rfg
->rfp_cfg
;
3901 /*------------------------------------------
3902 * rfapi_rfp_init_group_config_ptr_vty
3904 * This is used to init or return a previously init'ed group specific
3905 * configuration pointer. Group is identified by vty context.
3906 * NOTE: size is ignored when a previously init'ed value is returned.
3907 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3908 * bgp restart or shutdown.
3911 * rfp_start_val value returned by rfp_start
3913 * vty quagga vty context
3914 * size number of bytes to allocation
3920 * rfp_cfg_group NULL or Pointer to configuration structure
3921 --------------------------------------------*/
3922 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3923 rfapi_rfp_cfg_group_type type
,
3924 struct vty
*vty
, uint32_t size
)
3929 if (rfp_start_val
== NULL
|| vty
== NULL
)
3932 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3933 if (!bgp
|| !bgp
->rfapi_cfg
)
3937 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3938 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3941 case RFAPI_RFP_CFG_GROUP_NVE
:
3942 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3945 case RFAPI_RFP_CFG_GROUP_L2
:
3946 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3950 flog_err(LIB_ERR_DEVELOPMENT
, "%s: Unknown group type=%d",
3952 /* should never happen */
3953 assert("Unknown type" == NULL
);
3959 /*------------------------------------------
3960 * rfapi_rfp_get_group_config_ptr_vty
3962 * This is used to get group specific configuration pointer.
3963 * Group is identified by type and vty context.
3964 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3965 * bgp restart or shutdown.
3968 * rfp_start_val value returned by rfp_start
3970 * vty quagga vty context
3976 * rfp_cfg_group Pointer to configuration structure
3977 --------------------------------------------*/
3978 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3979 rfapi_rfp_cfg_group_type type
,
3982 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3986 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3988 rfp_group_config_search_cb_t
*search_cb
)
3990 struct rfapi_nve_group_cfg
*rfg
;
3991 struct listnode
*node
;
3993 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3994 if (!strcmp(rfg
->name
, name
) && /* name match */
3995 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3996 return rfg
->rfp_cfg
;
4002 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
4004 rfp_group_config_search_cb_t
*search_cb
)
4006 struct rfapi_l2_group_cfg
*rfg
;
4007 struct listnode
*node
;
4009 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
4010 if (!strcmp(rfg
->name
, name
) && /* name match */
4011 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
4012 return rfg
->rfp_cfg
;
4017 /*------------------------------------------
4018 * rfapi_rfp_get_group_config_ptr_name
4020 * This is used to get group specific configuration pointer.
4021 * Group is identified by type and name context.
4022 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4023 * bgp restart or shutdown.
4026 * rfp_start_val value returned by rfp_start
4029 * criteria RFAPI caller provided serach criteria
4030 * search_cb optional rfp_group_config_search_cb_t
4036 * rfp_cfg_group Pointer to configuration structure
4037 --------------------------------------------*/
4038 void *rfapi_rfp_get_group_config_ptr_name(
4039 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
4040 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
4045 if (rfp_start_val
== NULL
|| name
== NULL
)
4048 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4049 if (!bgp
|| !bgp
->rfapi_cfg
)
4053 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4054 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4056 case RFAPI_RFP_CFG_GROUP_NVE
:
4057 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4058 criteria
, search_cb
);
4060 case RFAPI_RFP_CFG_GROUP_L2
:
4061 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4062 criteria
, search_cb
);
4065 flog_err(LIB_ERR_DEVELOPMENT
, "%s: Unknown group type=%d",
4067 /* should never happen */
4068 assert("Unknown type" == NULL
);
4074 /*------------------------------------------
4075 * rfapi_rfp_get_l2_group_config_ptr_lni
4077 * This is used to get group specific configuration pointer.
4078 * Group is identified by type and logical network identifier.
4079 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4080 * bgp restart or shutdown.
4083 * rfp_start_val value returned by rfp_start
4085 * logical_net_id group logical network identifier
4086 * criteria RFAPI caller provided serach criteria
4087 * search_cb optional rfp_group_config_search_cb_t
4093 * rfp_cfg_group Pointer to configuration structure
4094 --------------------------------------------*/
4096 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4097 uint32_t logical_net_id
, void *criteria
,
4098 rfp_group_config_search_cb_t
*search_cb
)
4101 struct rfapi_l2_group_cfg
*rfg
;
4102 struct listnode
*node
;
4104 if (rfp_start_val
== NULL
)
4107 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4108 if (!bgp
|| !bgp
->rfapi_cfg
)
4111 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4112 if (rfg
->logical_net_id
== logical_net_id
4113 && (search_cb
== NULL
4114 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4115 if (rfg
->rfp_cfg
== NULL
)
4116 vnc_zlog_debug_verbose(
4117 "%s: returning rfp group config for lni=0",
4119 return rfg
->rfp_cfg
;