3 * Copyright 2009-2016, LabN Consulting, L.L.C.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "lib/zebra.h"
22 #include "lib/prefix.h"
23 #include "lib/agg_table.h"
25 #include "lib/memory.h"
26 #include "lib/routemap.h"
28 #include "lib/linklist.h"
29 #include "lib/command.h"
30 #include "lib/stream.h"
31 #include "lib/ringbuf.h"
32 #include "lib/lib_errors.h"
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_ecommunity.h"
36 #include "bgpd/bgp_attr.h"
38 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
39 #include "bgpd/rfapi/rfapi.h"
40 #include "bgpd/rfapi/rfapi_backend.h"
42 #include "bgpd/bgp_route.h"
43 #include "bgpd/bgp_mplsvpn.h"
44 #include "bgpd/bgp_aspath.h"
45 #include "bgpd/bgp_advertise.h"
46 #include "bgpd/bgp_vnc_types.h"
47 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/rfapi/rfapi_import.h"
50 #include "bgpd/rfapi/rfapi_private.h"
51 #include "bgpd/rfapi/rfapi_monitor.h"
52 #include "bgpd/rfapi/rfapi_vty.h"
53 #include "bgpd/rfapi/vnc_export_bgp.h"
54 #include "bgpd/rfapi/vnc_export_bgp_p.h"
55 #include "bgpd/rfapi/vnc_zebra.h"
56 #include "bgpd/rfapi/vnc_import_bgp.h"
57 #include "bgpd/rfapi/rfapi_rib.h"
58 #include "bgpd/rfapi/rfapi_ap.h"
59 #include "bgpd/rfapi/rfapi_encap_tlv.h"
60 #include "bgpd/rfapi/vnc_debug.h"
62 #ifdef HAVE_GLIBC_BACKTRACE
63 /* for backtrace and friends */
65 #endif /* HAVE_GLIBC_BACKTRACE */
67 struct ethaddr rfapi_ethaddr0
= {{0}};
69 #define DEBUG_RFAPI_STR "RF API debugging/testing command\n"
71 const char *rfapi_error_str(int code
)
77 return "BGP or VNC not configured";
81 return "Handle already open";
83 return "Incomplete configuration";
85 return "Invalid address family";
87 return "Called from within a callback procedure";
89 return "Invalid handle";
91 return "Invalid argument";
93 return "Stale descriptor";
95 return "Unknown error";
99 /*------------------------------------------
100 * rfapi_get_response_lifetime_default
102 * Returns the default lifetime for a response.
103 * rfp_start_val value returned by rfp_start or
104 * NULL (=use default instance)
111 * return value: The bgp instance default lifetime for a response.
112 --------------------------------------------*/
113 int rfapi_get_response_lifetime_default(void *rfp_start_val
)
115 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
117 return bgp
->rfapi_cfg
->default_response_lifetime
;
118 return BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
;
121 /*------------------------------------------
122 * rfapi_is_vnc_configured
124 * Returns if VNC is configured
127 * rfp_start_val value returned by rfp_start or
128 * NULL (=use default instance)
132 * return value: If VNC is configured for the bgpd instance
134 * ENXIO VNC not configured
135 --------------------------------------------*/
136 int rfapi_is_vnc_configured(void *rfp_start_val
)
138 struct bgp
*bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
139 if (bgp_rfapi_is_vnc_configured(bgp
) == 0)
145 /*------------------------------------------
148 * Get the virtual network address used by an NVE based on it's RFD
151 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
156 * vn NVE virtual network address
157 *------------------------------------------*/
158 struct rfapi_ip_addr
*rfapi_get_vn_addr(void *rfd
)
160 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
161 return &rrfd
->vn_addr
;
164 /*------------------------------------------
167 * Get the underlay network address used by an NVE based on it's RFD
170 * rfd: rfapi descriptor returned by rfapi_open or rfapi_create_generic
175 * un NVE underlay network address
176 *------------------------------------------*/
177 struct rfapi_ip_addr
*rfapi_get_un_addr(void *rfd
)
179 struct rfapi_descriptor
*rrfd
= (struct rfapi_descriptor
*)rfd
;
180 return &rrfd
->un_addr
;
183 int rfapi_ip_addr_cmp(struct rfapi_ip_addr
*a1
, struct rfapi_ip_addr
*a2
)
185 if (a1
->addr_family
!= a2
->addr_family
)
186 return a1
->addr_family
- a2
->addr_family
;
188 if (a1
->addr_family
== AF_INET
) {
189 return IPV4_ADDR_CMP(&a1
->addr
.v4
, &a2
->addr
.v4
);
192 if (a1
->addr_family
== AF_INET6
) {
193 return IPV6_ADDR_CMP(&a1
->addr
.v6
, &a2
->addr
.v6
);
201 static int rfapi_find_node(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
202 struct rfapi_ip_addr
*un_addr
,
203 struct agg_node
**node
)
220 afi
= family2afi(un_addr
->addr_family
);
225 if ((rc
= rfapiRaddr2Qprefix(un_addr
, &p
)))
228 rn
= agg_node_lookup(h
->un
[afi
], &p
);
241 int rfapi_find_rfd(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
242 struct rfapi_ip_addr
*un_addr
, struct rfapi_descriptor
**rfd
)
247 rc
= rfapi_find_node(bgp
, vn_addr
, un_addr
, &rn
);
252 for (*rfd
= (struct rfapi_descriptor
*)(rn
->info
); *rfd
;
253 *rfd
= (*rfd
)->next
) {
254 if (!rfapi_ip_addr_cmp(&(*rfd
)->vn_addr
, vn_addr
))
264 /*------------------------------------------
268 * un underlay network address
269 * vn virtual network address
272 * pHandle pointer to location to store handle
276 * ENOENT no matching handle
277 * ENXIO BGP or VNC not configured
278 *------------------------------------------*/
279 static int rfapi_find_handle(struct bgp
*bgp
, struct rfapi_ip_addr
*vn_addr
,
280 struct rfapi_ip_addr
*un_addr
,
281 rfapi_handle
*handle
)
283 struct rfapi_descriptor
**rfd
;
285 rfd
= (struct rfapi_descriptor
**)handle
;
287 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
290 static int rfapi_find_handle_vty(struct vty
*vty
, struct rfapi_ip_addr
*vn_addr
,
291 struct rfapi_ip_addr
*un_addr
,
292 rfapi_handle
*handle
)
295 struct rfapi_descriptor
**rfd
;
297 bgp
= bgp_get_default(); /* assume 1 instance for now */
299 rfd
= (struct rfapi_descriptor
**)handle
;
301 return rfapi_find_rfd(bgp
, vn_addr
, un_addr
, rfd
);
304 static int is_valid_rfd(struct rfapi_descriptor
*rfd
)
308 if (!rfd
|| rfd
->bgp
== NULL
)
313 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
316 if (rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &hh
))
326 * check status of descriptor
328 int rfapi_check(void *handle
)
330 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
334 if (!rfd
|| rfd
->bgp
== NULL
)
339 RFAPI_HD_FLAG_IS_VRF
)) /* assume VRF/internal are valid */
342 if ((rc
= rfapi_find_handle(rfd
->bgp
, &rfd
->vn_addr
, &rfd
->un_addr
,
356 void del_vnc_route(struct rfapi_descriptor
*rfd
,
357 struct peer
*peer
, /* rfd->peer for RFP regs */
358 struct bgp
*bgp
, safi_t safi
, const struct prefix
*p
,
359 struct prefix_rd
*prd
, uint8_t type
, uint8_t sub_type
,
360 struct rfapi_nexthop
*lnh
, int kill
)
362 afi_t afi
; /* of the VN address */
364 struct bgp_path_info
*bpi
;
365 char buf2
[RD_ADDRSTRLEN
];
366 struct prefix_rd prd0
;
368 afi
= family2afi(p
->family
);
369 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
371 if (safi
== SAFI_ENCAP
) {
372 memset(&prd0
, 0, sizeof(prd0
));
373 prd0
.family
= AF_UNSPEC
;
377 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
379 vnc_zlog_debug_verbose(
380 "%s: peer=%p, prefix=%pFX, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
381 __func__
, peer
, p
, prefix_rd2str(prd
, buf2
, sizeof(buf2
)), afi
,
382 safi
, bn
, (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
));
384 for (bpi
= (bn
? bgp_dest_get_bgp_path_info(bn
) : NULL
); bpi
;
387 vnc_zlog_debug_verbose(
388 "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64
,
389 __func__
, bpi
, bpi
->peer
, bpi
->type
, bpi
->sub_type
,
390 (bpi
->extra
? bpi
->extra
->vnc
.export
.rfapi_handle
392 CHECK_FLAG(bpi
->attr
->flag
,
393 ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)
394 ? bpi
->attr
->local_pref
: 0));
396 if (bpi
->peer
== peer
&& bpi
->type
== type
397 && bpi
->sub_type
== sub_type
&& bpi
->extra
398 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
400 vnc_zlog_debug_verbose("%s: matched it", __func__
);
408 * lnh set means to JUST delete the local nexthop from this
409 * route. Leave the route itself in place.
410 * TBD add return code reporting of success/failure
412 if (!bpi
|| !bpi
->extra
413 || !bpi
->extra
->vnc
.export
.local_nexthops
) {
417 vnc_zlog_debug_verbose(
418 "%s: lnh list already empty at prefix %pFX",
426 struct listnode
*node
;
427 struct rfapi_nexthop
*pLnh
= NULL
;
429 for (ALL_LIST_ELEMENTS_RO(bpi
->extra
->vnc
.export
.local_nexthops
,
432 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
438 listnode_delete(bpi
->extra
->vnc
.export
.local_nexthops
,
441 /* silly rabbit, listnode_delete doesn't invoke
442 * list->del on data */
443 rfapi_nexthop_free(pLnh
);
445 vnc_zlog_debug_verbose("%s: desired lnh not found %pFX",
452 * loop back to import tables
453 * Do this before removing from BGP RIB because rfapiProcessWithdraw
456 rfapiProcessWithdraw(peer
, rfd
, p
, prd
, NULL
, afi
, safi
, type
, kill
);
459 vnc_zlog_debug_verbose(
460 "%s: Found route (safi=%d) to delete at prefix %pFX",
463 if (safi
== SAFI_MPLS_VPN
) {
464 struct bgp_dest
*pdest
= NULL
;
465 struct bgp_table
*table
= NULL
;
467 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
468 (struct prefix
*)prd
);
469 table
= bgp_dest_get_bgp_table_info(pdest
);
471 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
472 bgp
, prd
, table
, p
, bpi
);
473 bgp_dest_unlock_node(pdest
);
477 * Delete local_nexthops list
479 if (bpi
->extra
&& bpi
->extra
->vnc
.export
.local_nexthops
)
480 list_delete(&bpi
->extra
->vnc
.export
.local_nexthops
);
482 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
483 bgp_path_info_delete(bn
, bpi
);
484 bgp_process(bgp
, bn
, afi
, safi
);
486 vnc_zlog_debug_verbose(
487 "%s: Couldn't find route (safi=%d) at prefix %pFX",
491 bgp_dest_unlock_node(bn
);
494 struct rfapi_nexthop
*rfapi_nexthop_new(struct rfapi_nexthop
*copyme
)
496 struct rfapi_nexthop
*new =
497 XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_nexthop
));
503 void rfapi_nexthop_free(void *p
)
505 struct rfapi_nexthop
*goner
= p
;
506 XFREE(MTYPE_RFAPI_NEXTHOP
, goner
);
509 struct rfapi_vn_option
*rfapi_vn_options_dup(struct rfapi_vn_option
*existing
)
511 struct rfapi_vn_option
*p
;
512 struct rfapi_vn_option
*head
= NULL
;
513 struct rfapi_vn_option
*tail
= NULL
;
515 for (p
= existing
; p
; p
= p
->next
) {
516 struct rfapi_vn_option
*new;
518 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
519 sizeof(struct rfapi_vn_option
));
532 void rfapi_un_options_free(struct rfapi_un_option
*p
)
534 struct rfapi_un_option
*next
;
538 XFREE(MTYPE_RFAPI_UN_OPTION
, p
);
543 void rfapi_vn_options_free(struct rfapi_vn_option
*p
)
545 struct rfapi_vn_option
*next
;
549 XFREE(MTYPE_RFAPI_VN_OPTION
, p
);
554 /* Based on bgp_redistribute_add() */
555 void add_vnc_route(struct rfapi_descriptor
*rfd
, /* cookie, VPN UN addr, peer */
556 struct bgp
*bgp
, int safi
, const struct prefix
*p
,
557 struct prefix_rd
*prd
, struct rfapi_ip_addr
*nexthop
,
558 uint32_t *local_pref
,
559 uint32_t *lifetime
, /* NULL => dont send lifetime */
560 struct bgp_tea_options
*rfp_options
,
561 struct rfapi_un_option
*options_un
,
562 struct rfapi_vn_option
*options_vn
,
563 struct ecommunity
*rt_export_list
, /* Copied, not consumed */
564 uint32_t *med
, /* NULL => don't set med */
565 uint32_t *label
, /* low order 3 bytes */
566 uint8_t type
, uint8_t sub_type
, /* RFP, NORMAL or REDIST */
569 afi_t afi
; /* of the VN address */
570 struct bgp_path_info
*new;
571 struct bgp_path_info
*bpi
;
574 struct attr attr
= {0};
575 struct attr
*new_attr
;
578 struct bgp_attr_encap_subtlv
*encaptlv
;
579 char buf
[PREFIX_STRLEN
];
580 char buf2
[RD_ADDRSTRLEN
];
582 struct rfapi_nexthop
*lnh
= NULL
; /* local nexthop */
583 struct rfapi_vn_option
*vo
;
584 struct rfapi_l2address_option
*l2o
= NULL
;
585 struct rfapi_ip_addr
*un_addr
= &rfd
->un_addr
;
587 bgp_encap_types TunnelType
= BGP_ENCAP_TYPE_RESERVED
;
588 struct bgp_redist
*red
;
590 if (safi
== SAFI_ENCAP
591 && !(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP
)) {
594 * Encap mode not enabled. UN addresses will be communicated
595 * via VNC Tunnel subtlv instead.
597 vnc_zlog_debug_verbose(
598 "%s: encap mode not enabled, not adding SAFI_ENCAP route",
603 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
604 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
606 if (RFAPI_0_ETHERADDR(&l2o
->macaddr
))
607 l2o
= NULL
; /* not MAC resolution */
609 if (RFAPI_VN_OPTION_TYPE_LOCAL_NEXTHOP
== vo
->type
) {
610 lnh
= &vo
->v
.local_nexthop
;
617 label_val
= MPLS_LABEL_IMPLICIT_NULL
;
619 prefix_rd2str(prd
, buf2
, sizeof(buf2
));
621 afi
= family2afi(p
->family
);
622 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
624 vnc_zlog_debug_verbose("%s: afi=%s, safi=%s", __func__
, afi2str(afi
),
627 /* Make default attribute. Produces already-interned attr.aspath */
628 /* Cripes, the memory management of attributes is byzantine */
630 bgp_attr_default_set(&attr
, BGP_ORIGIN_INCOMPLETE
);
635 * extra: dynamically allocated, owned by attr
636 * aspath: points to interned hash from aspath hash table
641 * Route-specific un_options get added to the VPN SAFI
642 * advertisement tunnel encap attribute. (the per-NVE
643 * "default" un_options are put into the 1-per-NVE ENCAP
644 * SAFI advertisement). The VPN SAFI also gets the
645 * default un_options if there are no route-specific options.
648 struct rfapi_un_option
*uo
;
650 for (uo
= options_un
; uo
; uo
= uo
->next
) {
651 if (RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== uo
->type
) {
652 TunnelType
= rfapi_tunneltype_option_to_tlv(
653 bgp
, un_addr
, &uo
->v
.tunnel
, &attr
,
660 * These are the NVE-specific "default" un_options which are
661 * put into the 1-per-NVE ENCAP advertisement.
663 if (rfd
->default_tunneltype_option
.type
) {
664 TunnelType
= rfapi_tunneltype_option_to_tlv(
665 bgp
, un_addr
, &rfd
->default_tunneltype_option
,
667 } else /* create default for local addse */
668 if (type
== ZEBRA_ROUTE_BGP
669 && sub_type
== BGP_ROUTE_RFP
)
670 TunnelType
= rfapi_tunneltype_option_to_tlv(
671 bgp
, un_addr
, NULL
, &attr
, l2o
!= NULL
);
674 if (TunnelType
== BGP_ENCAP_TYPE_MPLS
) {
675 if (safi
== SAFI_ENCAP
) {
676 /* Encap SAFI not used with MPLS */
677 vnc_zlog_debug_verbose(
678 "%s: mpls tunnel type, encap safi omitted",
680 aspath_unintern(&attr
.aspath
); /* Unintern original. */
686 attr
.local_pref
= *local_pref
;
687 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
692 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
695 /* override default weight assigned by bgp_attr_default_set() */
696 attr
.weight
= rfd
->peer
? rfd
->peer
->weight
[afi
][safi
] : 0;
699 * NB: ticket 81: do not reset attr.aspath here because it would
700 * cause iBGP peers to drop route
704 * Set originator ID for routes imported from BGP directly.
705 * These routes could be synthetic, and therefore could
706 * reuse the peer pointers of the routes they are derived
707 * from. Setting the originator ID to "us" prevents the
708 * wrong originator ID from being sent when this route is
709 * sent from a route reflector.
711 if (type
== ZEBRA_ROUTE_BGP_DIRECT
712 || type
== ZEBRA_ROUTE_BGP_DIRECT_EXT
) {
713 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
714 attr
.originator_id
= bgp
->router_id
;
718 /* Set up vnc attribute (sub-tlv for Prefix Lifetime) */
719 if (lifetime
&& *lifetime
!= RFAPI_INFINITE_LIFETIME
) {
722 encaptlv
= XCALLOC(MTYPE_ENCAP_TLV
,
723 sizeof(struct bgp_attr_encap_subtlv
) + 4);
726 BGP_VNC_SUBTLV_TYPE_LIFETIME
; /* prefix lifetime */
727 encaptlv
->length
= 4;
728 lt
= htonl(*lifetime
);
729 memcpy(encaptlv
->value
, <
, 4);
730 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
731 vnc_zlog_debug_verbose(
732 "%s: set Encap Attr Prefix Lifetime to %d", __func__
,
736 /* add rfp options to vnc attr */
739 if (flags
& RFAPI_AHR_RFPOPT_IS_VNCTLV
) {
740 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
741 bgp_attr_get_vnc_subtlvs(&attr
);
743 * this flag means we're passing a pointer to an
744 * existing encap tlv chain which we should copy.
745 * It's a hack to avoid adding yet another argument
748 encaptlv
= encap_tlv_dup(
749 (struct bgp_attr_encap_subtlv
*)rfp_options
);
751 vnc_subtlvs
->next
= encaptlv
;
753 bgp_attr_set_vnc_subtlvs(&attr
, encaptlv
);
755 struct bgp_tea_options
*hop
;
756 /* XXX max of one tlv present so far from above code */
757 struct bgp_attr_encap_subtlv
*tail
=
758 bgp_attr_get_vnc_subtlvs(&attr
);
760 for (hop
= rfp_options
; hop
; hop
= hop
->next
) {
767 sizeof(struct bgp_attr_encap_subtlv
) + 2
771 BGP_VNC_SUBTLV_TYPE_RFPOPTION
; /* RFP
774 encaptlv
->length
= 2 + hop
->length
;
775 *((uint8_t *)(encaptlv
->value
) + 0) = hop
->type
;
776 *((uint8_t *)(encaptlv
->value
) + 1) =
778 memcpy(((uint8_t *)encaptlv
->value
) + 2,
779 hop
->value
, hop
->length
);
782 * add to end of subtlv chain
785 tail
->next
= encaptlv
;
787 bgp_attr_set_vnc_subtlvs(&attr
,
797 * extra: dynamically allocated, owned by attr
798 * vnc_subtlvs: dynamic chain, length 1
799 * aspath: points to interned hash from aspath hash table
803 bgp_attr_set_ecommunity(&attr
, ecommunity_new());
804 assert(bgp_attr_get_ecommunity(&attr
));
806 if (TunnelType
!= BGP_ENCAP_TYPE_MPLS
807 && TunnelType
!= BGP_ENCAP_TYPE_RESERVED
) {
809 * Add BGP Encapsulation Extended Community. Format described in
810 * section 4.5 of RFC 5512.
811 * Always include when not MPLS type, to disambiguate this case.
813 struct ecommunity_val beec
;
815 memset(&beec
, 0, sizeof(beec
));
816 beec
.val
[0] = ECOMMUNITY_ENCODE_OPAQUE
;
817 beec
.val
[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
;
818 beec
.val
[6] = ((TunnelType
) >> 8) & 0xff;
819 beec
.val
[7] = (TunnelType
)&0xff;
820 ecommunity_add_val(bgp_attr_get_ecommunity(&attr
), &beec
, false,
825 * Add extended community attributes to match rt export list
827 if (rt_export_list
) {
828 bgp_attr_set_ecommunity(
829 &attr
, ecommunity_merge(bgp_attr_get_ecommunity(&attr
),
833 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(&attr
);
836 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
838 ecommunity_free(&ecomm
);
839 bgp_attr_set_ecommunity(&attr
, NULL
);
841 vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__
, ecomm
);
847 * extra: dynamically allocated, owned by attr
848 * vnc_subtlvs: dynamic chain, length 1
849 * ecommunity: dynamic 2-part
850 * aspath: points to interned hash from aspath hash table
853 /* stuff nexthop in attr_extra; which field depends on IPv4 or IPv6 */
854 switch (nexthop
->addr_family
) {
857 * set this field to prevent bgp_route.c code from setting
858 * mp_nexthop_global_in to self
860 attr
.nexthop
.s_addr
= nexthop
->addr
.v4
.s_addr
;
862 attr
.mp_nexthop_global_in
= nexthop
->addr
.v4
;
863 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
867 attr
.mp_nexthop_global
= nexthop
->addr
.v6
;
868 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV6_GLOBAL
;
876 prefix2str(p
, buf
, sizeof(buf
));
882 * extra: dynamically allocated, owned by attr
883 * vnc_subtlvs: dynamic chain, length 1
884 * ecommunity: dynamic 2-part
885 * aspath: points to interned hash from aspath hash table
888 red
= bgp_redist_lookup(bgp
, afi
, type
, 0);
890 if (red
&& red
->redist_metric_flag
) {
891 attr
.med
= red
->redist_metric
;
892 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
895 bn
= bgp_afi_node_get(bgp
->rib
[afi
][safi
], afi
, safi
, p
, prd
);
898 * bgp_attr_intern creates a new reference to a cached
899 * attribute, but leaves the following bits of trash:
901 * - old attr->extra (free via bgp_attr_extra_free(attr))
903 * Note that it frees the original attr->extra->ecommunity
904 * but leaves the new attribute pointing to the ORIGINAL
905 * vnc options (which therefore we needn't free from the
908 new_attr
= bgp_attr_intern(&attr
);
910 aspath_unintern(&attr
.aspath
); /* Unintern original. */
916 * extra: dynamically allocated, owned by attr
917 * vnc_subtlvs: dynamic chain, length 1
918 * ecommunity: POINTS TO INTERNED ecom, THIS REF NOT COUNTED
920 * new_attr: an attr that is part of the hash table, distinct
921 * from attr which is static.
922 * extra: dynamically allocated, owned by new_attr (in hash table)
923 * vnc_subtlvs: POINTS TO SAME dynamic chain AS attr
924 * ecommunity: POINTS TO interned/refcounted dynamic 2-part AS attr
925 * aspath: POINTS TO interned/refcounted hashed block
927 for (bpi
= bgp_dest_get_bgp_path_info(bn
); bpi
; bpi
= bpi
->next
) {
928 /* probably only need to check
929 * bpi->extra->vnc.export.rfapi_handle */
930 if (bpi
->peer
== rfd
->peer
&& bpi
->type
== type
931 && bpi
->sub_type
== sub_type
&& bpi
->extra
932 && bpi
->extra
->vnc
.export
.rfapi_handle
== (void *)rfd
) {
941 * Adding new local_nexthop, which does not by itself change
942 * what is advertised via BGP
945 if (!bpi
->extra
->vnc
.export
.local_nexthops
) {
946 /* TBD make arrangements to free when needed */
947 bpi
->extra
->vnc
.export
.local_nexthops
=
949 bpi
->extra
->vnc
.export
.local_nexthops
->del
=
956 struct listnode
*node
;
957 struct rfapi_nexthop
*pLnh
= NULL
;
959 for (ALL_LIST_ELEMENTS_RO(
960 bpi
->extra
->vnc
.export
.local_nexthops
,
963 if (prefix_same(&pLnh
->addr
, &lnh
->addr
)) {
969 * Not present, add new one
972 pLnh
= rfapi_nexthop_new(lnh
);
974 bpi
->extra
->vnc
.export
.local_nexthops
,
979 if (attrhash_cmp(bpi
->attr
, new_attr
)
980 && !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
981 bgp_attr_unintern(&new_attr
);
982 bgp_dest_unlock_node(bn
);
985 "%s: Found route (safi=%d) at prefix %s, no change",
986 __func__
, safi
, buf
);
990 /* The attribute is changed. */
991 bgp_path_info_set_flag(bn
, bpi
, BGP_PATH_ATTR_CHANGED
);
993 if (safi
== SAFI_MPLS_VPN
) {
994 struct bgp_dest
*pdest
= NULL
;
995 struct bgp_table
*table
= NULL
;
997 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
998 (struct prefix
*)prd
);
999 table
= bgp_dest_get_bgp_table_info(pdest
);
1001 vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
1002 bgp
, prd
, table
, p
, bpi
);
1003 bgp_dest_unlock_node(pdest
);
1006 /* Rewrite BGP route information. */
1007 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
1008 bgp_path_info_restore(bn
, bpi
);
1010 bgp_aggregate_decrement(bgp
, p
, bpi
, afi
, safi
);
1011 bgp_attr_unintern(&bpi
->attr
);
1012 bpi
->attr
= new_attr
;
1013 bpi
->uptime
= bgp_clock();
1016 if (safi
== SAFI_MPLS_VPN
) {
1017 struct bgp_dest
*pdest
= NULL
;
1018 struct bgp_table
*table
= NULL
;
1020 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
],
1021 (struct prefix
*)prd
);
1022 table
= bgp_dest_get_bgp_table_info(pdest
);
1024 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1025 bgp
, prd
, table
, p
, bpi
);
1026 bgp_dest_unlock_node(pdest
);
1029 /* Process change. */
1030 bgp_aggregate_increment(bgp
, p
, bpi
, afi
, safi
);
1031 bgp_process(bgp
, bn
, afi
, safi
);
1032 bgp_dest_unlock_node(bn
);
1035 "%s: Found route (safi=%d) at prefix %s, changed attr",
1036 __func__
, safi
, buf
);
1042 new = info_make(type
, sub_type
, 0, rfd
->peer
, new_attr
, NULL
);
1043 SET_FLAG(new->flags
, BGP_PATH_VALID
);
1045 /* save backref to rfapi handle */
1046 assert(bgp_path_info_extra_get(new));
1047 new->extra
->vnc
.export
.rfapi_handle
= (void *)rfd
;
1048 encode_label(label_val
, &new->extra
->label
[0]);
1052 if (VNC_DEBUG(VERBOSE
)) {
1053 vnc_zlog_debug_verbose("%s: printing BPI", __func__
);
1054 rfapiPrintBi(NULL
, new);
1057 bgp_aggregate_increment(bgp
, p
, new, afi
, safi
);
1058 bgp_path_info_add(bn
, new);
1060 if (safi
== SAFI_MPLS_VPN
) {
1061 struct bgp_dest
*pdest
= NULL
;
1062 struct bgp_table
*table
= NULL
;
1064 pdest
= bgp_node_get(bgp
->rib
[afi
][safi
], (struct prefix
*)prd
);
1065 table
= bgp_dest_get_bgp_table_info(pdest
);
1067 vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
1068 bgp
, prd
, table
, p
, new);
1069 bgp_dest_unlock_node(pdest
);
1070 encode_label(label_val
, &bn
->local_label
);
1073 bgp_dest_unlock_node(bn
);
1074 bgp_process(bgp
, bn
, afi
, safi
);
1077 "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
1078 __func__
, safi2str(safi
), buf
, bn
, buf2
);
1081 /* Loop back to import tables */
1082 rfapiProcessUpdate(rfd
->peer
, rfd
, p
, prd
, new_attr
, afi
, safi
, type
,
1083 sub_type
, &label_val
);
1084 vnc_zlog_debug_verbose("%s: looped back import route (safi=%d)",
1088 uint32_t rfp_cost_to_localpref(uint8_t cost
)
1093 static void rfapiTunnelRouteAnnounce(struct bgp
*bgp
,
1094 struct rfapi_descriptor
*rfd
,
1095 uint32_t *pLifetime
)
1097 struct prefix_rd prd
;
1098 struct prefix pfx_vn
;
1100 uint32_t local_pref
= rfp_cost_to_localpref(0);
1102 rc
= rfapiRaddr2Qprefix(&(rfd
->vn_addr
), &pfx_vn
);
1106 * Construct route distinguisher = 0
1108 memset(&prd
, 0, sizeof(prd
));
1109 prd
.family
= AF_UNSPEC
;
1112 add_vnc_route(rfd
, /* rfapi descr, for export list & backref */
1113 bgp
, /* which bgp instance */
1114 SAFI_ENCAP
, /* which SAFI */
1115 &pfx_vn
, /* prefix to advertise */
1116 &prd
, /* route distinguisher to use */
1117 &rfd
->un_addr
, /* nexthop */
1119 pLifetime
, /* max lifetime of child VPN routes */
1120 NULL
, /* no rfp options for ENCAP safi */
1121 NULL
, /* rfp un options */
1122 NULL
, /* rfp vn options */
1123 rfd
->rt_export_list
, NULL
, /* med */
1124 NULL
, /* label: default */
1125 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
1129 /***********************************************************************
1130 * RFP processing behavior configuration
1131 ***********************************************************************/
1133 /*------------------------------------------
1134 * rfapi_rfp_set_configuration
1136 * This is used to change rfapi's processing behavior based on
1140 * rfp_start_val value returned by rfp_start
1141 * rfapi_rfp_cfg Pointer to configuration structure
1148 * ENXIO Unabled to locate configured BGP/VNC
1149 --------------------------------------------*/
1150 int rfapi_rfp_set_configuration(void *rfp_start_val
, struct rfapi_rfp_cfg
*new)
1152 struct rfapi_rfp_cfg
*rcfg
;
1155 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1157 if (!new || !bgp
|| !bgp
->rfapi_cfg
)
1160 rcfg
= &bgp
->rfapi_cfg
->rfp_cfg
;
1161 rcfg
->download_type
= new->download_type
;
1162 rcfg
->ftd_advertisement_interval
= new->ftd_advertisement_interval
;
1163 rcfg
->holddown_factor
= new->holddown_factor
;
1165 if (rcfg
->use_updated_response
!= new->use_updated_response
) {
1166 rcfg
->use_updated_response
= new->use_updated_response
;
1167 if (rcfg
->use_updated_response
)
1168 rfapiMonitorCallbacksOn(bgp
);
1170 rfapiMonitorCallbacksOff(bgp
);
1172 if (rcfg
->use_removes
!= new->use_removes
) {
1173 rcfg
->use_removes
= new->use_removes
;
1174 if (rcfg
->use_removes
)
1175 rfapiMonitorResponseRemovalOn(bgp
);
1177 rfapiMonitorResponseRemovalOff(bgp
);
1182 /*------------------------------------------
1183 * rfapi_rfp_set_cb_methods
1185 * Change registered callback functions for asynchronous notifications
1186 * from RFAPI to the RFP client.
1189 * rfp_start_val value returned by rfp_start
1190 * methods Pointer to struct rfapi_rfp_cb_methods containing
1191 * pointers to callback methods as described above
1195 * ENXIO BGP or VNC not configured
1196 *------------------------------------------*/
1197 int rfapi_rfp_set_cb_methods(void *rfp_start_val
,
1198 struct rfapi_rfp_cb_methods
*methods
)
1203 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1211 h
->rfp_methods
= *methods
;
1216 /***********************************************************************
1218 ***********************************************************************/
1220 * Caller must supply an already-allocated rfd with the "caller"
1221 * fields already set (vn_addr, un_addr, callback, cookie)
1222 * The advertised_prefixes[] array elements should be NULL to
1223 * have this function set them to newly-allocated radix trees.
1225 static int rfapi_open_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
,
1226 struct rfapi
*h
, struct rfapi_nve_group_cfg
*rfg
)
1230 if (h
->flags
& RFAPI_INCALLBACK
)
1234 * Fill in configured fields
1238 * If group's RD is specified as "auto", then fill in based
1239 * on NVE's VN address
1243 if (rfd
->rd
.family
== AF_UNIX
) {
1244 ret
= rfapi_set_autord_from_vn(&rfd
->rd
, &rfd
->vn_addr
);
1248 rfd
->rt_export_list
= (rfg
->rt_export_list
)
1249 ? ecommunity_dup(rfg
->rt_export_list
)
1251 rfd
->response_lifetime
= rfg
->response_lifetime
;
1255 * Fill in BGP peer structure
1257 rfd
->peer
= peer_new(bgp
);
1258 rfd
->peer
->status
= Established
; /* keep bgp core happy */
1259 bgp_sync_delete(rfd
->peer
); /* don't need these */
1262 * since this peer is not on the I/O thread, this lock is not strictly
1263 * necessary, but serves as a reminder to those who may meddle...
1265 frr_with_mutex(&rfd
->peer
->io_mtx
) {
1266 // we don't need any I/O related facilities
1267 if (rfd
->peer
->ibuf
)
1268 stream_fifo_free(rfd
->peer
->ibuf
);
1269 if (rfd
->peer
->obuf
)
1270 stream_fifo_free(rfd
->peer
->obuf
);
1272 if (rfd
->peer
->ibuf_work
)
1273 ringbuf_del(rfd
->peer
->ibuf_work
);
1274 if (rfd
->peer
->obuf_work
)
1275 stream_free(rfd
->peer
->obuf_work
);
1277 rfd
->peer
->ibuf
= NULL
;
1278 rfd
->peer
->obuf
= NULL
;
1279 rfd
->peer
->obuf_work
= NULL
;
1280 rfd
->peer
->ibuf_work
= NULL
;
1283 { /* base code assumes have valid host pointer */
1287 if (rfd
->vn_addr
.addr_family
== AF_INET
) {
1288 inet_ntop(AF_INET
, &rfd
->vn_addr
.addr
.v4
, buf
, BUFSIZ
);
1289 } else if (rfd
->vn_addr
.addr_family
== AF_INET6
) {
1290 inet_ntop(AF_INET6
, &rfd
->vn_addr
.addr
.v6
, buf
, BUFSIZ
);
1292 rfd
->peer
->host
= XSTRDUP(MTYPE_BGP_PEER_HOST
, buf
);
1294 /* Mark peer as belonging to HD */
1295 SET_FLAG(rfd
->peer
->flags
, PEER_FLAG_IS_RFAPI_HD
);
1298 * Set min prefix lifetime to max value so it will get set
1299 * upon first rfapi_register()
1301 rfd
->min_prefix_lifetime
= UINT32_MAX
;
1304 * Allocate response tables if needed
1306 #define RFD_RTINIT_AFI(rh, ary, afi) \
1309 ary[afi] = agg_table_init(); \
1310 agg_set_table_info(ary[afi], rh); \
1314 #define RFD_RTINIT(rh, ary) \
1316 RFD_RTINIT_AFI(rh, ary, AFI_IP); \
1317 RFD_RTINIT_AFI(rh, ary, AFI_IP6); \
1318 RFD_RTINIT_AFI(rh, ary, AFI_L2VPN); \
1321 RFD_RTINIT(rfd
, rfd
->rib
);
1322 RFD_RTINIT(rfd
, rfd
->rib_pending
);
1323 RFD_RTINIT(rfd
, rfd
->rsp_times
);
1326 * Link to Import Table
1328 rfd
->import_table
= rfg
->rfapi_import_table
;
1329 rfd
->import_table
->refcount
+= 1;
1331 rfapiApInit(&rfd
->advertised
);
1334 * add this NVE descriptor to the list of NVEs in the NVE group
1337 rfg
->nves
= list_new();
1339 listnode_add(rfg
->nves
, rfd
);
1341 vnc_direct_bgp_add_nve(bgp
, rfd
);
1342 vnc_zebra_add_nve(bgp
, rfd
);
1347 /* moved from rfapi_register */
1348 int rfapi_init_and_open(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1349 struct rfapi_nve_group_cfg
*rfg
)
1351 struct rfapi
*h
= bgp
->rfapi
;
1352 char buf_vn
[BUFSIZ
];
1353 char buf_un
[BUFSIZ
];
1354 afi_t afi_vn
, afi_un
;
1355 struct prefix pfx_un
;
1356 struct agg_node
*rn
;
1359 rfapi_time(&rfd
->open_time
);
1361 if (rfg
->type
== RFAPI_GROUP_CFG_VRF
)
1362 SET_FLAG(rfd
->flags
, RFAPI_HD_FLAG_IS_VRF
);
1364 rfapiRfapiIpAddr2Str(&rfd
->vn_addr
, buf_vn
, BUFSIZ
);
1365 rfapiRfapiIpAddr2Str(&rfd
->un_addr
, buf_un
, BUFSIZ
);
1367 vnc_zlog_debug_verbose("%s: new RFD with VN=%s UN=%s cookie=%p",
1368 __func__
, buf_vn
, buf_un
, rfd
->cookie
);
1370 if (rfg
->type
!= RFAPI_GROUP_CFG_VRF
) /* unclear if needed for VRF */
1372 listnode_add(&h
->descriptors
, rfd
);
1373 if (h
->descriptors
.count
> h
->stat
.max_descriptors
) {
1374 h
->stat
.max_descriptors
= h
->descriptors
.count
;
1378 * attach to UN radix tree
1380 afi_vn
= family2afi(rfd
->vn_addr
.addr_family
);
1381 afi_un
= family2afi(rfd
->un_addr
.addr_family
);
1382 assert(afi_vn
&& afi_un
);
1383 assert(!rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
));
1385 rn
= agg_node_get(h
->un
[afi_un
], &pfx_un
);
1387 rfd
->next
= rn
->info
;
1391 return rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1394 struct rfapi_vn_option
*rfapiVnOptionsDup(struct rfapi_vn_option
*orig
)
1396 struct rfapi_vn_option
*head
= NULL
;
1397 struct rfapi_vn_option
*tail
= NULL
;
1398 struct rfapi_vn_option
*vo
= NULL
;
1400 for (vo
= orig
; vo
; vo
= vo
->next
) {
1401 struct rfapi_vn_option
*new;
1403 new = XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1404 sizeof(struct rfapi_vn_option
));
1405 memcpy(new, vo
, sizeof(struct rfapi_vn_option
));
1417 struct rfapi_un_option
*rfapiUnOptionsDup(struct rfapi_un_option
*orig
)
1419 struct rfapi_un_option
*head
= NULL
;
1420 struct rfapi_un_option
*tail
= NULL
;
1421 struct rfapi_un_option
*uo
= NULL
;
1423 for (uo
= orig
; uo
; uo
= uo
->next
) {
1424 struct rfapi_un_option
*new;
1426 new = XCALLOC(MTYPE_RFAPI_UN_OPTION
,
1427 sizeof(struct rfapi_un_option
));
1428 memcpy(new, uo
, sizeof(struct rfapi_un_option
));
1440 struct bgp_tea_options
*rfapiOptionsDup(struct bgp_tea_options
*orig
)
1442 struct bgp_tea_options
*head
= NULL
;
1443 struct bgp_tea_options
*tail
= NULL
;
1444 struct bgp_tea_options
*hop
= NULL
;
1446 for (hop
= orig
; hop
; hop
= hop
->next
) {
1447 struct bgp_tea_options
*new;
1449 new = XCALLOC(MTYPE_BGP_TEA_OPTIONS
,
1450 sizeof(struct bgp_tea_options
));
1451 memcpy(new, hop
, sizeof(struct bgp_tea_options
));
1454 new->value
= XCALLOC(MTYPE_BGP_TEA_OPTIONS_VALUE
,
1456 memcpy(new->value
, hop
->value
, hop
->length
);
1467 void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options
*p
)
1469 struct bgp_tea_options
*next
;
1474 XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE
, p
->value
);
1475 XFREE(MTYPE_BGP_TEA_OPTIONS
, p
);
1481 void rfapiAdbFree(struct rfapi_adb
*adb
)
1483 XFREE(MTYPE_RFAPI_ADB
, adb
);
1487 rfapi_query_inner(void *handle
, struct rfapi_ip_addr
*target
,
1488 struct rfapi_l2address_option
*l2o
, /* may be NULL */
1489 struct rfapi_next_hop_entry
**ppNextHopEntry
)
1493 struct prefix p_original
;
1494 struct agg_node
*rn
;
1495 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
1496 struct bgp
*bgp
= rfd
->bgp
;
1497 struct rfapi_next_hop_entry
*pNHE
= NULL
;
1498 struct rfapi_ip_addr
*self_vn_addr
= NULL
;
1500 int use_eth_resolution
= 0;
1501 struct rfapi_next_hop_entry
*i_nhe
;
1505 vnc_zlog_debug_verbose("%s: No BGP instance, returning ENXIO",
1510 vnc_zlog_debug_verbose("%s: No RFAPI instance, returning ENXIO",
1514 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
1515 vnc_zlog_debug_verbose(
1516 "%s: Called during calback, returning EDEADLK",
1521 if (!is_valid_rfd(rfd
)) {
1522 vnc_zlog_debug_verbose("%s: invalid handle, returning EBADF",
1527 rfd
->rsp_counter
++; /* dedup: identify this generation */
1528 rfd
->rsp_time
= rfapi_time(NULL
); /* response content dedup */
1529 rfd
->ftd_last_allowed_time
=
1531 - bgp
->rfapi_cfg
->rfp_cfg
.ftd_advertisement_interval
;
1534 if (!memcmp(l2o
->macaddr
.octet
, rfapi_ethaddr0
.octet
,
1538 /* per t/c Paul/Lou 151022 */
1539 if (!eth_is_0
|| l2o
->logical_net_id
) {
1540 use_eth_resolution
= 1;
1545 *ppNextHopEntry
= NULL
;
1548 * Save original target in prefix form. In case of L2-based queries,
1549 * p_original will be modified to reflect the L2 target
1551 assert(!rfapiRaddr2Qprefix(target
, &p_original
));
1553 if (bgp
->rfapi_cfg
->rfp_cfg
.download_type
== RFAPI_RFP_DOWNLOAD_FULL
) {
1554 /* convert query to 0/0 when full-table download is enabled */
1555 memset((char *)&p
, 0, sizeof(p
));
1556 p
.family
= target
->addr_family
;
1564 vnc_zlog_debug_verbose("%s(rfd=%p, target=%pFX, ppNextHop=%p)",
1565 __func__
, rfd
, &p
, ppNextHopEntry
);
1567 s
= ecommunity_ecom2str(rfd
->import_table
->rt_import_list
,
1568 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
1569 vnc_zlog_debug_verbose(
1570 "%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
1571 __func__
, rfd
->import_table
, s
);
1572 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
1575 afi
= family2afi(p
.family
);
1578 if (CHECK_FLAG(bgp
->rfapi_cfg
->flags
,
1579 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
)) {
1580 self_vn_addr
= &rfd
->vn_addr
;
1583 if (use_eth_resolution
) {
1584 uint32_t logical_net_id
= l2o
->logical_net_id
;
1585 struct ecommunity
*l2com
;
1588 * fix up p_original to contain L2 address
1590 rfapiL2o2Qprefix(l2o
, &p_original
);
1592 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
1593 bgp
, 1, logical_net_id
, l2o
->label
);
1595 uint8_t *v
= l2com
->val
;
1596 logical_net_id
= (v
[5] << 16) + (v
[6] << 8) + (v
[7]);
1599 * Ethernet/L2-based lookup
1601 * Always returns IT node corresponding to route
1604 if (RFAPI_RFP_DOWNLOAD_FULL
1605 == bgp
->rfapi_cfg
->rfp_cfg
.download_type
) {
1609 rn
= rfapiMonitorEthAdd(
1610 bgp
, rfd
, (eth_is_0
? &rfapi_ethaddr0
: &l2o
->macaddr
),
1614 struct rfapi_ip_prefix rprefix
;
1616 memset(&rprefix
, 0, sizeof(rprefix
));
1617 rprefix
.prefix
.addr_family
= target
->addr_family
;
1618 if (target
->addr_family
== AF_INET
) {
1619 rprefix
.length
= IPV4_MAX_BITLEN
;
1621 rprefix
.length
= IPV6_MAX_BITLEN
;
1624 pNHE
= rfapiEthRouteTable2NextHopList(
1625 logical_net_id
, &rprefix
,
1626 rfd
->response_lifetime
, self_vn_addr
,
1627 rfd
->rib
[afi
], &p_original
);
1637 rn
= rfapiMonitorAdd(bgp
, rfd
, &p
);
1640 * If target address is 0, this request is special: means to
1641 * return ALL routes in the table
1643 * Monitors for All-Routes queries get put on a special list,
1644 * not in the VPN tree
1646 if (RFAPI_0_PREFIX(&p
)) {
1648 vnc_zlog_debug_verbose("%s: 0-prefix", __func__
);
1651 * Generate nexthop list for caller
1653 pNHE
= rfapiRouteTable2NextHopList(
1654 rfd
->import_table
->imported_vpn
[afi
],
1655 rfd
->response_lifetime
, self_vn_addr
,
1656 rfd
->rib
[afi
], &p_original
);
1661 agg_lock_node(rn
); /* so we can unlock below */
1664 * returns locked node. Don't unlock yet because the
1666 * might free it before we're done with it. This
1668 * could occur when rfapiMonitorGetAttachNode() returns
1670 * newly-created default node.
1672 rn
= rfapiMonitorGetAttachNode(rfd
, &p
);
1678 agg_unlock_node(rn
);
1679 vnc_zlog_debug_verbose(
1680 "%s: VPN route not found, returning ENOENT", __func__
);
1684 if (VNC_DEBUG(RFAPI_QUERY
)) {
1685 rfapiShowImportTable(NULL
, "query",
1686 rfd
->import_table
->imported_vpn
[afi
], 1);
1689 if (use_eth_resolution
) {
1691 struct rfapi_ip_prefix rprefix
;
1693 memset(&rprefix
, 0, sizeof(rprefix
));
1694 rprefix
.prefix
.addr_family
= target
->addr_family
;
1695 if (target
->addr_family
== AF_INET
) {
1696 rprefix
.length
= IPV4_MAX_BITLEN
;
1698 rprefix
.length
= IPV6_MAX_BITLEN
;
1701 pNHE
= rfapiEthRouteNode2NextHopList(
1702 rn
, &rprefix
, rfd
->response_lifetime
, self_vn_addr
,
1703 rfd
->rib
[afi
], &p_original
);
1708 * Generate answer to query
1710 pNHE
= rfapiRouteNode2NextHopList(rn
, rfd
->response_lifetime
,
1711 self_vn_addr
, rfd
->rib
[afi
],
1715 agg_unlock_node(rn
);
1718 if (ppNextHopEntry
) {
1719 /* only count if caller gets it */
1720 ++bgp
->rfapi
->response_immediate_count
;
1724 vnc_zlog_debug_verbose("%s: NO NHEs, returning ENOENT",
1730 * count nexthops for statistics
1732 for (i_nhe
= pNHE
; i_nhe
; i_nhe
= i_nhe
->next
) {
1733 ++rfd
->stat_count_nh_reachable
;
1736 if (ppNextHopEntry
) {
1737 *ppNextHopEntry
= pNHE
;
1739 rfapi_free_next_hop_list(pNHE
);
1742 vnc_zlog_debug_verbose("%s: success", __func__
);
1747 * support on-the-fly reassignment of an already-open nve to a new
1748 * nve-group in the event that its original nve-group is
1749 * administratively deleted.
1751 static int rfapi_open_rfd(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
1753 struct prefix pfx_vn
;
1754 struct prefix pfx_un
;
1755 struct rfapi_nve_group_cfg
*rfg
;
1757 struct rfapi_cfg
*hc
;
1764 hc
= bgp
->rfapi_cfg
;
1768 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
1771 rc
= rfapiRaddr2Qprefix(&rfd
->un_addr
, &pfx_un
);
1775 * Find the matching nve group config block
1777 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1783 * check nve group config block for required values
1785 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1790 rc
= rfapi_open_inner(rfd
, bgp
, h
, rfg
);
1796 * re-advertise registered routes, this time as part of new NVE-group
1798 rfapiApReadvertiseAll(bgp
, rfd
);
1801 * re-attach callbacks to import table
1803 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1804 rfapiMonitorAttachImportHd(rfd
);
1810 /*------------------------------------------
1813 * This function initializes a NVE record and associates it with
1814 * the specified VN and underlay network addresses
1817 * rfp_start_val value returned by rfp_start
1818 * vn NVE virtual network address
1820 * un NVE underlay network address
1822 * default_options Default options to use on registrations.
1823 * For now only tunnel type is supported.
1824 * May be overridden per-prefix in rfapi_register().
1825 * Caller owns (rfapi_open() does not free)
1827 * response_cb Pointer to next hop list update callback function or
1828 * NULL when no callbacks are desired.
1830 * userdata Passed to subsequent response_cb invocations.
1833 * response_lifetime The length of time that responses sent to this
1836 * pHandle pointer to location to store rfapi handle. The
1837 * handle must be passed on subsequent rfapi_ calls.
1842 * EEXIST NVE with this {vn,un} already open
1843 * ENOENT No matching nve group config
1844 * ENOMSG Matched nve group config was incomplete
1845 * ENXIO BGP or VNC not configured
1846 * EAFNOSUPPORT Matched nve group specifies auto-assignment of RD,
1847 * but underlay network address is not IPv4
1848 * EDEADLK Called from within a callback procedure
1849 *------------------------------------------*/
1850 int rfapi_open(void *rfp_start_val
, struct rfapi_ip_addr
*vn
,
1851 struct rfapi_ip_addr
*un
,
1852 struct rfapi_un_option
*default_options
,
1853 uint32_t *response_lifetime
,
1854 void *userdata
, /* callback cookie */
1855 rfapi_handle
*pHandle
)
1859 struct rfapi_descriptor
*rfd
;
1860 struct rfapi_cfg
*hc
;
1861 struct rfapi_nve_group_cfg
*rfg
;
1863 struct prefix pfx_vn
;
1864 struct prefix pfx_un
;
1867 rfapi_handle hh
= NULL
;
1868 int reusing_provisional
= 0;
1871 char buf
[2][INET_ADDRSTRLEN
];
1872 vnc_zlog_debug_verbose(
1873 "%s: VN=%s UN=%s", __func__
,
1874 rfapiRfapiIpAddr2Str(vn
, buf
[0], INET_ADDRSTRLEN
),
1875 rfapiRfapiIpAddr2Str(un
, buf
[1], INET_ADDRSTRLEN
));
1881 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
1889 hc
= bgp
->rfapi_cfg
;
1893 if (h
->flags
& RFAPI_INCALLBACK
)
1896 rc
= rfapiRaddr2Qprefix(vn
, &pfx_vn
);
1899 rc
= rfapiRaddr2Qprefix(un
, &pfx_un
);
1903 * already have a descriptor with VN and UN?
1905 if (!rfapi_find_handle(bgp
, vn
, un
, &hh
)) {
1907 * we might have set up a handle for static routes before
1908 * this NVE was opened. In that case, reuse the handle
1911 if (!CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_PROVISIONAL
)) {
1916 * reuse provisional descriptor
1919 reusing_provisional
= 1;
1923 * Find the matching nve group config block
1925 rfg
= bgp_rfapi_cfg_match_group(hc
, &pfx_vn
, &pfx_un
);
1927 ++h
->stat
.count_unknown_nves
;
1929 char buf
[2][INET_ADDRSTRLEN
];
1930 zlog_notice("%s: no matching group VN=%s UN=%s",
1932 rfapiRfapiIpAddr2Str(vn
, buf
[0],
1934 rfapiRfapiIpAddr2Str(un
, buf
[1],
1941 * check nve group config block for required values
1943 if (!rfg
->rt_export_list
|| !rfg
->rfapi_import_table
) {
1945 ++h
->stat
.count_unknown_nves
;
1950 * If group config specifies auto-rd assignment, check that
1951 * VN address is IPv4|v6 so we don't fail in rfapi_open_inner().
1952 * Check here so we don't need to unwind memory allocations, &c.
1954 if ((rfg
->rd
.family
== AF_UNIX
) && (vn
->addr_family
!= AF_INET
)
1955 && (vn
->addr_family
!= AF_INET6
)) {
1956 return EAFNOSUPPORT
;
1961 * reusing provisional rfd
1965 rfd
= XCALLOC(MTYPE_RFAPI_DESC
,
1966 sizeof(struct rfapi_descriptor
));
1971 if (default_options
) {
1972 struct rfapi_un_option
*p
;
1974 for (p
= default_options
; p
; p
= p
->next
) {
1975 if ((RFAPI_UN_OPTION_TYPE_PROVISIONAL
== p
->type
)) {
1976 rfd
->flags
|= RFAPI_HD_FLAG_PROVISIONAL
;
1978 if ((RFAPI_UN_OPTION_TYPE_TUNNELTYPE
== p
->type
)) {
1979 rfd
->default_tunneltype_option
= p
->v
.tunnel
;
1985 * Fill in caller fields
1989 rfd
->cookie
= userdata
;
1991 if (!reusing_provisional
) {
1992 rc
= rfapi_init_and_open(bgp
, rfd
, rfg
);
1994 * This can fail only if the VN address is IPv6 and the group
1995 * specified auto-assignment of RDs, which only works for v4,
1996 * and the check above should catch it.
1998 * Another failure possibility is that we were called
1999 * during an rfapi callback. Also checked above.
2004 if (response_lifetime
)
2005 *response_lifetime
= rfd
->response_lifetime
;
2011 * For use with debug functions
2013 static int rfapi_set_response_cb(struct rfapi_descriptor
*rfd
,
2014 rfapi_response_cb_t
*response_cb
)
2016 if (!is_valid_rfd(rfd
))
2018 rfd
->response_cb
= response_cb
;
2025 * Does almost all the work of rfapi_close, except:
2026 * 1. preserves the descriptor (doesn't free it)
2027 * 2. preserves the prefix query list (i.e., rfd->mon list)
2028 * 3. preserves the advertised prefix list (rfd->advertised)
2029 * 4. preserves the rib and rib_pending tables
2031 * The purpose of organizing it this way is to support on-the-fly
2032 * reassignment of an already-open nve to a new nve-group in the
2033 * event that its original nve-group is administratively deleted.
2035 static int rfapi_close_inner(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2038 struct prefix pfx_vn
;
2039 struct prefix_rd prd
; /* currently always 0 for VN->UN */
2041 if (!is_valid_rfd(rfd
))
2044 rc
= rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn
);
2045 assert(!rc
); /* should never have bad AF in stored vn address */
2048 * update exported routes to reflect disappearance of this NVE as
2051 vnc_direct_bgp_del_nve(bgp
, rfd
);
2052 vnc_zebra_del_nve(bgp
, rfd
);
2055 * unlink this HD's monitors from import table
2057 rfapiMonitorDetachImportHd(rfd
);
2060 * Unlink from Import Table
2061 * NB rfd->import_table will be NULL if we are closing a stale
2064 if (rfd
->import_table
)
2065 rfapiImportTableRefDelByIt(bgp
, rfd
->import_table
);
2066 rfd
->import_table
= NULL
;
2069 * Construct route distinguisher
2071 memset(&prd
, 0, sizeof(prd
));
2073 prd
.family
= AF_UNSPEC
;
2079 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_ENCAP
,
2080 &pfx_vn
, /* prefix being advertised */
2081 &prd
, /* route distinguisher to use (0 for ENCAP) */
2082 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0); /* no kill */
2085 * Construct route distinguisher for VPN routes
2088 prd
.family
= AF_UNSPEC
;
2092 * find all VPN routes associated with this rfd and delete them, too
2094 rfapiApWithdrawAll(bgp
, rfd
);
2097 * remove this nve descriptor from the list of nves
2098 * associated with the nve group
2101 listnode_delete(rfd
->rfg
->nves
, rfd
);
2102 rfd
->rfg
= NULL
; /* XXX mark as orphaned/stale */
2105 if (rfd
->rt_export_list
)
2106 ecommunity_free(&rfd
->rt_export_list
);
2107 rfd
->rt_export_list
= NULL
;
2110 * free peer structure (possibly delayed until its
2111 * refcount reaches zero)
2114 vnc_zlog_debug_verbose("%s: calling peer_delete(%p), #%d",
2115 __func__
, rfd
->peer
, rfd
->peer
->lock
);
2116 peer_delete(rfd
->peer
);
2123 int rfapi_close(void *handle
)
2125 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2127 struct agg_node
*node
;
2131 vnc_zlog_debug_verbose("%s: rfd=%p", __func__
, rfd
);
2133 #ifdef RFAPI_WHO_IS_CALLING_ME
2134 #ifdef HAVE_GLIBC_BACKTRACE
2135 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 5
2137 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
2142 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
2143 syms
= backtrace_symbols(buf
, size
);
2144 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
;
2146 vnc_zlog_debug_verbose("backtrace[%2d]: %s", i
,
2162 if (!is_valid_rfd(rfd
))
2165 if (h
->flags
& RFAPI_INCALLBACK
) {
2167 * Queue these close requests for processing after callback
2170 if (!CHECK_FLAG(rfd
->flags
,
2171 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2172 work_queue_add(h
->deferred_close_q
, handle
);
2173 vnc_zlog_debug_verbose(
2174 "%s: added handle %p to deferred close queue",
2180 if (CHECK_FLAG(rfd
->flags
, RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)) {
2182 vnc_zlog_debug_verbose("%s administrative close rfd=%p",
2185 if (h
->rfp_methods
.close_cb
) {
2186 vnc_zlog_debug_verbose(
2187 "%s calling close callback rfd=%p", __func__
,
2191 * call the callback fairly early so that it can still
2195 * NB RFAPI_INCALLBACK is tested above, so if we reach
2197 * we are not already in the context of a callback.
2199 h
->flags
|= RFAPI_INCALLBACK
;
2200 (*h
->rfp_methods
.close_cb
)(handle
, EIDRM
);
2201 h
->flags
&= ~RFAPI_INCALLBACK
;
2207 * Orphaned descriptors have already done this part, so do
2208 * only for non-orphaned descriptors.
2210 if ((rc
= rfapi_close_inner(rfd
, bgp
)))
2215 * Remove descriptor from UN index
2216 * (remove from chain at node)
2218 rc
= rfapi_find_node(bgp
, &rfd
->vn_addr
, &rfd
->un_addr
, &node
);
2220 struct rfapi_descriptor
*hh
;
2222 if (node
->info
== rfd
) {
2223 node
->info
= rfd
->next
;
2226 for (hh
= node
->info
; hh
; hh
= hh
->next
) {
2227 if (hh
->next
== rfd
) {
2228 hh
->next
= rfd
->next
;
2233 agg_unlock_node(node
);
2237 * remove from descriptor list
2239 listnode_delete(&h
->descriptors
, rfd
);
2242 * Delete monitor list items and free monitor structures
2244 (void)rfapiMonitorDelHd(rfd
);
2247 * release advertised prefix data
2249 rfapiApRelease(&rfd
->advertised
);
2252 * Release RFP callback RIB
2259 memset(rfd
, 0, sizeof(struct rfapi_descriptor
));
2260 XFREE(MTYPE_RFAPI_DESC
, rfd
);
2266 * Reopen a nve descriptor. If the descriptor's NVE-group
2267 * does not exist (e.g., if it has been administratively removed),
2268 * reassignment to a new NVE-group is attempted.
2270 * If NVE-group reassignment fails, the descriptor becomes "stale"
2271 * (rfd->rfg == NULL implies "stale:). The only permissible API operation
2272 * on a stale descriptor is rfapi_close(). Any other rfapi_* API operation
2273 * on the descriptor will return ESTALE.
2275 * Reopening a descriptor is a potentially expensive operation, because
2276 * it involves withdrawing any routes advertised by the NVE, withdrawing
2277 * the NVE's route queries, and then re-adding them all after a new
2278 * NVE-group is assigned. There are also possible route-export affects
2279 * caused by deleting and then adding the NVE: advertised prefixes
2280 * and nexthop lists for exported routes can turn over.
2282 int rfapi_reopen(struct rfapi_descriptor
*rfd
, struct bgp
*bgp
)
2287 if ((rc
= rfapi_close_inner(rfd
, bgp
))) {
2290 if ((rc
= rfapi_open_rfd(rfd
, bgp
))) {
2294 assert(h
!= NULL
&& !CHECK_FLAG(h
->flags
, RFAPI_INCALLBACK
));
2296 if (CHECK_FLAG(rfd
->flags
,
2297 RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY
)
2298 && h
&& h
->rfp_methods
.close_cb
) {
2301 * NB RFAPI_INCALLBACK is tested above, so if we reach
2303 * we are not already in the context of a callback.
2305 h
->flags
|= RFAPI_INCALLBACK
;
2306 (*h
->rfp_methods
.close_cb
)((rfapi_handle
)rfd
, ESTALE
);
2307 h
->flags
&= ~RFAPI_INCALLBACK
;
2314 /***********************************************************************
2316 ***********************************************************************/
2318 * Announce reachability to this prefix via the NVE
2320 int rfapi_register(void *handle
, struct rfapi_ip_prefix
*prefix
,
2321 uint32_t lifetime
, /* host byte order */
2322 struct rfapi_un_option
*options_un
,
2323 struct rfapi_vn_option
*options_vn
,
2324 rfapi_register_action action
)
2326 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2329 struct prefix
*pfx_ip
= NULL
;
2330 struct prefix_rd prd
;
2332 struct prefix pfx_mac_buf
;
2333 struct prefix
*pfx_mac
= NULL
;
2334 struct prefix pfx_vn_buf
;
2335 const char *action_str
= NULL
;
2336 uint32_t *label
= NULL
;
2337 struct rfapi_vn_option
*vo
;
2338 struct rfapi_l2address_option
*l2o
= NULL
;
2339 struct prefix_rd
*prd_override
= NULL
;
2342 case RFAPI_REGISTER_ADD
:
2345 case RFAPI_REGISTER_WITHDRAW
:
2346 action_str
= "withdraw";
2348 case RFAPI_REGISTER_KILL
:
2349 action_str
= "kill";
2357 * Inspect VN options
2359 for (vo
= options_vn
; vo
; vo
= vo
->next
) {
2360 if (RFAPI_VN_OPTION_TYPE_L2ADDR
== vo
->type
) {
2361 l2o
= &vo
->v
.l2addr
;
2363 if (RFAPI_VN_OPTION_TYPE_INTERNAL_RD
== vo
->type
) {
2364 prd_override
= &vo
->v
.internal_rd
;
2368 /*********************************************************************
2370 *********************************************************************/
2373 * set <p> based on <prefix>
2375 assert(!rfapiRprefix2Qprefix(prefix
, &p
));
2377 afi
= family2afi(prefix
->prefix
.addr_family
);
2380 vnc_zlog_debug_verbose(
2381 "%s(rfd=%p, pfx=%pFX, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
2382 __func__
, rfd
, &p
, lifetime
, options_un
, options_vn
,
2386 * These tests come after the prefix conversion so that we can
2387 * print the prefix in a debug message before failing
2392 vnc_zlog_debug_verbose("%s: no BGP instance: returning ENXIO",
2397 vnc_zlog_debug_verbose("%s: no RFAPI instance: returning ENXIO",
2402 if (RFAPI_REGISTER_ADD
== action
) {
2403 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2405 vnc_zlog_debug_verbose(
2406 "%s: rfd=%p, no RF GRP instance: returning ESTALE",
2411 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
) {
2412 if (RFAPI_REGISTER_ADD
== action
) {
2413 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2415 vnc_zlog_debug_verbose("%s: in callback: returning EDEADLK",
2420 if (!is_valid_rfd(rfd
)) {
2421 if (RFAPI_REGISTER_ADD
== action
) {
2422 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2424 vnc_zlog_debug_verbose("%s: invalid handle: returning EBADF",
2430 * Is there a MAC address in this registration?
2432 if (l2o
&& !RFAPI_0_ETHERADDR(&l2o
->macaddr
)) {
2433 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2434 pfx_mac
= &pfx_mac_buf
;
2438 * Is there an IP prefix in this registration?
2440 if (!(RFAPI_0_PREFIX(&p
) && RFAPI_HOST_PREFIX(&p
))) {
2444 vnc_zlog_debug_verbose(
2445 "%s: missing mac addr that is required for host 0 pfx",
2447 if (RFAPI_REGISTER_ADD
== action
) {
2448 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2452 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
2453 vnc_zlog_debug_verbose(
2454 "%s: handle has bad vn_addr: returning EBADF",
2456 if (RFAPI_REGISTER_ADD
== action
) {
2457 ++bgp
->rfapi
->stat
.count_registrations_failed
;
2463 if (RFAPI_REGISTER_ADD
== action
) {
2464 ++bgp
->rfapi
->stat
.count_registrations
;
2468 * Figure out if this registration is missing an IP address
2472 * In RFAPI, we use prefixes in family AF_LINK to store
2473 * the MAC addresses. These prefixes are used for the
2474 * list of advertised prefixes and in the RFAPI import
2477 * In BGP proper, we use the prefix matching the NVE's
2478 * VN address with a host prefix-length (i.e., 32 or 128).
2481 if (l2o
&& l2o
->logical_net_id
&& RFAPI_0_PREFIX(&p
)
2482 && RFAPI_HOST_PREFIX(&p
)) {
2484 rfapiL2o2Qprefix(l2o
, &pfx_mac_buf
);
2485 pfx_mac
= &pfx_mac_buf
;
2489 * Construct route distinguisher
2492 prd
= *prd_override
;
2494 memset(&prd
, 0, sizeof(prd
));
2496 prd
.family
= AF_UNSPEC
;
2498 encode_rd_type(RD_TYPE_VNC_ETH
, prd
.val
);
2499 if (l2o
->local_nve_id
2500 || !(rfd
->rfg
->flags
& RFAPI_RFG_L2RD
)) {
2502 * If Local NVE ID is specified in message, use
2504 * (if no local default configured, also use it
2507 prd
.val
[1] = l2o
->local_nve_id
;
2509 if (rfd
->rfg
->l2rd
) {
2511 * locally-configured literal value
2513 prd
.val
[1] = rfd
->rfg
->l2rd
;
2516 * 0 means auto:vn, which means use LSB
2519 if (rfd
->vn_addr
.addr_family
2522 *(((char *)&rfd
->vn_addr
2528 *(((char *)&rfd
->vn_addr
2535 memcpy(prd
.val
+ 2, pfx_mac
->u
.prefix_eth
.octet
, 6);
2538 prd
.family
= AF_UNSPEC
;
2544 if (action
== RFAPI_REGISTER_WITHDRAW
2545 || action
== RFAPI_REGISTER_KILL
) {
2550 * withdraw previous advertisement
2553 rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
2555 : &pfx_vn_buf
, /* prefix being advertised */
2556 &prd
, /* route distinguisher (0 for ENCAP) */
2557 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
,
2558 action
== RFAPI_REGISTER_KILL
);
2560 if (0 == rfapiApDelete(bgp
, rfd
, &p
, pfx_mac
, &prd
,
2563 rfapiTunnelRouteAnnounce(
2564 bgp
, rfd
, &rfd
->max_prefix_lifetime
);
2570 uint32_t local_pref
;
2571 struct ecommunity
*rtlist
= NULL
;
2572 struct ecommunity_val ecom_value
;
2574 if (!rfapiApCount(rfd
)) {
2576 * make sure we advertise tunnel route upon adding the
2582 if (rfapiApAdd(bgp
, rfd
, &p
, pfx_mac
, &prd
, lifetime
,
2583 prefix
->cost
, l2o
)) {
2587 vnc_zlog_debug_verbose("%s: adv_tunnel = %d", __func__
,
2590 vnc_zlog_debug_verbose("%s: announcing tunnel route",
2592 rfapiTunnelRouteAnnounce(bgp
, rfd
,
2593 &rfd
->max_prefix_lifetime
);
2596 vnc_zlog_debug_verbose("%s: calling add_vnc_route", __func__
);
2598 local_pref
= rfp_cost_to_localpref(prefix
->cost
);
2600 if (l2o
&& l2o
->label
)
2601 label
= &l2o
->label
;
2604 struct ecommunity
*l2com
= NULL
;
2607 l2com
= bgp_rfapi_get_ecommunity_by_lni_label(
2608 bgp
, 1, l2o
->logical_net_id
, *label
);
2611 rtlist
= ecommunity_dup(l2com
);
2614 * If mac address is set, add an RT based on the
2617 memset((char *)&ecom_value
, 0,
2618 sizeof(ecom_value
));
2619 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2621 (l2o
->logical_net_id
>> 16) & 0xff;
2623 (l2o
->logical_net_id
>> 8) & 0xff;
2625 (l2o
->logical_net_id
>> 0) & 0xff;
2626 rtlist
= ecommunity_new();
2627 ecommunity_add_val(rtlist
, &ecom_value
,
2632 uint16_t val
= l2o
->tag_id
;
2633 memset((char *)&ecom_value
, 0,
2634 sizeof(ecom_value
));
2635 ecom_value
.val
[1] = ECOMMUNITY_ROUTE_TARGET
;
2636 if (as
> BGP_AS_MAX
) {
2638 ECOMMUNITY_ENCODE_AS4
;
2639 ecom_value
.val
[2] = (as
>> 24) & 0xff;
2640 ecom_value
.val
[3] = (as
>> 16) & 0xff;
2641 ecom_value
.val
[4] = (as
>> 8) & 0xff;
2642 ecom_value
.val
[5] = as
& 0xff;
2645 ECOMMUNITY_ENCODE_AS
;
2646 ecom_value
.val
[2] = (as
>> 8) & 0xff;
2647 ecom_value
.val
[3] = as
& 0xff;
2649 ecom_value
.val
[6] = (val
>> 8) & 0xff;
2650 ecom_value
.val
[7] = val
& 0xff;
2652 rtlist
= ecommunity_new();
2653 ecommunity_add_val(rtlist
, &ecom_value
,
2659 * advertise prefix via tunnel endpoint
2662 rfd
, /* rfapi descr, for export list & backref */
2663 bgp
, /* which bgp instance */
2664 SAFI_MPLS_VPN
, /* which SAFI */
2666 : &pfx_vn_buf
), /* prefix being advertised */
2667 &prd
, /* route distinguisher to use (0 for ENCAP) */
2668 &rfd
->vn_addr
, /* nexthop */
2670 &lifetime
, /* prefix lifetime -> Tunnel Encap attr */
2671 NULL
, options_un
, /* rfapi un options */
2672 options_vn
, /* rfapi vn options */
2673 (rtlist
? rtlist
: rfd
->rt_export_list
), NULL
, /* med */
2674 label
, /* label: default */
2675 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
2678 ecommunity_free(&rtlist
); /* sets rtlist = NULL */
2681 vnc_zlog_debug_verbose("%s: success", __func__
);
2685 int rfapi_query(void *handle
, struct rfapi_ip_addr
*target
,
2686 struct rfapi_l2address_option
*l2o
, /* may be NULL */
2687 struct rfapi_next_hop_entry
**ppNextHopEntry
)
2689 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2690 struct bgp
*bgp
= rfd
->bgp
;
2693 assert(ppNextHopEntry
);
2694 *ppNextHopEntry
= NULL
;
2696 if (bgp
&& bgp
->rfapi
) {
2697 bgp
->rfapi
->stat
.count_queries
++;
2701 if (bgp
&& bgp
->rfapi
)
2702 ++bgp
->rfapi
->stat
.count_queries_failed
;
2706 if ((rc
= rfapi_query_inner(handle
, target
, l2o
, ppNextHopEntry
))) {
2707 if (bgp
&& bgp
->rfapi
)
2708 ++bgp
->rfapi
->stat
.count_queries_failed
;
2713 int rfapi_query_done(rfapi_handle handle
, struct rfapi_ip_addr
*target
)
2717 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2718 struct bgp
*bgp
= rfd
->bgp
;
2724 rc
= rfapiRaddr2Qprefix(target
, &p
);
2727 if (!is_valid_rfd(rfd
))
2731 if (!bgp
|| !bgp
->rfapi
)
2734 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2737 rfapiMonitorDel(bgp
, rfd
, &p
);
2742 int rfapi_query_done_all(rfapi_handle handle
, int *count
)
2744 struct rfapi_descriptor
*rfd
= (struct rfapi_descriptor
*)handle
;
2745 struct bgp
*bgp
= rfd
->bgp
;
2752 if (!is_valid_rfd(rfd
))
2756 if (!bgp
|| !bgp
->rfapi
)
2759 if (bgp
->rfapi
->flags
& RFAPI_INCALLBACK
)
2762 num
= rfapiMonitorDelHd(rfd
);
2770 void rfapi_free_next_hop_list(struct rfapi_next_hop_entry
*list
)
2772 struct rfapi_next_hop_entry
*nh
;
2773 struct rfapi_next_hop_entry
*next
;
2775 for (nh
= list
; nh
; nh
= next
) {
2777 rfapi_un_options_free(nh
->un_options
);
2778 nh
->un_options
= NULL
;
2779 rfapi_vn_options_free(nh
->vn_options
);
2780 nh
->vn_options
= NULL
;
2781 XFREE(MTYPE_RFAPI_NEXTHOP
, nh
);
2786 * NULL handle => return total count across all nves
2788 uint32_t rfapi_monitor_count(void *handle
)
2790 struct bgp
*bgp
= bgp_get_default();
2794 struct rfapi_descriptor
*rfd
=
2795 (struct rfapi_descriptor
*)handle
;
2796 count
= rfd
->monitor_count
;
2799 if (!bgp
|| !bgp
->rfapi
)
2802 count
= bgp
->rfapi
->monitor_count
;
2808 /***********************************************************************
2810 ***********************************************************************/
2812 DEFUN (debug_rfapi_show_nves
,
2813 debug_rfapi_show_nves_cmd
,
2814 "debug rfapi-dev show nves",
2818 "NVE Information\n")
2820 rfapiPrintMatchingDescriptors(vty
, NULL
, NULL
);
2825 debug_rfapi_show_nves_vn_un
,
2826 debug_rfapi_show_nves_vn_un_cmd
,
2827 "debug rfapi-dev show nves <vn|un> <A.B.C.D|X:X::X:X>", /* prefix also ok */
2832 "Specify virtual network\n"
2833 "Specify underlay network interface\n"
2839 if (!str2prefix(argv
[5]->arg
, &pfx
)) {
2840 vty_out(vty
, "Malformed address \"%s\"\n", argv
[5]->arg
);
2841 return CMD_WARNING_CONFIG_FAILED
;
2843 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
2844 vty_out(vty
, "Invalid address \"%s\"\n", argv
[5]->arg
);
2845 return CMD_WARNING_CONFIG_FAILED
;
2848 if (argv
[4]->arg
[0] == 'u') {
2849 rfapiPrintMatchingDescriptors(vty
, NULL
, &pfx
);
2851 rfapiPrintMatchingDescriptors(vty
, &pfx
, NULL
);
2857 * Note: this function does not flush vty output, so if it is called
2858 * with a stream pointing to a vty, the user will have to type something
2859 * before the callback output shows up
2861 static void test_nexthops_callback(
2862 // struct rfapi_ip_addr *target,
2863 struct rfapi_next_hop_entry
*next_hops
, void *userdata
)
2865 void *stream
= userdata
;
2867 int (*fp
)(void *, const char *, ...);
2870 const char *vty_newline
;
2872 if (rfapiStream2Vty(stream
, &fp
, &vty
, &out
, &vty_newline
) == 0)
2875 fp(out
, "Nexthops Callback, Target=(");
2876 // rfapiPrintRfapiIpAddr(stream, target);
2879 rfapiPrintNhl(stream
, next_hops
);
2883 rfapi_free_next_hop_list(next_hops
);
2886 DEFUN (debug_rfapi_open
,
2887 debug_rfapi_open_cmd
,
2888 "debug rfapi-dev open vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2892 "indicate vn addr follows\n"
2893 "virtual network interface IPv4 address\n"
2894 "virtual network interface IPv6 address\n"
2895 "indicate xt addr follows\n"
2896 "underlay network interface IPv4 address\n"
2897 "underlay network interface IPv6 address\n")
2899 struct rfapi_ip_addr vn
;
2900 struct rfapi_ip_addr un
;
2901 uint32_t lifetime
= 0;
2903 rfapi_handle handle
;
2908 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2914 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2917 rc
= rfapi_open(rfapi_get_rfp_start_val_by_bgp(bgp_get_default()), &vn
,
2918 &un
, /*&uo */ NULL
, &lifetime
, NULL
, &handle
);
2920 vty_out(vty
, "rfapi_open: status %d, handle %p, lifetime %d\n", rc
,
2923 rc
= rfapi_set_response_cb(handle
, test_nexthops_callback
);
2925 vty_out(vty
, "rfapi_set_response_cb: status %d\n", rc
);
2931 DEFUN (debug_rfapi_close_vn_un
,
2932 debug_rfapi_close_vn_un_cmd
,
2933 "debug rfapi-dev close vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
2937 "indicate vn addr follows\n"
2938 "virtual network interface IPv4 address\n"
2939 "virtual network interface IPv6 address\n"
2940 "indicate xt addr follows\n"
2941 "underlay network interface IPv4 address\n"
2942 "underlay network interface IPv6 address\n")
2944 struct rfapi_ip_addr vn
;
2945 struct rfapi_ip_addr un
;
2946 rfapi_handle handle
;
2952 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
2959 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
2963 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
2964 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
2965 argv
[4]->arg
, argv
[6]->arg
);
2966 return CMD_WARNING_CONFIG_FAILED
;
2969 rc
= rfapi_close(handle
);
2971 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
2976 DEFUN (debug_rfapi_close_rfd
,
2977 debug_rfapi_close_rfd_cmd
,
2978 "debug rfapi-dev close rfd HANDLE",
2982 "indicate handle follows\n" "rfapi handle in hexadecimal\n")
2984 rfapi_handle handle
;
2986 char *endptr
= NULL
;
2988 handle
= (rfapi_handle
)(uintptr_t)(strtoull(argv
[4]->arg
, &endptr
, 16));
2990 if (*endptr
!= '\0' || (uintptr_t)handle
== UINTPTR_MAX
) {
2991 vty_out(vty
, "Invalid value: %s\n", argv
[4]->arg
);
2992 return CMD_WARNING_CONFIG_FAILED
;
2995 rc
= rfapi_close(handle
);
2997 vty_out(vty
, "rfapi_close(handle=%p): status %d\n", handle
, rc
);
3002 DEFUN (debug_rfapi_register_vn_un
,
3003 debug_rfapi_register_vn_un_cmd
,
3004 "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)]",
3008 "indicate vn addr follows\n"
3009 "virtual network IPv4 interface address\n"
3010 "virtual network IPv6 interface address\n"
3011 "indicate un addr follows\n"
3012 "underlay network IPv4 interface address\n"
3013 "underlay network IPv6 interface address\n"
3014 "indicate prefix follows\n"
3017 "indicate lifetime follows\n"
3019 "Cost (localpref = 255-cost)\n"
3022 struct rfapi_ip_addr vn
;
3023 struct rfapi_ip_addr un
;
3024 rfapi_handle handle
;
3027 struct rfapi_ip_prefix hpfx
;
3034 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3041 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3045 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3046 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3047 argv
[4]->arg
, argv
[6]->arg
);
3048 return CMD_WARNING_CONFIG_FAILED
;
3052 * Get prefix to advertise
3054 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3055 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3056 return CMD_WARNING_CONFIG_FAILED
;
3058 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3059 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3060 return CMD_WARNING_CONFIG_FAILED
;
3062 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3064 if (strmatch(argv
[10]->text
, "infinite")) {
3065 lifetime
= RFAPI_INFINITE_LIFETIME
;
3067 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3071 cost
= (uint8_t) strtoul(argv
[12]->arg
, NULL
, 10);
3074 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
, NULL
,
3075 RFAPI_REGISTER_ADD
);
3077 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3084 DEFUN (debug_rfapi_register_vn_un_l2o
,
3085 debug_rfapi_register_vn_un_l2o_cmd
,
3086 "debug rfapi-dev register vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> lifetime SECONDS macaddr YY:YY:YY:YY:YY:YY lni (0-16777215)",
3090 "indicate vn addr follows\n"
3091 "virtual network IPv4 interface address\n"
3092 "virtual network IPv6 interface address\n"
3093 "indicate un addr follows\n"
3094 "underlay network IPv4 interface address\n"
3095 "underlay network IPv6 interface address\n"
3096 "indicate prefix follows\n"
3099 "indicate lifetime follows\n"
3100 "Seconds of lifetime\n"
3101 "indicate MAC address follows\n"
3103 "indicate lni follows\n"
3104 "lni value range\n")
3106 struct rfapi_ip_addr vn
;
3107 struct rfapi_ip_addr un
;
3108 rfapi_handle handle
;
3111 struct rfapi_ip_prefix hpfx
;
3113 struct rfapi_vn_option optary
[10]; /* XXX must be big enough */
3114 struct rfapi_vn_option
*opt
= NULL
;
3120 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3127 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3131 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3132 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3133 argv
[4]->arg
, argv
[6]->arg
);
3134 return CMD_WARNING_CONFIG_FAILED
;
3138 * Get prefix to advertise
3140 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3141 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3142 return CMD_WARNING_CONFIG_FAILED
;
3144 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3145 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3146 return CMD_WARNING_CONFIG_FAILED
;
3148 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3150 if (strmatch(argv
[10]->text
, "infinite")) {
3151 lifetime
= RFAPI_INFINITE_LIFETIME
;
3153 lifetime
= strtoul(argv
[10]->arg
, NULL
, 10);
3156 /* L2 option parsing START */
3157 memset(optary
, 0, sizeof(optary
));
3158 optary
[opt_next
].v
.l2addr
.logical_net_id
=
3159 strtoul(argv
[14]->arg
, NULL
, 10);
3160 if (rfapiStr2EthAddr(argv
[12]->arg
,
3161 &optary
[opt_next
].v
.l2addr
.macaddr
)) {
3162 vty_out(vty
, "Bad mac address \"%s\"\n", argv
[12]->arg
);
3163 return CMD_WARNING_CONFIG_FAILED
;
3165 optary
[opt_next
].type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
3168 /* L2 option parsing END */
3171 rc
= rfapi_register(handle
, &hpfx
, lifetime
, NULL
/* &uo */, opt
,
3172 RFAPI_REGISTER_ADD
);
3174 vty_out(vty
, "rfapi_register failed with rc=%d (%s)\n", rc
,
3182 DEFUN (debug_rfapi_unregister_vn_un
,
3183 debug_rfapi_unregister_vn_un_cmd
,
3184 "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]",
3188 "indicate vn addr follows\n"
3189 "virtual network interface address\n"
3190 "indicate xt addr follows\n"
3191 "underlay network interface address\n"
3192 "prefix to remove\n"
3193 "Remove without holddown")
3195 struct rfapi_ip_addr vn
;
3196 struct rfapi_ip_addr un
;
3197 rfapi_handle handle
;
3199 struct rfapi_ip_prefix hpfx
;
3205 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3212 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3216 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3217 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3218 argv
[4]->arg
, argv
[6]->arg
);
3219 return CMD_WARNING_CONFIG_FAILED
;
3223 * Get prefix to advertise
3225 if (!str2prefix(argv
[8]->arg
, &pfx
)) {
3226 vty_out(vty
, "Malformed prefix \"%s\"\n", argv
[8]->arg
);
3227 return CMD_WARNING_CONFIG_FAILED
;
3229 if (pfx
.family
!= AF_INET
&& pfx
.family
!= AF_INET6
) {
3230 vty_out(vty
, "Bad family for prefix \"%s\"\n", argv
[8]->arg
);
3231 return CMD_WARNING_CONFIG_FAILED
;
3233 rfapiQprefix2Rprefix(&pfx
, &hpfx
);
3235 rfapi_register(handle
, &hpfx
, 0, NULL
, NULL
,
3237 RFAPI_REGISTER_KILL
: RFAPI_REGISTER_WITHDRAW
));
3242 DEFUN (debug_rfapi_query_vn_un
,
3243 debug_rfapi_query_vn_un_cmd
,
3244 "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>",
3248 "indicate vn addr follows\n"
3249 "virtual network interface IPv4 address\n"
3250 "virtual network interface IPv6 address\n"
3251 "indicate un addr follows\n"
3254 "indicate target follows\n"
3255 "target IPv4 address\n"
3256 "target IPv6 address\n")
3258 struct rfapi_ip_addr vn
;
3259 struct rfapi_ip_addr un
;
3260 struct rfapi_ip_addr target
;
3261 rfapi_handle handle
;
3263 struct rfapi_next_hop_entry
*pNextHopEntry
;
3268 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3275 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3282 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[8]->arg
, &target
)))
3286 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3287 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3288 argv
[4]->arg
, argv
[6]->arg
);
3289 return CMD_WARNING_CONFIG_FAILED
;
3293 * options parameter not used? Set to NULL for now
3295 rc
= rfapi_query(handle
, &target
, NULL
, &pNextHopEntry
);
3298 vty_out(vty
, "rfapi_query failed with rc=%d (%s)\n", rc
,
3302 * print nexthop list
3304 test_nexthops_callback(/*&target, */ pNextHopEntry
,
3305 vty
); /* frees nh list! */
3312 DEFUN (debug_rfapi_query_vn_un_l2o
,
3313 debug_rfapi_query_vn_un_l2o_cmd
,
3314 "debug rfapi-dev query vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> lni LNI target YY:YY:YY:YY:YY:YY",
3318 "indicate vn addr follows\n"
3319 "virtual network interface IPv4 address\n"
3320 "virtual network interface IPv6 address\n"
3321 "indicate xt addr follows\n"
3322 "underlay network interface IPv4 address\n"
3323 "underlay network interface IPv6 address\n"
3324 "logical network ID follows\n"
3325 "logical network ID\n"
3326 "indicate target MAC addr follows\n"
3327 "target MAC addr\n")
3329 struct rfapi_ip_addr vn
;
3330 struct rfapi_ip_addr un
;
3336 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[4]->arg
, &vn
)))
3343 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[6]->arg
, &un
)))
3346 vty_out(vty
, "%% This command is broken.\n");
3347 return CMD_WARNING_CONFIG_FAILED
;
3351 DEFUN (debug_rfapi_query_done_vn_un
,
3352 debug_rfapi_query_vn_un_done_cmd
,
3353 "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>",
3356 "rfapi_query_done\n"
3357 "rfapi_query_done\n"
3358 "indicate vn addr follows\n"
3359 "virtual network interface IPv4 address\n"
3360 "virtual network interface IPv6 address\n"
3361 "indicate xt addr follows\n"
3362 "underlay network interface IPv4 address\n"
3363 "underlay network interface IPv6 address\n"
3364 "indicate target follows\n"
3365 "Target IPv4 address\n"
3366 "Target IPv6 address\n")
3368 struct rfapi_ip_addr vn
;
3369 struct rfapi_ip_addr un
;
3370 struct rfapi_ip_addr target
;
3371 rfapi_handle handle
;
3377 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3384 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3391 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[9]->arg
, &target
)))
3395 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3396 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3397 argv
[5]->arg
, argv
[7]->arg
);
3398 return CMD_WARNING_CONFIG_FAILED
;
3402 * options parameter not used? Set to NULL for now
3404 rc
= rfapi_query_done(handle
, &target
);
3406 vty_out(vty
, "rfapi_query_done returned %d\n", rc
);
3411 DEFUN (debug_rfapi_show_import
,
3412 debug_rfapi_show_import_cmd
,
3413 "debug rfapi-dev show import",
3421 struct rfapi_import_table
*it
;
3426 * Show all import tables
3429 bgp
= bgp_get_default(); /* assume 1 instance for now */
3431 vty_out(vty
, "No BGP instance\n");
3432 return CMD_WARNING_CONFIG_FAILED
;
3437 vty_out(vty
, "No RFAPI instance\n");
3438 return CMD_WARNING_CONFIG_FAILED
;
3442 * Iterate over all import tables; do a filtered import
3443 * for the afi/safi combination
3447 for (it
= h
->imports
; it
; it
= it
->next
) {
3448 s
= ecommunity_ecom2str(it
->rt_import_list
,
3449 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
3450 vty_out(vty
, "Import Table %p, RTs: %s\n", it
, s
);
3451 XFREE(MTYPE_ECOMMUNITY_STR
, s
);
3453 rfapiShowImportTable(vty
, "IP VPN", it
->imported_vpn
[AFI_IP
],
3455 rfapiShowImportTable(vty
, "IP ENCAP",
3456 it
->imported_encap
[AFI_IP
], 0);
3457 rfapiShowImportTable(vty
, "IP6 VPN", it
->imported_vpn
[AFI_IP6
],
3459 rfapiShowImportTable(vty
, "IP6 ENCAP",
3460 it
->imported_encap
[AFI_IP6
], 0);
3463 if (h
->import_mac
) {
3464 void *cursor
= NULL
;
3466 uintptr_t lni_as_ptr
;
3470 for (rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3471 (void **)&it
, &cursor
);
3473 rc
= skiplist_next(h
->import_mac
, (void **)&lni_as_ptr
,
3474 (void **)&it
, &cursor
)) {
3476 if (it
->imported_vpn
[AFI_L2VPN
]) {
3480 "\nLNI-based Ethernet Tables:\n");
3483 snprintf(buf
, sizeof(buf
), "L2VPN LNI=%u", lni
);
3484 rfapiShowImportTable(
3485 vty
, buf
, it
->imported_vpn
[AFI_L2VPN
],
3491 rfapiShowImportTable(vty
, "CE IT - IP VPN",
3492 h
->it_ce
->imported_vpn
[AFI_IP
], 1);
3497 DEFUN (debug_rfapi_show_import_vn_un
,
3498 debug_rfapi_show_import_vn_un_cmd
,
3499 "debug rfapi-dev show import vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X>",
3504 "indicate vn addr follows\n"
3505 "virtual network interface IPv4 address\n"
3506 "virtual network interface IPv6 address\n"
3507 "indicate xt addr follows\n"
3508 "underlay network interface IPv4 address\n"
3509 "underlay network interface IPv6 address\n")
3511 struct rfapi_ip_addr vn
;
3512 struct rfapi_ip_addr un
;
3513 rfapi_handle handle
;
3515 struct rfapi_descriptor
*rfd
;
3520 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[5]->arg
, &vn
)))
3527 if ((rc
= rfapiCliGetRfapiIpAddr(vty
, argv
[7]->arg
, &un
)))
3531 if (rfapi_find_handle_vty(vty
, &vn
, &un
, &handle
)) {
3532 vty_out(vty
, "can't locate handle matching vn=%s, un=%s\n",
3533 argv
[5]->arg
, argv
[7]->arg
);
3534 return CMD_WARNING_CONFIG_FAILED
;
3537 rfd
= (struct rfapi_descriptor
*)handle
;
3539 rfapiShowImportTable(vty
, "IP VPN",
3540 rfd
->import_table
->imported_vpn
[AFI_IP
], 1);
3541 rfapiShowImportTable(vty
, "IP ENCAP",
3542 rfd
->import_table
->imported_encap
[AFI_IP
], 0);
3543 rfapiShowImportTable(vty
, "IP6 VPN",
3544 rfd
->import_table
->imported_vpn
[AFI_IP6
], 1);
3545 rfapiShowImportTable(vty
, "IP6 ENCAP",
3546 rfd
->import_table
->imported_encap
[AFI_IP6
], 0);
3551 DEFUN (debug_rfapi_response_omit_self
,
3552 debug_rfapi_response_omit_self_cmd
,
3553 "debug rfapi-dev response-omit-self <on|off>",
3556 "Omit self in RFP responses\n"
3557 "filter out self from responses\n" "leave self in responses\n")
3559 struct bgp
*bgp
= bgp_get_default();
3562 vty_out(vty
, "No BGP process is configured\n");
3563 return CMD_WARNING_CONFIG_FAILED
;
3565 if (!bgp
->rfapi_cfg
) {
3566 vty_out(vty
, "VNC not configured\n");
3567 return CMD_WARNING_CONFIG_FAILED
;
3570 if (strmatch(argv
[3]->text
, "on"))
3571 SET_FLAG(bgp
->rfapi_cfg
->flags
,
3572 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3574 UNSET_FLAG(bgp
->rfapi_cfg
->flags
,
3575 BGP_VNC_CONFIG_FILTER_SELF_FROM_RSP
);
3581 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3583 #include "lib/skiplist.h"
3584 DEFUN (skiplist_test_cli
,
3585 skiplist_test_cli_cmd
,
3587 "skiplist command\n"
3595 DEFUN (skiplist_debug_cli
,
3596 skiplist_debug_cli_cmd
,
3598 "skiplist command\n"
3601 skiplist_debug(vty
, NULL
);
3605 #endif /* RFAPI_DEBUG_SKIPLIST_CLI */
3607 void rfapi_init(void)
3609 bgp_rfapi_cfg_init();
3612 install_element(ENABLE_NODE
, &debug_rfapi_show_import_cmd
);
3613 install_element(ENABLE_NODE
, &debug_rfapi_show_import_vn_un_cmd
);
3615 install_element(ENABLE_NODE
, &debug_rfapi_open_cmd
);
3616 install_element(ENABLE_NODE
, &debug_rfapi_close_vn_un_cmd
);
3617 install_element(ENABLE_NODE
, &debug_rfapi_close_rfd_cmd
);
3618 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_cmd
);
3619 install_element(ENABLE_NODE
, &debug_rfapi_unregister_vn_un_cmd
);
3620 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_cmd
);
3621 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_done_cmd
);
3622 install_element(ENABLE_NODE
, &debug_rfapi_query_vn_un_l2o_cmd
);
3624 install_element(ENABLE_NODE
, &debug_rfapi_response_omit_self_cmd
);
3626 /* Need the following show commands for gpz test scripts */
3627 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_cmd
);
3628 install_element(ENABLE_NODE
, &debug_rfapi_show_nves_vn_un_cmd
);
3629 install_element(ENABLE_NODE
, &debug_rfapi_register_vn_un_l2o_cmd
);
3631 #ifdef RFAPI_DEBUG_SKIPLIST_CLI
3632 install_element(ENABLE_NODE
, &skiplist_test_cli_cmd
);
3633 install_element(ENABLE_NODE
, &skiplist_debug_cli_cmd
);
3640 static void rfapi_print_exported(struct bgp
*bgp
)
3642 struct bgp_dest
*destn
;
3643 struct bgp_dest
*dest
;
3644 struct bgp_path_info
*bpi
;
3649 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_MPLS_VPN
]); destn
;
3650 destn
= bgp_route_next(destn
)) {
3651 struct bgp_table
*table
;
3653 table
= bgp_dest_get_bgp_table_info(destn
);
3656 fprintf(stderr
, "%s: vpn destn=%p\n", __func__
, destn
);
3657 for (dest
= bgp_table_top(table
); dest
;
3658 dest
= bgp_route_next(dest
)) {
3659 bpi
= bgp_dest_get_bgp_path_info(dest
);
3663 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3664 for (; bpi
; bpi
= bpi
->next
) {
3665 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3669 for (destn
= bgp_table_top(bgp
->rib
[AFI_IP
][SAFI_ENCAP
]); destn
;
3670 destn
= bgp_route_next(destn
)) {
3671 struct bgp_table
*table
;
3673 table
= bgp_dest_get_bgp_table_info(destn
);
3676 fprintf(stderr
, "%s: encap destn=%p\n", __func__
, destn
);
3677 for (dest
= bgp_table_top(table
); dest
;
3678 dest
= bgp_route_next(dest
)) {
3679 bpi
= bgp_dest_get_bgp_path_info(dest
);
3682 fprintf(stderr
, "%s: dest=%p\n", __func__
, dest
);
3683 for (; bpi
; bpi
= bpi
->next
) {
3684 rfapiPrintBi((void *)2, bpi
); /* 2 => stderr */
3689 #endif /* defined(DEBUG_RFAPI) */
3692 * Free all memory to prepare for clean exit as seen by valgrind memcheck
3694 void rfapi_delete(struct bgp
*bgp
)
3696 extern void rfp_clear_vnc_nve_all(void); /* can't fix correctly yet */
3699 * This clears queries and registered routes, and closes nves
3702 rfp_clear_vnc_nve_all();
3703 bgp_rfapi_cfg_destroy(bgp
, bgp
->rfapi_cfg
);
3704 bgp
->rfapi_cfg
= NULL
;
3705 bgp_rfapi_destroy(bgp
, bgp
->rfapi
);
3709 * show what's left in the BGP MPLSVPN RIB
3711 rfapi_print_exported(bgp
);
3715 int rfapi_set_autord_from_vn(struct prefix_rd
*rd
, struct rfapi_ip_addr
*vn
)
3717 vnc_zlog_debug_verbose("%s: auto-assigning RD", __func__
);
3718 if (vn
->addr_family
!= AF_INET
&& vn
->addr_family
!= AF_INET6
) {
3719 vnc_zlog_debug_verbose(
3720 "%s: can't auto-assign RD, VN addr family is not IPv4|v6",
3722 return EAFNOSUPPORT
;
3724 rd
->family
= AF_UNSPEC
;
3726 rd
->val
[1] = RD_TYPE_IP
;
3727 if (vn
->addr_family
== AF_INET
) {
3728 memcpy(rd
->val
+ 2, &vn
->addr
.v4
.s_addr
, 4);
3729 } else { /* is v6 */
3730 memcpy(rd
->val
+ 2, &vn
->addr
.v6
.s6_addr32
[3],
3731 4); /* low order 4 bytes */
3734 char buf
[RD_ADDRSTRLEN
];
3736 vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__
,
3737 prefix_rd2str(rd
, buf
, sizeof(buf
)));
3742 /*------------------------------------------
3743 * rfapi_bgp_lookup_by_rfp
3745 * Find bgp instance pointer based on value returned by rfp_start
3748 * rfp_start_val value returned by rfp_startor
3749 * NULL (=get default instance)
3755 * bgp bgp instance pointer
3758 --------------------------------------------*/
3759 struct bgp
*rfapi_bgp_lookup_by_rfp(void *rfp_start_val
)
3761 struct bgp
*bgp
= NULL
;
3762 struct listnode
*node
, *nnode
;
3764 if (rfp_start_val
== NULL
)
3765 bgp
= bgp_get_default();
3767 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
3768 if (bgp
->rfapi
!= NULL
3769 && bgp
->rfapi
->rfp
== rfp_start_val
)
3774 /*------------------------------------------
3775 * rfapi_get_rfp_start_val_by_bgp
3777 * Find bgp instance pointer based on value returned by rfp_start
3780 * bgp bgp instance pointer
3789 --------------------------------------------*/
3790 void *rfapi_get_rfp_start_val_by_bgp(struct bgp
*bgp
)
3792 if (!bgp
|| !bgp
->rfapi
)
3794 return bgp
->rfapi
->rfp
;
3797 /***********************************************************************
3798 * RFP group specific configuration
3799 ***********************************************************************/
3800 static void *rfapi_rfp_get_or_init_group_config_default(struct rfapi_cfg
*rfc
,
3804 if (rfc
->default_rfp_cfg
== NULL
&& size
> 0) {
3805 rfc
->default_rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3806 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3809 return rfc
->default_rfp_cfg
;
3812 static void *rfapi_rfp_get_or_init_group_config_nve(struct rfapi_cfg
*rfc
,
3816 struct rfapi_nve_group_cfg
*rfg
=
3817 VTY_GET_CONTEXT_SUB(rfapi_nve_group_cfg
);
3819 /* make sure group is still in list */
3820 if (!rfg
|| !listnode_lookup(rfc
->nve_groups_sequential
, rfg
)) {
3821 /* Not in list anymore */
3822 vty_out(vty
, "Current NVE group no longer exists\n");
3826 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3827 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3828 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3831 return rfg
->rfp_cfg
;
3834 static void *rfapi_rfp_get_or_init_group_config_l2(struct rfapi_cfg
*rfc
,
3838 struct rfapi_l2_group_cfg
*rfg
=
3839 VTY_GET_CONTEXT_SUB(rfapi_l2_group_cfg
);
3841 /* make sure group is still in list */
3842 if (!rfg
|| !listnode_lookup(rfc
->l2_groups
, rfg
)) {
3843 /* Not in list anymore */
3844 vty_out(vty
, "Current L2 group no longer exists\n");
3847 if (rfg
->rfp_cfg
== NULL
&& size
> 0) {
3848 rfg
->rfp_cfg
= XCALLOC(MTYPE_RFAPI_RFP_GROUP_CFG
, size
);
3849 vnc_zlog_debug_verbose("%s: allocated, size=%d", __func__
,
3852 return rfg
->rfp_cfg
;
3855 /*------------------------------------------
3856 * rfapi_rfp_init_group_config_ptr_vty
3858 * This is used to init or return a previously init'ed group specific
3859 * configuration pointer. Group is identified by vty context.
3860 * NOTE: size is ignored when a previously init'ed value is returned.
3861 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3862 * bgp restart or shutdown.
3865 * rfp_start_val value returned by rfp_start
3867 * vty quagga vty context
3868 * size number of bytes to allocation
3874 * rfp_cfg_group NULL or Pointer to configuration structure
3875 --------------------------------------------*/
3876 void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val
,
3877 rfapi_rfp_cfg_group_type type
,
3878 struct vty
*vty
, uint32_t size
)
3883 if (rfp_start_val
== NULL
|| vty
== NULL
)
3886 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
3887 if (!bgp
|| !bgp
->rfapi_cfg
)
3891 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
3892 ret
= rfapi_rfp_get_or_init_group_config_default(bgp
->rfapi_cfg
,
3895 case RFAPI_RFP_CFG_GROUP_NVE
:
3896 ret
= rfapi_rfp_get_or_init_group_config_nve(bgp
->rfapi_cfg
,
3899 case RFAPI_RFP_CFG_GROUP_L2
:
3900 ret
= rfapi_rfp_get_or_init_group_config_l2(bgp
->rfapi_cfg
, vty
,
3904 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
3906 /* should never happen */
3907 assert("Unknown type" == NULL
);
3913 /*------------------------------------------
3914 * rfapi_rfp_get_group_config_ptr_vty
3916 * This is used to get group specific configuration pointer.
3917 * Group is identified by type and vty context.
3918 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3919 * bgp restart or shutdown.
3922 * rfp_start_val value returned by rfp_start
3924 * vty quagga vty context
3930 * rfp_cfg_group Pointer to configuration structure
3931 --------------------------------------------*/
3932 void *rfapi_rfp_get_group_config_ptr_vty(void *rfp_start_val
,
3933 rfapi_rfp_cfg_group_type type
,
3936 return rfapi_rfp_init_group_config_ptr_vty(rfp_start_val
, type
, vty
, 0);
3940 rfapi_rfp_get_group_config_name_nve(struct rfapi_cfg
*rfc
, const char *name
,
3942 rfp_group_config_search_cb_t
*search_cb
)
3944 struct rfapi_nve_group_cfg
*rfg
;
3945 struct listnode
*node
;
3947 for (ALL_LIST_ELEMENTS_RO(rfc
->nve_groups_sequential
, node
, rfg
)) {
3948 if (!strcmp(rfg
->name
, name
) && /* name match */
3949 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3950 return rfg
->rfp_cfg
;
3956 rfapi_rfp_get_group_config_name_l2(struct rfapi_cfg
*rfc
, const char *name
,
3958 rfp_group_config_search_cb_t
*search_cb
)
3960 struct rfapi_l2_group_cfg
*rfg
;
3961 struct listnode
*node
;
3963 for (ALL_LIST_ELEMENTS_RO(rfc
->l2_groups
, node
, rfg
)) {
3964 if (!strcmp(rfg
->name
, name
) && /* name match */
3965 (search_cb
== NULL
|| !search_cb(criteria
, rfg
->rfp_cfg
)))
3966 return rfg
->rfp_cfg
;
3971 /*------------------------------------------
3972 * rfapi_rfp_get_group_config_ptr_name
3974 * This is used to get group specific configuration pointer.
3975 * Group is identified by type and name context.
3976 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
3977 * bgp restart or shutdown.
3980 * rfp_start_val value returned by rfp_start
3983 * criteria RFAPI caller provided serach criteria
3984 * search_cb optional rfp_group_config_search_cb_t
3990 * rfp_cfg_group Pointer to configuration structure
3991 --------------------------------------------*/
3992 void *rfapi_rfp_get_group_config_ptr_name(
3993 void *rfp_start_val
, rfapi_rfp_cfg_group_type type
, const char *name
,
3994 void *criteria
, rfp_group_config_search_cb_t
*search_cb
)
3999 if (rfp_start_val
== NULL
|| name
== NULL
)
4002 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4003 if (!bgp
|| !bgp
->rfapi_cfg
)
4007 case RFAPI_RFP_CFG_GROUP_DEFAULT
:
4008 ret
= bgp
->rfapi_cfg
->default_rfp_cfg
;
4010 case RFAPI_RFP_CFG_GROUP_NVE
:
4011 ret
= rfapi_rfp_get_group_config_name_nve(bgp
->rfapi_cfg
, name
,
4012 criteria
, search_cb
);
4014 case RFAPI_RFP_CFG_GROUP_L2
:
4015 ret
= rfapi_rfp_get_group_config_name_l2(bgp
->rfapi_cfg
, name
,
4016 criteria
, search_cb
);
4019 flog_err(EC_LIB_DEVELOPMENT
, "%s: Unknown group type=%d",
4021 /* should never happen */
4022 assert("Unknown type" == NULL
);
4028 /*------------------------------------------
4029 * rfapi_rfp_get_l2_group_config_ptr_lni
4031 * This is used to get group specific configuration pointer.
4032 * Group is identified by type and logical network identifier.
4033 * RFAPI frees rfp_cfg_group when group is deleted during reconfig,
4034 * bgp restart or shutdown.
4037 * rfp_start_val value returned by rfp_start
4039 * logical_net_id group logical network identifier
4040 * criteria RFAPI caller provided serach criteria
4041 * search_cb optional rfp_group_config_search_cb_t
4047 * rfp_cfg_group Pointer to configuration structure
4048 --------------------------------------------*/
4050 rfapi_rfp_get_l2_group_config_ptr_lni(void *rfp_start_val
,
4051 uint32_t logical_net_id
, void *criteria
,
4052 rfp_group_config_search_cb_t
*search_cb
)
4055 struct rfapi_l2_group_cfg
*rfg
;
4056 struct listnode
*node
;
4058 if (rfp_start_val
== NULL
)
4061 bgp
= rfapi_bgp_lookup_by_rfp(rfp_start_val
);
4062 if (!bgp
|| !bgp
->rfapi_cfg
)
4065 for (ALL_LIST_ELEMENTS_RO(bgp
->rfapi_cfg
->l2_groups
, node
, rfg
)) {
4066 if (rfg
->logical_net_id
== logical_net_id
4067 && (search_cb
== NULL
4068 || !search_cb(criteria
, rfg
->rfp_cfg
))) {
4069 if (rfg
->rfp_cfg
== NULL
)
4070 vnc_zlog_debug_verbose(
4071 "%s: returning rfp group config for lni=0",
4073 return rfg
->rfp_cfg
;