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 struct prefix_rd prd0
;
367 afi
= family2afi(p
->family
);
368 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
370 if (safi
== SAFI_ENCAP
) {
371 memset(&prd0
, 0, sizeof(prd0
));
372 prd0
.family
= AF_UNSPEC
;
376 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
378 vnc_zlog_debug_verbose(
379 "%s: peer=%p, prefix=%pFX, prd=%pRD afi=%d, safi=%d bn=%p, bn->info=%p",
380 __func__
, peer
, p
, prd
, afi
, safi
, bn
,
381 (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
));
383 for (bpi
= (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
); bpi
;
386 vnc_zlog_debug_verbose(
387 "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64
,
388 __func__
, bpi
, bpi
->peer
, bpi
->type
, bpi
->sub_type
,
389 (bpi
->extra
? bpi
->extra
->vnc
.export
.rfapi_handle
391 CHECK_FLAG(bpi
->attr
->flag
,
392 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)
393 ? bpi
->attr
->local_pref
: 0));
395 if (bpi
->peer
== peer
&& bpi
->type
== type
396 && bpi
->sub_type
== sub_type
&& bpi
->extra
397 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
399 vnc_zlog_debug_verbose("%s: matched it", __func__
);
407 * lnh set means to JUST delete the local nexthop from this
408 * route. Leave the route itself in place.
409 * TBD add return code reporting of success/failure
411 if (!bpi
|| !bpi
->extra
412 || !bpi
->extra
->vnc
.export
.local_nexthops
) {
416 vnc_zlog_debug_verbose(
417 "%s: lnh list already empty at prefix %pFX",
425 struct listnode
*node
;
426 struct rfapi_nexthop
*pLnh
= NULL
;
428 for (ALL_LIST_ELEMENTS_RO(bpi
->extra
->vnc
.export
.local_nexthops
,
431 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
437 listnode_delete(bpi
->extra
->vnc
.export
.local_nexthops
,
440 /* silly rabbit, listnode_delete doesn't invoke
441 * list->del on data */
442 rfapi_nexthop_free(pLnh
);
444 vnc_zlog_debug_verbose("%s: desired lnh not found %pFX",
451 * loop back to import tables
452 * Do this before removing from BGP RIB because rfapiProcessWithdraw
455 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
458 vnc_zlog_debug_verbose(
459 "%s: Found route (safi=%d) to delete at prefix %pFX",
462 if (safi
== SAFI_MPLS_VPN
) {
463 struct bgp_dest
*pdest
= NULL
;
464 struct bgp_table
*table
= NULL
;
466 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
467 (struct prefix
*)prd
);
468 table
= bgp_dest_get_bgp_table_info(pdest
);
470 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
471 bgp
, prd
, table
, p
, bpi
);
472 bgp_dest_unlock_node(pdest
);
476 * Delete local_nexthops list
478 if (bpi
->extra
&& bpi
->extra
->vnc
.export
.local_nexthops
)
479 list_delete(&bpi
->extra
->vnc
.export
.local_nexthops
);
481 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
482 bgp_path_info_delete(bn
, bpi
);
483 bgp_process(bgp
, bn
, afi
, safi
);
485 vnc_zlog_debug_verbose(
486 "%s: Couldn't find route (safi=%d) at prefix %pFX",
490 bgp_dest_unlock_node(bn
);
493 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
495 struct rfapi_nexthop
*new =
496 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
502 void rfapi_nexthop_free(void *p
)
504 struct rfapi_nexthop
*goner
= p
;
505 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
508 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
510 struct rfapi_vn_option
*p
;
511 struct rfapi_vn_option
*head
= NULL
;
512 struct rfapi_vn_option
*tail
= NULL
;
514 for (p
= existing
; p
; p
= p
->next
) {
515 struct rfapi_vn_option
*new;
517 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
518 sizeof(struct rfapi_vn_option
));
531 void rfapi_un_options_free(struct rfapi_un_option
*p
)
533 struct rfapi_un_option
*next
;
537 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
542 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
544 struct rfapi_vn_option
*next
;
548 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
553 /* Based on bgp_redistribute_add() */
554 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
555 struct bgp
*bgp
, int safi
, const struct prefix
*p
,
556 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
557 uint32_t *local_pref
,
558 uint32_t *lifetime
, /* NULL => dont send lifetime */
559 struct bgp_tea_options
*rfp_options
,
560 struct rfapi_un_option
*options_un
,
561 struct rfapi_vn_option
*options_vn
,
562 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
563 uint32_t *med
, /* NULL => don't set med */
564 uint32_t *label
, /* low order 3 bytes */
565 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
568 afi_t afi
; /* of the VN address */
569 struct bgp_path_info
*new;
570 struct bgp_path_info
*bpi
;
573 struct attr attr
= {0};
574 struct attr
*new_attr
;
577 struct bgp_attr_encap_subtlv
*encaptlv
;
578 char buf
[PREFIX_STRLEN
];
580 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
581 struct rfapi_vn_option
*vo
;
582 struct rfapi_l2address_option
*l2o
= NULL
;
583 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
585 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
586 struct bgp_redist
*red
;
588 if (safi
== SAFI_ENCAP
589 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
592 * Encap mode not enabled. UN addresses will be communicated
593 * via VNC Tunnel subtlv instead.
595 vnc_zlog_debug_verbose(
596 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
601 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
602 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
604 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
605 l2o
= NULL
; /* not MAC resolution */
607 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
608 lnh
= &vo
->v
.local_nexthop
;
615 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
617 afi
= family2afi(p
->family
);
618 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
620 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
623 /* Make default attribute. Produces already-interned attr.aspath */
624 /* Cripes, the memory management of attributes is byzantine */
626 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_INCOMPLETE
);
631 * extra: dynamically allocated, owned by attr
632 * aspath: points to interned hash from aspath hash table
637 * Route-specific un_options get added to the VPN SAFI
638 * advertisement tunnel encap attribute. (the per-NVE
639 * "default" un_options are put into the 1-per-NVE ENCAP
640 * SAFI advertisement). The VPN SAFI also gets the
641 * default un_options if there are no route-specific options.
644 struct rfapi_un_option
*uo
;
646 for (uo
= options_un
; uo
; uo
= uo
->next
) {
647 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
648 TunnelType
= rfapi_tunneltype_option_to_tlv(
649 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
656 * These are the NVE-specific "default" un_options which are
657 * put into the 1-per-NVE ENCAP advertisement.
659 if (rfd
->default_tunneltype_option
.type
) {
660 TunnelType
= rfapi_tunneltype_option_to_tlv(
661 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
663 } else /* create default for local addse */
664 if (type
== ZEBRA_ROUTE_BGP
665 && sub_type
== BGP_ROUTE_RFP
)
666 TunnelType
= rfapi_tunneltype_option_to_tlv(
667 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
670 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
671 if (safi
== SAFI_ENCAP
) {
672 /* Encap SAFI not used with MPLS */
673 vnc_zlog_debug_verbose(
674 "%s: mpls tunnel type, encap safi omitted",
676 aspath_unintern(&attr
.aspath
); /* Unintern original. */
682 attr
.local_pref
= *local_pref
;
683 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
688 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
691 /* override default weight assigned by bgp_attr_default_set() */
692 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
695 * NB: ticket 81: do not reset attr.aspath here because it would
696 * cause iBGP peers to drop route
700 * Set originator ID for routes imported from BGP directly.
701 * These routes could be synthetic, and therefore could
702 * reuse the peer pointers of the routes they are derived
703 * from. Setting the originator ID to "us" prevents the
704 * wrong originator ID from being sent when this route is
705 * sent from a route reflector.
707 if (type
== ZEBRA_ROUTE_BGP_DIRECT
708 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
709 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
710 attr
.originator_id
= bgp
->router_id
;
714 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
715 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
718 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
719 sizeof(struct bgp_attr_encap_subtlv
) + 4);
721 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
722 encaptlv
->length
= 4;
723 lt
= htonl(*lifetime
);
724 memcpy(encaptlv
->value
, <
, 4);
725 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
726 vnc_zlog_debug_verbose(
727 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
731 /* add rfp options to vnc attr */
734 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
735 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
736 bgp_attr_get_vnc_subtlvs(&attr
);
738 * this flag means we're passing a pointer to an
739 * existing encap tlv chain which we should copy.
740 * It's a hack to avoid adding yet another argument
743 encaptlv
= encap_tlv_dup(
744 (struct bgp_attr_encap_subtlv
*)rfp_options
);
746 vnc_subtlvs
->next
= encaptlv
;
748 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
750 struct bgp_tea_options
*hop
;
751 /* XXX max of one tlv present so far from above code */
752 struct bgp_attr_encap_subtlv
*tail
=
753 bgp_attr_get_vnc_subtlvs(&attr
);
755 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
762 sizeof(struct bgp_attr_encap_subtlv
) + 2
765 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
768 encaptlv
->length
= 2 + hop
->length
;
769 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
770 *((uint8_t *)(encaptlv
->value
) + 1) =
772 memcpy(((uint8_t *)encaptlv
->value
) + 2,
773 hop
->value
, hop
->length
);
776 * add to end of subtlv chain
779 tail
->next
= encaptlv
;
781 bgp_attr_set_vnc_subtlvs(&attr
,
791 * extra: dynamically allocated, owned by attr
792 * vnc_subtlvs: dynamic chain, length 1
793 * aspath: points to interned hash from aspath hash table
797 bgp_attr_set_ecommunity(&attr
, ecommunity_new());
798 assert(bgp_attr_get_ecommunity(&attr
));
800 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
801 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
803 * Add BGP Encapsulation Extended Community. Format described in
804 * section 4.5 of RFC 5512.
805 * Always include when not MPLS type, to disambiguate this case.
807 struct ecommunity_val beec
;
809 memset(&beec
, 0, sizeof(beec
));
810 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
811 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
812 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
813 beec
.val
[7] = (TunnelType
)&0xff;
814 ecommunity_add_val(bgp_attr_get_ecommunity(&attr
), &beec
, false,
819 * Add extended community attributes to match rt export list
821 if (rt_export_list
) {
822 bgp_attr_set_ecommunity(
823 &attr
, ecommunity_merge(bgp_attr_get_ecommunity(&attr
),
827 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(&attr
);
830 ecommunity_free(&ecomm
);
831 bgp_attr_set_ecommunity(&attr
, NULL
);
833 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
, ecomm
);
839 * extra: dynamically allocated, owned by attr
840 * vnc_subtlvs: dynamic chain, length 1
841 * ecommunity: dynamic 2-part
842 * aspath: points to interned hash from aspath hash table
845 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
846 switch (nexthop
->addr_family
) {
849 * set this field to prevent bgp_route.c code from setting
850 * mp_nexthop_global_in to self
852 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
854 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
855 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
859 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
860 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV6_GLOBAL
;
868 prefix2str(p
, buf
, sizeof(buf
));
874 * extra: dynamically allocated, owned by attr
875 * vnc_subtlvs: dynamic chain, length 1
876 * ecommunity: dynamic 2-part
877 * aspath: points to interned hash from aspath hash table
880 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
882 if (red
&& red
->redist_metric_flag
) {
883 attr
.med
= red
->redist_metric
;
884 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
887 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
890 * bgp_attr_intern creates a new reference to a cached
891 * attribute, but leaves the following bits of trash:
893 * - old attr->extra (free via bgp_attr_extra_free(attr))
895 * Note that it frees the original attr->extra->ecommunity
896 * but leaves the new attribute pointing to the ORIGINAL
897 * vnc options (which therefore we needn't free from the
900 new_attr
= bgp_attr_intern(&attr
);
902 aspath_unintern(&attr
.aspath
); /* Unintern original. */
908 * extra: dynamically allocated, owned by attr
909 * vnc_subtlvs: dynamic chain, length 1
910 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
912 * new_attr: an attr that is part of the hash table, distinct
913 * from attr which is static.
914 * extra: dynamically allocated, owned by new_attr (in hash table)
915 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
916 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
917 * aspath: POINTS TO interned/refcounted hashed block
919 for (bpi
= bgp_dest_get_bgp_path_info(bn
); bpi
; bpi
= bpi
->next
) {
920 /* probably only need to check
921 * bpi->extra->vnc.export.rfapi_handle */
922 if (bpi
->peer
== rfd
->peer
&& bpi
->type
== type
923 && bpi
->sub_type
== sub_type
&& bpi
->extra
924 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
933 * Adding new local_nexthop, which does not by itself change
934 * what is advertised via BGP
937 if (!bpi
->extra
->vnc
.export
.local_nexthops
) {
938 /* TBD make arrangements to free when needed */
939 bpi
->extra
->vnc
.export
.local_nexthops
=
941 bpi
->extra
->vnc
.export
.local_nexthops
->del
=
948 struct listnode
*node
;
949 struct rfapi_nexthop
*pLnh
= NULL
;
951 for (ALL_LIST_ELEMENTS_RO(
952 bpi
->extra
->vnc
.export
.local_nexthops
,
955 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
961 * Not present, add new one
964 pLnh
= rfapi_nexthop_new(lnh
);
966 bpi
->extra
->vnc
.export
.local_nexthops
,
971 if (attrhash_cmp(bpi
->attr
, new_attr
)
972 && !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
973 bgp_attr_unintern(&new_attr
);
974 bgp_dest_unlock_node(bn
);
977 "%s: Found route (safi=%d) at prefix %s, no change",
978 __func__
, safi
, buf
);
982 /* The attribute is changed. */
983 bgp_path_info_set_flag(bn
, bpi
, BGP_PATH_ATTR_CHANGED
);
985 if (safi
== SAFI_MPLS_VPN
) {
986 struct bgp_dest
*pdest
= NULL
;
987 struct bgp_table
*table
= NULL
;
989 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
990 (struct prefix
*)prd
);
991 table
= bgp_dest_get_bgp_table_info(pdest
);
993 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
994 bgp
, prd
, table
, p
, bpi
);
995 bgp_dest_unlock_node(pdest
);
998 /* Rewrite BGP route information. */
999 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
1000 bgp_path_info_restore(bn
, bpi
);
1002 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
1003 bgp_attr_unintern(&bpi
->attr
);
1004 bpi
->attr
= new_attr
;
1005 bpi
->uptime
= monotime(NULL
);
1008 if (safi
== SAFI_MPLS_VPN
) {
1009 struct bgp_dest
*pdest
= NULL
;
1010 struct bgp_table
*table
= NULL
;
1012 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
1013 (struct prefix
*)prd
);
1014 table
= bgp_dest_get_bgp_table_info(pdest
);
1016 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1017 bgp
, prd
, table
, p
, bpi
);
1018 bgp_dest_unlock_node(pdest
);
1021 /* Process change. */
1022 bgp_aggregate_increment(bgp
, p
, bpi
, afi
, safi
);
1023 bgp_process(bgp
, bn
, afi
, safi
);
1024 bgp_dest_unlock_node(bn
);
1027 "%s: Found route (safi=%d) at prefix %s, changed attr",
1028 __func__
, safi
, buf
);
1034 new = info_make(type
, sub_type
, 0, rfd
->peer
, new_attr
, NULL
);
1035 SET_FLAG(new->flags
, BGP_PATH_VALID
);
1037 /* save backref to rfapi handle */
1038 bgp_path_info_extra_get(new);
1039 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1040 encode_label(label_val
, &new->extra
->label
[0]);
1044 if (VNC_DEBUG(VERBOSE
)) {
1045 vnc_zlog_debug_verbose("%s: printing BPI", __func__
);
1046 rfapiPrintBi(NULL
, new);
1049 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1050 bgp_path_info_add(bn
, new);
1052 if (safi
== SAFI_MPLS_VPN
) {
1053 struct bgp_dest
*pdest
= NULL
;
1054 struct bgp_table
*table
= NULL
;
1056 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1057 table
= bgp_dest_get_bgp_table_info(pdest
);
1059 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1060 bgp
, prd
, table
, p
, new);
1061 bgp_dest_unlock_node(pdest
);
1062 encode_label(label_val
, &bn
->local_label
);
1065 bgp_dest_unlock_node(bn
);
1066 bgp_process(bgp
, bn
, afi
, safi
);
1069 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRD)",
1070 __func__
, safi2str(safi
), buf
, bn
, prd
);
1073 /* Loop back to import tables */
1074 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1075 sub_type
, &label_val
);
1076 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1080 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1085 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1086 struct rfapi_descriptor
*rfd
,
1087 uint32_t *pLifetime
)
1089 struct prefix_rd prd
;
1090 struct prefix pfx_vn
;
1092 uint32_t local_pref
= rfp_cost_to_localpref(0);
1094 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1098 * Construct route distinguisher = 0
1100 memset(&prd
, 0, sizeof(prd
));
1101 prd
.family
= AF_UNSPEC
;
1104 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1105 bgp
, /* which bgp instance */
1106 SAFI_ENCAP
, /* which SAFI */
1107 &pfx_vn
, /* prefix to advertise */
1108 &prd
, /* route distinguisher to use */
1109 &rfd
->un_addr
, /* nexthop */
1111 pLifetime
, /* max lifetime of child VPN routes */
1112 NULL
, /* no rfp options for ENCAP safi */
1113 NULL
, /* rfp un options */
1114 NULL
, /* rfp vn options */
1115 rfd
->rt_export_list
, NULL
, /* med */
1116 NULL
, /* label: default */
1117 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1121 /***********************************************************************
1122 * RFP processing behavior configuration
1123 ***********************************************************************/
1125 /*------------------------------------------
1126 * rfapi_rfp_set_configuration
1128 * This is used to change rfapi's processing behavior based on
1132 * rfp_start_val value returned by rfp_start
1133 * rfapi_rfp_cfg Pointer to configuration structure
1140 * ENXIO Unabled to locate configured BGP/VNC
1141 --------------------------------------------*/
1142 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1144 struct rfapi_rfp_cfg
*rcfg
;
1147 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1149 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1152 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1153 rcfg
->download_type
= new->download_type
;
1154 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1155 rcfg
->holddown_factor
= new->holddown_factor
;
1157 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1158 rcfg
->use_updated_response
= new->use_updated_response
;
1159 if (rcfg
->use_updated_response
)
1160 rfapiMonitorCallbacksOn(bgp
);
1162 rfapiMonitorCallbacksOff(bgp
);
1164 if (rcfg
->use_removes
!= new->use_removes
) {
1165 rcfg
->use_removes
= new->use_removes
;
1166 if (rcfg
->use_removes
)
1167 rfapiMonitorResponseRemovalOn(bgp
);
1169 rfapiMonitorResponseRemovalOff(bgp
);
1174 /*------------------------------------------
1175 * rfapi_rfp_set_cb_methods
1177 * Change registered callback functions for asynchronous notifications
1178 * from RFAPI to the RFP client.
1181 * rfp_start_val value returned by rfp_start
1182 * methods Pointer to struct rfapi_rfp_cb_methods containing
1183 * pointers to callback methods as described above
1187 * ENXIO BGP or VNC not configured
1188 *------------------------------------------*/
1189 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1190 struct rfapi_rfp_cb_methods
*methods
)
1195 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1203 h
->rfp_methods
= *methods
;
1208 /***********************************************************************
1210 ***********************************************************************/
1212 * Caller must supply an already-allocated rfd with the "caller"
1213 * fields already set (vn_addr, un_addr, callback, cookie)
1214 * The advertised_prefixes[] array elements should be NULL to
1215 * have this function set them to newly-allocated radix trees.
1217 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1218 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1222 if (h
->flags
& RFAPI_INCALLBACK
)
1226 * Fill in configured fields
1230 * If group's RD is specified as "auto", then fill in based
1231 * on NVE's VN address
1235 if (rfd
->rd
.family
== AF_UNIX
) {
1236 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1240 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1241 ? ecommunity_dup(rfg
->rt_export_list
)
1243 rfd
->response_lifetime
= rfg
->response_lifetime
;
1247 * Fill in BGP peer structure
1249 rfd
->peer
= peer_new(bgp
);
1250 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1251 bgp_sync_delete(rfd
->peer
); /* don't need these */
1254 * since this peer is not on the I/O thread, this lock is not strictly
1255 * necessary, but serves as a reminder to those who may meddle...
1257 frr_with_mutex (&rfd
->peer
->io_mtx
) {
1258 // we don't need any I/O related facilities
1259 if (rfd
->peer
->ibuf
)
1260 stream_fifo_free(rfd
->peer
->ibuf
);
1261 if (rfd
->peer
->obuf
)
1262 stream_fifo_free(rfd
->peer
->obuf
);
1264 if (rfd
->peer
->ibuf_work
)
1265 ringbuf_del(rfd
->peer
->ibuf_work
);
1266 if (rfd
->peer
->obuf_work
)
1267 stream_free(rfd
->peer
->obuf_work
);
1269 rfd
->peer
->ibuf
= NULL
;
1270 rfd
->peer
->obuf
= NULL
;
1271 rfd
->peer
->obuf_work
= NULL
;
1272 rfd
->peer
->ibuf_work
= NULL
;
1275 { /* base code assumes have valid host pointer */
1276 char buf
[INET6_ADDRSTRLEN
];
1279 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1280 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
,
1282 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1283 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
,
1286 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1288 /* Mark peer as belonging to HD */
1289 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1292 * Set min prefix lifetime to max value so it will get set
1293 * upon first rfapi_register()
1295 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1298 * Allocate response tables if needed
1300 #define RFD_RTINIT_AFI(rh, ary, afi) \
1303 ary[afi] = agg_table_init(); \
1304 agg_set_table_info(ary[afi], rh); \
1308 #define RFD_RTINIT(rh, ary) \
1310 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1311 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1312 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1315 RFD_RTINIT(rfd
, rfd
->rib
);
1316 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1317 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1320 * Link to Import Table
1322 rfd
->import_table
= rfg
->rfapi_import_table
;
1323 rfd
->import_table
->refcount
+= 1;
1325 rfapiApInit(&rfd
->advertised
);
1328 * add this NVE descriptor to the list of NVEs in the NVE group
1331 rfg
->nves
= list_new();
1333 listnode_add(rfg
->nves
, rfd
);
1335 vnc_direct_bgp_add_nve(bgp
, rfd
);
1336 vnc_zebra_add_nve(bgp
, rfd
);
1341 /* moved from rfapi_register */
1342 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1343 struct rfapi_nve_group_cfg
*rfg
)
1345 struct rfapi
*h
= bgp
->rfapi
;
1346 char buf_vn
[BUFSIZ
];
1347 char buf_un
[BUFSIZ
];
1348 afi_t afi_vn
, afi_un
;
1349 struct prefix pfx_un
;
1350 struct agg_node
*rn
;
1352 rfd
->open_time
= monotime(NULL
);
1354 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1355 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1357 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1358 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1360 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1361 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1363 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1365 listnode_add(&h
->descriptors
, rfd
);
1366 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1367 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1371 * attach to UN radix tree
1373 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1374 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1375 assert(afi_vn
&& afi_un
);
1376 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1378 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1380 rfd
->next
= rn
->info
;
1384 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1387 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1389 struct rfapi_vn_option
*head
= NULL
;
1390 struct rfapi_vn_option
*tail
= NULL
;
1391 struct rfapi_vn_option
*vo
= NULL
;
1393 for (vo
= orig
; vo
; vo
= vo
->next
) {
1394 struct rfapi_vn_option
*new;
1396 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1397 sizeof(struct rfapi_vn_option
));
1398 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1410 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1412 struct rfapi_un_option
*head
= NULL
;
1413 struct rfapi_un_option
*tail
= NULL
;
1414 struct rfapi_un_option
*uo
= NULL
;
1416 for (uo
= orig
; uo
; uo
= uo
->next
) {
1417 struct rfapi_un_option
*new;
1419 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1420 sizeof(struct rfapi_un_option
));
1421 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1433 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1435 struct bgp_tea_options
*head
= NULL
;
1436 struct bgp_tea_options
*tail
= NULL
;
1437 struct bgp_tea_options
*hop
= NULL
;
1439 for (hop
= orig
; hop
; hop
= hop
->next
) {
1440 struct bgp_tea_options
*new;
1442 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1443 sizeof(struct bgp_tea_options
));
1444 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1447 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1449 memcpy(new->value
, hop
->value
, hop
->length
);
1460 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1462 struct bgp_tea_options
*next
;
1467 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1468 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1474 void rfapiAdbFree(struct rfapi_adb
*adb
)
1476 XFREE(MTYPE_RFAPI_ADB
, adb
);
1480 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1481 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1482 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1486 struct prefix p_original
;
1487 struct agg_node
*rn
;
1488 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1489 struct bgp
*bgp
= rfd
->bgp
;
1490 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1491 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1493 int use_eth_resolution
= 0;
1494 struct rfapi_next_hop_entry
*i_nhe
;
1498 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1503 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1507 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1508 vnc_zlog_debug_verbose(
1509 "%s: Called during calback, returning EDEADLK",
1514 if (!is_valid_rfd(rfd
)) {
1515 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1520 rfd
->rsp_counter
++; /* dedup: identify this generation */
1521 rfd
->rsp_time
= monotime(NULL
); /* response content dedup */
1522 rfd
->ftd_last_allowed_time
=
1524 bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1527 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1531 /* per t/c Paul/Lou 151022 */
1532 if (!eth_is_0
|| l2o
->logical_net_id
) {
1533 use_eth_resolution
= 1;
1538 *ppNextHopEntry
= NULL
;
1541 * Save original target in prefix form. In case of L2-based queries,
1542 * p_original will be modified to reflect the L2 target
1544 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1546 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1547 /* convert query to 0/0 when full-table download is enabled */
1548 memset((char *)&p
, 0, sizeof(p
));
1549 p
.family
= target
->addr_family
;
1557 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1558 __func__
, rfd
, &p
, ppNextHopEntry
);
1560 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1561 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1562 vnc_zlog_debug_verbose(
1563 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1564 __func__
, rfd
->import_table
, s
);
1565 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1568 afi
= family2afi(p
.family
);
1571 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1572 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1573 self_vn_addr
= &rfd
->vn_addr
;
1576 if (use_eth_resolution
) {
1577 uint32_t logical_net_id
= l2o
->logical_net_id
;
1578 struct ecommunity
*l2com
;
1581 * fix up p_original to contain L2 address
1583 rfapiL2o2Qprefix(l2o
, &p_original
);
1585 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1586 bgp
, 1, logical_net_id
, l2o
->label
);
1588 uint8_t *v
= l2com
->val
;
1589 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1592 * Ethernet/L2-based lookup
1594 * Always returns IT node corresponding to route
1597 if (RFAPI_RFP_DOWNLOAD_FULL
1598 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1602 rn
= rfapiMonitorEthAdd(
1603 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1607 struct rfapi_ip_prefix rprefix
;
1609 memset(&rprefix
, 0, sizeof(rprefix
));
1610 rprefix
.prefix
.addr_family
= target
->addr_family
;
1611 if (target
->addr_family
== AF_INET
) {
1612 rprefix
.length
= IPV4_MAX_BITLEN
;
1614 rprefix
.length
= IPV6_MAX_BITLEN
;
1617 pNHE
= rfapiEthRouteTable2NextHopList(
1618 logical_net_id
, &rprefix
,
1619 rfd
->response_lifetime
, self_vn_addr
,
1620 rfd
->rib
[afi
], &p_original
);
1630 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1633 * If target address is 0, this request is special: means to
1634 * return ALL routes in the table
1636 * Monitors for All-Routes queries get put on a special list,
1637 * not in the VPN tree
1639 if (RFAPI_0_PREFIX(&p
)) {
1641 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1644 * Generate nexthop list for caller
1646 pNHE
= rfapiRouteTable2NextHopList(
1647 rfd
->import_table
->imported_vpn
[afi
],
1648 rfd
->response_lifetime
, self_vn_addr
,
1649 rfd
->rib
[afi
], &p_original
);
1654 agg_lock_node(rn
); /* so we can unlock below */
1657 * returns locked node. Don't unlock yet because the
1659 * might free it before we're done with it. This
1661 * could occur when rfapiMonitorGetAttachNode() returns
1663 * newly-created default node.
1665 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1671 agg_unlock_node(rn
);
1672 vnc_zlog_debug_verbose(
1673 "%s: VPN route not found, returning ENOENT", __func__
);
1677 if (VNC_DEBUG(RFAPI_QUERY
)) {
1678 rfapiShowImportTable(NULL
, "query",
1679 rfd
->import_table
->imported_vpn
[afi
], 1);
1682 if (use_eth_resolution
) {
1684 struct rfapi_ip_prefix rprefix
;
1686 memset(&rprefix
, 0, sizeof(rprefix
));
1687 rprefix
.prefix
.addr_family
= target
->addr_family
;
1688 if (target
->addr_family
== AF_INET
) {
1689 rprefix
.length
= IPV4_MAX_BITLEN
;
1691 rprefix
.length
= IPV6_MAX_BITLEN
;
1694 pNHE
= rfapiEthRouteNode2NextHopList(
1695 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1696 rfd
->rib
[afi
], &p_original
);
1701 * Generate answer to query
1703 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1704 self_vn_addr
, rfd
->rib
[afi
],
1708 agg_unlock_node(rn
);
1711 if (ppNextHopEntry
) {
1712 /* only count if caller gets it */
1713 ++bgp
->rfapi
->response_immediate_count
;
1717 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1723 * count nexthops for statistics
1725 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1726 ++rfd
->stat_count_nh_reachable
;
1729 if (ppNextHopEntry
) {
1730 *ppNextHopEntry
= pNHE
;
1732 rfapi_free_next_hop_list(pNHE
);
1735 vnc_zlog_debug_verbose("%s: success", __func__
);
1740 * support on-the-fly reassignment of an already-open nve to a new
1741 * nve-group in the event that its original nve-group is
1742 * administratively deleted.
1744 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1746 struct prefix pfx_vn
;
1747 struct prefix pfx_un
;
1748 struct rfapi_nve_group_cfg
*rfg
;
1750 struct rfapi_cfg
*hc
;
1757 hc
= bgp
->rfapi_cfg
;
1761 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1764 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1768 * Find the matching nve group config block
1770 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1776 * check nve group config block for required values
1778 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1783 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1789 * re-advertise registered routes, this time as part of new NVE-group
1791 rfapiApReadvertiseAll(bgp
, rfd
);
1794 * re-attach callbacks to import table
1796 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1797 rfapiMonitorAttachImportHd(rfd
);
1803 /*------------------------------------------
1806 * This function initializes a NVE record and associates it with
1807 * the specified VN and underlay network addresses
1810 * rfp_start_val value returned by rfp_start
1811 * vn NVE virtual network address
1813 * un NVE underlay network address
1815 * default_options Default options to use on registrations.
1816 * For now only tunnel type is supported.
1817 * May be overridden per-prefix in rfapi_register().
1818 * Caller owns (rfapi_open() does not free)
1820 * response_cb Pointer to next hop list update callback function or
1821 * NULL when no callbacks are desired.
1823 * userdata Passed to subsequent response_cb invocations.
1826 * response_lifetime The length of time that responses sent to this
1829 * pHandle pointer to location to store rfapi handle. The
1830 * handle must be passed on subsequent rfapi_ calls.
1835 * EEXIST NVE with this {vn,un} already open
1836 * ENOENT No matching nve group config
1837 * ENOMSG Matched nve group config was incomplete
1838 * ENXIO BGP or VNC not configured
1839 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1840 * but underlay network address is not IPv4
1841 * EDEADLK Called from within a callback procedure
1842 *------------------------------------------*/
1843 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1844 struct rfapi_ip_addr
*un
,
1845 struct rfapi_un_option
*default_options
,
1846 uint32_t *response_lifetime
,
1847 void *userdata
, /* callback cookie */
1848 rfapi_handle
*pHandle
)
1852 struct rfapi_descriptor
*rfd
;
1853 struct rfapi_cfg
*hc
;
1854 struct rfapi_nve_group_cfg
*rfg
;
1856 struct prefix pfx_vn
;
1857 struct prefix pfx_un
;
1860 rfapi_handle hh
= NULL
;
1861 int reusing_provisional
= 0;
1864 char buf
[2][INET_ADDRSTRLEN
];
1865 vnc_zlog_debug_verbose(
1866 "%s: VN=%s UN=%s", __func__
,
1867 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1868 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1874 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1882 hc
= bgp
->rfapi_cfg
;
1886 if (h
->flags
& RFAPI_INCALLBACK
)
1889 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1892 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1896 * already have a descriptor with VN and UN?
1898 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1900 * we might have set up a handle for static routes before
1901 * this NVE was opened. In that case, reuse the handle
1904 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1909 * reuse provisional descriptor
1912 reusing_provisional
= 1;
1916 * Find the matching nve group config block
1918 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1920 ++h
->stat
.count_unknown_nves
;
1922 char buf
[2][INET_ADDRSTRLEN
];
1923 zlog_notice("%s: no matching group VN=%s UN=%s",
1925 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1927 rfapiRfapiIpAddr2Str(un
, buf
[1],
1934 * check nve group config block for required values
1936 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1938 ++h
->stat
.count_unknown_nves
;
1943 * If group config specifies auto-rd assignment, check that
1944 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1945 * Check here so we don't need to unwind memory allocations, &c.
1947 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1948 && (vn
->addr_family
!= AF_INET6
)) {
1949 return EAFNOSUPPORT
;
1954 * reusing provisional rfd
1958 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1959 sizeof(struct rfapi_descriptor
));
1963 if (default_options
) {
1964 struct rfapi_un_option
*p
;
1966 for (p
= default_options
; p
; p
= p
->next
) {
1967 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1968 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1970 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1971 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1977 * Fill in caller fields
1981 rfd
->cookie
= userdata
;
1983 if (!reusing_provisional
) {
1984 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1986 * This can fail only if the VN address is IPv6 and the group
1987 * specified auto-assignment of RDs, which only works for v4,
1988 * and the check above should catch it.
1990 * Another failure possibility is that we were called
1991 * during an rfapi callback. Also checked above.
1996 if (response_lifetime
)
1997 *response_lifetime
= rfd
->response_lifetime
;
2003 * For use with debug functions
2005 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2006 rfapi_response_cb_t
*response_cb
)
2008 if (!is_valid_rfd(rfd
))
2010 rfd
->response_cb
= response_cb
;
2017 * Does almost all the work of rfapi_close, except:
2018 * 1. preserves the descriptor (doesn't free it)
2019 * 2. preserves the prefix query list (i.e., rfd->mon list)
2020 * 3. preserves the advertised prefix list (rfd->advertised)
2021 * 4. preserves the rib and rib_pending tables
2023 * The purpose of organizing it this way is to support on-the-fly
2024 * reassignment of an already-open nve to a new nve-group in the
2025 * event that its original nve-group is administratively deleted.
2027 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2030 struct prefix pfx_vn
;
2031 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2033 if (!is_valid_rfd(rfd
))
2036 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2037 assert(!rc
); /* should never have bad AF in stored vn address */
2040 * update exported routes to reflect disappearance of this NVE as
2043 vnc_direct_bgp_del_nve(bgp
, rfd
);
2044 vnc_zebra_del_nve(bgp
, rfd
);
2047 * unlink this HD's monitors from import table
2049 rfapiMonitorDetachImportHd(rfd
);
2052 * Unlink from Import Table
2053 * NB rfd->import_table will be NULL if we are closing a stale
2056 if (rfd
->import_table
)
2057 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2058 rfd
->import_table
= NULL
;
2061 * Construct route distinguisher
2063 memset(&prd
, 0, sizeof(prd
));
2065 prd
.family
= AF_UNSPEC
;
2071 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2072 &pfx_vn
, /* prefix being advertised */
2073 &prd
, /* route distinguisher to use (0 for ENCAP) */
2074 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2077 * Construct route distinguisher for VPN routes
2080 prd
.family
= AF_UNSPEC
;
2084 * find all VPN routes associated with this rfd and delete them, too
2086 rfapiApWithdrawAll(bgp
, rfd
);
2089 * remove this nve descriptor from the list of nves
2090 * associated with the nve group
2093 listnode_delete(rfd
->rfg
->nves
, rfd
);
2094 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2097 if (rfd
->rt_export_list
)
2098 ecommunity_free(&rfd
->rt_export_list
);
2099 rfd
->rt_export_list
= NULL
;
2102 * free peer structure (possibly delayed until its
2103 * refcount reaches zero)
2106 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2107 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2108 peer_delete(rfd
->peer
);
2115 int rfapi_close(void *handle
)
2117 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2119 struct agg_node
*node
;
2123 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2125 #ifdef RFAPI_WHO_IS_CALLING_ME
2126 #ifdef HAVE_GLIBC_BACKTRACE
2127 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2129 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2134 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2135 syms
= backtrace_symbols(buf
, size
);
2136 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2138 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2154 if (!is_valid_rfd(rfd
))
2157 if (h
->flags
& RFAPI_INCALLBACK
) {
2159 * Queue these close requests for processing after callback
2162 if (!CHECK_FLAG(rfd
->flags
,
2163 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2164 work_queue_add(h
->deferred_close_q
, handle
);
2165 vnc_zlog_debug_verbose(
2166 "%s: added handle %p to deferred close queue",
2172 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2174 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2177 if (h
->rfp_methods
.close_cb
) {
2178 vnc_zlog_debug_verbose(
2179 "%s calling close callback rfd=%p", __func__
,
2183 * call the callback fairly early so that it can still
2187 * NB RFAPI_INCALLBACK is tested above, so if we reach
2189 * we are not already in the context of a callback.
2191 h
->flags
|= RFAPI_INCALLBACK
;
2192 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2193 h
->flags
&= ~RFAPI_INCALLBACK
;
2199 * Orphaned descriptors have already done this part, so do
2200 * only for non-orphaned descriptors.
2202 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2207 * Remove descriptor from UN index
2208 * (remove from chain at node)
2210 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2212 struct rfapi_descriptor
*hh
;
2214 if (node
->info
== rfd
) {
2215 node
->info
= rfd
->next
;
2218 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2219 if (hh
->next
== rfd
) {
2220 hh
->next
= rfd
->next
;
2225 agg_unlock_node(node
);
2229 * remove from descriptor list
2231 listnode_delete(&h
->descriptors
, rfd
);
2234 * Delete monitor list items and free monitor structures
2236 (void)rfapiMonitorDelHd(rfd
);
2239 * release advertised prefix data
2241 rfapiApRelease(&rfd
->advertised
);
2244 * Release RFP callback RIB
2251 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2252 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2258 * Reopen a nve descriptor. If the descriptor's NVE-group
2259 * does not exist (e.g., if it has been administratively removed),
2260 * reassignment to a new NVE-group is attempted.
2262 * If NVE-group reassignment fails, the descriptor becomes "stale"
2263 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2264 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2265 * on the descriptor will return ESTALE.
2267 * Reopening a descriptor is a potentially expensive operation, because
2268 * it involves withdrawing any routes advertised by the NVE, withdrawing
2269 * the NVE's route queries, and then re-adding them all after a new
2270 * NVE-group is assigned. There are also possible route-export affects
2271 * caused by deleting and then adding the NVE: advertised prefixes
2272 * and nexthop lists for exported routes can turn over.
2274 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2279 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2282 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2286 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2288 if (CHECK_FLAG(rfd
->flags
,
2289 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2290 && h
&& h
->rfp_methods
.close_cb
) {
2293 * NB RFAPI_INCALLBACK is tested above, so if we reach
2295 * we are not already in the context of a callback.
2297 h
->flags
|= RFAPI_INCALLBACK
;
2298 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2299 h
->flags
&= ~RFAPI_INCALLBACK
;
2306 /***********************************************************************
2308 ***********************************************************************/
2310 * Announce reachability to this prefix via the NVE
2312 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2313 uint32_t lifetime
, /* host byte order */
2314 struct rfapi_un_option
*options_un
,
2315 struct rfapi_vn_option
*options_vn
,
2316 rfapi_register_action action
)
2318 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2321 struct prefix
*pfx_ip
= NULL
;
2322 struct prefix_rd prd
;
2324 struct prefix pfx_mac_buf
;
2325 struct prefix
*pfx_mac
= NULL
;
2326 struct prefix pfx_vn_buf
;
2327 const char *action_str
= NULL
;
2328 uint32_t *label
= NULL
;
2329 struct rfapi_vn_option
*vo
;
2330 struct rfapi_l2address_option
*l2o
= NULL
;
2331 struct prefix_rd
*prd_override
= NULL
;
2334 case RFAPI_REGISTER_ADD
:
2337 case RFAPI_REGISTER_WITHDRAW
:
2338 action_str
= "withdraw";
2340 case RFAPI_REGISTER_KILL
:
2341 action_str
= "kill";
2349 * Inspect VN options
2351 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2352 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2353 l2o
= &vo
->v
.l2addr
;
2355 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2356 prd_override
= &vo
->v
.internal_rd
;
2360 /*********************************************************************
2362 *********************************************************************/
2365 * set <p> based on <prefix>
2367 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2369 afi
= family2afi(prefix
->prefix
.addr_family
);
2372 vnc_zlog_debug_verbose(
2373 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2374 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2378 * These tests come after the prefix conversion so that we can
2379 * print the prefix in a debug message before failing
2384 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2389 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2394 if (RFAPI_REGISTER_ADD
== action
) {
2395 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2397 vnc_zlog_debug_verbose(
2398 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2403 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2404 if (RFAPI_REGISTER_ADD
== action
) {
2405 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2407 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2412 if (!is_valid_rfd(rfd
)) {
2413 if (RFAPI_REGISTER_ADD
== action
) {
2414 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2416 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2422 * Is there a MAC address in this registration?
2424 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2425 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2426 pfx_mac
= &pfx_mac_buf
;
2430 * Is there an IP prefix in this registration?
2432 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2436 vnc_zlog_debug_verbose(
2437 "%s: missing mac addr that is required for host 0 pfx",
2439 if (RFAPI_REGISTER_ADD
== action
) {
2440 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2444 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2445 vnc_zlog_debug_verbose(
2446 "%s: handle has bad vn_addr: returning EBADF",
2448 if (RFAPI_REGISTER_ADD
== action
) {
2449 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2455 if (RFAPI_REGISTER_ADD
== action
) {
2456 ++bgp
->rfapi
->stat
.count_registrations
;
2460 * Figure out if this registration is missing an IP address
2464 * In RFAPI, we use prefixes in family AF_LINK to store
2465 * the MAC addresses. These prefixes are used for the
2466 * list of advertised prefixes and in the RFAPI import
2469 * In BGP proper, we use the prefix matching the NVE's
2470 * VN address with a host prefix-length (i.e., 32 or 128).
2473 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2474 && RFAPI_HOST_PREFIX(&p
)) {
2476 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2477 pfx_mac
= &pfx_mac_buf
;
2481 * Construct route distinguisher
2484 prd
= *prd_override
;
2486 memset(&prd
, 0, sizeof(prd
));
2488 prd
.family
= AF_UNSPEC
;
2490 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2491 if (l2o
->local_nve_id
2492 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2494 * If Local NVE ID is specified in message, use
2496 * (if no local default configured, also use it
2499 prd
.val
[1] = l2o
->local_nve_id
;
2501 if (rfd
->rfg
->l2rd
) {
2503 * locally-configured literal value
2505 prd
.val
[1] = rfd
->rfg
->l2rd
;
2508 * 0 means auto:vn, which means use LSB
2511 if (rfd
->vn_addr
.addr_family
2514 *(((char *)&rfd
->vn_addr
2520 *(((char *)&rfd
->vn_addr
2527 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2530 prd
.family
= AF_UNSPEC
;
2536 if (action
== RFAPI_REGISTER_WITHDRAW
2537 || action
== RFAPI_REGISTER_KILL
) {
2542 * withdraw previous advertisement
2545 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2547 : &pfx_vn_buf
, /* prefix being advertised */
2548 &prd
, /* route distinguisher (0 for ENCAP) */
2549 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2550 action
== RFAPI_REGISTER_KILL
);
2552 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2555 rfapiTunnelRouteAnnounce(
2556 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2562 uint32_t local_pref
;
2563 struct ecommunity
*rtlist
= NULL
;
2564 struct ecommunity_val ecom_value
;
2566 if (!rfapiApCount(rfd
)) {
2568 * make sure we advertise tunnel route upon adding the
2574 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2575 prefix
->cost
, l2o
)) {
2579 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2582 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2584 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2585 &rfd
->max_prefix_lifetime
);
2588 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2590 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2592 if (l2o
&& l2o
->label
)
2593 label
= &l2o
->label
;
2596 struct ecommunity
*l2com
= NULL
;
2599 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2600 bgp
, 1, l2o
->logical_net_id
, *label
);
2603 rtlist
= ecommunity_dup(l2com
);
2606 * If mac address is set, add an RT based on the
2609 memset((char *)&ecom_value
, 0,
2610 sizeof(ecom_value
));
2611 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2613 (l2o
->logical_net_id
>> 16) & 0xff;
2615 (l2o
->logical_net_id
>> 8) & 0xff;
2617 (l2o
->logical_net_id
>> 0) & 0xff;
2618 rtlist
= ecommunity_new();
2619 ecommunity_add_val(rtlist
, &ecom_value
,
2624 uint16_t val
= l2o
->tag_id
;
2625 memset((char *)&ecom_value
, 0,
2626 sizeof(ecom_value
));
2627 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2628 if (as
> BGP_AS_MAX
) {
2630 ECOMMUNITY_ENCODE_AS4
;
2631 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2632 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2633 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2634 ecom_value
.val
[5] = as
& 0xff;
2637 ECOMMUNITY_ENCODE_AS
;
2638 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2639 ecom_value
.val
[3] = as
& 0xff;
2641 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2642 ecom_value
.val
[7] = val
& 0xff;
2644 rtlist
= ecommunity_new();
2645 ecommunity_add_val(rtlist
, &ecom_value
,
2651 * advertise prefix via tunnel endpoint
2654 rfd
, /* rfapi descr, for export list & backref */
2655 bgp
, /* which bgp instance */
2656 SAFI_MPLS_VPN
, /* which SAFI */
2658 : &pfx_vn_buf
), /* prefix being advertised */
2659 &prd
, /* route distinguisher to use (0 for ENCAP) */
2660 &rfd
->vn_addr
, /* nexthop */
2662 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2663 NULL
, options_un
, /* rfapi un options */
2664 options_vn
, /* rfapi vn options */
2665 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2666 label
, /* label: default */
2667 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2670 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2673 vnc_zlog_debug_verbose("%s: success", __func__
);
2677 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2678 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2679 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2681 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2682 struct bgp
*bgp
= rfd
->bgp
;
2685 assert(ppNextHopEntry
);
2686 *ppNextHopEntry
= NULL
;
2688 if (bgp
&& bgp
->rfapi
) {
2689 bgp
->rfapi
->stat
.count_queries
++;
2693 if (bgp
&& bgp
->rfapi
)
2694 ++bgp
->rfapi
->stat
.count_queries_failed
;
2698 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2699 if (bgp
&& bgp
->rfapi
)
2700 ++bgp
->rfapi
->stat
.count_queries_failed
;
2705 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2709 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2710 struct bgp
*bgp
= rfd
->bgp
;
2716 rc
= rfapiRaddr2Qprefix(target
, &p
);
2719 if (!is_valid_rfd(rfd
))
2723 if (!bgp
|| !bgp
->rfapi
)
2726 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2729 rfapiMonitorDel(bgp
, rfd
, &p
);
2734 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2736 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2737 struct bgp
*bgp
= rfd
->bgp
;
2744 if (!is_valid_rfd(rfd
))
2748 if (!bgp
|| !bgp
->rfapi
)
2751 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2754 num
= rfapiMonitorDelHd(rfd
);
2762 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2764 struct rfapi_next_hop_entry
*nh
;
2765 struct rfapi_next_hop_entry
*next
;
2767 for (nh
= list
; nh
; nh
= next
) {
2769 rfapi_un_options_free(nh
->un_options
);
2770 nh
->un_options
= NULL
;
2771 rfapi_vn_options_free(nh
->vn_options
);
2772 nh
->vn_options
= NULL
;
2773 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2778 * NULL handle => return total count across all nves
2780 uint32_t rfapi_monitor_count(void *handle
)
2782 struct bgp
*bgp
= bgp_get_default();
2786 struct rfapi_descriptor
*rfd
=
2787 (struct rfapi_descriptor
*)handle
;
2788 count
= rfd
->monitor_count
;
2791 if (!bgp
|| !bgp
->rfapi
)
2794 count
= bgp
->rfapi
->monitor_count
;
2800 /***********************************************************************
2802 ***********************************************************************/
2804 DEFUN (debug_rfapi_show_nves
,
2805 debug_rfapi_show_nves_cmd
,
2806 "debug rfapi-dev show nves",
2810 "NVE Information\n")
2812 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2817 debug_rfapi_show_nves_vn_un
,
2818 debug_rfapi_show_nves_vn_un_cmd
,
2819 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2824 "Specify virtual network\n"
2825 "Specify underlay network interface\n"
2831 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2832 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2833 return CMD_WARNING_CONFIG_FAILED
;
2835 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2836 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2837 return CMD_WARNING_CONFIG_FAILED
;
2840 if (argv
[4]->arg
[0] == 'u') {
2841 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2843 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2849 * Note: this function does not flush vty output, so if it is called
2850 * with a stream pointing to a vty, the user will have to type something
2851 * before the callback output shows up
2853 static void test_nexthops_callback(
2854 // struct rfapi_ip_addr *target,
2855 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2857 void *stream
= userdata
;
2859 int (*fp
)(void *, const char *, ...);
2862 const char *vty_newline
;
2864 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2867 fp(out
, "Nexthops Callback, Target=(");
2868 // rfapiPrintRfapiIpAddr(stream, target);
2871 rfapiPrintNhl(stream
, next_hops
);
2875 rfapi_free_next_hop_list(next_hops
);
2878 DEFUN (debug_rfapi_open
,
2879 debug_rfapi_open_cmd
,
2880 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2884 "indicate vn addr follows\n"
2885 "virtual network interface IPv4 address\n"
2886 "virtual network interface IPv6 address\n"
2887 "indicate xt addr follows\n"
2888 "underlay network interface IPv4 address\n"
2889 "underlay network interface IPv6 address\n")
2891 struct rfapi_ip_addr vn
;
2892 struct rfapi_ip_addr un
;
2893 uint32_t lifetime
= 0;
2895 rfapi_handle handle
;
2900 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2906 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2909 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2910 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2912 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2915 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2917 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2923 DEFUN (debug_rfapi_close_vn_un
,
2924 debug_rfapi_close_vn_un_cmd
,
2925 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2929 "indicate vn addr follows\n"
2930 "virtual network interface IPv4 address\n"
2931 "virtual network interface IPv6 address\n"
2932 "indicate xt addr follows\n"
2933 "underlay network interface IPv4 address\n"
2934 "underlay network interface IPv6 address\n")
2936 struct rfapi_ip_addr vn
;
2937 struct rfapi_ip_addr un
;
2938 rfapi_handle handle
;
2944 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2951 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2955 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2956 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2957 argv
[4]->arg
, argv
[6]->arg
);
2958 return CMD_WARNING_CONFIG_FAILED
;
2961 rc
= rfapi_close(handle
);
2963 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2968 DEFUN (debug_rfapi_close_rfd
,
2969 debug_rfapi_close_rfd_cmd
,
2970 "debug rfapi-dev close rfd HANDLE",
2974 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2976 rfapi_handle handle
;
2978 char *endptr
= NULL
;
2980 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2982 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2983 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2984 return CMD_WARNING_CONFIG_FAILED
;
2987 rc
= rfapi_close(handle
);
2989 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2994 DEFUN (debug_rfapi_register_vn_un
,
2995 debug_rfapi_register_vn_un_cmd
,
2996 "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)]",
3000 "indicate vn addr follows\n"
3001 "virtual network IPv4 interface address\n"
3002 "virtual network IPv6 interface address\n"
3003 "indicate un addr follows\n"
3004 "underlay network IPv4 interface address\n"
3005 "underlay network IPv6 interface address\n"
3006 "indicate prefix follows\n"
3009 "indicate lifetime follows\n"
3011 "Cost (localpref = 255-cost)\n"
3014 struct rfapi_ip_addr vn
;
3015 struct rfapi_ip_addr un
;
3016 rfapi_handle handle
;
3019 struct rfapi_ip_prefix hpfx
;
3026 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3033 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3037 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3038 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3039 argv
[4]->arg
, argv
[6]->arg
);
3040 return CMD_WARNING_CONFIG_FAILED
;
3044 * Get prefix to advertise
3046 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3047 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3048 return CMD_WARNING_CONFIG_FAILED
;
3050 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3051 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3052 return CMD_WARNING_CONFIG_FAILED
;
3054 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3056 if (strmatch(argv
[10]->text
, "infinite")) {
3057 lifetime
= RFAPI_INFINITE_LIFETIME
;
3059 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3063 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3066 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3067 RFAPI_REGISTER_ADD
);
3069 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3076 DEFUN (debug_rfapi_register_vn_un_l2o
,
3077 debug_rfapi_register_vn_un_l2o_cmd
,
3078 "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)",
3082 "indicate vn addr follows\n"
3083 "virtual network IPv4 interface address\n"
3084 "virtual network IPv6 interface address\n"
3085 "indicate un addr follows\n"
3086 "underlay network IPv4 interface address\n"
3087 "underlay network IPv6 interface address\n"
3088 "indicate prefix follows\n"
3091 "indicate lifetime follows\n"
3092 "Seconds of lifetime\n"
3093 "indicate MAC address follows\n"
3095 "indicate lni follows\n"
3096 "lni value range\n")
3098 struct rfapi_ip_addr vn
;
3099 struct rfapi_ip_addr un
;
3100 rfapi_handle handle
;
3103 struct rfapi_ip_prefix hpfx
;
3105 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3106 struct rfapi_vn_option
*opt
= NULL
;
3112 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3119 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3123 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3124 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3125 argv
[4]->arg
, argv
[6]->arg
);
3126 return CMD_WARNING_CONFIG_FAILED
;
3130 * Get prefix to advertise
3132 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3133 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3134 return CMD_WARNING_CONFIG_FAILED
;
3136 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3137 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3138 return CMD_WARNING_CONFIG_FAILED
;
3140 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3142 if (strmatch(argv
[10]->text
, "infinite")) {
3143 lifetime
= RFAPI_INFINITE_LIFETIME
;
3145 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3148 /* L2 option parsing START */
3149 memset(optary
, 0, sizeof(optary
));
3150 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3151 strtoul(argv
[14]->arg
, NULL
, 10);
3152 if (rfapiStr2EthAddr(argv
[12]->arg
,
3153 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3154 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3155 return CMD_WARNING_CONFIG_FAILED
;
3157 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3160 /* L2 option parsing END */
3163 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3164 RFAPI_REGISTER_ADD
);
3166 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3174 DEFUN (debug_rfapi_unregister_vn_un
,
3175 debug_rfapi_unregister_vn_un_cmd
,
3176 "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]",
3179 "rfapi_unregister\n"
3180 "indicate vn addr follows\n"
3181 "virtual network interface address\n"
3182 "virtual network interface address\n"
3183 "indicate xt addr follows\n"
3184 "underlay network interface address\n"
3185 "underlay network interface address\n"
3186 "prefix to remove\n"
3187 "prefix to remove\n"
3188 "prefix to remove\n"
3189 "Remove without holddown\n")
3191 struct rfapi_ip_addr vn
;
3192 struct rfapi_ip_addr un
;
3193 rfapi_handle handle
;
3195 struct rfapi_ip_prefix hpfx
;
3201 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 X:X:X:X:X:X",
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 */
3728 vnc_zlog_debug_verbose("%s: auto-RD is set to %pRD", __func__
, rd
);
3732 /*------------------------------------------
3733 * rfapi_bgp_lookup_by_rfp
3735 * Find bgp instance pointer based on value returned by rfp_start
3738 * rfp_start_val value returned by rfp_startor
3739 * NULL (=get default instance)
3745 * bgp bgp instance pointer
3748 --------------------------------------------*/
3749 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3751 struct bgp
*bgp
= NULL
;
3752 struct listnode
*node
, *nnode
;
3754 if (rfp_start_val
== NULL
)
3755 bgp
= bgp_get_default();
3757 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3758 if (bgp
->rfapi
!= NULL
3759 && bgp
->rfapi
->rfp
== rfp_start_val
)
3764 /*------------------------------------------
3765 * rfapi_get_rfp_start_val_by_bgp
3767 * Find bgp instance pointer based on value returned by rfp_start
3770 * bgp bgp instance pointer
3779 --------------------------------------------*/
3780 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3782 if (!bgp
|| !bgp
->rfapi
)
3784 return bgp
->rfapi
->rfp
;
3787 /***********************************************************************
3788 * RFP group specific configuration
3789 ***********************************************************************/
3790 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3794 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3795 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3796 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3799 return rfc
->default_rfp_cfg
;
3802 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3806 struct rfapi_nve_group_cfg
*rfg
=
3807 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3809 /* make sure group is still in list */
3810 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3811 /* Not in list anymore */
3812 vty_out(vty
, "Current NVE group no longer exists\n");
3816 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3817 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3818 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3821 return rfg
->rfp_cfg
;
3824 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3828 struct rfapi_l2_group_cfg
*rfg
=
3829 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3831 /* make sure group is still in list */
3832 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3833 /* Not in list anymore */
3834 vty_out(vty
, "Current L2 group no longer exists\n");
3837 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3838 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3839 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3842 return rfg
->rfp_cfg
;
3845 /*------------------------------------------
3846 * rfapi_rfp_init_group_config_ptr_vty
3848 * This is used to init or return a previously init'ed group specific
3849 * configuration pointer. Group is identified by vty context.
3850 * NOTE: size is ignored when a previously init'ed value is returned.
3851 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3852 * bgp restart or shutdown.
3855 * rfp_start_val value returned by rfp_start
3857 * vty quagga vty context
3858 * size number of bytes to allocation
3864 * rfp_cfg_group NULL or Pointer to configuration structure
3865 --------------------------------------------*/
3866 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3867 rfapi_rfp_cfg_group_type type
,
3868 struct vty
*vty
, uint32_t size
)
3873 if (rfp_start_val
== NULL
|| vty
== NULL
)
3876 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3877 if (!bgp
|| !bgp
->rfapi_cfg
)
3881 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3882 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3885 case RFAPI_RFP_CFG_GROUP_NVE
:
3886 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3889 case RFAPI_RFP_CFG_GROUP_L2
:
3890 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3894 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3896 /* should never happen */
3897 assert("Unknown type" == NULL
);
3903 /*------------------------------------------
3904 * rfapi_rfp_get_group_config_ptr_vty
3906 * This is used to get group specific configuration pointer.
3907 * Group is identified by type and vty context.
3908 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3909 * bgp restart or shutdown.
3912 * rfp_start_val value returned by rfp_start
3914 * vty quagga vty context
3920 * rfp_cfg_group Pointer to configuration structure
3921 --------------------------------------------*/
3922 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3923 rfapi_rfp_cfg_group_type type
,
3926 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3930 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3932 rfp_group_config_search_cb_t
*search_cb
)
3934 struct rfapi_nve_group_cfg
*rfg
;
3935 struct listnode
*node
;
3937 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3938 if (!strcmp(rfg
->name
, name
) && /* name match */
3939 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3940 return rfg
->rfp_cfg
;
3946 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3948 rfp_group_config_search_cb_t
*search_cb
)
3950 struct rfapi_l2_group_cfg
*rfg
;
3951 struct listnode
*node
;
3953 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3954 if (!strcmp(rfg
->name
, name
) && /* name match */
3955 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3956 return rfg
->rfp_cfg
;
3961 /*------------------------------------------
3962 * rfapi_rfp_get_group_config_ptr_name
3964 * This is used to get group specific configuration pointer.
3965 * Group is identified by type and name context.
3966 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3967 * bgp restart or shutdown.
3970 * rfp_start_val value returned by rfp_start
3973 * criteria RFAPI caller provided search criteria
3974 * search_cb optional rfp_group_config_search_cb_t
3980 * rfp_cfg_group Pointer to configuration structure
3981 --------------------------------------------*/
3982 void *rfapi_rfp_get_group_config_ptr_name(
3983 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3984 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
3989 if (rfp_start_val
== NULL
|| name
== NULL
)
3992 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3993 if (!bgp
|| !bgp
->rfapi_cfg
)
3997 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3998 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4000 case RFAPI_RFP_CFG_GROUP_NVE
:
4001 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4002 criteria
, search_cb
);
4004 case RFAPI_RFP_CFG_GROUP_L2
:
4005 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4006 criteria
, search_cb
);
4009 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4011 /* should never happen */
4012 assert("Unknown type" == NULL
);
4018 /*------------------------------------------
4019 * rfapi_rfp_get_l2_group_config_ptr_lni
4021 * This is used to get group specific configuration pointer.
4022 * Group is identified by type and logical network identifier.
4023 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4024 * bgp restart or shutdown.
4027 * rfp_start_val value returned by rfp_start
4029 * logical_net_id group logical network identifier
4030 * criteria RFAPI caller provided search criteria
4031 * search_cb optional rfp_group_config_search_cb_t
4037 * rfp_cfg_group Pointer to configuration structure
4038 --------------------------------------------*/
4040 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4041 uint32_t logical_net_id
, void *criteria
,
4042 rfp_group_config_search_cb_t
*search_cb
)
4045 struct rfapi_l2_group_cfg
*rfg
;
4046 struct listnode
*node
;
4048 if (rfp_start_val
== NULL
)
4051 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4052 if (!bgp
|| !bgp
->rfapi_cfg
)
4055 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4056 if (rfg
->logical_net_id
== logical_net_id
4057 && (search_cb
== NULL
4058 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4059 if (rfg
->rfp_cfg
== NULL
)
4060 vnc_zlog_debug_verbose(
4061 "%s: returning rfp group config for lni=0",
4063 return rfg
->rfp_cfg
;