3 * Copyright 2009-2016, LabN Consulting, L.L.C.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "lib/zebra.h"
22 #include "lib/prefix.h"
23 #include "lib/agg_table.h"
25 #include "lib/memory.h"
26 #include "lib/routemap.h"
28 #include "lib/linklist.h"
29 #include "lib/command.h"
30 #include "lib/stream.h"
31 #include "lib/ringbuf.h"
32 #include "lib/lib_errors.h"
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_ecommunity.h"
36 #include "bgpd/bgp_attr.h"
38 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
39 #include "bgpd/rfapi/rfapi.h"
40 #include "bgpd/rfapi/rfapi_backend.h"
42 #include "bgpd/bgp_route.h"
43 #include "bgpd/bgp_mplsvpn.h"
44 #include "bgpd/bgp_aspath.h"
45 #include "bgpd/bgp_advertise.h"
46 #include "bgpd/bgp_vnc_types.h"
47 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/rfapi/rfapi_import.h"
50 #include "bgpd/rfapi/rfapi_private.h"
51 #include "bgpd/rfapi/rfapi_monitor.h"
52 #include "bgpd/rfapi/rfapi_vty.h"
53 #include "bgpd/rfapi/vnc_export_bgp.h"
54 #include "bgpd/rfapi/vnc_export_bgp_p.h"
55 #include "bgpd/rfapi/vnc_zebra.h"
56 #include "bgpd/rfapi/vnc_import_bgp.h"
57 #include "bgpd/rfapi/rfapi_rib.h"
58 #include "bgpd/rfapi/rfapi_ap.h"
59 #include "bgpd/rfapi/rfapi_encap_tlv.h"
60 #include "bgpd/rfapi/vnc_debug.h"
62 #ifdef HAVE_GLIBC_BACKTRACE
63 /* for backtrace and friends */
65 #endif /* HAVE_GLIBC_BACKTRACE */
67 struct ethaddr rfapi_ethaddr0
= {{0}};
69 #define DEBUG_RFAPI_STR "RF API debugging/testing command\n"
71 const char *rfapi_error_str(int code
)
77 return "BGP or VNC not configured";
81 return "Handle already open";
83 return "Incomplete configuration";
85 return "Invalid address family";
87 return "Called from within a callback procedure";
89 return "Invalid handle";
91 return "Invalid argument";
93 return "Stale descriptor";
95 return "Unknown error";
99 /*------------------------------------------
100 * rfapi_get_response_lifetime_default
102 * Returns the default lifetime for a response.
103 * rfp_start_val value returned by rfp_start or
104 * NULL (=use default instance)
111 * return value: The bgp instance default lifetime for a response.
112 --------------------------------------------*/
113 int rfapi_get_response_lifetime_default(void *rfp_start_val
)
115 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
117 return bgp
->rfapi_cfg
->default_response_lifetime
;
118 return BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
;
121 /*------------------------------------------
122 * rfapi_is_vnc_configured
124 * Returns if VNC is configured
127 * rfp_start_val value returned by rfp_start or
128 * NULL (=use default instance)
132 * return value: If VNC is configured for the bgpd instance
134 * ENXIO VNC not configured
135 --------------------------------------------*/
136 int rfapi_is_vnc_configured(void *rfp_start_val
)
138 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
139 if (bgp_rfapi_is_vnc_configured(bgp
) == 0)
145 /*------------------------------------------
148 * Get the virtual network address used by an NVE based on it's RFD
151 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
156 * vn NVE virtual network address
157 *------------------------------------------*/
158 struct rfapi_ip_addr
*rfapi_get_vn_addr(void *rfd
)
160 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
161 return &rrfd
->vn_addr
;
164 /*------------------------------------------
167 * Get the underlay network address used by an NVE based on it's RFD
170 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
175 * un NVE underlay network address
176 *------------------------------------------*/
177 struct rfapi_ip_addr
*rfapi_get_un_addr(void *rfd
)
179 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
180 return &rrfd
->un_addr
;
183 int rfapi_ip_addr_cmp(struct rfapi_ip_addr
*a1
, struct rfapi_ip_addr
*a2
)
185 if (a1
->addr_family
!= a2
->addr_family
)
186 return a1
->addr_family
- a2
->addr_family
;
188 if (a1
->addr_family
== AF_INET
) {
189 return IPV4_ADDR_CMP(&a1
->addr
.v4
, &a2
->addr
.v4
);
192 if (a1
->addr_family
== AF_INET6
) {
193 return IPV6_ADDR_CMP(&a1
->addr
.v6
, &a2
->addr
.v6
);
201 static int rfapi_find_node(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
202 struct rfapi_ip_addr
*un_addr
,
203 struct agg_node
**node
)
220 afi
= family2afi(un_addr
->addr_family
);
225 if ((rc
= rfapiRaddr2Qprefix(un_addr
, &p
)))
228 rn
= agg_node_lookup(h
->un
[afi
], &p
);
241 int rfapi_find_rfd(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
242 struct rfapi_ip_addr
*un_addr
, struct rfapi_descriptor
**rfd
)
247 rc
= rfapi_find_node(bgp
, vn_addr
, un_addr
, &rn
);
252 for (*rfd
= (struct rfapi_descriptor
*)(rn
->info
); *rfd
;
253 *rfd
= (*rfd
)->next
) {
254 if (!rfapi_ip_addr_cmp(&(*rfd
)->vn_addr
, vn_addr
))
264 /*------------------------------------------
268 * un underlay network address
269 * vn virtual network address
272 * pHandle pointer to location to store handle
276 * ENOENT no matching handle
277 * ENXIO BGP or VNC not configured
278 *------------------------------------------*/
279 static int rfapi_find_handle(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
280 struct rfapi_ip_addr
*un_addr
,
281 rfapi_handle
*handle
)
283 struct rfapi_descriptor
**rfd
;
285 rfd
= (struct rfapi_descriptor
**)handle
;
287 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
290 static int rfapi_find_handle_vty(struct vty
*vty
, struct rfapi_ip_addr
*vn_addr
,
291 struct rfapi_ip_addr
*un_addr
,
292 rfapi_handle
*handle
)
295 struct rfapi_descriptor
**rfd
;
297 bgp
= bgp_get_default(); /* assume 1 instance for now */
299 rfd
= (struct rfapi_descriptor
**)handle
;
301 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
304 static int is_valid_rfd(struct rfapi_descriptor
*rfd
)
308 if (!rfd
|| rfd
->bgp
== NULL
)
313 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
316 if (rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &hh
))
326 * check status of descriptor
328 int rfapi_check(void *handle
)
330 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
334 if (!rfd
|| rfd
->bgp
== NULL
)
339 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
342 if ((rc
= rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
,
356 void del_vnc_route(struct rfapi_descriptor
*rfd
,
357 struct peer
*peer
, /* rfd->peer for RFP regs */
358 struct bgp
*bgp
, safi_t safi
, const struct prefix
*p
,
359 struct prefix_rd
*prd
, uint8_t type
, uint8_t sub_type
,
360 struct rfapi_nexthop
*lnh
, int kill
)
362 afi_t afi
; /* of the VN address */
364 struct bgp_path_info
*bpi
;
365 char buf2
[RD_ADDRSTRLEN
];
366 struct prefix_rd prd0
;
368 afi
= family2afi(p
->family
);
369 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
371 if (safi
== SAFI_ENCAP
) {
372 memset(&prd0
, 0, sizeof(prd0
));
373 prd0
.family
= AF_UNSPEC
;
377 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
379 vnc_zlog_debug_verbose(
380 "%s: peer=%p, prefix=%pFX, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
381 __func__
, peer
, p
, prefix_rd2str(prd
, buf2
, sizeof(buf2
)), afi
,
382 safi
, bn
, (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
));
384 for (bpi
= (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
); bpi
;
387 vnc_zlog_debug_verbose(
388 "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64
,
389 __func__
, bpi
, bpi
->peer
, bpi
->type
, bpi
->sub_type
,
390 (bpi
->extra
? bpi
->extra
->vnc
.export
.rfapi_handle
392 CHECK_FLAG(bpi
->attr
->flag
,
393 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)
394 ? bpi
->attr
->local_pref
: 0));
396 if (bpi
->peer
== peer
&& bpi
->type
== type
397 && bpi
->sub_type
== sub_type
&& bpi
->extra
398 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
400 vnc_zlog_debug_verbose("%s: matched it", __func__
);
408 * lnh set means to JUST delete the local nexthop from this
409 * route. Leave the route itself in place.
410 * TBD add return code reporting of success/failure
412 if (!bpi
|| !bpi
->extra
413 || !bpi
->extra
->vnc
.export
.local_nexthops
) {
417 vnc_zlog_debug_verbose(
418 "%s: lnh list already empty at prefix %pFX",
426 struct listnode
*node
;
427 struct rfapi_nexthop
*pLnh
= NULL
;
429 for (ALL_LIST_ELEMENTS_RO(bpi
->extra
->vnc
.export
.local_nexthops
,
432 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
438 listnode_delete(bpi
->extra
->vnc
.export
.local_nexthops
,
441 /* silly rabbit, listnode_delete doesn't invoke
442 * list->del on data */
443 rfapi_nexthop_free(pLnh
);
445 vnc_zlog_debug_verbose("%s: desired lnh not found %pFX",
452 * loop back to import tables
453 * Do this before removing from BGP RIB because rfapiProcessWithdraw
456 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
459 vnc_zlog_debug_verbose(
460 "%s: Found route (safi=%d) to delete at prefix %pFX",
463 if (safi
== SAFI_MPLS_VPN
) {
464 struct bgp_dest
*pdest
= NULL
;
465 struct bgp_table
*table
= NULL
;
467 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
468 (struct prefix
*)prd
);
469 table
= bgp_dest_get_bgp_table_info(pdest
);
471 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
472 bgp
, prd
, table
, p
, bpi
);
473 bgp_dest_unlock_node(pdest
);
477 * Delete local_nexthops list
479 if (bpi
->extra
&& bpi
->extra
->vnc
.export
.local_nexthops
)
480 list_delete(&bpi
->extra
->vnc
.export
.local_nexthops
);
482 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
483 bgp_path_info_delete(bn
, bpi
);
484 bgp_process(bgp
, bn
, afi
, safi
);
486 vnc_zlog_debug_verbose(
487 "%s: Couldn't find route (safi=%d) at prefix %pFX",
491 bgp_dest_unlock_node(bn
);
494 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
496 struct rfapi_nexthop
*new =
497 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
503 void rfapi_nexthop_free(void *p
)
505 struct rfapi_nexthop
*goner
= p
;
506 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
509 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
511 struct rfapi_vn_option
*p
;
512 struct rfapi_vn_option
*head
= NULL
;
513 struct rfapi_vn_option
*tail
= NULL
;
515 for (p
= existing
; p
; p
= p
->next
) {
516 struct rfapi_vn_option
*new;
518 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
519 sizeof(struct rfapi_vn_option
));
532 void rfapi_un_options_free(struct rfapi_un_option
*p
)
534 struct rfapi_un_option
*next
;
538 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
543 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
545 struct rfapi_vn_option
*next
;
549 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
554 /* Based on bgp_redistribute_add() */
555 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
556 struct bgp
*bgp
, int safi
, const struct prefix
*p
,
557 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
558 uint32_t *local_pref
,
559 uint32_t *lifetime
, /* NULL => dont send lifetime */
560 struct bgp_tea_options
*rfp_options
,
561 struct rfapi_un_option
*options_un
,
562 struct rfapi_vn_option
*options_vn
,
563 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
564 uint32_t *med
, /* NULL => don't set med */
565 uint32_t *label
, /* low order 3 bytes */
566 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
569 afi_t afi
; /* of the VN address */
570 struct bgp_path_info
*new;
571 struct bgp_path_info
*bpi
;
574 struct attr attr
= {0};
575 struct attr
*new_attr
;
578 struct bgp_attr_encap_subtlv
*encaptlv
;
579 char buf
[PREFIX_STRLEN
];
580 char buf2
[RD_ADDRSTRLEN
];
582 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
583 struct rfapi_vn_option
*vo
;
584 struct rfapi_l2address_option
*l2o
= NULL
;
585 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
587 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
588 struct bgp_redist
*red
;
590 if (safi
== SAFI_ENCAP
591 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
594 * Encap mode not enabled. UN addresses will be communicated
595 * via VNC Tunnel subtlv instead.
597 vnc_zlog_debug_verbose(
598 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
603 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
604 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
606 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
607 l2o
= NULL
; /* not MAC resolution */
609 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
610 lnh
= &vo
->v
.local_nexthop
;
617 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
619 prefix_rd2str(prd
, buf2
, sizeof(buf2
));
621 afi
= family2afi(p
->family
);
622 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
624 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
627 /* Make default attribute. Produces already-interned attr.aspath */
628 /* Cripes, the memory management of attributes is byzantine */
630 bgp_attr_default_set(&attr
, BGP_ORIGIN_INCOMPLETE
);
635 * extra: dynamically allocated, owned by attr
636 * aspath: points to interned hash from aspath hash table
641 * Route-specific un_options get added to the VPN SAFI
642 * advertisement tunnel encap attribute. (the per-NVE
643 * "default" un_options are put into the 1-per-NVE ENCAP
644 * SAFI advertisement). The VPN SAFI also gets the
645 * default un_options if there are no route-specific options.
648 struct rfapi_un_option
*uo
;
650 for (uo
= options_un
; uo
; uo
= uo
->next
) {
651 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
652 TunnelType
= rfapi_tunneltype_option_to_tlv(
653 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
660 * These are the NVE-specific "default" un_options which are
661 * put into the 1-per-NVE ENCAP advertisement.
663 if (rfd
->default_tunneltype_option
.type
) {
664 TunnelType
= rfapi_tunneltype_option_to_tlv(
665 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
667 } else /* create default for local addse */
668 if (type
== ZEBRA_ROUTE_BGP
669 && sub_type
== BGP_ROUTE_RFP
)
670 TunnelType
= rfapi_tunneltype_option_to_tlv(
671 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
674 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
675 if (safi
== SAFI_ENCAP
) {
676 /* Encap SAFI not used with MPLS */
677 vnc_zlog_debug_verbose(
678 "%s: mpls tunnel type, encap safi omitted",
680 aspath_unintern(&attr
.aspath
); /* Unintern original. */
686 attr
.local_pref
= *local_pref
;
687 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
692 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
695 /* override default weight assigned by bgp_attr_default_set() */
696 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
699 * NB: ticket 81: do not reset attr.aspath here because it would
700 * cause iBGP peers to drop route
704 * Set originator ID for routes imported from BGP directly.
705 * These routes could be synthetic, and therefore could
706 * reuse the peer pointers of the routes they are derived
707 * from. Setting the originator ID to "us" prevents the
708 * wrong originator ID from being sent when this route is
709 * sent from a route reflector.
711 if (type
== ZEBRA_ROUTE_BGP_DIRECT
712 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
713 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
714 attr
.originator_id
= bgp
->router_id
;
718 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
719 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
722 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
723 sizeof(struct bgp_attr_encap_subtlv
) + 4);
726 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
727 encaptlv
->length
= 4;
728 lt
= htonl(*lifetime
);
729 memcpy(encaptlv
->value
, <
, 4);
730 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
731 vnc_zlog_debug_verbose(
732 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
736 /* add rfp options to vnc attr */
739 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
740 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
741 bgp_attr_get_vnc_subtlvs(&attr
);
743 * this flag means we're passing a pointer to an
744 * existing encap tlv chain which we should copy.
745 * It's a hack to avoid adding yet another argument
748 encaptlv
= encap_tlv_dup(
749 (struct bgp_attr_encap_subtlv
*)rfp_options
);
751 vnc_subtlvs
->next
= encaptlv
;
753 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
755 struct bgp_tea_options
*hop
;
756 /* XXX max of one tlv present so far from above code */
757 struct bgp_attr_encap_subtlv
*tail
=
758 bgp_attr_get_vnc_subtlvs(&attr
);
760 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
767 sizeof(struct bgp_attr_encap_subtlv
) + 2
771 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
774 encaptlv
->length
= 2 + hop
->length
;
775 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
776 *((uint8_t *)(encaptlv
->value
) + 1) =
778 memcpy(((uint8_t *)encaptlv
->value
) + 2,
779 hop
->value
, hop
->length
);
782 * add to end of subtlv chain
785 tail
->next
= encaptlv
;
787 bgp_attr_set_vnc_subtlvs(&attr
,
797 * extra: dynamically allocated, owned by attr
798 * vnc_subtlvs: dynamic chain, length 1
799 * aspath: points to interned hash from aspath hash table
803 attr
.ecommunity
= ecommunity_new();
804 assert(attr
.ecommunity
);
806 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
807 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
809 * Add BGP Encapsulation Extended Community. Format described in
810 * section 4.5 of RFC 5512.
811 * Always include when not MPLS type, to disambiguate this case.
813 struct ecommunity_val beec
;
815 memset(&beec
, 0, sizeof(beec
));
816 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
817 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
818 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
819 beec
.val
[7] = (TunnelType
)&0xff;
820 ecommunity_add_val(attr
.ecommunity
, &beec
, false, false);
824 * Add extended community attributes to match rt export list
826 if (rt_export_list
) {
828 ecommunity_merge(attr
.ecommunity
, rt_export_list
);
831 if (attr
.ecommunity
->size
) {
832 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
834 ecommunity_free(&attr
.ecommunity
);
835 attr
.ecommunity
= NULL
;
837 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
,
844 * extra: dynamically allocated, owned by attr
845 * vnc_subtlvs: dynamic chain, length 1
846 * ecommunity: dynamic 2-part
847 * aspath: points to interned hash from aspath hash table
850 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
851 switch (nexthop
->addr_family
) {
854 * set this field to prevent bgp_route.c code from setting
855 * mp_nexthop_global_in to self
857 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
859 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
860 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
864 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
865 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV6_GLOBAL
;
873 prefix2str(p
, buf
, sizeof(buf
));
879 * extra: dynamically allocated, owned by attr
880 * vnc_subtlvs: dynamic chain, length 1
881 * ecommunity: dynamic 2-part
882 * aspath: points to interned hash from aspath hash table
885 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
887 if (red
&& red
->redist_metric_flag
) {
888 attr
.med
= red
->redist_metric
;
889 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
892 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
895 * bgp_attr_intern creates a new reference to a cached
896 * attribute, but leaves the following bits of trash:
898 * - old attr->extra (free via bgp_attr_extra_free(attr))
900 * Note that it frees the original attr->extra->ecommunity
901 * but leaves the new attribute pointing to the ORIGINAL
902 * vnc options (which therefore we needn't free from the
905 new_attr
= bgp_attr_intern(&attr
);
907 aspath_unintern(&attr
.aspath
); /* Unintern original. */
913 * extra: dynamically allocated, owned by attr
914 * vnc_subtlvs: dynamic chain, length 1
915 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
917 * new_attr: an attr that is part of the hash table, distinct
918 * from attr which is static.
919 * extra: dynamically allocated, owned by new_attr (in hash table)
920 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
921 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
922 * aspath: POINTS TO interned/refcounted hashed block
924 for (bpi
= bgp_dest_get_bgp_path_info(bn
); bpi
; bpi
= bpi
->next
) {
925 /* probably only need to check
926 * bpi->extra->vnc.export.rfapi_handle */
927 if (bpi
->peer
== rfd
->peer
&& bpi
->type
== type
928 && bpi
->sub_type
== sub_type
&& bpi
->extra
929 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
938 * Adding new local_nexthop, which does not by itself change
939 * what is advertised via BGP
942 if (!bpi
->extra
->vnc
.export
.local_nexthops
) {
943 /* TBD make arrangements to free when needed */
944 bpi
->extra
->vnc
.export
.local_nexthops
=
946 bpi
->extra
->vnc
.export
.local_nexthops
->del
=
953 struct listnode
*node
;
954 struct rfapi_nexthop
*pLnh
= NULL
;
956 for (ALL_LIST_ELEMENTS_RO(
957 bpi
->extra
->vnc
.export
.local_nexthops
,
960 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
966 * Not present, add new one
969 pLnh
= rfapi_nexthop_new(lnh
);
971 bpi
->extra
->vnc
.export
.local_nexthops
,
976 if (attrhash_cmp(bpi
->attr
, new_attr
)
977 && !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
978 bgp_attr_unintern(&new_attr
);
979 bgp_dest_unlock_node(bn
);
982 "%s: Found route (safi=%d) at prefix %s, no change",
983 __func__
, safi
, buf
);
987 /* The attribute is changed. */
988 bgp_path_info_set_flag(bn
, bpi
, BGP_PATH_ATTR_CHANGED
);
990 if (safi
== SAFI_MPLS_VPN
) {
991 struct bgp_dest
*pdest
= NULL
;
992 struct bgp_table
*table
= NULL
;
994 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
995 (struct prefix
*)prd
);
996 table
= bgp_dest_get_bgp_table_info(pdest
);
998 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
999 bgp
, prd
, table
, p
, bpi
);
1000 bgp_dest_unlock_node(pdest
);
1003 /* Rewrite BGP route information. */
1004 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
1005 bgp_path_info_restore(bn
, bpi
);
1007 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
1008 bgp_attr_unintern(&bpi
->attr
);
1009 bpi
->attr
= new_attr
;
1010 bpi
->uptime
= bgp_clock();
1013 if (safi
== SAFI_MPLS_VPN
) {
1014 struct bgp_dest
*pdest
= NULL
;
1015 struct bgp_table
*table
= NULL
;
1017 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
1018 (struct prefix
*)prd
);
1019 table
= bgp_dest_get_bgp_table_info(pdest
);
1021 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1022 bgp
, prd
, table
, p
, bpi
);
1023 bgp_dest_unlock_node(pdest
);
1026 /* Process change. */
1027 bgp_aggregate_increment(bgp
, p
, bpi
, afi
, safi
);
1028 bgp_process(bgp
, bn
, afi
, safi
);
1029 bgp_dest_unlock_node(bn
);
1032 "%s: Found route (safi=%d) at prefix %s, changed attr",
1033 __func__
, safi
, buf
);
1039 new = info_make(type
, sub_type
, 0, rfd
->peer
, new_attr
, NULL
);
1040 SET_FLAG(new->flags
, BGP_PATH_VALID
);
1042 /* save backref to rfapi handle */
1043 assert(bgp_path_info_extra_get(new));
1044 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1045 encode_label(label_val
, &new->extra
->label
[0]);
1049 if (VNC_DEBUG(VERBOSE
)) {
1050 vnc_zlog_debug_verbose("%s: printing BPI", __func__
);
1051 rfapiPrintBi(NULL
, new);
1054 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1055 bgp_path_info_add(bn
, new);
1057 if (safi
== SAFI_MPLS_VPN
) {
1058 struct bgp_dest
*pdest
= NULL
;
1059 struct bgp_table
*table
= NULL
;
1061 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1062 table
= bgp_dest_get_bgp_table_info(pdest
);
1064 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1065 bgp
, prd
, table
, p
, new);
1066 bgp_dest_unlock_node(pdest
);
1067 encode_label(label_val
, &bn
->local_label
);
1070 bgp_dest_unlock_node(bn
);
1071 bgp_process(bgp
, bn
, afi
, safi
);
1074 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
1075 __func__
, safi2str(safi
), buf
, bn
, buf2
);
1078 /* Loop back to import tables */
1079 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1080 sub_type
, &label_val
);
1081 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1085 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1090 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1091 struct rfapi_descriptor
*rfd
,
1092 uint32_t *pLifetime
)
1094 struct prefix_rd prd
;
1095 struct prefix pfx_vn
;
1097 uint32_t local_pref
= rfp_cost_to_localpref(0);
1099 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1103 * Construct route distinguisher = 0
1105 memset(&prd
, 0, sizeof(prd
));
1106 prd
.family
= AF_UNSPEC
;
1109 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1110 bgp
, /* which bgp instance */
1111 SAFI_ENCAP
, /* which SAFI */
1112 &pfx_vn
, /* prefix to advertise */
1113 &prd
, /* route distinguisher to use */
1114 &rfd
->un_addr
, /* nexthop */
1116 pLifetime
, /* max lifetime of child VPN routes */
1117 NULL
, /* no rfp options for ENCAP safi */
1118 NULL
, /* rfp un options */
1119 NULL
, /* rfp vn options */
1120 rfd
->rt_export_list
, NULL
, /* med */
1121 NULL
, /* label: default */
1122 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1126 /***********************************************************************
1127 * RFP processing behavior configuration
1128 ***********************************************************************/
1130 /*------------------------------------------
1131 * rfapi_rfp_set_configuration
1133 * This is used to change rfapi's processing behavior based on
1137 * rfp_start_val value returned by rfp_start
1138 * rfapi_rfp_cfg Pointer to configuration structure
1145 * ENXIO Unabled to locate configured BGP/VNC
1146 --------------------------------------------*/
1147 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1149 struct rfapi_rfp_cfg
*rcfg
;
1152 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1154 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1157 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1158 rcfg
->download_type
= new->download_type
;
1159 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1160 rcfg
->holddown_factor
= new->holddown_factor
;
1162 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1163 rcfg
->use_updated_response
= new->use_updated_response
;
1164 if (rcfg
->use_updated_response
)
1165 rfapiMonitorCallbacksOn(bgp
);
1167 rfapiMonitorCallbacksOff(bgp
);
1169 if (rcfg
->use_removes
!= new->use_removes
) {
1170 rcfg
->use_removes
= new->use_removes
;
1171 if (rcfg
->use_removes
)
1172 rfapiMonitorResponseRemovalOn(bgp
);
1174 rfapiMonitorResponseRemovalOff(bgp
);
1179 /*------------------------------------------
1180 * rfapi_rfp_set_cb_methods
1182 * Change registered callback functions for asynchronous notifications
1183 * from RFAPI to the RFP client.
1186 * rfp_start_val value returned by rfp_start
1187 * methods Pointer to struct rfapi_rfp_cb_methods containing
1188 * pointers to callback methods as described above
1192 * ENXIO BGP or VNC not configured
1193 *------------------------------------------*/
1194 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1195 struct rfapi_rfp_cb_methods
*methods
)
1200 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1208 h
->rfp_methods
= *methods
;
1213 /***********************************************************************
1215 ***********************************************************************/
1217 * Caller must supply an already-allocated rfd with the "caller"
1218 * fields already set (vn_addr, un_addr, callback, cookie)
1219 * The advertised_prefixes[] array elements should be NULL to
1220 * have this function set them to newly-allocated radix trees.
1222 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1223 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1227 if (h
->flags
& RFAPI_INCALLBACK
)
1231 * Fill in configured fields
1235 * If group's RD is specified as "auto", then fill in based
1236 * on NVE's VN address
1240 if (rfd
->rd
.family
== AF_UNIX
) {
1241 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1245 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1246 ? ecommunity_dup(rfg
->rt_export_list
)
1248 rfd
->response_lifetime
= rfg
->response_lifetime
;
1252 * Fill in BGP peer structure
1254 rfd
->peer
= peer_new(bgp
);
1255 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1256 bgp_sync_delete(rfd
->peer
); /* don't need these */
1259 * since this peer is not on the I/O thread, this lock is not strictly
1260 * necessary, but serves as a reminder to those who may meddle...
1262 frr_with_mutex(&rfd
->peer
->io_mtx
) {
1263 // we don't need any I/O related facilities
1264 if (rfd
->peer
->ibuf
)
1265 stream_fifo_free(rfd
->peer
->ibuf
);
1266 if (rfd
->peer
->obuf
)
1267 stream_fifo_free(rfd
->peer
->obuf
);
1269 if (rfd
->peer
->ibuf_work
)
1270 ringbuf_del(rfd
->peer
->ibuf_work
);
1271 if (rfd
->peer
->obuf_work
)
1272 stream_free(rfd
->peer
->obuf_work
);
1274 rfd
->peer
->ibuf
= NULL
;
1275 rfd
->peer
->obuf
= NULL
;
1276 rfd
->peer
->obuf_work
= NULL
;
1277 rfd
->peer
->ibuf_work
= NULL
;
1280 { /* base code assumes have valid host pointer */
1284 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1285 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
, BUFSIZ
);
1286 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1287 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
, BUFSIZ
);
1289 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1291 /* Mark peer as belonging to HD */
1292 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1295 * Set min prefix lifetime to max value so it will get set
1296 * upon first rfapi_register()
1298 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1301 * Allocate response tables if needed
1303 #define RFD_RTINIT_AFI(rh, ary, afi) \
1306 ary[afi] = agg_table_init(); \
1307 agg_set_table_info(ary[afi], rh); \
1311 #define RFD_RTINIT(rh, ary) \
1313 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1314 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1315 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1318 RFD_RTINIT(rfd
, rfd
->rib
);
1319 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1320 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1323 * Link to Import Table
1325 rfd
->import_table
= rfg
->rfapi_import_table
;
1326 rfd
->import_table
->refcount
+= 1;
1328 rfapiApInit(&rfd
->advertised
);
1331 * add this NVE descriptor to the list of NVEs in the NVE group
1334 rfg
->nves
= list_new();
1336 listnode_add(rfg
->nves
, rfd
);
1338 vnc_direct_bgp_add_nve(bgp
, rfd
);
1339 vnc_zebra_add_nve(bgp
, rfd
);
1344 /* moved from rfapi_register */
1345 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1346 struct rfapi_nve_group_cfg
*rfg
)
1348 struct rfapi
*h
= bgp
->rfapi
;
1349 char buf_vn
[BUFSIZ
];
1350 char buf_un
[BUFSIZ
];
1351 afi_t afi_vn
, afi_un
;
1352 struct prefix pfx_un
;
1353 struct agg_node
*rn
;
1356 rfapi_time(&rfd
->open_time
);
1358 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1359 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1361 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1362 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1364 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1365 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1367 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1369 listnode_add(&h
->descriptors
, rfd
);
1370 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1371 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1375 * attach to UN radix tree
1377 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1378 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1379 assert(afi_vn
&& afi_un
);
1380 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1382 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1384 rfd
->next
= rn
->info
;
1388 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1391 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1393 struct rfapi_vn_option
*head
= NULL
;
1394 struct rfapi_vn_option
*tail
= NULL
;
1395 struct rfapi_vn_option
*vo
= NULL
;
1397 for (vo
= orig
; vo
; vo
= vo
->next
) {
1398 struct rfapi_vn_option
*new;
1400 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1401 sizeof(struct rfapi_vn_option
));
1402 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1414 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1416 struct rfapi_un_option
*head
= NULL
;
1417 struct rfapi_un_option
*tail
= NULL
;
1418 struct rfapi_un_option
*uo
= NULL
;
1420 for (uo
= orig
; uo
; uo
= uo
->next
) {
1421 struct rfapi_un_option
*new;
1423 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1424 sizeof(struct rfapi_un_option
));
1425 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1437 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1439 struct bgp_tea_options
*head
= NULL
;
1440 struct bgp_tea_options
*tail
= NULL
;
1441 struct bgp_tea_options
*hop
= NULL
;
1443 for (hop
= orig
; hop
; hop
= hop
->next
) {
1444 struct bgp_tea_options
*new;
1446 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1447 sizeof(struct bgp_tea_options
));
1448 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1451 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1453 memcpy(new->value
, hop
->value
, hop
->length
);
1464 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1466 struct bgp_tea_options
*next
;
1471 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1472 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1478 void rfapiAdbFree(struct rfapi_adb
*adb
)
1480 XFREE(MTYPE_RFAPI_ADB
, adb
);
1484 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1485 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1486 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1490 struct prefix p_original
;
1491 struct agg_node
*rn
;
1492 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1493 struct bgp
*bgp
= rfd
->bgp
;
1494 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1495 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1497 int use_eth_resolution
= 0;
1498 struct rfapi_next_hop_entry
*i_nhe
;
1502 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1507 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1511 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1512 vnc_zlog_debug_verbose(
1513 "%s: Called during calback, returning EDEADLK",
1518 if (!is_valid_rfd(rfd
)) {
1519 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1524 rfd
->rsp_counter
++; /* dedup: identify this generation */
1525 rfd
->rsp_time
= rfapi_time(NULL
); /* response content dedup */
1526 rfd
->ftd_last_allowed_time
=
1528 - bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1531 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1535 /* per t/c Paul/Lou 151022 */
1536 if (!eth_is_0
|| l2o
->logical_net_id
) {
1537 use_eth_resolution
= 1;
1542 *ppNextHopEntry
= NULL
;
1545 * Save original target in prefix form. In case of L2-based queries,
1546 * p_original will be modified to reflect the L2 target
1548 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1550 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1551 /* convert query to 0/0 when full-table download is enabled */
1552 memset((char *)&p
, 0, sizeof(p
));
1553 p
.family
= target
->addr_family
;
1561 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1562 __func__
, rfd
, &p
, ppNextHopEntry
);
1564 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1565 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1566 vnc_zlog_debug_verbose(
1567 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1568 __func__
, rfd
->import_table
, s
);
1569 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1572 afi
= family2afi(p
.family
);
1575 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1576 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1577 self_vn_addr
= &rfd
->vn_addr
;
1580 if (use_eth_resolution
) {
1581 uint32_t logical_net_id
= l2o
->logical_net_id
;
1582 struct ecommunity
*l2com
;
1585 * fix up p_original to contain L2 address
1587 rfapiL2o2Qprefix(l2o
, &p_original
);
1589 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1590 bgp
, 1, logical_net_id
, l2o
->label
);
1592 uint8_t *v
= l2com
->val
;
1593 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1596 * Ethernet/L2-based lookup
1598 * Always returns IT node corresponding to route
1601 if (RFAPI_RFP_DOWNLOAD_FULL
1602 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1606 rn
= rfapiMonitorEthAdd(
1607 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1611 struct rfapi_ip_prefix rprefix
;
1613 memset(&rprefix
, 0, sizeof(rprefix
));
1614 rprefix
.prefix
.addr_family
= target
->addr_family
;
1615 if (target
->addr_family
== AF_INET
) {
1616 rprefix
.length
= IPV4_MAX_BITLEN
;
1618 rprefix
.length
= IPV6_MAX_BITLEN
;
1621 pNHE
= rfapiEthRouteTable2NextHopList(
1622 logical_net_id
, &rprefix
,
1623 rfd
->response_lifetime
, self_vn_addr
,
1624 rfd
->rib
[afi
], &p_original
);
1634 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1637 * If target address is 0, this request is special: means to
1638 * return ALL routes in the table
1640 * Monitors for All-Routes queries get put on a special list,
1641 * not in the VPN tree
1643 if (RFAPI_0_PREFIX(&p
)) {
1645 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1648 * Generate nexthop list for caller
1650 pNHE
= rfapiRouteTable2NextHopList(
1651 rfd
->import_table
->imported_vpn
[afi
],
1652 rfd
->response_lifetime
, self_vn_addr
,
1653 rfd
->rib
[afi
], &p_original
);
1658 agg_lock_node(rn
); /* so we can unlock below */
1661 * returns locked node. Don't unlock yet because the
1663 * might free it before we're done with it. This
1665 * could occur when rfapiMonitorGetAttachNode() returns
1667 * newly-created default node.
1669 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1675 agg_unlock_node(rn
);
1676 vnc_zlog_debug_verbose(
1677 "%s: VPN route not found, returning ENOENT", __func__
);
1681 if (VNC_DEBUG(RFAPI_QUERY
)) {
1682 rfapiShowImportTable(NULL
, "query",
1683 rfd
->import_table
->imported_vpn
[afi
], 1);
1686 if (use_eth_resolution
) {
1688 struct rfapi_ip_prefix rprefix
;
1690 memset(&rprefix
, 0, sizeof(rprefix
));
1691 rprefix
.prefix
.addr_family
= target
->addr_family
;
1692 if (target
->addr_family
== AF_INET
) {
1693 rprefix
.length
= IPV4_MAX_BITLEN
;
1695 rprefix
.length
= IPV6_MAX_BITLEN
;
1698 pNHE
= rfapiEthRouteNode2NextHopList(
1699 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1700 rfd
->rib
[afi
], &p_original
);
1705 * Generate answer to query
1707 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1708 self_vn_addr
, rfd
->rib
[afi
],
1712 agg_unlock_node(rn
);
1715 if (ppNextHopEntry
) {
1716 /* only count if caller gets it */
1717 ++bgp
->rfapi
->response_immediate_count
;
1721 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1727 * count nexthops for statistics
1729 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1730 ++rfd
->stat_count_nh_reachable
;
1733 if (ppNextHopEntry
) {
1734 *ppNextHopEntry
= pNHE
;
1736 rfapi_free_next_hop_list(pNHE
);
1739 vnc_zlog_debug_verbose("%s: success", __func__
);
1744 * support on-the-fly reassignment of an already-open nve to a new
1745 * nve-group in the event that its original nve-group is
1746 * administratively deleted.
1748 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1750 struct prefix pfx_vn
;
1751 struct prefix pfx_un
;
1752 struct rfapi_nve_group_cfg
*rfg
;
1754 struct rfapi_cfg
*hc
;
1761 hc
= bgp
->rfapi_cfg
;
1765 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1768 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1772 * Find the matching nve group config block
1774 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1780 * check nve group config block for required values
1782 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1787 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1793 * re-advertise registered routes, this time as part of new NVE-group
1795 rfapiApReadvertiseAll(bgp
, rfd
);
1798 * re-attach callbacks to import table
1800 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1801 rfapiMonitorAttachImportHd(rfd
);
1807 /*------------------------------------------
1810 * This function initializes a NVE record and associates it with
1811 * the specified VN and underlay network addresses
1814 * rfp_start_val value returned by rfp_start
1815 * vn NVE virtual network address
1817 * un NVE underlay network address
1819 * default_options Default options to use on registrations.
1820 * For now only tunnel type is supported.
1821 * May be overridden per-prefix in rfapi_register().
1822 * Caller owns (rfapi_open() does not free)
1824 * response_cb Pointer to next hop list update callback function or
1825 * NULL when no callbacks are desired.
1827 * userdata Passed to subsequent response_cb invocations.
1830 * response_lifetime The length of time that responses sent to this
1833 * pHandle pointer to location to store rfapi handle. The
1834 * handle must be passed on subsequent rfapi_ calls.
1839 * EEXIST NVE with this {vn,un} already open
1840 * ENOENT No matching nve group config
1841 * ENOMSG Matched nve group config was incomplete
1842 * ENXIO BGP or VNC not configured
1843 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1844 * but underlay network address is not IPv4
1845 * EDEADLK Called from within a callback procedure
1846 *------------------------------------------*/
1847 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1848 struct rfapi_ip_addr
*un
,
1849 struct rfapi_un_option
*default_options
,
1850 uint32_t *response_lifetime
,
1851 void *userdata
, /* callback cookie */
1852 rfapi_handle
*pHandle
)
1856 struct rfapi_descriptor
*rfd
;
1857 struct rfapi_cfg
*hc
;
1858 struct rfapi_nve_group_cfg
*rfg
;
1860 struct prefix pfx_vn
;
1861 struct prefix pfx_un
;
1864 rfapi_handle hh
= NULL
;
1865 int reusing_provisional
= 0;
1868 char buf
[2][INET_ADDRSTRLEN
];
1869 vnc_zlog_debug_verbose(
1870 "%s: VN=%s UN=%s", __func__
,
1871 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1872 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1878 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1886 hc
= bgp
->rfapi_cfg
;
1890 if (h
->flags
& RFAPI_INCALLBACK
)
1893 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1896 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1900 * already have a descriptor with VN and UN?
1902 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1904 * we might have set up a handle for static routes before
1905 * this NVE was opened. In that case, reuse the handle
1908 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1913 * reuse provisional descriptor
1916 reusing_provisional
= 1;
1920 * Find the matching nve group config block
1922 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1924 ++h
->stat
.count_unknown_nves
;
1926 char buf
[2][INET_ADDRSTRLEN
];
1927 zlog_notice("%s: no matching group VN=%s UN=%s",
1929 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1931 rfapiRfapiIpAddr2Str(un
, buf
[1],
1938 * check nve group config block for required values
1940 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1942 ++h
->stat
.count_unknown_nves
;
1947 * If group config specifies auto-rd assignment, check that
1948 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1949 * Check here so we don't need to unwind memory allocations, &c.
1951 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1952 && (vn
->addr_family
!= AF_INET6
)) {
1953 return EAFNOSUPPORT
;
1958 * reusing provisional rfd
1962 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1963 sizeof(struct rfapi_descriptor
));
1968 if (default_options
) {
1969 struct rfapi_un_option
*p
;
1971 for (p
= default_options
; p
; p
= p
->next
) {
1972 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1973 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1975 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1976 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1982 * Fill in caller fields
1986 rfd
->cookie
= userdata
;
1988 if (!reusing_provisional
) {
1989 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1991 * This can fail only if the VN address is IPv6 and the group
1992 * specified auto-assignment of RDs, which only works for v4,
1993 * and the check above should catch it.
1995 * Another failure possibility is that we were called
1996 * during an rfapi callback. Also checked above.
2001 if (response_lifetime
)
2002 *response_lifetime
= rfd
->response_lifetime
;
2008 * For use with debug functions
2010 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2011 rfapi_response_cb_t
*response_cb
)
2013 if (!is_valid_rfd(rfd
))
2015 rfd
->response_cb
= response_cb
;
2022 * Does almost all the work of rfapi_close, except:
2023 * 1. preserves the descriptor (doesn't free it)
2024 * 2. preserves the prefix query list (i.e., rfd->mon list)
2025 * 3. preserves the advertised prefix list (rfd->advertised)
2026 * 4. preserves the rib and rib_pending tables
2028 * The purpose of organizing it this way is to support on-the-fly
2029 * reassignment of an already-open nve to a new nve-group in the
2030 * event that its original nve-group is administratively deleted.
2032 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2035 struct prefix pfx_vn
;
2036 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2038 if (!is_valid_rfd(rfd
))
2041 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2042 assert(!rc
); /* should never have bad AF in stored vn address */
2045 * update exported routes to reflect disappearance of this NVE as
2048 vnc_direct_bgp_del_nve(bgp
, rfd
);
2049 vnc_zebra_del_nve(bgp
, rfd
);
2052 * unlink this HD's monitors from import table
2054 rfapiMonitorDetachImportHd(rfd
);
2057 * Unlink from Import Table
2058 * NB rfd->import_table will be NULL if we are closing a stale
2061 if (rfd
->import_table
)
2062 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2063 rfd
->import_table
= NULL
;
2066 * Construct route distinguisher
2068 memset(&prd
, 0, sizeof(prd
));
2070 prd
.family
= AF_UNSPEC
;
2076 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2077 &pfx_vn
, /* prefix being advertised */
2078 &prd
, /* route distinguisher to use (0 for ENCAP) */
2079 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2082 * Construct route distinguisher for VPN routes
2085 prd
.family
= AF_UNSPEC
;
2089 * find all VPN routes associated with this rfd and delete them, too
2091 rfapiApWithdrawAll(bgp
, rfd
);
2094 * remove this nve descriptor from the list of nves
2095 * associated with the nve group
2098 listnode_delete(rfd
->rfg
->nves
, rfd
);
2099 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2102 if (rfd
->rt_export_list
)
2103 ecommunity_free(&rfd
->rt_export_list
);
2104 rfd
->rt_export_list
= NULL
;
2107 * free peer structure (possibly delayed until its
2108 * refcount reaches zero)
2111 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2112 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2113 peer_delete(rfd
->peer
);
2120 int rfapi_close(void *handle
)
2122 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2124 struct agg_node
*node
;
2128 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2130 #ifdef RFAPI_WHO_IS_CALLING_ME
2131 #ifdef HAVE_GLIBC_BACKTRACE
2132 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2134 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2139 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2140 syms
= backtrace_symbols(buf
, size
);
2141 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2143 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2159 if (!is_valid_rfd(rfd
))
2162 if (h
->flags
& RFAPI_INCALLBACK
) {
2164 * Queue these close requests for processing after callback
2167 if (!CHECK_FLAG(rfd
->flags
,
2168 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2169 work_queue_add(h
->deferred_close_q
, handle
);
2170 vnc_zlog_debug_verbose(
2171 "%s: added handle %p to deferred close queue",
2177 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2179 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2182 if (h
->rfp_methods
.close_cb
) {
2183 vnc_zlog_debug_verbose(
2184 "%s calling close callback rfd=%p", __func__
,
2188 * call the callback fairly early so that it can still
2192 * NB RFAPI_INCALLBACK is tested above, so if we reach
2194 * we are not already in the context of a callback.
2196 h
->flags
|= RFAPI_INCALLBACK
;
2197 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2198 h
->flags
&= ~RFAPI_INCALLBACK
;
2204 * Orphaned descriptors have already done this part, so do
2205 * only for non-orphaned descriptors.
2207 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2212 * Remove descriptor from UN index
2213 * (remove from chain at node)
2215 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2217 struct rfapi_descriptor
*hh
;
2219 if (node
->info
== rfd
) {
2220 node
->info
= rfd
->next
;
2223 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2224 if (hh
->next
== rfd
) {
2225 hh
->next
= rfd
->next
;
2230 agg_unlock_node(node
);
2234 * remove from descriptor list
2236 listnode_delete(&h
->descriptors
, rfd
);
2239 * Delete monitor list items and free monitor structures
2241 (void)rfapiMonitorDelHd(rfd
);
2244 * release advertised prefix data
2246 rfapiApRelease(&rfd
->advertised
);
2249 * Release RFP callback RIB
2256 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2257 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2263 * Reopen a nve descriptor. If the descriptor's NVE-group
2264 * does not exist (e.g., if it has been administratively removed),
2265 * reassignment to a new NVE-group is attempted.
2267 * If NVE-group reassignment fails, the descriptor becomes "stale"
2268 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2269 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2270 * on the descriptor will return ESTALE.
2272 * Reopening a descriptor is a potentially expensive operation, because
2273 * it involves withdrawing any routes advertised by the NVE, withdrawing
2274 * the NVE's route queries, and then re-adding them all after a new
2275 * NVE-group is assigned. There are also possible route-export affects
2276 * caused by deleting and then adding the NVE: advertised prefixes
2277 * and nexthop lists for exported routes can turn over.
2279 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2284 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2287 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2291 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2293 if (CHECK_FLAG(rfd
->flags
,
2294 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2295 && h
&& h
->rfp_methods
.close_cb
) {
2298 * NB RFAPI_INCALLBACK is tested above, so if we reach
2300 * we are not already in the context of a callback.
2302 h
->flags
|= RFAPI_INCALLBACK
;
2303 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2304 h
->flags
&= ~RFAPI_INCALLBACK
;
2311 /***********************************************************************
2313 ***********************************************************************/
2315 * Announce reachability to this prefix via the NVE
2317 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2318 uint32_t lifetime
, /* host byte order */
2319 struct rfapi_un_option
*options_un
,
2320 struct rfapi_vn_option
*options_vn
,
2321 rfapi_register_action action
)
2323 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2326 struct prefix
*pfx_ip
= NULL
;
2327 struct prefix_rd prd
;
2329 struct prefix pfx_mac_buf
;
2330 struct prefix
*pfx_mac
= NULL
;
2331 struct prefix pfx_vn_buf
;
2332 const char *action_str
= NULL
;
2333 uint32_t *label
= NULL
;
2334 struct rfapi_vn_option
*vo
;
2335 struct rfapi_l2address_option
*l2o
= NULL
;
2336 struct prefix_rd
*prd_override
= NULL
;
2339 case RFAPI_REGISTER_ADD
:
2342 case RFAPI_REGISTER_WITHDRAW
:
2343 action_str
= "withdraw";
2345 case RFAPI_REGISTER_KILL
:
2346 action_str
= "kill";
2354 * Inspect VN options
2356 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2357 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2358 l2o
= &vo
->v
.l2addr
;
2360 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2361 prd_override
= &vo
->v
.internal_rd
;
2365 /*********************************************************************
2367 *********************************************************************/
2370 * set <p> based on <prefix>
2372 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2374 afi
= family2afi(prefix
->prefix
.addr_family
);
2377 vnc_zlog_debug_verbose(
2378 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2379 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2383 * These tests come after the prefix conversion so that we can
2384 * print the prefix in a debug message before failing
2389 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2394 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2399 if (RFAPI_REGISTER_ADD
== action
) {
2400 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2402 vnc_zlog_debug_verbose(
2403 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2408 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2409 if (RFAPI_REGISTER_ADD
== action
) {
2410 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2412 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2417 if (!is_valid_rfd(rfd
)) {
2418 if (RFAPI_REGISTER_ADD
== action
) {
2419 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2421 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2427 * Is there a MAC address in this registration?
2429 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2430 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2431 pfx_mac
= &pfx_mac_buf
;
2435 * Is there an IP prefix in this registration?
2437 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2441 vnc_zlog_debug_verbose(
2442 "%s: missing mac addr that is required for host 0 pfx",
2444 if (RFAPI_REGISTER_ADD
== action
) {
2445 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2449 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2450 vnc_zlog_debug_verbose(
2451 "%s: handle has bad vn_addr: returning EBADF",
2453 if (RFAPI_REGISTER_ADD
== action
) {
2454 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2460 if (RFAPI_REGISTER_ADD
== action
) {
2461 ++bgp
->rfapi
->stat
.count_registrations
;
2465 * Figure out if this registration is missing an IP address
2469 * In RFAPI, we use prefixes in family AF_LINK to store
2470 * the MAC addresses. These prefixes are used for the
2471 * list of advertised prefixes and in the RFAPI import
2474 * In BGP proper, we use the prefix matching the NVE's
2475 * VN address with a host prefix-length (i.e., 32 or 128).
2478 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2479 && RFAPI_HOST_PREFIX(&p
)) {
2481 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2482 pfx_mac
= &pfx_mac_buf
;
2486 * Construct route distinguisher
2489 prd
= *prd_override
;
2491 memset(&prd
, 0, sizeof(prd
));
2493 prd
.family
= AF_UNSPEC
;
2495 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2496 if (l2o
->local_nve_id
2497 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2499 * If Local NVE ID is specified in message, use
2501 * (if no local default configured, also use it
2504 prd
.val
[1] = l2o
->local_nve_id
;
2506 if (rfd
->rfg
->l2rd
) {
2508 * locally-configured literal value
2510 prd
.val
[1] = rfd
->rfg
->l2rd
;
2513 * 0 means auto:vn, which means use LSB
2516 if (rfd
->vn_addr
.addr_family
2519 *(((char *)&rfd
->vn_addr
2525 *(((char *)&rfd
->vn_addr
2532 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2535 prd
.family
= AF_UNSPEC
;
2541 if (action
== RFAPI_REGISTER_WITHDRAW
2542 || action
== RFAPI_REGISTER_KILL
) {
2547 * withdraw previous advertisement
2550 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2552 : &pfx_vn_buf
, /* prefix being advertised */
2553 &prd
, /* route distinguisher (0 for ENCAP) */
2554 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2555 action
== RFAPI_REGISTER_KILL
);
2557 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2560 rfapiTunnelRouteAnnounce(
2561 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2567 uint32_t local_pref
;
2568 struct ecommunity
*rtlist
= NULL
;
2569 struct ecommunity_val ecom_value
;
2571 if (!rfapiApCount(rfd
)) {
2573 * make sure we advertise tunnel route upon adding the
2579 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2580 prefix
->cost
, l2o
)) {
2584 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2587 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2589 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2590 &rfd
->max_prefix_lifetime
);
2593 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2595 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2597 if (l2o
&& l2o
->label
)
2598 label
= &l2o
->label
;
2601 struct ecommunity
*l2com
= NULL
;
2604 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2605 bgp
, 1, l2o
->logical_net_id
, *label
);
2608 rtlist
= ecommunity_dup(l2com
);
2611 * If mac address is set, add an RT based on the
2614 memset((char *)&ecom_value
, 0,
2615 sizeof(ecom_value
));
2616 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2618 (l2o
->logical_net_id
>> 16) & 0xff;
2620 (l2o
->logical_net_id
>> 8) & 0xff;
2622 (l2o
->logical_net_id
>> 0) & 0xff;
2623 rtlist
= ecommunity_new();
2624 ecommunity_add_val(rtlist
, &ecom_value
,
2629 uint16_t val
= l2o
->tag_id
;
2630 memset((char *)&ecom_value
, 0,
2631 sizeof(ecom_value
));
2632 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2633 if (as
> BGP_AS_MAX
) {
2635 ECOMMUNITY_ENCODE_AS4
;
2636 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2637 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2638 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2639 ecom_value
.val
[5] = as
& 0xff;
2642 ECOMMUNITY_ENCODE_AS
;
2643 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2644 ecom_value
.val
[3] = as
& 0xff;
2646 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2647 ecom_value
.val
[7] = val
& 0xff;
2649 rtlist
= ecommunity_new();
2650 ecommunity_add_val(rtlist
, &ecom_value
,
2656 * advertise prefix via tunnel endpoint
2659 rfd
, /* rfapi descr, for export list & backref */
2660 bgp
, /* which bgp instance */
2661 SAFI_MPLS_VPN
, /* which SAFI */
2663 : &pfx_vn_buf
), /* prefix being advertised */
2664 &prd
, /* route distinguisher to use (0 for ENCAP) */
2665 &rfd
->vn_addr
, /* nexthop */
2667 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2668 NULL
, options_un
, /* rfapi un options */
2669 options_vn
, /* rfapi vn options */
2670 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2671 label
, /* label: default */
2672 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2675 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2678 vnc_zlog_debug_verbose("%s: success", __func__
);
2682 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2683 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2684 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2686 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2687 struct bgp
*bgp
= rfd
->bgp
;
2690 assert(ppNextHopEntry
);
2691 *ppNextHopEntry
= NULL
;
2693 if (bgp
&& bgp
->rfapi
) {
2694 bgp
->rfapi
->stat
.count_queries
++;
2698 if (bgp
&& bgp
->rfapi
)
2699 ++bgp
->rfapi
->stat
.count_queries_failed
;
2703 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2704 if (bgp
&& bgp
->rfapi
)
2705 ++bgp
->rfapi
->stat
.count_queries_failed
;
2710 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2714 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2715 struct bgp
*bgp
= rfd
->bgp
;
2721 rc
= rfapiRaddr2Qprefix(target
, &p
);
2724 if (!is_valid_rfd(rfd
))
2728 if (!bgp
|| !bgp
->rfapi
)
2731 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2734 rfapiMonitorDel(bgp
, rfd
, &p
);
2739 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2741 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2742 struct bgp
*bgp
= rfd
->bgp
;
2749 if (!is_valid_rfd(rfd
))
2753 if (!bgp
|| !bgp
->rfapi
)
2756 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2759 num
= rfapiMonitorDelHd(rfd
);
2767 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2769 struct rfapi_next_hop_entry
*nh
;
2770 struct rfapi_next_hop_entry
*next
;
2772 for (nh
= list
; nh
; nh
= next
) {
2774 rfapi_un_options_free(nh
->un_options
);
2775 nh
->un_options
= NULL
;
2776 rfapi_vn_options_free(nh
->vn_options
);
2777 nh
->vn_options
= NULL
;
2778 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2783 * NULL handle => return total count across all nves
2785 uint32_t rfapi_monitor_count(void *handle
)
2787 struct bgp
*bgp
= bgp_get_default();
2791 struct rfapi_descriptor
*rfd
=
2792 (struct rfapi_descriptor
*)handle
;
2793 count
= rfd
->monitor_count
;
2796 if (!bgp
|| !bgp
->rfapi
)
2799 count
= bgp
->rfapi
->monitor_count
;
2805 /***********************************************************************
2807 ***********************************************************************/
2809 DEFUN (debug_rfapi_show_nves
,
2810 debug_rfapi_show_nves_cmd
,
2811 "debug rfapi-dev show nves",
2815 "NVE Information\n")
2817 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2822 debug_rfapi_show_nves_vn_un
,
2823 debug_rfapi_show_nves_vn_un_cmd
,
2824 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2829 "Specify virtual network\n"
2830 "Specify underlay network interface\n"
2836 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2837 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2838 return CMD_WARNING_CONFIG_FAILED
;
2840 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2841 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2842 return CMD_WARNING_CONFIG_FAILED
;
2845 if (argv
[4]->arg
[0] == 'u') {
2846 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2848 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2854 * Note: this function does not flush vty output, so if it is called
2855 * with a stream pointing to a vty, the user will have to type something
2856 * before the callback output shows up
2858 static void test_nexthops_callback(
2859 // struct rfapi_ip_addr *target,
2860 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2862 void *stream
= userdata
;
2864 int (*fp
)(void *, const char *, ...);
2867 const char *vty_newline
;
2869 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2872 fp(out
, "Nexthops Callback, Target=(");
2873 // rfapiPrintRfapiIpAddr(stream, target);
2876 rfapiPrintNhl(stream
, next_hops
);
2880 rfapi_free_next_hop_list(next_hops
);
2883 DEFUN (debug_rfapi_open
,
2884 debug_rfapi_open_cmd
,
2885 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2889 "indicate vn addr follows\n"
2890 "virtual network interface IPv4 address\n"
2891 "virtual network interface IPv6 address\n"
2892 "indicate xt addr follows\n"
2893 "underlay network interface IPv4 address\n"
2894 "underlay network interface IPv6 address\n")
2896 struct rfapi_ip_addr vn
;
2897 struct rfapi_ip_addr un
;
2898 uint32_t lifetime
= 0;
2900 rfapi_handle handle
;
2905 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2911 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2914 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2915 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2917 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2920 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2922 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2928 DEFUN (debug_rfapi_close_vn_un
,
2929 debug_rfapi_close_vn_un_cmd
,
2930 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2934 "indicate vn addr follows\n"
2935 "virtual network interface IPv4 address\n"
2936 "virtual network interface IPv6 address\n"
2937 "indicate xt addr follows\n"
2938 "underlay network interface IPv4 address\n"
2939 "underlay network interface IPv6 address\n")
2941 struct rfapi_ip_addr vn
;
2942 struct rfapi_ip_addr un
;
2943 rfapi_handle handle
;
2949 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2956 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2960 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2961 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2962 argv
[4]->arg
, argv
[6]->arg
);
2963 return CMD_WARNING_CONFIG_FAILED
;
2966 rc
= rfapi_close(handle
);
2968 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2973 DEFUN (debug_rfapi_close_rfd
,
2974 debug_rfapi_close_rfd_cmd
,
2975 "debug rfapi-dev close rfd HANDLE",
2979 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2981 rfapi_handle handle
;
2983 char *endptr
= NULL
;
2985 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2987 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2988 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2989 return CMD_WARNING_CONFIG_FAILED
;
2992 rc
= rfapi_close(handle
);
2994 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2999 DEFUN (debug_rfapi_register_vn_un
,
3000 debug_rfapi_register_vn_un_cmd
,
3001 "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)]",
3005 "indicate vn addr follows\n"
3006 "virtual network IPv4 interface address\n"
3007 "virtual network IPv6 interface address\n"
3008 "indicate un addr follows\n"
3009 "underlay network IPv4 interface address\n"
3010 "underlay network IPv6 interface address\n"
3011 "indicate prefix follows\n"
3014 "indicate lifetime follows\n"
3016 "Cost (localpref = 255-cost)\n"
3019 struct rfapi_ip_addr vn
;
3020 struct rfapi_ip_addr un
;
3021 rfapi_handle handle
;
3024 struct rfapi_ip_prefix hpfx
;
3031 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3038 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3042 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3043 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3044 argv
[4]->arg
, argv
[6]->arg
);
3045 return CMD_WARNING_CONFIG_FAILED
;
3049 * Get prefix to advertise
3051 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3052 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3053 return CMD_WARNING_CONFIG_FAILED
;
3055 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3056 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3057 return CMD_WARNING_CONFIG_FAILED
;
3059 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3061 if (strmatch(argv
[10]->text
, "infinite")) {
3062 lifetime
= RFAPI_INFINITE_LIFETIME
;
3064 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3068 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3071 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3072 RFAPI_REGISTER_ADD
);
3074 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3081 DEFUN (debug_rfapi_register_vn_un_l2o
,
3082 debug_rfapi_register_vn_un_l2o_cmd
,
3083 "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)",
3087 "indicate vn addr follows\n"
3088 "virtual network IPv4 interface address\n"
3089 "virtual network IPv6 interface address\n"
3090 "indicate un addr follows\n"
3091 "underlay network IPv4 interface address\n"
3092 "underlay network IPv6 interface address\n"
3093 "indicate prefix follows\n"
3096 "indicate lifetime follows\n"
3097 "Seconds of lifetime\n"
3098 "indicate MAC address follows\n"
3100 "indicate lni follows\n"
3101 "lni value range\n")
3103 struct rfapi_ip_addr vn
;
3104 struct rfapi_ip_addr un
;
3105 rfapi_handle handle
;
3108 struct rfapi_ip_prefix hpfx
;
3110 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3111 struct rfapi_vn_option
*opt
= NULL
;
3117 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3124 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3128 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3129 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3130 argv
[4]->arg
, argv
[6]->arg
);
3131 return CMD_WARNING_CONFIG_FAILED
;
3135 * Get prefix to advertise
3137 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3138 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3139 return CMD_WARNING_CONFIG_FAILED
;
3141 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3142 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3143 return CMD_WARNING_CONFIG_FAILED
;
3145 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3147 if (strmatch(argv
[10]->text
, "infinite")) {
3148 lifetime
= RFAPI_INFINITE_LIFETIME
;
3150 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3153 /* L2 option parsing START */
3154 memset(optary
, 0, sizeof(optary
));
3155 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3156 strtoul(argv
[14]->arg
, NULL
, 10);
3157 if (rfapiStr2EthAddr(argv
[12]->arg
,
3158 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3159 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3160 return CMD_WARNING_CONFIG_FAILED
;
3162 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3165 /* L2 option parsing END */
3168 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3169 RFAPI_REGISTER_ADD
);
3171 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3179 DEFUN (debug_rfapi_unregister_vn_un
,
3180 debug_rfapi_unregister_vn_un_cmd
,
3181 "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]",
3185 "indicate vn addr follows\n"
3186 "virtual network interface address\n"
3187 "indicate xt addr follows\n"
3188 "underlay network interface address\n"
3189 "prefix to remove\n"
3190 "Remove without holddown")
3192 struct rfapi_ip_addr vn
;
3193 struct rfapi_ip_addr un
;
3194 rfapi_handle handle
;
3196 struct rfapi_ip_prefix hpfx
;
3202 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3209 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3213 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3214 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3215 argv
[4]->arg
, argv
[6]->arg
);
3216 return CMD_WARNING_CONFIG_FAILED
;
3220 * Get prefix to advertise
3222 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3223 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3224 return CMD_WARNING_CONFIG_FAILED
;
3226 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3227 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3228 return CMD_WARNING_CONFIG_FAILED
;
3230 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3232 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3234 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3239 DEFUN (debug_rfapi_query_vn_un
,
3240 debug_rfapi_query_vn_un_cmd
,
3241 "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>",
3245 "indicate vn addr follows\n"
3246 "virtual network interface IPv4 address\n"
3247 "virtual network interface IPv6 address\n"
3248 "indicate un addr follows\n"
3251 "indicate target follows\n"
3252 "target IPv4 address\n"
3253 "target IPv6 address\n")
3255 struct rfapi_ip_addr vn
;
3256 struct rfapi_ip_addr un
;
3257 struct rfapi_ip_addr target
;
3258 rfapi_handle handle
;
3260 struct rfapi_next_hop_entry
*pNextHopEntry
;
3265 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3272 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3279 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3283 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3284 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3285 argv
[4]->arg
, argv
[6]->arg
);
3286 return CMD_WARNING_CONFIG_FAILED
;
3290 * options parameter not used? Set to NULL for now
3292 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3295 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3299 * print nexthop list
3301 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3302 vty
); /* frees nh list! */
3309 DEFUN (debug_rfapi_query_vn_un_l2o
,
3310 debug_rfapi_query_vn_un_l2o_cmd
,
3311 "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",
3315 "indicate vn addr follows\n"
3316 "virtual network interface IPv4 address\n"
3317 "virtual network interface IPv6 address\n"
3318 "indicate xt addr follows\n"
3319 "underlay network interface IPv4 address\n"
3320 "underlay network interface IPv6 address\n"
3321 "logical network ID follows\n"
3322 "logical network ID\n"
3323 "indicate target MAC addr follows\n"
3324 "target MAC addr\n")
3326 struct rfapi_ip_addr vn
;
3327 struct rfapi_ip_addr un
;
3333 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3340 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3343 vty_out(vty
, "%% This command is broken.\n");
3344 return CMD_WARNING_CONFIG_FAILED
;
3348 DEFUN (debug_rfapi_query_done_vn_un
,
3349 debug_rfapi_query_vn_un_done_cmd
,
3350 "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>",
3353 "rfapi_query_done\n"
3354 "rfapi_query_done\n"
3355 "indicate vn addr follows\n"
3356 "virtual network interface IPv4 address\n"
3357 "virtual network interface IPv6 address\n"
3358 "indicate xt addr follows\n"
3359 "underlay network interface IPv4 address\n"
3360 "underlay network interface IPv6 address\n"
3361 "indicate target follows\n"
3362 "Target IPv4 address\n"
3363 "Target IPv6 address\n")
3365 struct rfapi_ip_addr vn
;
3366 struct rfapi_ip_addr un
;
3367 struct rfapi_ip_addr target
;
3368 rfapi_handle handle
;
3374 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3381 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3388 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3392 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3393 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3394 argv
[5]->arg
, argv
[7]->arg
);
3395 return CMD_WARNING_CONFIG_FAILED
;
3399 * options parameter not used? Set to NULL for now
3401 rc
= rfapi_query_done(handle
, &target
);
3403 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3408 DEFUN (debug_rfapi_show_import
,
3409 debug_rfapi_show_import_cmd
,
3410 "debug rfapi-dev show import",
3418 struct rfapi_import_table
*it
;
3423 * Show all import tables
3426 bgp
= bgp_get_default(); /* assume 1 instance for now */
3428 vty_out(vty
, "No BGP instance\n");
3429 return CMD_WARNING_CONFIG_FAILED
;
3434 vty_out(vty
, "No RFAPI instance\n");
3435 return CMD_WARNING_CONFIG_FAILED
;
3439 * Iterate over all import tables; do a filtered import
3440 * for the afi/safi combination
3444 for (it
= h
->imports
; it
; it
= it
->next
) {
3445 s
= ecommunity_ecom2str(it
->rt_import_list
,
3446 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3447 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3448 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3450 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3452 rfapiShowImportTable(vty
, "IP ENCAP",
3453 it
->imported_encap
[AFI_IP
], 0);
3454 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3456 rfapiShowImportTable(vty
, "IP6 ENCAP",
3457 it
->imported_encap
[AFI_IP6
], 0);
3460 if (h
->import_mac
) {
3461 void *cursor
= NULL
;
3463 uintptr_t lni_as_ptr
;
3467 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3468 (void **)&it
, &cursor
);
3470 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3471 (void **)&it
, &cursor
)) {
3473 if (it
->imported_vpn
[AFI_L2VPN
]) {
3477 "\nLNI-based Ethernet Tables:\n");
3480 snprintf(buf
, sizeof(buf
), "L2VPN LNI=%u", lni
);
3481 rfapiShowImportTable(
3482 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3488 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3489 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3494 DEFUN (debug_rfapi_show_import_vn_un
,
3495 debug_rfapi_show_import_vn_un_cmd
,
3496 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3501 "indicate vn addr follows\n"
3502 "virtual network interface IPv4 address\n"
3503 "virtual network interface IPv6 address\n"
3504 "indicate xt addr follows\n"
3505 "underlay network interface IPv4 address\n"
3506 "underlay network interface IPv6 address\n")
3508 struct rfapi_ip_addr vn
;
3509 struct rfapi_ip_addr un
;
3510 rfapi_handle handle
;
3512 struct rfapi_descriptor
*rfd
;
3517 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3524 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3528 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3529 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3530 argv
[5]->arg
, argv
[7]->arg
);
3531 return CMD_WARNING_CONFIG_FAILED
;
3534 rfd
= (struct rfapi_descriptor
*)handle
;
3536 rfapiShowImportTable(vty
, "IP VPN",
3537 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3538 rfapiShowImportTable(vty
, "IP ENCAP",
3539 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3540 rfapiShowImportTable(vty
, "IP6 VPN",
3541 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3542 rfapiShowImportTable(vty
, "IP6 ENCAP",
3543 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3548 DEFUN (debug_rfapi_response_omit_self
,
3549 debug_rfapi_response_omit_self_cmd
,
3550 "debug rfapi-dev response-omit-self <on|off>",
3553 "Omit self in RFP responses\n"
3554 "filter out self from responses\n" "leave self in responses\n")
3556 struct bgp
*bgp
= bgp_get_default();
3559 vty_out(vty
, "No BGP process is configured\n");
3560 return CMD_WARNING_CONFIG_FAILED
;
3562 if (!bgp
->rfapi_cfg
) {
3563 vty_out(vty
, "VNC not configured\n");
3564 return CMD_WARNING_CONFIG_FAILED
;
3567 if (strmatch(argv
[3]->text
, "on"))
3568 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3569 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3571 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3572 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3578 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3580 #include "lib/skiplist.h"
3581 DEFUN (skiplist_test_cli
,
3582 skiplist_test_cli_cmd
,
3584 "skiplist command\n"
3592 DEFUN (skiplist_debug_cli
,
3593 skiplist_debug_cli_cmd
,
3595 "skiplist command\n"
3598 skiplist_debug(vty
, NULL
);
3602 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3604 void rfapi_init(void)
3606 bgp_rfapi_cfg_init();
3609 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3610 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3612 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3613 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3614 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3615 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3616 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3617 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3618 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3619 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3621 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3623 /* Need the following show commands for gpz test scripts */
3624 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3625 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3626 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3628 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3629 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3630 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3637 static void rfapi_print_exported(struct bgp
*bgp
)
3639 struct bgp_dest
*destn
;
3640 struct bgp_dest
*dest
;
3641 struct bgp_path_info
*bpi
;
3646 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); destn
;
3647 destn
= bgp_route_next(destn
)) {
3648 struct bgp_table
*table
;
3650 table
= bgp_dest_get_bgp_table_info(destn
);
3653 fprintf(stderr
, "%s: vpn destn=%p\n", __func__
, destn
);
3654 for (dest
= bgp_table_top(table
); dest
;
3655 dest
= bgp_route_next(dest
)) {
3656 bpi
= bgp_dest_get_bgp_path_info(dest
);
3660 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3661 for (; bpi
; bpi
= bpi
->next
) {
3662 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3666 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); destn
;
3667 destn
= bgp_route_next(destn
)) {
3668 struct bgp_table
*table
;
3670 table
= bgp_dest_get_bgp_table_info(destn
);
3673 fprintf(stderr
, "%s: encap destn=%p\n", __func__
, destn
);
3674 for (dest
= bgp_table_top(table
); dest
;
3675 dest
= bgp_route_next(dest
)) {
3676 bpi
= bgp_dest_get_bgp_path_info(dest
);
3679 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3680 for (; bpi
; bpi
= bpi
->next
) {
3681 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3686 #endif /* defined(DEBUG_RFAPI) */
3689 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3691 void rfapi_delete(struct bgp
*bgp
)
3693 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3696 * This clears queries and registered routes, and closes nves
3699 rfp_clear_vnc_nve_all();
3700 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3701 bgp
->rfapi_cfg
= NULL
;
3702 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3706 * show what's left in the BGP MPLSVPN RIB
3708 rfapi_print_exported(bgp
);
3712 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3714 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3715 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3716 vnc_zlog_debug_verbose(
3717 "%s: can't auto-assign RD, VN addr family is not IPv4|v6",
3719 return EAFNOSUPPORT
;
3721 rd
->family
= AF_UNSPEC
;
3723 rd
->val
[1] = RD_TYPE_IP
;
3724 if (vn
->addr_family
== AF_INET
) {
3725 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3726 } else { /* is v6 */
3727 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3728 4); /* low order 4 bytes */
3731 char buf
[RD_ADDRSTRLEN
];
3733 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3734 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3739 /*------------------------------------------
3740 * rfapi_bgp_lookup_by_rfp
3742 * Find bgp instance pointer based on value returned by rfp_start
3745 * rfp_start_val value returned by rfp_startor
3746 * NULL (=get default instance)
3752 * bgp bgp instance pointer
3755 --------------------------------------------*/
3756 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3758 struct bgp
*bgp
= NULL
;
3759 struct listnode
*node
, *nnode
;
3761 if (rfp_start_val
== NULL
)
3762 bgp
= bgp_get_default();
3764 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3765 if (bgp
->rfapi
!= NULL
3766 && bgp
->rfapi
->rfp
== rfp_start_val
)
3771 /*------------------------------------------
3772 * rfapi_get_rfp_start_val_by_bgp
3774 * Find bgp instance pointer based on value returned by rfp_start
3777 * bgp bgp instance pointer
3786 --------------------------------------------*/
3787 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3789 if (!bgp
|| !bgp
->rfapi
)
3791 return bgp
->rfapi
->rfp
;
3794 /***********************************************************************
3795 * RFP group specific configuration
3796 ***********************************************************************/
3797 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3801 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3802 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3803 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3806 return rfc
->default_rfp_cfg
;
3809 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3813 struct rfapi_nve_group_cfg
*rfg
=
3814 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3816 /* make sure group is still in list */
3817 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3818 /* Not in list anymore */
3819 vty_out(vty
, "Current NVE group no longer exists\n");
3823 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3824 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3825 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3828 return rfg
->rfp_cfg
;
3831 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3835 struct rfapi_l2_group_cfg
*rfg
=
3836 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3838 /* make sure group is still in list */
3839 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3840 /* Not in list anymore */
3841 vty_out(vty
, "Current L2 group no longer exists\n");
3844 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3845 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3846 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3849 return rfg
->rfp_cfg
;
3852 /*------------------------------------------
3853 * rfapi_rfp_init_group_config_ptr_vty
3855 * This is used to init or return a previously init'ed group specific
3856 * configuration pointer. Group is identified by vty context.
3857 * NOTE: size is ignored when a previously init'ed value is returned.
3858 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3859 * bgp restart or shutdown.
3862 * rfp_start_val value returned by rfp_start
3864 * vty quagga vty context
3865 * size number of bytes to allocation
3871 * rfp_cfg_group NULL or Pointer to configuration structure
3872 --------------------------------------------*/
3873 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3874 rfapi_rfp_cfg_group_type type
,
3875 struct vty
*vty
, uint32_t size
)
3880 if (rfp_start_val
== NULL
|| vty
== NULL
)
3883 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3884 if (!bgp
|| !bgp
->rfapi_cfg
)
3888 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3889 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3892 case RFAPI_RFP_CFG_GROUP_NVE
:
3893 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3896 case RFAPI_RFP_CFG_GROUP_L2
:
3897 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3901 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3903 /* should never happen */
3904 assert("Unknown type" == NULL
);
3910 /*------------------------------------------
3911 * rfapi_rfp_get_group_config_ptr_vty
3913 * This is used to get group specific configuration pointer.
3914 * Group is identified by type and vty context.
3915 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3916 * bgp restart or shutdown.
3919 * rfp_start_val value returned by rfp_start
3921 * vty quagga vty context
3927 * rfp_cfg_group Pointer to configuration structure
3928 --------------------------------------------*/
3929 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3930 rfapi_rfp_cfg_group_type type
,
3933 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3937 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3939 rfp_group_config_search_cb_t
*search_cb
)
3941 struct rfapi_nve_group_cfg
*rfg
;
3942 struct listnode
*node
;
3944 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3945 if (!strcmp(rfg
->name
, name
) && /* name match */
3946 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3947 return rfg
->rfp_cfg
;
3953 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3955 rfp_group_config_search_cb_t
*search_cb
)
3957 struct rfapi_l2_group_cfg
*rfg
;
3958 struct listnode
*node
;
3960 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3961 if (!strcmp(rfg
->name
, name
) && /* name match */
3962 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3963 return rfg
->rfp_cfg
;
3968 /*------------------------------------------
3969 * rfapi_rfp_get_group_config_ptr_name
3971 * This is used to get group specific configuration pointer.
3972 * Group is identified by type and name context.
3973 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3974 * bgp restart or shutdown.
3977 * rfp_start_val value returned by rfp_start
3980 * criteria RFAPI caller provided serach criteria
3981 * search_cb optional rfp_group_config_search_cb_t
3987 * rfp_cfg_group Pointer to configuration structure
3988 --------------------------------------------*/
3989 void *rfapi_rfp_get_group_config_ptr_name(
3990 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3991 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
3996 if (rfp_start_val
== NULL
|| name
== NULL
)
3999 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4000 if (!bgp
|| !bgp
->rfapi_cfg
)
4004 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4005 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4007 case RFAPI_RFP_CFG_GROUP_NVE
:
4008 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4009 criteria
, search_cb
);
4011 case RFAPI_RFP_CFG_GROUP_L2
:
4012 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4013 criteria
, search_cb
);
4016 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4018 /* should never happen */
4019 assert("Unknown type" == NULL
);
4025 /*------------------------------------------
4026 * rfapi_rfp_get_l2_group_config_ptr_lni
4028 * This is used to get group specific configuration pointer.
4029 * Group is identified by type and logical network identifier.
4030 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4031 * bgp restart or shutdown.
4034 * rfp_start_val value returned by rfp_start
4036 * logical_net_id group logical network identifier
4037 * criteria RFAPI caller provided serach criteria
4038 * search_cb optional rfp_group_config_search_cb_t
4044 * rfp_cfg_group Pointer to configuration structure
4045 --------------------------------------------*/
4047 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4048 uint32_t logical_net_id
, void *criteria
,
4049 rfp_group_config_search_cb_t
*search_cb
)
4052 struct rfapi_l2_group_cfg
*rfg
;
4053 struct listnode
*node
;
4055 if (rfp_start_val
== NULL
)
4058 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4059 if (!bgp
|| !bgp
->rfapi_cfg
)
4062 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4063 if (rfg
->logical_net_id
== logical_net_id
4064 && (search_cb
== NULL
4065 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4066 if (rfg
->rfp_cfg
== NULL
)
4067 vnc_zlog_debug_verbose(
4068 "%s: returning rfp group config for lni=0",
4070 return rfg
->rfp_cfg
;