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
= monotime(NULL
);
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
;
1354 rfd
->open_time
= monotime(NULL
);
1356 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1357 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1359 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1360 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1362 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1363 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1365 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1367 listnode_add(&h
->descriptors
, rfd
);
1368 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1369 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1373 * attach to UN radix tree
1375 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1376 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1377 assert(afi_vn
&& afi_un
);
1378 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1380 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1382 rfd
->next
= rn
->info
;
1386 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1389 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1391 struct rfapi_vn_option
*head
= NULL
;
1392 struct rfapi_vn_option
*tail
= NULL
;
1393 struct rfapi_vn_option
*vo
= NULL
;
1395 for (vo
= orig
; vo
; vo
= vo
->next
) {
1396 struct rfapi_vn_option
*new;
1398 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1399 sizeof(struct rfapi_vn_option
));
1400 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1412 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1414 struct rfapi_un_option
*head
= NULL
;
1415 struct rfapi_un_option
*tail
= NULL
;
1416 struct rfapi_un_option
*uo
= NULL
;
1418 for (uo
= orig
; uo
; uo
= uo
->next
) {
1419 struct rfapi_un_option
*new;
1421 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1422 sizeof(struct rfapi_un_option
));
1423 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1435 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1437 struct bgp_tea_options
*head
= NULL
;
1438 struct bgp_tea_options
*tail
= NULL
;
1439 struct bgp_tea_options
*hop
= NULL
;
1441 for (hop
= orig
; hop
; hop
= hop
->next
) {
1442 struct bgp_tea_options
*new;
1444 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1445 sizeof(struct bgp_tea_options
));
1446 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1449 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1451 memcpy(new->value
, hop
->value
, hop
->length
);
1462 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1464 struct bgp_tea_options
*next
;
1469 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1470 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1476 void rfapiAdbFree(struct rfapi_adb
*adb
)
1478 XFREE(MTYPE_RFAPI_ADB
, adb
);
1482 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1483 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1484 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1488 struct prefix p_original
;
1489 struct agg_node
*rn
;
1490 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1491 struct bgp
*bgp
= rfd
->bgp
;
1492 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1493 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1495 int use_eth_resolution
= 0;
1496 struct rfapi_next_hop_entry
*i_nhe
;
1500 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1505 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1509 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1510 vnc_zlog_debug_verbose(
1511 "%s: Called during calback, returning EDEADLK",
1516 if (!is_valid_rfd(rfd
)) {
1517 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1522 rfd
->rsp_counter
++; /* dedup: identify this generation */
1523 rfd
->rsp_time
= monotime(NULL
); /* response content dedup */
1524 rfd
->ftd_last_allowed_time
=
1526 bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1529 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1533 /* per t/c Paul/Lou 151022 */
1534 if (!eth_is_0
|| l2o
->logical_net_id
) {
1535 use_eth_resolution
= 1;
1540 *ppNextHopEntry
= NULL
;
1543 * Save original target in prefix form. In case of L2-based queries,
1544 * p_original will be modified to reflect the L2 target
1546 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1548 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1549 /* convert query to 0/0 when full-table download is enabled */
1550 memset((char *)&p
, 0, sizeof(p
));
1551 p
.family
= target
->addr_family
;
1559 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1560 __func__
, rfd
, &p
, ppNextHopEntry
);
1562 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1563 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1564 vnc_zlog_debug_verbose(
1565 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1566 __func__
, rfd
->import_table
, s
);
1567 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1570 afi
= family2afi(p
.family
);
1573 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1574 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1575 self_vn_addr
= &rfd
->vn_addr
;
1578 if (use_eth_resolution
) {
1579 uint32_t logical_net_id
= l2o
->logical_net_id
;
1580 struct ecommunity
*l2com
;
1583 * fix up p_original to contain L2 address
1585 rfapiL2o2Qprefix(l2o
, &p_original
);
1587 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1588 bgp
, 1, logical_net_id
, l2o
->label
);
1590 uint8_t *v
= l2com
->val
;
1591 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1594 * Ethernet/L2-based lookup
1596 * Always returns IT node corresponding to route
1599 if (RFAPI_RFP_DOWNLOAD_FULL
1600 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1604 rn
= rfapiMonitorEthAdd(
1605 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1609 struct rfapi_ip_prefix rprefix
;
1611 memset(&rprefix
, 0, sizeof(rprefix
));
1612 rprefix
.prefix
.addr_family
= target
->addr_family
;
1613 if (target
->addr_family
== AF_INET
) {
1614 rprefix
.length
= IPV4_MAX_BITLEN
;
1616 rprefix
.length
= IPV6_MAX_BITLEN
;
1619 pNHE
= rfapiEthRouteTable2NextHopList(
1620 logical_net_id
, &rprefix
,
1621 rfd
->response_lifetime
, self_vn_addr
,
1622 rfd
->rib
[afi
], &p_original
);
1632 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1635 * If target address is 0, this request is special: means to
1636 * return ALL routes in the table
1638 * Monitors for All-Routes queries get put on a special list,
1639 * not in the VPN tree
1641 if (RFAPI_0_PREFIX(&p
)) {
1643 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1646 * Generate nexthop list for caller
1648 pNHE
= rfapiRouteTable2NextHopList(
1649 rfd
->import_table
->imported_vpn
[afi
],
1650 rfd
->response_lifetime
, self_vn_addr
,
1651 rfd
->rib
[afi
], &p_original
);
1656 agg_lock_node(rn
); /* so we can unlock below */
1659 * returns locked node. Don't unlock yet because the
1661 * might free it before we're done with it. This
1663 * could occur when rfapiMonitorGetAttachNode() returns
1665 * newly-created default node.
1667 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1673 agg_unlock_node(rn
);
1674 vnc_zlog_debug_verbose(
1675 "%s: VPN route not found, returning ENOENT", __func__
);
1679 if (VNC_DEBUG(RFAPI_QUERY
)) {
1680 rfapiShowImportTable(NULL
, "query",
1681 rfd
->import_table
->imported_vpn
[afi
], 1);
1684 if (use_eth_resolution
) {
1686 struct rfapi_ip_prefix rprefix
;
1688 memset(&rprefix
, 0, sizeof(rprefix
));
1689 rprefix
.prefix
.addr_family
= target
->addr_family
;
1690 if (target
->addr_family
== AF_INET
) {
1691 rprefix
.length
= IPV4_MAX_BITLEN
;
1693 rprefix
.length
= IPV6_MAX_BITLEN
;
1696 pNHE
= rfapiEthRouteNode2NextHopList(
1697 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1698 rfd
->rib
[afi
], &p_original
);
1703 * Generate answer to query
1705 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1706 self_vn_addr
, rfd
->rib
[afi
],
1710 agg_unlock_node(rn
);
1713 if (ppNextHopEntry
) {
1714 /* only count if caller gets it */
1715 ++bgp
->rfapi
->response_immediate_count
;
1719 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1725 * count nexthops for statistics
1727 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1728 ++rfd
->stat_count_nh_reachable
;
1731 if (ppNextHopEntry
) {
1732 *ppNextHopEntry
= pNHE
;
1734 rfapi_free_next_hop_list(pNHE
);
1737 vnc_zlog_debug_verbose("%s: success", __func__
);
1742 * support on-the-fly reassignment of an already-open nve to a new
1743 * nve-group in the event that its original nve-group is
1744 * administratively deleted.
1746 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1748 struct prefix pfx_vn
;
1749 struct prefix pfx_un
;
1750 struct rfapi_nve_group_cfg
*rfg
;
1752 struct rfapi_cfg
*hc
;
1759 hc
= bgp
->rfapi_cfg
;
1763 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1766 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1770 * Find the matching nve group config block
1772 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1778 * check nve group config block for required values
1780 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1785 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1791 * re-advertise registered routes, this time as part of new NVE-group
1793 rfapiApReadvertiseAll(bgp
, rfd
);
1796 * re-attach callbacks to import table
1798 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1799 rfapiMonitorAttachImportHd(rfd
);
1805 /*------------------------------------------
1808 * This function initializes a NVE record and associates it with
1809 * the specified VN and underlay network addresses
1812 * rfp_start_val value returned by rfp_start
1813 * vn NVE virtual network address
1815 * un NVE underlay network address
1817 * default_options Default options to use on registrations.
1818 * For now only tunnel type is supported.
1819 * May be overridden per-prefix in rfapi_register().
1820 * Caller owns (rfapi_open() does not free)
1822 * response_cb Pointer to next hop list update callback function or
1823 * NULL when no callbacks are desired.
1825 * userdata Passed to subsequent response_cb invocations.
1828 * response_lifetime The length of time that responses sent to this
1831 * pHandle pointer to location to store rfapi handle. The
1832 * handle must be passed on subsequent rfapi_ calls.
1837 * EEXIST NVE with this {vn,un} already open
1838 * ENOENT No matching nve group config
1839 * ENOMSG Matched nve group config was incomplete
1840 * ENXIO BGP or VNC not configured
1841 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1842 * but underlay network address is not IPv4
1843 * EDEADLK Called from within a callback procedure
1844 *------------------------------------------*/
1845 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1846 struct rfapi_ip_addr
*un
,
1847 struct rfapi_un_option
*default_options
,
1848 uint32_t *response_lifetime
,
1849 void *userdata
, /* callback cookie */
1850 rfapi_handle
*pHandle
)
1854 struct rfapi_descriptor
*rfd
;
1855 struct rfapi_cfg
*hc
;
1856 struct rfapi_nve_group_cfg
*rfg
;
1858 struct prefix pfx_vn
;
1859 struct prefix pfx_un
;
1862 rfapi_handle hh
= NULL
;
1863 int reusing_provisional
= 0;
1866 char buf
[2][INET_ADDRSTRLEN
];
1867 vnc_zlog_debug_verbose(
1868 "%s: VN=%s UN=%s", __func__
,
1869 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1870 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1876 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1884 hc
= bgp
->rfapi_cfg
;
1888 if (h
->flags
& RFAPI_INCALLBACK
)
1891 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1894 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1898 * already have a descriptor with VN and UN?
1900 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1902 * we might have set up a handle for static routes before
1903 * this NVE was opened. In that case, reuse the handle
1906 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1911 * reuse provisional descriptor
1914 reusing_provisional
= 1;
1918 * Find the matching nve group config block
1920 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1922 ++h
->stat
.count_unknown_nves
;
1924 char buf
[2][INET_ADDRSTRLEN
];
1925 zlog_notice("%s: no matching group VN=%s UN=%s",
1927 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1929 rfapiRfapiIpAddr2Str(un
, buf
[1],
1936 * check nve group config block for required values
1938 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1940 ++h
->stat
.count_unknown_nves
;
1945 * If group config specifies auto-rd assignment, check that
1946 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1947 * Check here so we don't need to unwind memory allocations, &c.
1949 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1950 && (vn
->addr_family
!= AF_INET6
)) {
1951 return EAFNOSUPPORT
;
1956 * reusing provisional rfd
1960 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1961 sizeof(struct rfapi_descriptor
));
1965 if (default_options
) {
1966 struct rfapi_un_option
*p
;
1968 for (p
= default_options
; p
; p
= p
->next
) {
1969 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1970 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1972 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1973 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1979 * Fill in caller fields
1983 rfd
->cookie
= userdata
;
1985 if (!reusing_provisional
) {
1986 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1988 * This can fail only if the VN address is IPv6 and the group
1989 * specified auto-assignment of RDs, which only works for v4,
1990 * and the check above should catch it.
1992 * Another failure possibility is that we were called
1993 * during an rfapi callback. Also checked above.
1998 if (response_lifetime
)
1999 *response_lifetime
= rfd
->response_lifetime
;
2005 * For use with debug functions
2007 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2008 rfapi_response_cb_t
*response_cb
)
2010 if (!is_valid_rfd(rfd
))
2012 rfd
->response_cb
= response_cb
;
2019 * Does almost all the work of rfapi_close, except:
2020 * 1. preserves the descriptor (doesn't free it)
2021 * 2. preserves the prefix query list (i.e., rfd->mon list)
2022 * 3. preserves the advertised prefix list (rfd->advertised)
2023 * 4. preserves the rib and rib_pending tables
2025 * The purpose of organizing it this way is to support on-the-fly
2026 * reassignment of an already-open nve to a new nve-group in the
2027 * event that its original nve-group is administratively deleted.
2029 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2032 struct prefix pfx_vn
;
2033 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2035 if (!is_valid_rfd(rfd
))
2038 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2039 assert(!rc
); /* should never have bad AF in stored vn address */
2042 * update exported routes to reflect disappearance of this NVE as
2045 vnc_direct_bgp_del_nve(bgp
, rfd
);
2046 vnc_zebra_del_nve(bgp
, rfd
);
2049 * unlink this HD's monitors from import table
2051 rfapiMonitorDetachImportHd(rfd
);
2054 * Unlink from Import Table
2055 * NB rfd->import_table will be NULL if we are closing a stale
2058 if (rfd
->import_table
)
2059 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2060 rfd
->import_table
= NULL
;
2063 * Construct route distinguisher
2065 memset(&prd
, 0, sizeof(prd
));
2067 prd
.family
= AF_UNSPEC
;
2073 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2074 &pfx_vn
, /* prefix being advertised */
2075 &prd
, /* route distinguisher to use (0 for ENCAP) */
2076 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2079 * Construct route distinguisher for VPN routes
2082 prd
.family
= AF_UNSPEC
;
2086 * find all VPN routes associated with this rfd and delete them, too
2088 rfapiApWithdrawAll(bgp
, rfd
);
2091 * remove this nve descriptor from the list of nves
2092 * associated with the nve group
2095 listnode_delete(rfd
->rfg
->nves
, rfd
);
2096 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2099 if (rfd
->rt_export_list
)
2100 ecommunity_free(&rfd
->rt_export_list
);
2101 rfd
->rt_export_list
= NULL
;
2104 * free peer structure (possibly delayed until its
2105 * refcount reaches zero)
2108 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2109 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2110 peer_delete(rfd
->peer
);
2117 int rfapi_close(void *handle
)
2119 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2121 struct agg_node
*node
;
2125 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2127 #ifdef RFAPI_WHO_IS_CALLING_ME
2128 #ifdef HAVE_GLIBC_BACKTRACE
2129 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2131 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2136 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2137 syms
= backtrace_symbols(buf
, size
);
2138 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2140 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2156 if (!is_valid_rfd(rfd
))
2159 if (h
->flags
& RFAPI_INCALLBACK
) {
2161 * Queue these close requests for processing after callback
2164 if (!CHECK_FLAG(rfd
->flags
,
2165 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2166 work_queue_add(h
->deferred_close_q
, handle
);
2167 vnc_zlog_debug_verbose(
2168 "%s: added handle %p to deferred close queue",
2174 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2176 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2179 if (h
->rfp_methods
.close_cb
) {
2180 vnc_zlog_debug_verbose(
2181 "%s calling close callback rfd=%p", __func__
,
2185 * call the callback fairly early so that it can still
2189 * NB RFAPI_INCALLBACK is tested above, so if we reach
2191 * we are not already in the context of a callback.
2193 h
->flags
|= RFAPI_INCALLBACK
;
2194 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2195 h
->flags
&= ~RFAPI_INCALLBACK
;
2201 * Orphaned descriptors have already done this part, so do
2202 * only for non-orphaned descriptors.
2204 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2209 * Remove descriptor from UN index
2210 * (remove from chain at node)
2212 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2214 struct rfapi_descriptor
*hh
;
2216 if (node
->info
== rfd
) {
2217 node
->info
= rfd
->next
;
2220 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2221 if (hh
->next
== rfd
) {
2222 hh
->next
= rfd
->next
;
2227 agg_unlock_node(node
);
2231 * remove from descriptor list
2233 listnode_delete(&h
->descriptors
, rfd
);
2236 * Delete monitor list items and free monitor structures
2238 (void)rfapiMonitorDelHd(rfd
);
2241 * release advertised prefix data
2243 rfapiApRelease(&rfd
->advertised
);
2246 * Release RFP callback RIB
2253 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2254 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2260 * Reopen a nve descriptor. If the descriptor's NVE-group
2261 * does not exist (e.g., if it has been administratively removed),
2262 * reassignment to a new NVE-group is attempted.
2264 * If NVE-group reassignment fails, the descriptor becomes "stale"
2265 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2266 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2267 * on the descriptor will return ESTALE.
2269 * Reopening a descriptor is a potentially expensive operation, because
2270 * it involves withdrawing any routes advertised by the NVE, withdrawing
2271 * the NVE's route queries, and then re-adding them all after a new
2272 * NVE-group is assigned. There are also possible route-export affects
2273 * caused by deleting and then adding the NVE: advertised prefixes
2274 * and nexthop lists for exported routes can turn over.
2276 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2281 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2284 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2288 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2290 if (CHECK_FLAG(rfd
->flags
,
2291 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2292 && h
&& h
->rfp_methods
.close_cb
) {
2295 * NB RFAPI_INCALLBACK is tested above, so if we reach
2297 * we are not already in the context of a callback.
2299 h
->flags
|= RFAPI_INCALLBACK
;
2300 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2301 h
->flags
&= ~RFAPI_INCALLBACK
;
2308 /***********************************************************************
2310 ***********************************************************************/
2312 * Announce reachability to this prefix via the NVE
2314 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2315 uint32_t lifetime
, /* host byte order */
2316 struct rfapi_un_option
*options_un
,
2317 struct rfapi_vn_option
*options_vn
,
2318 rfapi_register_action action
)
2320 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2323 struct prefix
*pfx_ip
= NULL
;
2324 struct prefix_rd prd
;
2326 struct prefix pfx_mac_buf
;
2327 struct prefix
*pfx_mac
= NULL
;
2328 struct prefix pfx_vn_buf
;
2329 const char *action_str
= NULL
;
2330 uint32_t *label
= NULL
;
2331 struct rfapi_vn_option
*vo
;
2332 struct rfapi_l2address_option
*l2o
= NULL
;
2333 struct prefix_rd
*prd_override
= NULL
;
2336 case RFAPI_REGISTER_ADD
:
2339 case RFAPI_REGISTER_WITHDRAW
:
2340 action_str
= "withdraw";
2342 case RFAPI_REGISTER_KILL
:
2343 action_str
= "kill";
2351 * Inspect VN options
2353 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2354 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2355 l2o
= &vo
->v
.l2addr
;
2357 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2358 prd_override
= &vo
->v
.internal_rd
;
2362 /*********************************************************************
2364 *********************************************************************/
2367 * set <p> based on <prefix>
2369 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2371 afi
= family2afi(prefix
->prefix
.addr_family
);
2374 vnc_zlog_debug_verbose(
2375 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2376 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2380 * These tests come after the prefix conversion so that we can
2381 * print the prefix in a debug message before failing
2386 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2391 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2396 if (RFAPI_REGISTER_ADD
== action
) {
2397 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2399 vnc_zlog_debug_verbose(
2400 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2405 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2406 if (RFAPI_REGISTER_ADD
== action
) {
2407 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2409 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2414 if (!is_valid_rfd(rfd
)) {
2415 if (RFAPI_REGISTER_ADD
== action
) {
2416 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2418 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2424 * Is there a MAC address in this registration?
2426 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2427 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2428 pfx_mac
= &pfx_mac_buf
;
2432 * Is there an IP prefix in this registration?
2434 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2438 vnc_zlog_debug_verbose(
2439 "%s: missing mac addr that is required for host 0 pfx",
2441 if (RFAPI_REGISTER_ADD
== action
) {
2442 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2446 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2447 vnc_zlog_debug_verbose(
2448 "%s: handle has bad vn_addr: returning EBADF",
2450 if (RFAPI_REGISTER_ADD
== action
) {
2451 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2457 if (RFAPI_REGISTER_ADD
== action
) {
2458 ++bgp
->rfapi
->stat
.count_registrations
;
2462 * Figure out if this registration is missing an IP address
2466 * In RFAPI, we use prefixes in family AF_LINK to store
2467 * the MAC addresses. These prefixes are used for the
2468 * list of advertised prefixes and in the RFAPI import
2471 * In BGP proper, we use the prefix matching the NVE's
2472 * VN address with a host prefix-length (i.e., 32 or 128).
2475 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2476 && RFAPI_HOST_PREFIX(&p
)) {
2478 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2479 pfx_mac
= &pfx_mac_buf
;
2483 * Construct route distinguisher
2486 prd
= *prd_override
;
2488 memset(&prd
, 0, sizeof(prd
));
2490 prd
.family
= AF_UNSPEC
;
2492 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2493 if (l2o
->local_nve_id
2494 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2496 * If Local NVE ID is specified in message, use
2498 * (if no local default configured, also use it
2501 prd
.val
[1] = l2o
->local_nve_id
;
2503 if (rfd
->rfg
->l2rd
) {
2505 * locally-configured literal value
2507 prd
.val
[1] = rfd
->rfg
->l2rd
;
2510 * 0 means auto:vn, which means use LSB
2513 if (rfd
->vn_addr
.addr_family
2516 *(((char *)&rfd
->vn_addr
2522 *(((char *)&rfd
->vn_addr
2529 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2532 prd
.family
= AF_UNSPEC
;
2538 if (action
== RFAPI_REGISTER_WITHDRAW
2539 || action
== RFAPI_REGISTER_KILL
) {
2544 * withdraw previous advertisement
2547 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2549 : &pfx_vn_buf
, /* prefix being advertised */
2550 &prd
, /* route distinguisher (0 for ENCAP) */
2551 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2552 action
== RFAPI_REGISTER_KILL
);
2554 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2557 rfapiTunnelRouteAnnounce(
2558 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2564 uint32_t local_pref
;
2565 struct ecommunity
*rtlist
= NULL
;
2566 struct ecommunity_val ecom_value
;
2568 if (!rfapiApCount(rfd
)) {
2570 * make sure we advertise tunnel route upon adding the
2576 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2577 prefix
->cost
, l2o
)) {
2581 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2584 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2586 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2587 &rfd
->max_prefix_lifetime
);
2590 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2592 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2594 if (l2o
&& l2o
->label
)
2595 label
= &l2o
->label
;
2598 struct ecommunity
*l2com
= NULL
;
2601 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2602 bgp
, 1, l2o
->logical_net_id
, *label
);
2605 rtlist
= ecommunity_dup(l2com
);
2608 * If mac address is set, add an RT based on the
2611 memset((char *)&ecom_value
, 0,
2612 sizeof(ecom_value
));
2613 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2615 (l2o
->logical_net_id
>> 16) & 0xff;
2617 (l2o
->logical_net_id
>> 8) & 0xff;
2619 (l2o
->logical_net_id
>> 0) & 0xff;
2620 rtlist
= ecommunity_new();
2621 ecommunity_add_val(rtlist
, &ecom_value
,
2626 uint16_t val
= l2o
->tag_id
;
2627 memset((char *)&ecom_value
, 0,
2628 sizeof(ecom_value
));
2629 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2630 if (as
> BGP_AS_MAX
) {
2632 ECOMMUNITY_ENCODE_AS4
;
2633 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2634 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2635 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2636 ecom_value
.val
[5] = as
& 0xff;
2639 ECOMMUNITY_ENCODE_AS
;
2640 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2641 ecom_value
.val
[3] = as
& 0xff;
2643 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2644 ecom_value
.val
[7] = val
& 0xff;
2646 rtlist
= ecommunity_new();
2647 ecommunity_add_val(rtlist
, &ecom_value
,
2653 * advertise prefix via tunnel endpoint
2656 rfd
, /* rfapi descr, for export list & backref */
2657 bgp
, /* which bgp instance */
2658 SAFI_MPLS_VPN
, /* which SAFI */
2660 : &pfx_vn_buf
), /* prefix being advertised */
2661 &prd
, /* route distinguisher to use (0 for ENCAP) */
2662 &rfd
->vn_addr
, /* nexthop */
2664 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2665 NULL
, options_un
, /* rfapi un options */
2666 options_vn
, /* rfapi vn options */
2667 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2668 label
, /* label: default */
2669 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2672 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2675 vnc_zlog_debug_verbose("%s: success", __func__
);
2679 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2680 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2681 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2683 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2684 struct bgp
*bgp
= rfd
->bgp
;
2687 assert(ppNextHopEntry
);
2688 *ppNextHopEntry
= NULL
;
2690 if (bgp
&& bgp
->rfapi
) {
2691 bgp
->rfapi
->stat
.count_queries
++;
2695 if (bgp
&& bgp
->rfapi
)
2696 ++bgp
->rfapi
->stat
.count_queries_failed
;
2700 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2701 if (bgp
&& bgp
->rfapi
)
2702 ++bgp
->rfapi
->stat
.count_queries_failed
;
2707 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2711 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2712 struct bgp
*bgp
= rfd
->bgp
;
2718 rc
= rfapiRaddr2Qprefix(target
, &p
);
2721 if (!is_valid_rfd(rfd
))
2725 if (!bgp
|| !bgp
->rfapi
)
2728 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2731 rfapiMonitorDel(bgp
, rfd
, &p
);
2736 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2738 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2739 struct bgp
*bgp
= rfd
->bgp
;
2746 if (!is_valid_rfd(rfd
))
2750 if (!bgp
|| !bgp
->rfapi
)
2753 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2756 num
= rfapiMonitorDelHd(rfd
);
2764 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2766 struct rfapi_next_hop_entry
*nh
;
2767 struct rfapi_next_hop_entry
*next
;
2769 for (nh
= list
; nh
; nh
= next
) {
2771 rfapi_un_options_free(nh
->un_options
);
2772 nh
->un_options
= NULL
;
2773 rfapi_vn_options_free(nh
->vn_options
);
2774 nh
->vn_options
= NULL
;
2775 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2780 * NULL handle => return total count across all nves
2782 uint32_t rfapi_monitor_count(void *handle
)
2784 struct bgp
*bgp
= bgp_get_default();
2788 struct rfapi_descriptor
*rfd
=
2789 (struct rfapi_descriptor
*)handle
;
2790 count
= rfd
->monitor_count
;
2793 if (!bgp
|| !bgp
->rfapi
)
2796 count
= bgp
->rfapi
->monitor_count
;
2802 /***********************************************************************
2804 ***********************************************************************/
2806 DEFUN (debug_rfapi_show_nves
,
2807 debug_rfapi_show_nves_cmd
,
2808 "debug rfapi-dev show nves",
2812 "NVE Information\n")
2814 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2819 debug_rfapi_show_nves_vn_un
,
2820 debug_rfapi_show_nves_vn_un_cmd
,
2821 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2826 "Specify virtual network\n"
2827 "Specify underlay network interface\n"
2833 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2834 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2835 return CMD_WARNING_CONFIG_FAILED
;
2837 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2838 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2839 return CMD_WARNING_CONFIG_FAILED
;
2842 if (argv
[4]->arg
[0] == 'u') {
2843 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2845 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2851 * Note: this function does not flush vty output, so if it is called
2852 * with a stream pointing to a vty, the user will have to type something
2853 * before the callback output shows up
2855 static void test_nexthops_callback(
2856 // struct rfapi_ip_addr *target,
2857 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2859 void *stream
= userdata
;
2861 int (*fp
)(void *, const char *, ...);
2864 const char *vty_newline
;
2866 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2869 fp(out
, "Nexthops Callback, Target=(");
2870 // rfapiPrintRfapiIpAddr(stream, target);
2873 rfapiPrintNhl(stream
, next_hops
);
2877 rfapi_free_next_hop_list(next_hops
);
2880 DEFUN (debug_rfapi_open
,
2881 debug_rfapi_open_cmd
,
2882 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2886 "indicate vn addr follows\n"
2887 "virtual network interface IPv4 address\n"
2888 "virtual network interface IPv6 address\n"
2889 "indicate xt addr follows\n"
2890 "underlay network interface IPv4 address\n"
2891 "underlay network interface IPv6 address\n")
2893 struct rfapi_ip_addr vn
;
2894 struct rfapi_ip_addr un
;
2895 uint32_t lifetime
= 0;
2897 rfapi_handle handle
;
2902 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2908 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2911 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2912 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2914 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2917 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2919 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2925 DEFUN (debug_rfapi_close_vn_un
,
2926 debug_rfapi_close_vn_un_cmd
,
2927 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2931 "indicate vn addr follows\n"
2932 "virtual network interface IPv4 address\n"
2933 "virtual network interface IPv6 address\n"
2934 "indicate xt addr follows\n"
2935 "underlay network interface IPv4 address\n"
2936 "underlay network interface IPv6 address\n")
2938 struct rfapi_ip_addr vn
;
2939 struct rfapi_ip_addr un
;
2940 rfapi_handle handle
;
2946 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2953 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2957 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2958 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2959 argv
[4]->arg
, argv
[6]->arg
);
2960 return CMD_WARNING_CONFIG_FAILED
;
2963 rc
= rfapi_close(handle
);
2965 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2970 DEFUN (debug_rfapi_close_rfd
,
2971 debug_rfapi_close_rfd_cmd
,
2972 "debug rfapi-dev close rfd HANDLE",
2976 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2978 rfapi_handle handle
;
2980 char *endptr
= NULL
;
2982 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2984 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2985 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2986 return CMD_WARNING_CONFIG_FAILED
;
2989 rc
= rfapi_close(handle
);
2991 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2996 DEFUN (debug_rfapi_register_vn_un
,
2997 debug_rfapi_register_vn_un_cmd
,
2998 "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)]",
3002 "indicate vn addr follows\n"
3003 "virtual network IPv4 interface address\n"
3004 "virtual network IPv6 interface address\n"
3005 "indicate un addr follows\n"
3006 "underlay network IPv4 interface address\n"
3007 "underlay network IPv6 interface address\n"
3008 "indicate prefix follows\n"
3011 "indicate lifetime follows\n"
3013 "Cost (localpref = 255-cost)\n"
3016 struct rfapi_ip_addr vn
;
3017 struct rfapi_ip_addr un
;
3018 rfapi_handle handle
;
3021 struct rfapi_ip_prefix hpfx
;
3028 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3035 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3039 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3040 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3041 argv
[4]->arg
, argv
[6]->arg
);
3042 return CMD_WARNING_CONFIG_FAILED
;
3046 * Get prefix to advertise
3048 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3049 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3050 return CMD_WARNING_CONFIG_FAILED
;
3052 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3053 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3054 return CMD_WARNING_CONFIG_FAILED
;
3056 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3058 if (strmatch(argv
[10]->text
, "infinite")) {
3059 lifetime
= RFAPI_INFINITE_LIFETIME
;
3061 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3065 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3068 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3069 RFAPI_REGISTER_ADD
);
3071 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3078 DEFUN (debug_rfapi_register_vn_un_l2o
,
3079 debug_rfapi_register_vn_un_l2o_cmd
,
3080 "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS macaddr X:X:X:X:X:X lni (0-16777215)",
3084 "indicate vn addr follows\n"
3085 "virtual network IPv4 interface address\n"
3086 "virtual network IPv6 interface address\n"
3087 "indicate un addr follows\n"
3088 "underlay network IPv4 interface address\n"
3089 "underlay network IPv6 interface address\n"
3090 "indicate prefix follows\n"
3093 "indicate lifetime follows\n"
3094 "Seconds of lifetime\n"
3095 "indicate MAC address follows\n"
3097 "indicate lni follows\n"
3098 "lni value range\n")
3100 struct rfapi_ip_addr vn
;
3101 struct rfapi_ip_addr un
;
3102 rfapi_handle handle
;
3105 struct rfapi_ip_prefix hpfx
;
3107 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3108 struct rfapi_vn_option
*opt
= NULL
;
3114 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3121 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3125 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3126 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3127 argv
[4]->arg
, argv
[6]->arg
);
3128 return CMD_WARNING_CONFIG_FAILED
;
3132 * Get prefix to advertise
3134 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3135 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3136 return CMD_WARNING_CONFIG_FAILED
;
3138 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3139 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3140 return CMD_WARNING_CONFIG_FAILED
;
3142 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3144 if (strmatch(argv
[10]->text
, "infinite")) {
3145 lifetime
= RFAPI_INFINITE_LIFETIME
;
3147 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3150 /* L2 option parsing START */
3151 memset(optary
, 0, sizeof(optary
));
3152 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3153 strtoul(argv
[14]->arg
, NULL
, 10);
3154 if (rfapiStr2EthAddr(argv
[12]->arg
,
3155 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3156 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3157 return CMD_WARNING_CONFIG_FAILED
;
3159 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3162 /* L2 option parsing END */
3165 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3166 RFAPI_REGISTER_ADD
);
3168 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3176 DEFUN (debug_rfapi_unregister_vn_un
,
3177 debug_rfapi_unregister_vn_un_cmd
,
3178 "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]",
3182 "indicate vn addr follows\n"
3183 "virtual network interface address\n"
3184 "indicate xt addr follows\n"
3185 "underlay network interface address\n"
3186 "prefix to remove\n"
3187 "Remove without holddown")
3189 struct rfapi_ip_addr vn
;
3190 struct rfapi_ip_addr un
;
3191 rfapi_handle handle
;
3193 struct rfapi_ip_prefix hpfx
;
3199 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3206 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3210 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3211 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3212 argv
[4]->arg
, argv
[6]->arg
);
3213 return CMD_WARNING_CONFIG_FAILED
;
3217 * Get prefix to advertise
3219 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3220 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3221 return CMD_WARNING_CONFIG_FAILED
;
3223 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3224 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3225 return CMD_WARNING_CONFIG_FAILED
;
3227 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3229 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3231 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3236 DEFUN (debug_rfapi_query_vn_un
,
3237 debug_rfapi_query_vn_un_cmd
,
3238 "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>",
3242 "indicate vn addr follows\n"
3243 "virtual network interface IPv4 address\n"
3244 "virtual network interface IPv6 address\n"
3245 "indicate un addr follows\n"
3248 "indicate target follows\n"
3249 "target IPv4 address\n"
3250 "target IPv6 address\n")
3252 struct rfapi_ip_addr vn
;
3253 struct rfapi_ip_addr un
;
3254 struct rfapi_ip_addr target
;
3255 rfapi_handle handle
;
3257 struct rfapi_next_hop_entry
*pNextHopEntry
;
3262 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3269 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3276 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3280 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3281 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3282 argv
[4]->arg
, argv
[6]->arg
);
3283 return CMD_WARNING_CONFIG_FAILED
;
3287 * options parameter not used? Set to NULL for now
3289 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3292 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3296 * print nexthop list
3298 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3299 vty
); /* frees nh list! */
3306 DEFUN (debug_rfapi_query_vn_un_l2o
,
3307 debug_rfapi_query_vn_un_l2o_cmd
,
3308 "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lni LNI target X:X:X:X:X:X",
3312 "indicate vn addr follows\n"
3313 "virtual network interface IPv4 address\n"
3314 "virtual network interface IPv6 address\n"
3315 "indicate xt addr follows\n"
3316 "underlay network interface IPv4 address\n"
3317 "underlay network interface IPv6 address\n"
3318 "logical network ID follows\n"
3319 "logical network ID\n"
3320 "indicate target MAC addr follows\n"
3321 "target MAC addr\n")
3323 struct rfapi_ip_addr vn
;
3324 struct rfapi_ip_addr un
;
3330 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3337 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3340 vty_out(vty
, "%% This command is broken.\n");
3341 return CMD_WARNING_CONFIG_FAILED
;
3345 DEFUN (debug_rfapi_query_done_vn_un
,
3346 debug_rfapi_query_vn_un_done_cmd
,
3347 "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>",
3350 "rfapi_query_done\n"
3351 "rfapi_query_done\n"
3352 "indicate vn addr follows\n"
3353 "virtual network interface IPv4 address\n"
3354 "virtual network interface IPv6 address\n"
3355 "indicate xt addr follows\n"
3356 "underlay network interface IPv4 address\n"
3357 "underlay network interface IPv6 address\n"
3358 "indicate target follows\n"
3359 "Target IPv4 address\n"
3360 "Target IPv6 address\n")
3362 struct rfapi_ip_addr vn
;
3363 struct rfapi_ip_addr un
;
3364 struct rfapi_ip_addr target
;
3365 rfapi_handle handle
;
3371 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3378 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3385 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3389 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3390 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3391 argv
[5]->arg
, argv
[7]->arg
);
3392 return CMD_WARNING_CONFIG_FAILED
;
3396 * options parameter not used? Set to NULL for now
3398 rc
= rfapi_query_done(handle
, &target
);
3400 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3405 DEFUN (debug_rfapi_show_import
,
3406 debug_rfapi_show_import_cmd
,
3407 "debug rfapi-dev show import",
3415 struct rfapi_import_table
*it
;
3420 * Show all import tables
3423 bgp
= bgp_get_default(); /* assume 1 instance for now */
3425 vty_out(vty
, "No BGP instance\n");
3426 return CMD_WARNING_CONFIG_FAILED
;
3431 vty_out(vty
, "No RFAPI instance\n");
3432 return CMD_WARNING_CONFIG_FAILED
;
3436 * Iterate over all import tables; do a filtered import
3437 * for the afi/safi combination
3441 for (it
= h
->imports
; it
; it
= it
->next
) {
3442 s
= ecommunity_ecom2str(it
->rt_import_list
,
3443 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3444 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3445 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3447 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3449 rfapiShowImportTable(vty
, "IP ENCAP",
3450 it
->imported_encap
[AFI_IP
], 0);
3451 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3453 rfapiShowImportTable(vty
, "IP6 ENCAP",
3454 it
->imported_encap
[AFI_IP6
], 0);
3457 if (h
->import_mac
) {
3458 void *cursor
= NULL
;
3460 uintptr_t lni_as_ptr
;
3464 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3465 (void **)&it
, &cursor
);
3467 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3468 (void **)&it
, &cursor
)) {
3470 if (it
->imported_vpn
[AFI_L2VPN
]) {
3474 "\nLNI-based Ethernet Tables:\n");
3477 snprintf(buf
, sizeof(buf
), "L2VPN LNI=%u", lni
);
3478 rfapiShowImportTable(
3479 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3485 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3486 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3491 DEFUN (debug_rfapi_show_import_vn_un
,
3492 debug_rfapi_show_import_vn_un_cmd
,
3493 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3498 "indicate vn addr follows\n"
3499 "virtual network interface IPv4 address\n"
3500 "virtual network interface IPv6 address\n"
3501 "indicate xt addr follows\n"
3502 "underlay network interface IPv4 address\n"
3503 "underlay network interface IPv6 address\n")
3505 struct rfapi_ip_addr vn
;
3506 struct rfapi_ip_addr un
;
3507 rfapi_handle handle
;
3509 struct rfapi_descriptor
*rfd
;
3514 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3521 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3525 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3526 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3527 argv
[5]->arg
, argv
[7]->arg
);
3528 return CMD_WARNING_CONFIG_FAILED
;
3531 rfd
= (struct rfapi_descriptor
*)handle
;
3533 rfapiShowImportTable(vty
, "IP VPN",
3534 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3535 rfapiShowImportTable(vty
, "IP ENCAP",
3536 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3537 rfapiShowImportTable(vty
, "IP6 VPN",
3538 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3539 rfapiShowImportTable(vty
, "IP6 ENCAP",
3540 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3545 DEFUN (debug_rfapi_response_omit_self
,
3546 debug_rfapi_response_omit_self_cmd
,
3547 "debug rfapi-dev response-omit-self <on|off>",
3550 "Omit self in RFP responses\n"
3551 "filter out self from responses\n" "leave self in responses\n")
3553 struct bgp
*bgp
= bgp_get_default();
3556 vty_out(vty
, "No BGP process is configured\n");
3557 return CMD_WARNING_CONFIG_FAILED
;
3559 if (!bgp
->rfapi_cfg
) {
3560 vty_out(vty
, "VNC not configured\n");
3561 return CMD_WARNING_CONFIG_FAILED
;
3564 if (strmatch(argv
[3]->text
, "on"))
3565 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3566 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3568 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3569 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3575 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3577 #include "lib/skiplist.h"
3578 DEFUN (skiplist_test_cli
,
3579 skiplist_test_cli_cmd
,
3581 "skiplist command\n"
3589 DEFUN (skiplist_debug_cli
,
3590 skiplist_debug_cli_cmd
,
3592 "skiplist command\n"
3595 skiplist_debug(vty
, NULL
);
3599 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3601 void rfapi_init(void)
3603 bgp_rfapi_cfg_init();
3606 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3607 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3609 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3610 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3611 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3612 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3613 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3614 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3615 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3616 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3618 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3620 /* Need the following show commands for gpz test scripts */
3621 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3622 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3623 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3625 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3626 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3627 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3634 static void rfapi_print_exported(struct bgp
*bgp
)
3636 struct bgp_dest
*destn
;
3637 struct bgp_dest
*dest
;
3638 struct bgp_path_info
*bpi
;
3643 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); destn
;
3644 destn
= bgp_route_next(destn
)) {
3645 struct bgp_table
*table
;
3647 table
= bgp_dest_get_bgp_table_info(destn
);
3650 fprintf(stderr
, "%s: vpn destn=%p\n", __func__
, destn
);
3651 for (dest
= bgp_table_top(table
); dest
;
3652 dest
= bgp_route_next(dest
)) {
3653 bpi
= bgp_dest_get_bgp_path_info(dest
);
3657 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3658 for (; bpi
; bpi
= bpi
->next
) {
3659 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3663 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); destn
;
3664 destn
= bgp_route_next(destn
)) {
3665 struct bgp_table
*table
;
3667 table
= bgp_dest_get_bgp_table_info(destn
);
3670 fprintf(stderr
, "%s: encap destn=%p\n", __func__
, destn
);
3671 for (dest
= bgp_table_top(table
); dest
;
3672 dest
= bgp_route_next(dest
)) {
3673 bpi
= bgp_dest_get_bgp_path_info(dest
);
3676 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3677 for (; bpi
; bpi
= bpi
->next
) {
3678 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3683 #endif /* defined(DEBUG_RFAPI) */
3686 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3688 void rfapi_delete(struct bgp
*bgp
)
3690 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3693 * This clears queries and registered routes, and closes nves
3696 rfp_clear_vnc_nve_all();
3697 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3698 bgp
->rfapi_cfg
= NULL
;
3699 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3703 * show what's left in the BGP MPLSVPN RIB
3705 rfapi_print_exported(bgp
);
3709 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3711 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3712 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3713 vnc_zlog_debug_verbose(
3714 "%s: can't auto-assign RD, VN addr family is not IPv4|v6",
3716 return EAFNOSUPPORT
;
3718 rd
->family
= AF_UNSPEC
;
3720 rd
->val
[1] = RD_TYPE_IP
;
3721 if (vn
->addr_family
== AF_INET
) {
3722 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3723 } else { /* is v6 */
3724 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3725 4); /* low order 4 bytes */
3728 char buf
[RD_ADDRSTRLEN
];
3730 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3731 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3736 /*------------------------------------------
3737 * rfapi_bgp_lookup_by_rfp
3739 * Find bgp instance pointer based on value returned by rfp_start
3742 * rfp_start_val value returned by rfp_startor
3743 * NULL (=get default instance)
3749 * bgp bgp instance pointer
3752 --------------------------------------------*/
3753 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3755 struct bgp
*bgp
= NULL
;
3756 struct listnode
*node
, *nnode
;
3758 if (rfp_start_val
== NULL
)
3759 bgp
= bgp_get_default();
3761 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3762 if (bgp
->rfapi
!= NULL
3763 && bgp
->rfapi
->rfp
== rfp_start_val
)
3768 /*------------------------------------------
3769 * rfapi_get_rfp_start_val_by_bgp
3771 * Find bgp instance pointer based on value returned by rfp_start
3774 * bgp bgp instance pointer
3783 --------------------------------------------*/
3784 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3786 if (!bgp
|| !bgp
->rfapi
)
3788 return bgp
->rfapi
->rfp
;
3791 /***********************************************************************
3792 * RFP group specific configuration
3793 ***********************************************************************/
3794 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3798 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3799 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3800 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3803 return rfc
->default_rfp_cfg
;
3806 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3810 struct rfapi_nve_group_cfg
*rfg
=
3811 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3813 /* make sure group is still in list */
3814 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3815 /* Not in list anymore */
3816 vty_out(vty
, "Current NVE group no longer exists\n");
3820 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3821 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3822 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3825 return rfg
->rfp_cfg
;
3828 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3832 struct rfapi_l2_group_cfg
*rfg
=
3833 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3835 /* make sure group is still in list */
3836 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3837 /* Not in list anymore */
3838 vty_out(vty
, "Current L2 group no longer exists\n");
3841 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3842 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3843 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3846 return rfg
->rfp_cfg
;
3849 /*------------------------------------------
3850 * rfapi_rfp_init_group_config_ptr_vty
3852 * This is used to init or return a previously init'ed group specific
3853 * configuration pointer. Group is identified by vty context.
3854 * NOTE: size is ignored when a previously init'ed value is returned.
3855 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3856 * bgp restart or shutdown.
3859 * rfp_start_val value returned by rfp_start
3861 * vty quagga vty context
3862 * size number of bytes to allocation
3868 * rfp_cfg_group NULL or Pointer to configuration structure
3869 --------------------------------------------*/
3870 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3871 rfapi_rfp_cfg_group_type type
,
3872 struct vty
*vty
, uint32_t size
)
3877 if (rfp_start_val
== NULL
|| vty
== NULL
)
3880 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3881 if (!bgp
|| !bgp
->rfapi_cfg
)
3885 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3886 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3889 case RFAPI_RFP_CFG_GROUP_NVE
:
3890 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3893 case RFAPI_RFP_CFG_GROUP_L2
:
3894 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3898 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3900 /* should never happen */
3901 assert("Unknown type" == NULL
);
3907 /*------------------------------------------
3908 * rfapi_rfp_get_group_config_ptr_vty
3910 * This is used to get group specific configuration pointer.
3911 * Group is identified by type and vty context.
3912 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3913 * bgp restart or shutdown.
3916 * rfp_start_val value returned by rfp_start
3918 * vty quagga vty context
3924 * rfp_cfg_group Pointer to configuration structure
3925 --------------------------------------------*/
3926 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3927 rfapi_rfp_cfg_group_type type
,
3930 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3934 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3936 rfp_group_config_search_cb_t
*search_cb
)
3938 struct rfapi_nve_group_cfg
*rfg
;
3939 struct listnode
*node
;
3941 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3942 if (!strcmp(rfg
->name
, name
) && /* name match */
3943 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3944 return rfg
->rfp_cfg
;
3950 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3952 rfp_group_config_search_cb_t
*search_cb
)
3954 struct rfapi_l2_group_cfg
*rfg
;
3955 struct listnode
*node
;
3957 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3958 if (!strcmp(rfg
->name
, name
) && /* name match */
3959 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3960 return rfg
->rfp_cfg
;
3965 /*------------------------------------------
3966 * rfapi_rfp_get_group_config_ptr_name
3968 * This is used to get group specific configuration pointer.
3969 * Group is identified by type and name context.
3970 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3971 * bgp restart or shutdown.
3974 * rfp_start_val value returned by rfp_start
3977 * criteria RFAPI caller provided search criteria
3978 * search_cb optional rfp_group_config_search_cb_t
3984 * rfp_cfg_group Pointer to configuration structure
3985 --------------------------------------------*/
3986 void *rfapi_rfp_get_group_config_ptr_name(
3987 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3988 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
3993 if (rfp_start_val
== NULL
|| name
== NULL
)
3996 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3997 if (!bgp
|| !bgp
->rfapi_cfg
)
4001 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4002 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4004 case RFAPI_RFP_CFG_GROUP_NVE
:
4005 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4006 criteria
, search_cb
);
4008 case RFAPI_RFP_CFG_GROUP_L2
:
4009 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4010 criteria
, search_cb
);
4013 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4015 /* should never happen */
4016 assert("Unknown type" == NULL
);
4022 /*------------------------------------------
4023 * rfapi_rfp_get_l2_group_config_ptr_lni
4025 * This is used to get group specific configuration pointer.
4026 * Group is identified by type and logical network identifier.
4027 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4028 * bgp restart or shutdown.
4031 * rfp_start_val value returned by rfp_start
4033 * logical_net_id group logical network identifier
4034 * criteria RFAPI caller provided search criteria
4035 * search_cb optional rfp_group_config_search_cb_t
4041 * rfp_cfg_group Pointer to configuration structure
4042 --------------------------------------------*/
4044 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4045 uint32_t logical_net_id
, void *criteria
,
4046 rfp_group_config_search_cb_t
*search_cb
)
4049 struct rfapi_l2_group_cfg
*rfg
;
4050 struct listnode
*node
;
4052 if (rfp_start_val
== NULL
)
4055 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4056 if (!bgp
|| !bgp
->rfapi_cfg
)
4059 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4060 if (rfg
->logical_net_id
== logical_net_id
4061 && (search_cb
== NULL
4062 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4063 if (rfg
->rfp_cfg
== NULL
)
4064 vnc_zlog_debug_verbose(
4065 "%s: returning rfp group config for lni=0",
4067 return rfg
->rfp_cfg
;