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
, 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);
725 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
726 encaptlv
->length
= 4;
727 lt
= htonl(*lifetime
);
728 memcpy(encaptlv
->value
, <
, 4);
729 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
730 vnc_zlog_debug_verbose(
731 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
735 /* add rfp options to vnc attr */
738 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
739 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
740 bgp_attr_get_vnc_subtlvs(&attr
);
742 * this flag means we're passing a pointer to an
743 * existing encap tlv chain which we should copy.
744 * It's a hack to avoid adding yet another argument
747 encaptlv
= encap_tlv_dup(
748 (struct bgp_attr_encap_subtlv
*)rfp_options
);
750 vnc_subtlvs
->next
= encaptlv
;
752 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
754 struct bgp_tea_options
*hop
;
755 /* XXX max of one tlv present so far from above code */
756 struct bgp_attr_encap_subtlv
*tail
=
757 bgp_attr_get_vnc_subtlvs(&attr
);
759 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
766 sizeof(struct bgp_attr_encap_subtlv
) + 2
769 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
772 encaptlv
->length
= 2 + hop
->length
;
773 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
774 *((uint8_t *)(encaptlv
->value
) + 1) =
776 memcpy(((uint8_t *)encaptlv
->value
) + 2,
777 hop
->value
, hop
->length
);
780 * add to end of subtlv chain
783 tail
->next
= encaptlv
;
785 bgp_attr_set_vnc_subtlvs(&attr
,
795 * extra: dynamically allocated, owned by attr
796 * vnc_subtlvs: dynamic chain, length 1
797 * aspath: points to interned hash from aspath hash table
801 bgp_attr_set_ecommunity(&attr
, ecommunity_new());
802 assert(bgp_attr_get_ecommunity(&attr
));
804 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
805 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
807 * Add BGP Encapsulation Extended Community. Format described in
808 * section 4.5 of RFC 5512.
809 * Always include when not MPLS type, to disambiguate this case.
811 struct ecommunity_val beec
;
813 memset(&beec
, 0, sizeof(beec
));
814 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
815 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
816 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
817 beec
.val
[7] = (TunnelType
)&0xff;
818 ecommunity_add_val(bgp_attr_get_ecommunity(&attr
), &beec
, false,
823 * Add extended community attributes to match rt export list
825 if (rt_export_list
) {
826 bgp_attr_set_ecommunity(
827 &attr
, ecommunity_merge(bgp_attr_get_ecommunity(&attr
),
831 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(&attr
);
834 ecommunity_free(&ecomm
);
835 bgp_attr_set_ecommunity(&attr
, NULL
);
837 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
, ecomm
);
843 * extra: dynamically allocated, owned by attr
844 * vnc_subtlvs: dynamic chain, length 1
845 * ecommunity: dynamic 2-part
846 * aspath: points to interned hash from aspath hash table
849 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
850 switch (nexthop
->addr_family
) {
853 * set this field to prevent bgp_route.c code from setting
854 * mp_nexthop_global_in to self
856 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
858 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
859 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
863 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
864 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV6_GLOBAL
;
872 prefix2str(p
, buf
, sizeof(buf
));
878 * extra: dynamically allocated, owned by attr
879 * vnc_subtlvs: dynamic chain, length 1
880 * ecommunity: dynamic 2-part
881 * aspath: points to interned hash from aspath hash table
884 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
886 if (red
&& red
->redist_metric_flag
) {
887 attr
.med
= red
->redist_metric
;
888 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
891 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
894 * bgp_attr_intern creates a new reference to a cached
895 * attribute, but leaves the following bits of trash:
897 * - old attr->extra (free via bgp_attr_extra_free(attr))
899 * Note that it frees the original attr->extra->ecommunity
900 * but leaves the new attribute pointing to the ORIGINAL
901 * vnc options (which therefore we needn't free from the
904 new_attr
= bgp_attr_intern(&attr
);
906 aspath_unintern(&attr
.aspath
); /* Unintern original. */
912 * extra: dynamically allocated, owned by attr
913 * vnc_subtlvs: dynamic chain, length 1
914 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
916 * new_attr: an attr that is part of the hash table, distinct
917 * from attr which is static.
918 * extra: dynamically allocated, owned by new_attr (in hash table)
919 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
920 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
921 * aspath: POINTS TO interned/refcounted hashed block
923 for (bpi
= bgp_dest_get_bgp_path_info(bn
); bpi
; bpi
= bpi
->next
) {
924 /* probably only need to check
925 * bpi->extra->vnc.export.rfapi_handle */
926 if (bpi
->peer
== rfd
->peer
&& bpi
->type
== type
927 && bpi
->sub_type
== sub_type
&& bpi
->extra
928 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
937 * Adding new local_nexthop, which does not by itself change
938 * what is advertised via BGP
941 if (!bpi
->extra
->vnc
.export
.local_nexthops
) {
942 /* TBD make arrangements to free when needed */
943 bpi
->extra
->vnc
.export
.local_nexthops
=
945 bpi
->extra
->vnc
.export
.local_nexthops
->del
=
952 struct listnode
*node
;
953 struct rfapi_nexthop
*pLnh
= NULL
;
955 for (ALL_LIST_ELEMENTS_RO(
956 bpi
->extra
->vnc
.export
.local_nexthops
,
959 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
965 * Not present, add new one
968 pLnh
= rfapi_nexthop_new(lnh
);
970 bpi
->extra
->vnc
.export
.local_nexthops
,
975 if (attrhash_cmp(bpi
->attr
, new_attr
)
976 && !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
977 bgp_attr_unintern(&new_attr
);
978 bgp_dest_unlock_node(bn
);
981 "%s: Found route (safi=%d) at prefix %s, no change",
982 __func__
, safi
, buf
);
986 /* The attribute is changed. */
987 bgp_path_info_set_flag(bn
, bpi
, BGP_PATH_ATTR_CHANGED
);
989 if (safi
== SAFI_MPLS_VPN
) {
990 struct bgp_dest
*pdest
= NULL
;
991 struct bgp_table
*table
= NULL
;
993 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
994 (struct prefix
*)prd
);
995 table
= bgp_dest_get_bgp_table_info(pdest
);
997 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
998 bgp
, prd
, table
, p
, bpi
);
999 bgp_dest_unlock_node(pdest
);
1002 /* Rewrite BGP route information. */
1003 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
1004 bgp_path_info_restore(bn
, bpi
);
1006 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
1007 bgp_attr_unintern(&bpi
->attr
);
1008 bpi
->attr
= new_attr
;
1009 bpi
->uptime
= bgp_clock();
1012 if (safi
== SAFI_MPLS_VPN
) {
1013 struct bgp_dest
*pdest
= NULL
;
1014 struct bgp_table
*table
= NULL
;
1016 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
1017 (struct prefix
*)prd
);
1018 table
= bgp_dest_get_bgp_table_info(pdest
);
1020 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1021 bgp
, prd
, table
, p
, bpi
);
1022 bgp_dest_unlock_node(pdest
);
1025 /* Process change. */
1026 bgp_aggregate_increment(bgp
, p
, bpi
, afi
, safi
);
1027 bgp_process(bgp
, bn
, afi
, safi
);
1028 bgp_dest_unlock_node(bn
);
1031 "%s: Found route (safi=%d) at prefix %s, changed attr",
1032 __func__
, safi
, buf
);
1038 new = info_make(type
, sub_type
, 0, rfd
->peer
, new_attr
, NULL
);
1039 SET_FLAG(new->flags
, BGP_PATH_VALID
);
1041 /* save backref to rfapi handle */
1042 bgp_path_info_extra_get(new);
1043 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1044 encode_label(label_val
, &new->extra
->label
[0]);
1048 if (VNC_DEBUG(VERBOSE
)) {
1049 vnc_zlog_debug_verbose("%s: printing BPI", __func__
);
1050 rfapiPrintBi(NULL
, new);
1053 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1054 bgp_path_info_add(bn
, new);
1056 if (safi
== SAFI_MPLS_VPN
) {
1057 struct bgp_dest
*pdest
= NULL
;
1058 struct bgp_table
*table
= NULL
;
1060 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1061 table
= bgp_dest_get_bgp_table_info(pdest
);
1063 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1064 bgp
, prd
, table
, p
, new);
1065 bgp_dest_unlock_node(pdest
);
1066 encode_label(label_val
, &bn
->local_label
);
1069 bgp_dest_unlock_node(bn
);
1070 bgp_process(bgp
, bn
, afi
, safi
);
1073 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
1074 __func__
, safi2str(safi
), buf
, bn
, buf2
);
1077 /* Loop back to import tables */
1078 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1079 sub_type
, &label_val
);
1080 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1084 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1089 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1090 struct rfapi_descriptor
*rfd
,
1091 uint32_t *pLifetime
)
1093 struct prefix_rd prd
;
1094 struct prefix pfx_vn
;
1096 uint32_t local_pref
= rfp_cost_to_localpref(0);
1098 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1102 * Construct route distinguisher = 0
1104 memset(&prd
, 0, sizeof(prd
));
1105 prd
.family
= AF_UNSPEC
;
1108 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1109 bgp
, /* which bgp instance */
1110 SAFI_ENCAP
, /* which SAFI */
1111 &pfx_vn
, /* prefix to advertise */
1112 &prd
, /* route distinguisher to use */
1113 &rfd
->un_addr
, /* nexthop */
1115 pLifetime
, /* max lifetime of child VPN routes */
1116 NULL
, /* no rfp options for ENCAP safi */
1117 NULL
, /* rfp un options */
1118 NULL
, /* rfp vn options */
1119 rfd
->rt_export_list
, NULL
, /* med */
1120 NULL
, /* label: default */
1121 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1125 /***********************************************************************
1126 * RFP processing behavior configuration
1127 ***********************************************************************/
1129 /*------------------------------------------
1130 * rfapi_rfp_set_configuration
1132 * This is used to change rfapi's processing behavior based on
1136 * rfp_start_val value returned by rfp_start
1137 * rfapi_rfp_cfg Pointer to configuration structure
1144 * ENXIO Unabled to locate configured BGP/VNC
1145 --------------------------------------------*/
1146 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1148 struct rfapi_rfp_cfg
*rcfg
;
1151 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1153 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1156 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1157 rcfg
->download_type
= new->download_type
;
1158 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1159 rcfg
->holddown_factor
= new->holddown_factor
;
1161 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1162 rcfg
->use_updated_response
= new->use_updated_response
;
1163 if (rcfg
->use_updated_response
)
1164 rfapiMonitorCallbacksOn(bgp
);
1166 rfapiMonitorCallbacksOff(bgp
);
1168 if (rcfg
->use_removes
!= new->use_removes
) {
1169 rcfg
->use_removes
= new->use_removes
;
1170 if (rcfg
->use_removes
)
1171 rfapiMonitorResponseRemovalOn(bgp
);
1173 rfapiMonitorResponseRemovalOff(bgp
);
1178 /*------------------------------------------
1179 * rfapi_rfp_set_cb_methods
1181 * Change registered callback functions for asynchronous notifications
1182 * from RFAPI to the RFP client.
1185 * rfp_start_val value returned by rfp_start
1186 * methods Pointer to struct rfapi_rfp_cb_methods containing
1187 * pointers to callback methods as described above
1191 * ENXIO BGP or VNC not configured
1192 *------------------------------------------*/
1193 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1194 struct rfapi_rfp_cb_methods
*methods
)
1199 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1207 h
->rfp_methods
= *methods
;
1212 /***********************************************************************
1214 ***********************************************************************/
1216 * Caller must supply an already-allocated rfd with the "caller"
1217 * fields already set (vn_addr, un_addr, callback, cookie)
1218 * The advertised_prefixes[] array elements should be NULL to
1219 * have this function set them to newly-allocated radix trees.
1221 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1222 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1226 if (h
->flags
& RFAPI_INCALLBACK
)
1230 * Fill in configured fields
1234 * If group's RD is specified as "auto", then fill in based
1235 * on NVE's VN address
1239 if (rfd
->rd
.family
== AF_UNIX
) {
1240 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1244 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1245 ? ecommunity_dup(rfg
->rt_export_list
)
1247 rfd
->response_lifetime
= rfg
->response_lifetime
;
1251 * Fill in BGP peer structure
1253 rfd
->peer
= peer_new(bgp
);
1254 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1255 bgp_sync_delete(rfd
->peer
); /* don't need these */
1258 * since this peer is not on the I/O thread, this lock is not strictly
1259 * necessary, but serves as a reminder to those who may meddle...
1261 frr_with_mutex(&rfd
->peer
->io_mtx
) {
1262 // we don't need any I/O related facilities
1263 if (rfd
->peer
->ibuf
)
1264 stream_fifo_free(rfd
->peer
->ibuf
);
1265 if (rfd
->peer
->obuf
)
1266 stream_fifo_free(rfd
->peer
->obuf
);
1268 if (rfd
->peer
->ibuf_work
)
1269 ringbuf_del(rfd
->peer
->ibuf_work
);
1270 if (rfd
->peer
->obuf_work
)
1271 stream_free(rfd
->peer
->obuf_work
);
1273 rfd
->peer
->ibuf
= NULL
;
1274 rfd
->peer
->obuf
= NULL
;
1275 rfd
->peer
->obuf_work
= NULL
;
1276 rfd
->peer
->ibuf_work
= NULL
;
1279 { /* base code assumes have valid host pointer */
1283 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1284 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
, BUFSIZ
);
1285 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1286 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
, BUFSIZ
);
1288 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1290 /* Mark peer as belonging to HD */
1291 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1294 * Set min prefix lifetime to max value so it will get set
1295 * upon first rfapi_register()
1297 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1300 * Allocate response tables if needed
1302 #define RFD_RTINIT_AFI(rh, ary, afi) \
1305 ary[afi] = agg_table_init(); \
1306 agg_set_table_info(ary[afi], rh); \
1310 #define RFD_RTINIT(rh, ary) \
1312 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1313 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1314 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1317 RFD_RTINIT(rfd
, rfd
->rib
);
1318 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1319 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1322 * Link to Import Table
1324 rfd
->import_table
= rfg
->rfapi_import_table
;
1325 rfd
->import_table
->refcount
+= 1;
1327 rfapiApInit(&rfd
->advertised
);
1330 * add this NVE descriptor to the list of NVEs in the NVE group
1333 rfg
->nves
= list_new();
1335 listnode_add(rfg
->nves
, rfd
);
1337 vnc_direct_bgp_add_nve(bgp
, rfd
);
1338 vnc_zebra_add_nve(bgp
, rfd
);
1343 /* moved from rfapi_register */
1344 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1345 struct rfapi_nve_group_cfg
*rfg
)
1347 struct rfapi
*h
= bgp
->rfapi
;
1348 char buf_vn
[BUFSIZ
];
1349 char buf_un
[BUFSIZ
];
1350 afi_t afi_vn
, afi_un
;
1351 struct prefix pfx_un
;
1352 struct agg_node
*rn
;
1355 rfapi_time(&rfd
->open_time
);
1357 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1358 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1360 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1361 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1363 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1364 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1366 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1368 listnode_add(&h
->descriptors
, rfd
);
1369 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1370 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1374 * attach to UN radix tree
1376 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1377 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1378 assert(afi_vn
&& afi_un
);
1379 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1381 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1383 rfd
->next
= rn
->info
;
1387 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1390 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1392 struct rfapi_vn_option
*head
= NULL
;
1393 struct rfapi_vn_option
*tail
= NULL
;
1394 struct rfapi_vn_option
*vo
= NULL
;
1396 for (vo
= orig
; vo
; vo
= vo
->next
) {
1397 struct rfapi_vn_option
*new;
1399 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1400 sizeof(struct rfapi_vn_option
));
1401 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1413 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1415 struct rfapi_un_option
*head
= NULL
;
1416 struct rfapi_un_option
*tail
= NULL
;
1417 struct rfapi_un_option
*uo
= NULL
;
1419 for (uo
= orig
; uo
; uo
= uo
->next
) {
1420 struct rfapi_un_option
*new;
1422 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1423 sizeof(struct rfapi_un_option
));
1424 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1436 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1438 struct bgp_tea_options
*head
= NULL
;
1439 struct bgp_tea_options
*tail
= NULL
;
1440 struct bgp_tea_options
*hop
= NULL
;
1442 for (hop
= orig
; hop
; hop
= hop
->next
) {
1443 struct bgp_tea_options
*new;
1445 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1446 sizeof(struct bgp_tea_options
));
1447 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1450 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1452 memcpy(new->value
, hop
->value
, hop
->length
);
1463 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1465 struct bgp_tea_options
*next
;
1470 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1471 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1477 void rfapiAdbFree(struct rfapi_adb
*adb
)
1479 XFREE(MTYPE_RFAPI_ADB
, adb
);
1483 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1484 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1485 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1489 struct prefix p_original
;
1490 struct agg_node
*rn
;
1491 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1492 struct bgp
*bgp
= rfd
->bgp
;
1493 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1494 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1496 int use_eth_resolution
= 0;
1497 struct rfapi_next_hop_entry
*i_nhe
;
1501 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1506 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1510 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1511 vnc_zlog_debug_verbose(
1512 "%s: Called during calback, returning EDEADLK",
1517 if (!is_valid_rfd(rfd
)) {
1518 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1523 rfd
->rsp_counter
++; /* dedup: identify this generation */
1524 rfd
->rsp_time
= rfapi_time(NULL
); /* response content dedup */
1525 rfd
->ftd_last_allowed_time
=
1527 - bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1530 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1534 /* per t/c Paul/Lou 151022 */
1535 if (!eth_is_0
|| l2o
->logical_net_id
) {
1536 use_eth_resolution
= 1;
1541 *ppNextHopEntry
= NULL
;
1544 * Save original target in prefix form. In case of L2-based queries,
1545 * p_original will be modified to reflect the L2 target
1547 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1549 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1550 /* convert query to 0/0 when full-table download is enabled */
1551 memset((char *)&p
, 0, sizeof(p
));
1552 p
.family
= target
->addr_family
;
1560 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1561 __func__
, rfd
, &p
, ppNextHopEntry
);
1563 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1564 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1565 vnc_zlog_debug_verbose(
1566 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1567 __func__
, rfd
->import_table
, s
);
1568 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1571 afi
= family2afi(p
.family
);
1574 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1575 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1576 self_vn_addr
= &rfd
->vn_addr
;
1579 if (use_eth_resolution
) {
1580 uint32_t logical_net_id
= l2o
->logical_net_id
;
1581 struct ecommunity
*l2com
;
1584 * fix up p_original to contain L2 address
1586 rfapiL2o2Qprefix(l2o
, &p_original
);
1588 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1589 bgp
, 1, logical_net_id
, l2o
->label
);
1591 uint8_t *v
= l2com
->val
;
1592 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1595 * Ethernet/L2-based lookup
1597 * Always returns IT node corresponding to route
1600 if (RFAPI_RFP_DOWNLOAD_FULL
1601 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1605 rn
= rfapiMonitorEthAdd(
1606 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1610 struct rfapi_ip_prefix rprefix
;
1612 memset(&rprefix
, 0, sizeof(rprefix
));
1613 rprefix
.prefix
.addr_family
= target
->addr_family
;
1614 if (target
->addr_family
== AF_INET
) {
1615 rprefix
.length
= IPV4_MAX_BITLEN
;
1617 rprefix
.length
= IPV6_MAX_BITLEN
;
1620 pNHE
= rfapiEthRouteTable2NextHopList(
1621 logical_net_id
, &rprefix
,
1622 rfd
->response_lifetime
, self_vn_addr
,
1623 rfd
->rib
[afi
], &p_original
);
1633 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1636 * If target address is 0, this request is special: means to
1637 * return ALL routes in the table
1639 * Monitors for All-Routes queries get put on a special list,
1640 * not in the VPN tree
1642 if (RFAPI_0_PREFIX(&p
)) {
1644 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1647 * Generate nexthop list for caller
1649 pNHE
= rfapiRouteTable2NextHopList(
1650 rfd
->import_table
->imported_vpn
[afi
],
1651 rfd
->response_lifetime
, self_vn_addr
,
1652 rfd
->rib
[afi
], &p_original
);
1657 agg_lock_node(rn
); /* so we can unlock below */
1660 * returns locked node. Don't unlock yet because the
1662 * might free it before we're done with it. This
1664 * could occur when rfapiMonitorGetAttachNode() returns
1666 * newly-created default node.
1668 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1674 agg_unlock_node(rn
);
1675 vnc_zlog_debug_verbose(
1676 "%s: VPN route not found, returning ENOENT", __func__
);
1680 if (VNC_DEBUG(RFAPI_QUERY
)) {
1681 rfapiShowImportTable(NULL
, "query",
1682 rfd
->import_table
->imported_vpn
[afi
], 1);
1685 if (use_eth_resolution
) {
1687 struct rfapi_ip_prefix rprefix
;
1689 memset(&rprefix
, 0, sizeof(rprefix
));
1690 rprefix
.prefix
.addr_family
= target
->addr_family
;
1691 if (target
->addr_family
== AF_INET
) {
1692 rprefix
.length
= IPV4_MAX_BITLEN
;
1694 rprefix
.length
= IPV6_MAX_BITLEN
;
1697 pNHE
= rfapiEthRouteNode2NextHopList(
1698 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1699 rfd
->rib
[afi
], &p_original
);
1704 * Generate answer to query
1706 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1707 self_vn_addr
, rfd
->rib
[afi
],
1711 agg_unlock_node(rn
);
1714 if (ppNextHopEntry
) {
1715 /* only count if caller gets it */
1716 ++bgp
->rfapi
->response_immediate_count
;
1720 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1726 * count nexthops for statistics
1728 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1729 ++rfd
->stat_count_nh_reachable
;
1732 if (ppNextHopEntry
) {
1733 *ppNextHopEntry
= pNHE
;
1735 rfapi_free_next_hop_list(pNHE
);
1738 vnc_zlog_debug_verbose("%s: success", __func__
);
1743 * support on-the-fly reassignment of an already-open nve to a new
1744 * nve-group in the event that its original nve-group is
1745 * administratively deleted.
1747 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1749 struct prefix pfx_vn
;
1750 struct prefix pfx_un
;
1751 struct rfapi_nve_group_cfg
*rfg
;
1753 struct rfapi_cfg
*hc
;
1760 hc
= bgp
->rfapi_cfg
;
1764 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1767 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1771 * Find the matching nve group config block
1773 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1779 * check nve group config block for required values
1781 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1786 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1792 * re-advertise registered routes, this time as part of new NVE-group
1794 rfapiApReadvertiseAll(bgp
, rfd
);
1797 * re-attach callbacks to import table
1799 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1800 rfapiMonitorAttachImportHd(rfd
);
1806 /*------------------------------------------
1809 * This function initializes a NVE record and associates it with
1810 * the specified VN and underlay network addresses
1813 * rfp_start_val value returned by rfp_start
1814 * vn NVE virtual network address
1816 * un NVE underlay network address
1818 * default_options Default options to use on registrations.
1819 * For now only tunnel type is supported.
1820 * May be overridden per-prefix in rfapi_register().
1821 * Caller owns (rfapi_open() does not free)
1823 * response_cb Pointer to next hop list update callback function or
1824 * NULL when no callbacks are desired.
1826 * userdata Passed to subsequent response_cb invocations.
1829 * response_lifetime The length of time that responses sent to this
1832 * pHandle pointer to location to store rfapi handle. The
1833 * handle must be passed on subsequent rfapi_ calls.
1838 * EEXIST NVE with this {vn,un} already open
1839 * ENOENT No matching nve group config
1840 * ENOMSG Matched nve group config was incomplete
1841 * ENXIO BGP or VNC not configured
1842 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1843 * but underlay network address is not IPv4
1844 * EDEADLK Called from within a callback procedure
1845 *------------------------------------------*/
1846 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1847 struct rfapi_ip_addr
*un
,
1848 struct rfapi_un_option
*default_options
,
1849 uint32_t *response_lifetime
,
1850 void *userdata
, /* callback cookie */
1851 rfapi_handle
*pHandle
)
1855 struct rfapi_descriptor
*rfd
;
1856 struct rfapi_cfg
*hc
;
1857 struct rfapi_nve_group_cfg
*rfg
;
1859 struct prefix pfx_vn
;
1860 struct prefix pfx_un
;
1863 rfapi_handle hh
= NULL
;
1864 int reusing_provisional
= 0;
1867 char buf
[2][INET_ADDRSTRLEN
];
1868 vnc_zlog_debug_verbose(
1869 "%s: VN=%s UN=%s", __func__
,
1870 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1871 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1877 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1885 hc
= bgp
->rfapi_cfg
;
1889 if (h
->flags
& RFAPI_INCALLBACK
)
1892 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1895 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1899 * already have a descriptor with VN and UN?
1901 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1903 * we might have set up a handle for static routes before
1904 * this NVE was opened. In that case, reuse the handle
1907 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1912 * reuse provisional descriptor
1915 reusing_provisional
= 1;
1919 * Find the matching nve group config block
1921 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1923 ++h
->stat
.count_unknown_nves
;
1925 char buf
[2][INET_ADDRSTRLEN
];
1926 zlog_notice("%s: no matching group VN=%s UN=%s",
1928 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1930 rfapiRfapiIpAddr2Str(un
, buf
[1],
1937 * check nve group config block for required values
1939 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1941 ++h
->stat
.count_unknown_nves
;
1946 * If group config specifies auto-rd assignment, check that
1947 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1948 * Check here so we don't need to unwind memory allocations, &c.
1950 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1951 && (vn
->addr_family
!= AF_INET6
)) {
1952 return EAFNOSUPPORT
;
1957 * reusing provisional rfd
1961 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1962 sizeof(struct rfapi_descriptor
));
1966 if (default_options
) {
1967 struct rfapi_un_option
*p
;
1969 for (p
= default_options
; p
; p
= p
->next
) {
1970 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1971 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1973 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1974 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1980 * Fill in caller fields
1984 rfd
->cookie
= userdata
;
1986 if (!reusing_provisional
) {
1987 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1989 * This can fail only if the VN address is IPv6 and the group
1990 * specified auto-assignment of RDs, which only works for v4,
1991 * and the check above should catch it.
1993 * Another failure possibility is that we were called
1994 * during an rfapi callback. Also checked above.
1999 if (response_lifetime
)
2000 *response_lifetime
= rfd
->response_lifetime
;
2006 * For use with debug functions
2008 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2009 rfapi_response_cb_t
*response_cb
)
2011 if (!is_valid_rfd(rfd
))
2013 rfd
->response_cb
= response_cb
;
2020 * Does almost all the work of rfapi_close, except:
2021 * 1. preserves the descriptor (doesn't free it)
2022 * 2. preserves the prefix query list (i.e., rfd->mon list)
2023 * 3. preserves the advertised prefix list (rfd->advertised)
2024 * 4. preserves the rib and rib_pending tables
2026 * The purpose of organizing it this way is to support on-the-fly
2027 * reassignment of an already-open nve to a new nve-group in the
2028 * event that its original nve-group is administratively deleted.
2030 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2033 struct prefix pfx_vn
;
2034 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2036 if (!is_valid_rfd(rfd
))
2039 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2040 assert(!rc
); /* should never have bad AF in stored vn address */
2043 * update exported routes to reflect disappearance of this NVE as
2046 vnc_direct_bgp_del_nve(bgp
, rfd
);
2047 vnc_zebra_del_nve(bgp
, rfd
);
2050 * unlink this HD's monitors from import table
2052 rfapiMonitorDetachImportHd(rfd
);
2055 * Unlink from Import Table
2056 * NB rfd->import_table will be NULL if we are closing a stale
2059 if (rfd
->import_table
)
2060 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2061 rfd
->import_table
= NULL
;
2064 * Construct route distinguisher
2066 memset(&prd
, 0, sizeof(prd
));
2068 prd
.family
= AF_UNSPEC
;
2074 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2075 &pfx_vn
, /* prefix being advertised */
2076 &prd
, /* route distinguisher to use (0 for ENCAP) */
2077 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2080 * Construct route distinguisher for VPN routes
2083 prd
.family
= AF_UNSPEC
;
2087 * find all VPN routes associated with this rfd and delete them, too
2089 rfapiApWithdrawAll(bgp
, rfd
);
2092 * remove this nve descriptor from the list of nves
2093 * associated with the nve group
2096 listnode_delete(rfd
->rfg
->nves
, rfd
);
2097 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2100 if (rfd
->rt_export_list
)
2101 ecommunity_free(&rfd
->rt_export_list
);
2102 rfd
->rt_export_list
= NULL
;
2105 * free peer structure (possibly delayed until its
2106 * refcount reaches zero)
2109 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2110 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2111 peer_delete(rfd
->peer
);
2118 int rfapi_close(void *handle
)
2120 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2122 struct agg_node
*node
;
2126 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2128 #ifdef RFAPI_WHO_IS_CALLING_ME
2129 #ifdef HAVE_GLIBC_BACKTRACE
2130 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2132 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2137 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2138 syms
= backtrace_symbols(buf
, size
);
2139 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2141 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2157 if (!is_valid_rfd(rfd
))
2160 if (h
->flags
& RFAPI_INCALLBACK
) {
2162 * Queue these close requests for processing after callback
2165 if (!CHECK_FLAG(rfd
->flags
,
2166 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2167 work_queue_add(h
->deferred_close_q
, handle
);
2168 vnc_zlog_debug_verbose(
2169 "%s: added handle %p to deferred close queue",
2175 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2177 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2180 if (h
->rfp_methods
.close_cb
) {
2181 vnc_zlog_debug_verbose(
2182 "%s calling close callback rfd=%p", __func__
,
2186 * call the callback fairly early so that it can still
2190 * NB RFAPI_INCALLBACK is tested above, so if we reach
2192 * we are not already in the context of a callback.
2194 h
->flags
|= RFAPI_INCALLBACK
;
2195 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2196 h
->flags
&= ~RFAPI_INCALLBACK
;
2202 * Orphaned descriptors have already done this part, so do
2203 * only for non-orphaned descriptors.
2205 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2210 * Remove descriptor from UN index
2211 * (remove from chain at node)
2213 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2215 struct rfapi_descriptor
*hh
;
2217 if (node
->info
== rfd
) {
2218 node
->info
= rfd
->next
;
2221 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2222 if (hh
->next
== rfd
) {
2223 hh
->next
= rfd
->next
;
2228 agg_unlock_node(node
);
2232 * remove from descriptor list
2234 listnode_delete(&h
->descriptors
, rfd
);
2237 * Delete monitor list items and free monitor structures
2239 (void)rfapiMonitorDelHd(rfd
);
2242 * release advertised prefix data
2244 rfapiApRelease(&rfd
->advertised
);
2247 * Release RFP callback RIB
2254 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2255 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2261 * Reopen a nve descriptor. If the descriptor's NVE-group
2262 * does not exist (e.g., if it has been administratively removed),
2263 * reassignment to a new NVE-group is attempted.
2265 * If NVE-group reassignment fails, the descriptor becomes "stale"
2266 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2267 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2268 * on the descriptor will return ESTALE.
2270 * Reopening a descriptor is a potentially expensive operation, because
2271 * it involves withdrawing any routes advertised by the NVE, withdrawing
2272 * the NVE's route queries, and then re-adding them all after a new
2273 * NVE-group is assigned. There are also possible route-export affects
2274 * caused by deleting and then adding the NVE: advertised prefixes
2275 * and nexthop lists for exported routes can turn over.
2277 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2282 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2285 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2289 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2291 if (CHECK_FLAG(rfd
->flags
,
2292 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2293 && h
&& h
->rfp_methods
.close_cb
) {
2296 * NB RFAPI_INCALLBACK is tested above, so if we reach
2298 * we are not already in the context of a callback.
2300 h
->flags
|= RFAPI_INCALLBACK
;
2301 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2302 h
->flags
&= ~RFAPI_INCALLBACK
;
2309 /***********************************************************************
2311 ***********************************************************************/
2313 * Announce reachability to this prefix via the NVE
2315 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2316 uint32_t lifetime
, /* host byte order */
2317 struct rfapi_un_option
*options_un
,
2318 struct rfapi_vn_option
*options_vn
,
2319 rfapi_register_action action
)
2321 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2324 struct prefix
*pfx_ip
= NULL
;
2325 struct prefix_rd prd
;
2327 struct prefix pfx_mac_buf
;
2328 struct prefix
*pfx_mac
= NULL
;
2329 struct prefix pfx_vn_buf
;
2330 const char *action_str
= NULL
;
2331 uint32_t *label
= NULL
;
2332 struct rfapi_vn_option
*vo
;
2333 struct rfapi_l2address_option
*l2o
= NULL
;
2334 struct prefix_rd
*prd_override
= NULL
;
2337 case RFAPI_REGISTER_ADD
:
2340 case RFAPI_REGISTER_WITHDRAW
:
2341 action_str
= "withdraw";
2343 case RFAPI_REGISTER_KILL
:
2344 action_str
= "kill";
2352 * Inspect VN options
2354 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2355 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2356 l2o
= &vo
->v
.l2addr
;
2358 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2359 prd_override
= &vo
->v
.internal_rd
;
2363 /*********************************************************************
2365 *********************************************************************/
2368 * set <p> based on <prefix>
2370 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2372 afi
= family2afi(prefix
->prefix
.addr_family
);
2375 vnc_zlog_debug_verbose(
2376 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2377 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2381 * These tests come after the prefix conversion so that we can
2382 * print the prefix in a debug message before failing
2387 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2392 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2397 if (RFAPI_REGISTER_ADD
== action
) {
2398 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2400 vnc_zlog_debug_verbose(
2401 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2406 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2407 if (RFAPI_REGISTER_ADD
== action
) {
2408 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2410 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2415 if (!is_valid_rfd(rfd
)) {
2416 if (RFAPI_REGISTER_ADD
== action
) {
2417 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2419 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2425 * Is there a MAC address in this registration?
2427 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2428 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2429 pfx_mac
= &pfx_mac_buf
;
2433 * Is there an IP prefix in this registration?
2435 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2439 vnc_zlog_debug_verbose(
2440 "%s: missing mac addr that is required for host 0 pfx",
2442 if (RFAPI_REGISTER_ADD
== action
) {
2443 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2447 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2448 vnc_zlog_debug_verbose(
2449 "%s: handle has bad vn_addr: returning EBADF",
2451 if (RFAPI_REGISTER_ADD
== action
) {
2452 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2458 if (RFAPI_REGISTER_ADD
== action
) {
2459 ++bgp
->rfapi
->stat
.count_registrations
;
2463 * Figure out if this registration is missing an IP address
2467 * In RFAPI, we use prefixes in family AF_LINK to store
2468 * the MAC addresses. These prefixes are used for the
2469 * list of advertised prefixes and in the RFAPI import
2472 * In BGP proper, we use the prefix matching the NVE's
2473 * VN address with a host prefix-length (i.e., 32 or 128).
2476 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2477 && RFAPI_HOST_PREFIX(&p
)) {
2479 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2480 pfx_mac
= &pfx_mac_buf
;
2484 * Construct route distinguisher
2487 prd
= *prd_override
;
2489 memset(&prd
, 0, sizeof(prd
));
2491 prd
.family
= AF_UNSPEC
;
2493 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2494 if (l2o
->local_nve_id
2495 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2497 * If Local NVE ID is specified in message, use
2499 * (if no local default configured, also use it
2502 prd
.val
[1] = l2o
->local_nve_id
;
2504 if (rfd
->rfg
->l2rd
) {
2506 * locally-configured literal value
2508 prd
.val
[1] = rfd
->rfg
->l2rd
;
2511 * 0 means auto:vn, which means use LSB
2514 if (rfd
->vn_addr
.addr_family
2517 *(((char *)&rfd
->vn_addr
2523 *(((char *)&rfd
->vn_addr
2530 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2533 prd
.family
= AF_UNSPEC
;
2539 if (action
== RFAPI_REGISTER_WITHDRAW
2540 || action
== RFAPI_REGISTER_KILL
) {
2545 * withdraw previous advertisement
2548 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2550 : &pfx_vn_buf
, /* prefix being advertised */
2551 &prd
, /* route distinguisher (0 for ENCAP) */
2552 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2553 action
== RFAPI_REGISTER_KILL
);
2555 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2558 rfapiTunnelRouteAnnounce(
2559 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2565 uint32_t local_pref
;
2566 struct ecommunity
*rtlist
= NULL
;
2567 struct ecommunity_val ecom_value
;
2569 if (!rfapiApCount(rfd
)) {
2571 * make sure we advertise tunnel route upon adding the
2577 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2578 prefix
->cost
, l2o
)) {
2582 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2585 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2587 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2588 &rfd
->max_prefix_lifetime
);
2591 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2593 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2595 if (l2o
&& l2o
->label
)
2596 label
= &l2o
->label
;
2599 struct ecommunity
*l2com
= NULL
;
2602 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2603 bgp
, 1, l2o
->logical_net_id
, *label
);
2606 rtlist
= ecommunity_dup(l2com
);
2609 * If mac address is set, add an RT based on the
2612 memset((char *)&ecom_value
, 0,
2613 sizeof(ecom_value
));
2614 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2616 (l2o
->logical_net_id
>> 16) & 0xff;
2618 (l2o
->logical_net_id
>> 8) & 0xff;
2620 (l2o
->logical_net_id
>> 0) & 0xff;
2621 rtlist
= ecommunity_new();
2622 ecommunity_add_val(rtlist
, &ecom_value
,
2627 uint16_t val
= l2o
->tag_id
;
2628 memset((char *)&ecom_value
, 0,
2629 sizeof(ecom_value
));
2630 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2631 if (as
> BGP_AS_MAX
) {
2633 ECOMMUNITY_ENCODE_AS4
;
2634 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2635 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2636 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2637 ecom_value
.val
[5] = as
& 0xff;
2640 ECOMMUNITY_ENCODE_AS
;
2641 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2642 ecom_value
.val
[3] = as
& 0xff;
2644 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2645 ecom_value
.val
[7] = val
& 0xff;
2647 rtlist
= ecommunity_new();
2648 ecommunity_add_val(rtlist
, &ecom_value
,
2654 * advertise prefix via tunnel endpoint
2657 rfd
, /* rfapi descr, for export list & backref */
2658 bgp
, /* which bgp instance */
2659 SAFI_MPLS_VPN
, /* which SAFI */
2661 : &pfx_vn_buf
), /* prefix being advertised */
2662 &prd
, /* route distinguisher to use (0 for ENCAP) */
2663 &rfd
->vn_addr
, /* nexthop */
2665 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2666 NULL
, options_un
, /* rfapi un options */
2667 options_vn
, /* rfapi vn options */
2668 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2669 label
, /* label: default */
2670 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2673 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2676 vnc_zlog_debug_verbose("%s: success", __func__
);
2680 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2681 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2682 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2684 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2685 struct bgp
*bgp
= rfd
->bgp
;
2688 assert(ppNextHopEntry
);
2689 *ppNextHopEntry
= NULL
;
2691 if (bgp
&& bgp
->rfapi
) {
2692 bgp
->rfapi
->stat
.count_queries
++;
2696 if (bgp
&& bgp
->rfapi
)
2697 ++bgp
->rfapi
->stat
.count_queries_failed
;
2701 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2702 if (bgp
&& bgp
->rfapi
)
2703 ++bgp
->rfapi
->stat
.count_queries_failed
;
2708 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2712 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2713 struct bgp
*bgp
= rfd
->bgp
;
2719 rc
= rfapiRaddr2Qprefix(target
, &p
);
2722 if (!is_valid_rfd(rfd
))
2726 if (!bgp
|| !bgp
->rfapi
)
2729 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2732 rfapiMonitorDel(bgp
, rfd
, &p
);
2737 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2739 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2740 struct bgp
*bgp
= rfd
->bgp
;
2747 if (!is_valid_rfd(rfd
))
2751 if (!bgp
|| !bgp
->rfapi
)
2754 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2757 num
= rfapiMonitorDelHd(rfd
);
2765 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2767 struct rfapi_next_hop_entry
*nh
;
2768 struct rfapi_next_hop_entry
*next
;
2770 for (nh
= list
; nh
; nh
= next
) {
2772 rfapi_un_options_free(nh
->un_options
);
2773 nh
->un_options
= NULL
;
2774 rfapi_vn_options_free(nh
->vn_options
);
2775 nh
->vn_options
= NULL
;
2776 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2781 * NULL handle => return total count across all nves
2783 uint32_t rfapi_monitor_count(void *handle
)
2785 struct bgp
*bgp
= bgp_get_default();
2789 struct rfapi_descriptor
*rfd
=
2790 (struct rfapi_descriptor
*)handle
;
2791 count
= rfd
->monitor_count
;
2794 if (!bgp
|| !bgp
->rfapi
)
2797 count
= bgp
->rfapi
->monitor_count
;
2803 /***********************************************************************
2805 ***********************************************************************/
2807 DEFUN (debug_rfapi_show_nves
,
2808 debug_rfapi_show_nves_cmd
,
2809 "debug rfapi-dev show nves",
2813 "NVE Information\n")
2815 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2820 debug_rfapi_show_nves_vn_un
,
2821 debug_rfapi_show_nves_vn_un_cmd
,
2822 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2827 "Specify virtual network\n"
2828 "Specify underlay network interface\n"
2834 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2835 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2836 return CMD_WARNING_CONFIG_FAILED
;
2838 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2839 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2840 return CMD_WARNING_CONFIG_FAILED
;
2843 if (argv
[4]->arg
[0] == 'u') {
2844 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2846 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2852 * Note: this function does not flush vty output, so if it is called
2853 * with a stream pointing to a vty, the user will have to type something
2854 * before the callback output shows up
2856 static void test_nexthops_callback(
2857 // struct rfapi_ip_addr *target,
2858 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2860 void *stream
= userdata
;
2862 int (*fp
)(void *, const char *, ...);
2865 const char *vty_newline
;
2867 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2870 fp(out
, "Nexthops Callback, Target=(");
2871 // rfapiPrintRfapiIpAddr(stream, target);
2874 rfapiPrintNhl(stream
, next_hops
);
2878 rfapi_free_next_hop_list(next_hops
);
2881 DEFUN (debug_rfapi_open
,
2882 debug_rfapi_open_cmd
,
2883 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2887 "indicate vn addr follows\n"
2888 "virtual network interface IPv4 address\n"
2889 "virtual network interface IPv6 address\n"
2890 "indicate xt addr follows\n"
2891 "underlay network interface IPv4 address\n"
2892 "underlay network interface IPv6 address\n")
2894 struct rfapi_ip_addr vn
;
2895 struct rfapi_ip_addr un
;
2896 uint32_t lifetime
= 0;
2898 rfapi_handle handle
;
2903 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2909 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2912 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2913 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2915 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2918 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2920 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2926 DEFUN (debug_rfapi_close_vn_un
,
2927 debug_rfapi_close_vn_un_cmd
,
2928 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2932 "indicate vn addr follows\n"
2933 "virtual network interface IPv4 address\n"
2934 "virtual network interface IPv6 address\n"
2935 "indicate xt addr follows\n"
2936 "underlay network interface IPv4 address\n"
2937 "underlay network interface IPv6 address\n")
2939 struct rfapi_ip_addr vn
;
2940 struct rfapi_ip_addr un
;
2941 rfapi_handle handle
;
2947 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2954 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2958 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2959 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2960 argv
[4]->arg
, argv
[6]->arg
);
2961 return CMD_WARNING_CONFIG_FAILED
;
2964 rc
= rfapi_close(handle
);
2966 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2971 DEFUN (debug_rfapi_close_rfd
,
2972 debug_rfapi_close_rfd_cmd
,
2973 "debug rfapi-dev close rfd HANDLE",
2977 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2979 rfapi_handle handle
;
2981 char *endptr
= NULL
;
2983 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2985 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2986 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2987 return CMD_WARNING_CONFIG_FAILED
;
2990 rc
= rfapi_close(handle
);
2992 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2997 DEFUN (debug_rfapi_register_vn_un
,
2998 debug_rfapi_register_vn_un_cmd
,
2999 "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)]",
3003 "indicate vn addr follows\n"
3004 "virtual network IPv4 interface address\n"
3005 "virtual network IPv6 interface address\n"
3006 "indicate un addr follows\n"
3007 "underlay network IPv4 interface address\n"
3008 "underlay network IPv6 interface address\n"
3009 "indicate prefix follows\n"
3012 "indicate lifetime follows\n"
3014 "Cost (localpref = 255-cost)\n"
3017 struct rfapi_ip_addr vn
;
3018 struct rfapi_ip_addr un
;
3019 rfapi_handle handle
;
3022 struct rfapi_ip_prefix hpfx
;
3029 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3036 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3040 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3041 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3042 argv
[4]->arg
, argv
[6]->arg
);
3043 return CMD_WARNING_CONFIG_FAILED
;
3047 * Get prefix to advertise
3049 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3050 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3051 return CMD_WARNING_CONFIG_FAILED
;
3053 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3054 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3055 return CMD_WARNING_CONFIG_FAILED
;
3057 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3059 if (strmatch(argv
[10]->text
, "infinite")) {
3060 lifetime
= RFAPI_INFINITE_LIFETIME
;
3062 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3066 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3069 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3070 RFAPI_REGISTER_ADD
);
3072 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3079 DEFUN (debug_rfapi_register_vn_un_l2o
,
3080 debug_rfapi_register_vn_un_l2o_cmd
,
3081 "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)",
3085 "indicate vn addr follows\n"
3086 "virtual network IPv4 interface address\n"
3087 "virtual network IPv6 interface address\n"
3088 "indicate un addr follows\n"
3089 "underlay network IPv4 interface address\n"
3090 "underlay network IPv6 interface address\n"
3091 "indicate prefix follows\n"
3094 "indicate lifetime follows\n"
3095 "Seconds of lifetime\n"
3096 "indicate MAC address follows\n"
3098 "indicate lni follows\n"
3099 "lni value range\n")
3101 struct rfapi_ip_addr vn
;
3102 struct rfapi_ip_addr un
;
3103 rfapi_handle handle
;
3106 struct rfapi_ip_prefix hpfx
;
3108 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3109 struct rfapi_vn_option
*opt
= NULL
;
3115 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3122 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3126 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3127 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3128 argv
[4]->arg
, argv
[6]->arg
);
3129 return CMD_WARNING_CONFIG_FAILED
;
3133 * Get prefix to advertise
3135 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3136 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3137 return CMD_WARNING_CONFIG_FAILED
;
3139 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3140 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3141 return CMD_WARNING_CONFIG_FAILED
;
3143 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3145 if (strmatch(argv
[10]->text
, "infinite")) {
3146 lifetime
= RFAPI_INFINITE_LIFETIME
;
3148 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3151 /* L2 option parsing START */
3152 memset(optary
, 0, sizeof(optary
));
3153 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3154 strtoul(argv
[14]->arg
, NULL
, 10);
3155 if (rfapiStr2EthAddr(argv
[12]->arg
,
3156 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3157 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3158 return CMD_WARNING_CONFIG_FAILED
;
3160 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3163 /* L2 option parsing END */
3166 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3167 RFAPI_REGISTER_ADD
);
3169 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3177 DEFUN (debug_rfapi_unregister_vn_un
,
3178 debug_rfapi_unregister_vn_un_cmd
,
3179 "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]",
3183 "indicate vn addr follows\n"
3184 "virtual network interface address\n"
3185 "indicate xt addr follows\n"
3186 "underlay network interface address\n"
3187 "prefix to remove\n"
3188 "Remove without holddown")
3190 struct rfapi_ip_addr vn
;
3191 struct rfapi_ip_addr un
;
3192 rfapi_handle handle
;
3194 struct rfapi_ip_prefix hpfx
;
3200 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3207 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3211 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3212 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3213 argv
[4]->arg
, argv
[6]->arg
);
3214 return CMD_WARNING_CONFIG_FAILED
;
3218 * Get prefix to advertise
3220 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3221 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3222 return CMD_WARNING_CONFIG_FAILED
;
3224 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3225 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3226 return CMD_WARNING_CONFIG_FAILED
;
3228 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3230 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3232 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3237 DEFUN (debug_rfapi_query_vn_un
,
3238 debug_rfapi_query_vn_un_cmd
,
3239 "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>",
3243 "indicate vn addr follows\n"
3244 "virtual network interface IPv4 address\n"
3245 "virtual network interface IPv6 address\n"
3246 "indicate un addr follows\n"
3249 "indicate target follows\n"
3250 "target IPv4 address\n"
3251 "target IPv6 address\n")
3253 struct rfapi_ip_addr vn
;
3254 struct rfapi_ip_addr un
;
3255 struct rfapi_ip_addr target
;
3256 rfapi_handle handle
;
3258 struct rfapi_next_hop_entry
*pNextHopEntry
;
3263 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3270 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3277 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3281 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3282 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3283 argv
[4]->arg
, argv
[6]->arg
);
3284 return CMD_WARNING_CONFIG_FAILED
;
3288 * options parameter not used? Set to NULL for now
3290 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3293 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3297 * print nexthop list
3299 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3300 vty
); /* frees nh list! */
3307 DEFUN (debug_rfapi_query_vn_un_l2o
,
3308 debug_rfapi_query_vn_un_l2o_cmd
,
3309 "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",
3313 "indicate vn addr follows\n"
3314 "virtual network interface IPv4 address\n"
3315 "virtual network interface IPv6 address\n"
3316 "indicate xt addr follows\n"
3317 "underlay network interface IPv4 address\n"
3318 "underlay network interface IPv6 address\n"
3319 "logical network ID follows\n"
3320 "logical network ID\n"
3321 "indicate target MAC addr follows\n"
3322 "target MAC addr\n")
3324 struct rfapi_ip_addr vn
;
3325 struct rfapi_ip_addr un
;
3331 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3338 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3341 vty_out(vty
, "%% This command is broken.\n");
3342 return CMD_WARNING_CONFIG_FAILED
;
3346 DEFUN (debug_rfapi_query_done_vn_un
,
3347 debug_rfapi_query_vn_un_done_cmd
,
3348 "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>",
3351 "rfapi_query_done\n"
3352 "rfapi_query_done\n"
3353 "indicate vn addr follows\n"
3354 "virtual network interface IPv4 address\n"
3355 "virtual network interface IPv6 address\n"
3356 "indicate xt addr follows\n"
3357 "underlay network interface IPv4 address\n"
3358 "underlay network interface IPv6 address\n"
3359 "indicate target follows\n"
3360 "Target IPv4 address\n"
3361 "Target IPv6 address\n")
3363 struct rfapi_ip_addr vn
;
3364 struct rfapi_ip_addr un
;
3365 struct rfapi_ip_addr target
;
3366 rfapi_handle handle
;
3372 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3379 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3386 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3390 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3391 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3392 argv
[5]->arg
, argv
[7]->arg
);
3393 return CMD_WARNING_CONFIG_FAILED
;
3397 * options parameter not used? Set to NULL for now
3399 rc
= rfapi_query_done(handle
, &target
);
3401 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3406 DEFUN (debug_rfapi_show_import
,
3407 debug_rfapi_show_import_cmd
,
3408 "debug rfapi-dev show import",
3416 struct rfapi_import_table
*it
;
3421 * Show all import tables
3424 bgp
= bgp_get_default(); /* assume 1 instance for now */
3426 vty_out(vty
, "No BGP instance\n");
3427 return CMD_WARNING_CONFIG_FAILED
;
3432 vty_out(vty
, "No RFAPI instance\n");
3433 return CMD_WARNING_CONFIG_FAILED
;
3437 * Iterate over all import tables; do a filtered import
3438 * for the afi/safi combination
3442 for (it
= h
->imports
; it
; it
= it
->next
) {
3443 s
= ecommunity_ecom2str(it
->rt_import_list
,
3444 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3445 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3446 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3448 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3450 rfapiShowImportTable(vty
, "IP ENCAP",
3451 it
->imported_encap
[AFI_IP
], 0);
3452 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3454 rfapiShowImportTable(vty
, "IP6 ENCAP",
3455 it
->imported_encap
[AFI_IP6
], 0);
3458 if (h
->import_mac
) {
3459 void *cursor
= NULL
;
3461 uintptr_t lni_as_ptr
;
3465 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3466 (void **)&it
, &cursor
);
3468 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3469 (void **)&it
, &cursor
)) {
3471 if (it
->imported_vpn
[AFI_L2VPN
]) {
3475 "\nLNI-based Ethernet Tables:\n");
3478 snprintf(buf
, sizeof(buf
), "L2VPN LNI=%u", lni
);
3479 rfapiShowImportTable(
3480 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3486 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3487 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3492 DEFUN (debug_rfapi_show_import_vn_un
,
3493 debug_rfapi_show_import_vn_un_cmd
,
3494 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3499 "indicate vn addr follows\n"
3500 "virtual network interface IPv4 address\n"
3501 "virtual network interface IPv6 address\n"
3502 "indicate xt addr follows\n"
3503 "underlay network interface IPv4 address\n"
3504 "underlay network interface IPv6 address\n")
3506 struct rfapi_ip_addr vn
;
3507 struct rfapi_ip_addr un
;
3508 rfapi_handle handle
;
3510 struct rfapi_descriptor
*rfd
;
3515 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3522 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3526 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3527 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3528 argv
[5]->arg
, argv
[7]->arg
);
3529 return CMD_WARNING_CONFIG_FAILED
;
3532 rfd
= (struct rfapi_descriptor
*)handle
;
3534 rfapiShowImportTable(vty
, "IP VPN",
3535 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3536 rfapiShowImportTable(vty
, "IP ENCAP",
3537 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3538 rfapiShowImportTable(vty
, "IP6 VPN",
3539 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3540 rfapiShowImportTable(vty
, "IP6 ENCAP",
3541 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3546 DEFUN (debug_rfapi_response_omit_self
,
3547 debug_rfapi_response_omit_self_cmd
,
3548 "debug rfapi-dev response-omit-self <on|off>",
3551 "Omit self in RFP responses\n"
3552 "filter out self from responses\n" "leave self in responses\n")
3554 struct bgp
*bgp
= bgp_get_default();
3557 vty_out(vty
, "No BGP process is configured\n");
3558 return CMD_WARNING_CONFIG_FAILED
;
3560 if (!bgp
->rfapi_cfg
) {
3561 vty_out(vty
, "VNC not configured\n");
3562 return CMD_WARNING_CONFIG_FAILED
;
3565 if (strmatch(argv
[3]->text
, "on"))
3566 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3567 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3569 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3570 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3576 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3578 #include "lib/skiplist.h"
3579 DEFUN (skiplist_test_cli
,
3580 skiplist_test_cli_cmd
,
3582 "skiplist command\n"
3590 DEFUN (skiplist_debug_cli
,
3591 skiplist_debug_cli_cmd
,
3593 "skiplist command\n"
3596 skiplist_debug(vty
, NULL
);
3600 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3602 void rfapi_init(void)
3604 bgp_rfapi_cfg_init();
3607 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3608 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3610 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3611 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3612 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3613 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3614 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3615 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3616 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3617 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3619 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3621 /* Need the following show commands for gpz test scripts */
3622 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3623 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3624 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3626 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3627 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3628 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3635 static void rfapi_print_exported(struct bgp
*bgp
)
3637 struct bgp_dest
*destn
;
3638 struct bgp_dest
*dest
;
3639 struct bgp_path_info
*bpi
;
3644 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); destn
;
3645 destn
= bgp_route_next(destn
)) {
3646 struct bgp_table
*table
;
3648 table
= bgp_dest_get_bgp_table_info(destn
);
3651 fprintf(stderr
, "%s: vpn destn=%p\n", __func__
, destn
);
3652 for (dest
= bgp_table_top(table
); dest
;
3653 dest
= bgp_route_next(dest
)) {
3654 bpi
= bgp_dest_get_bgp_path_info(dest
);
3658 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3659 for (; bpi
; bpi
= bpi
->next
) {
3660 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3664 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); destn
;
3665 destn
= bgp_route_next(destn
)) {
3666 struct bgp_table
*table
;
3668 table
= bgp_dest_get_bgp_table_info(destn
);
3671 fprintf(stderr
, "%s: encap destn=%p\n", __func__
, destn
);
3672 for (dest
= bgp_table_top(table
); dest
;
3673 dest
= bgp_route_next(dest
)) {
3674 bpi
= bgp_dest_get_bgp_path_info(dest
);
3677 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3678 for (; bpi
; bpi
= bpi
->next
) {
3679 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3684 #endif /* defined(DEBUG_RFAPI) */
3687 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3689 void rfapi_delete(struct bgp
*bgp
)
3691 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3694 * This clears queries and registered routes, and closes nves
3697 rfp_clear_vnc_nve_all();
3698 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3699 bgp
->rfapi_cfg
= NULL
;
3700 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3704 * show what's left in the BGP MPLSVPN RIB
3706 rfapi_print_exported(bgp
);
3710 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3712 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3713 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3714 vnc_zlog_debug_verbose(
3715 "%s: can't auto-assign RD, VN addr family is not IPv4|v6",
3717 return EAFNOSUPPORT
;
3719 rd
->family
= AF_UNSPEC
;
3721 rd
->val
[1] = RD_TYPE_IP
;
3722 if (vn
->addr_family
== AF_INET
) {
3723 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3724 } else { /* is v6 */
3725 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3726 4); /* low order 4 bytes */
3729 char buf
[RD_ADDRSTRLEN
];
3731 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3732 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3737 /*------------------------------------------
3738 * rfapi_bgp_lookup_by_rfp
3740 * Find bgp instance pointer based on value returned by rfp_start
3743 * rfp_start_val value returned by rfp_startor
3744 * NULL (=get default instance)
3750 * bgp bgp instance pointer
3753 --------------------------------------------*/
3754 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3756 struct bgp
*bgp
= NULL
;
3757 struct listnode
*node
, *nnode
;
3759 if (rfp_start_val
== NULL
)
3760 bgp
= bgp_get_default();
3762 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3763 if (bgp
->rfapi
!= NULL
3764 && bgp
->rfapi
->rfp
== rfp_start_val
)
3769 /*------------------------------------------
3770 * rfapi_get_rfp_start_val_by_bgp
3772 * Find bgp instance pointer based on value returned by rfp_start
3775 * bgp bgp instance pointer
3784 --------------------------------------------*/
3785 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3787 if (!bgp
|| !bgp
->rfapi
)
3789 return bgp
->rfapi
->rfp
;
3792 /***********************************************************************
3793 * RFP group specific configuration
3794 ***********************************************************************/
3795 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3799 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3800 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3801 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3804 return rfc
->default_rfp_cfg
;
3807 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3811 struct rfapi_nve_group_cfg
*rfg
=
3812 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3814 /* make sure group is still in list */
3815 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3816 /* Not in list anymore */
3817 vty_out(vty
, "Current NVE group no longer exists\n");
3821 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3822 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3823 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3826 return rfg
->rfp_cfg
;
3829 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3833 struct rfapi_l2_group_cfg
*rfg
=
3834 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3836 /* make sure group is still in list */
3837 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3838 /* Not in list anymore */
3839 vty_out(vty
, "Current L2 group no longer exists\n");
3842 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3843 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3844 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3847 return rfg
->rfp_cfg
;
3850 /*------------------------------------------
3851 * rfapi_rfp_init_group_config_ptr_vty
3853 * This is used to init or return a previously init'ed group specific
3854 * configuration pointer. Group is identified by vty context.
3855 * NOTE: size is ignored when a previously init'ed value is returned.
3856 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3857 * bgp restart or shutdown.
3860 * rfp_start_val value returned by rfp_start
3862 * vty quagga vty context
3863 * size number of bytes to allocation
3869 * rfp_cfg_group NULL or Pointer to configuration structure
3870 --------------------------------------------*/
3871 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3872 rfapi_rfp_cfg_group_type type
,
3873 struct vty
*vty
, uint32_t size
)
3878 if (rfp_start_val
== NULL
|| vty
== NULL
)
3881 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3882 if (!bgp
|| !bgp
->rfapi_cfg
)
3886 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3887 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3890 case RFAPI_RFP_CFG_GROUP_NVE
:
3891 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3894 case RFAPI_RFP_CFG_GROUP_L2
:
3895 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3899 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3901 /* should never happen */
3902 assert("Unknown type" == NULL
);
3908 /*------------------------------------------
3909 * rfapi_rfp_get_group_config_ptr_vty
3911 * This is used to get group specific configuration pointer.
3912 * Group is identified by type and vty context.
3913 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3914 * bgp restart or shutdown.
3917 * rfp_start_val value returned by rfp_start
3919 * vty quagga vty context
3925 * rfp_cfg_group Pointer to configuration structure
3926 --------------------------------------------*/
3927 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3928 rfapi_rfp_cfg_group_type type
,
3931 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3935 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3937 rfp_group_config_search_cb_t
*search_cb
)
3939 struct rfapi_nve_group_cfg
*rfg
;
3940 struct listnode
*node
;
3942 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3943 if (!strcmp(rfg
->name
, name
) && /* name match */
3944 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3945 return rfg
->rfp_cfg
;
3951 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3953 rfp_group_config_search_cb_t
*search_cb
)
3955 struct rfapi_l2_group_cfg
*rfg
;
3956 struct listnode
*node
;
3958 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3959 if (!strcmp(rfg
->name
, name
) && /* name match */
3960 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3961 return rfg
->rfp_cfg
;
3966 /*------------------------------------------
3967 * rfapi_rfp_get_group_config_ptr_name
3969 * This is used to get group specific configuration pointer.
3970 * Group is identified by type and name context.
3971 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3972 * bgp restart or shutdown.
3975 * rfp_start_val value returned by rfp_start
3978 * criteria RFAPI caller provided search criteria
3979 * search_cb optional rfp_group_config_search_cb_t
3985 * rfp_cfg_group Pointer to configuration structure
3986 --------------------------------------------*/
3987 void *rfapi_rfp_get_group_config_ptr_name(
3988 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3989 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
3994 if (rfp_start_val
== NULL
|| name
== NULL
)
3997 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3998 if (!bgp
|| !bgp
->rfapi_cfg
)
4002 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4003 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4005 case RFAPI_RFP_CFG_GROUP_NVE
:
4006 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4007 criteria
, search_cb
);
4009 case RFAPI_RFP_CFG_GROUP_L2
:
4010 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4011 criteria
, search_cb
);
4014 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4016 /* should never happen */
4017 assert("Unknown type" == NULL
);
4023 /*------------------------------------------
4024 * rfapi_rfp_get_l2_group_config_ptr_lni
4026 * This is used to get group specific configuration pointer.
4027 * Group is identified by type and logical network identifier.
4028 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4029 * bgp restart or shutdown.
4032 * rfp_start_val value returned by rfp_start
4034 * logical_net_id group logical network identifier
4035 * criteria RFAPI caller provided search criteria
4036 * search_cb optional rfp_group_config_search_cb_t
4042 * rfp_cfg_group Pointer to configuration structure
4043 --------------------------------------------*/
4045 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4046 uint32_t logical_net_id
, void *criteria
,
4047 rfp_group_config_search_cb_t
*search_cb
)
4050 struct rfapi_l2_group_cfg
*rfg
;
4051 struct listnode
*node
;
4053 if (rfp_start_val
== NULL
)
4056 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4057 if (!bgp
|| !bgp
->rfapi_cfg
)
4060 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4061 if (rfg
->logical_net_id
== logical_net_id
4062 && (search_cb
== NULL
4063 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4064 if (rfg
->rfp_cfg
== NULL
)
4065 vnc_zlog_debug_verbose(
4066 "%s: returning rfp group config for lni=0",
4068 return rfg
->rfp_cfg
;