1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright 2009-2016, LabN Consulting, L.L.C.
9 * File: rfapi_monitor.c
12 /* TBD remove unneeded includes */
14 #include "lib/zebra.h"
15 #include "lib/prefix.h"
16 #include "lib/agg_table.h"
18 #include "lib/memory.h"
20 #include "lib/table.h"
21 #include "lib/skiplist.h"
23 #include "bgpd/bgpd.h"
25 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
26 #include "bgpd/rfapi/rfapi.h"
27 #include "bgpd/rfapi/rfapi_backend.h"
29 #include "bgpd/rfapi/rfapi.h"
30 #include "bgpd/rfapi/rfapi_import.h"
31 #include "bgpd/rfapi/vnc_import_bgp.h"
32 #include "bgpd/rfapi/rfapi_private.h"
33 #include "bgpd/rfapi/rfapi_monitor.h"
34 #include "bgpd/rfapi/rfapi_vty.h"
35 #include "bgpd/rfapi/rfapi_rib.h"
36 #include "bgpd/rfapi/vnc_debug.h"
38 #define DEBUG_L2_EXTRA 0
39 #define DEBUG_DUP_CHECK 0
40 #define DEBUG_ETH_SL 0
42 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn
*m
);
44 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth
*m
);
47 * Forward declarations
49 static void rfapiMonitorEthDetachImport(struct bgp
*bgp
,
50 struct rfapi_monitor_eth
*mon
);
54 * Debug function, special case
56 void rfapiMonitorEthSlCheck(struct agg_node
*rn
, const char *tag1
,
59 struct agg_node
*rn_saved
= NULL
;
60 static struct skiplist
*sl_saved
= NULL
;
66 if (rn_saved
&& (rn
!= rn_saved
))
72 sl
= RFAPI_MONITOR_ETH(rn
);
74 vnc_zlog_debug_verbose(
75 "%s[%s%s]: rn=%p, rn->lock=%d, old sl=%p, new sl=%p",
76 __func__
, (tag1
? tag1
: ""), (tag2
? tag2
: ""), rn
,
77 rn
->lock
, sl_saved
, sl
);
84 * Debugging function that aborts when it finds monitors whose
85 * "next" pointer * references themselves
87 void rfapiMonitorLoopCheck(struct rfapi_monitor_vpn
*mchain
)
89 struct rfapi_monitor_vpn
*m
;
91 for (m
= mchain
; m
; m
= m
->next
)
97 * Debugging code: see if a monitor is mentioned more than once
98 * in a HD's monitor list
100 void rfapiMonitorDupCheck(struct bgp
*bgp
)
102 struct listnode
*hnode
;
103 struct rfapi_descriptor
*rfd
;
105 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
106 struct agg_node
*mrn
;
111 for (mrn
= agg_route_top(rfd
->mon
); mrn
;
112 mrn
= agg_route_next(mrn
)) {
113 struct rfapi_monitor_vpn
*m
;
114 for (m
= (struct rfapi_monitor_vpn
*)(mrn
->info
); m
;
120 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
121 struct agg_node
*mrn
;
126 for (mrn
= agg_route_top(rfd
->mon
); mrn
;
127 mrn
= agg_route_next(mrn
)) {
128 struct rfapi_monitor_vpn
*m
;
130 for (m
= (struct rfapi_monitor_vpn
*)(mrn
->info
); m
;
132 assert(++m
->dcount
== 1);
139 void rfapiMonitorCleanCheck(struct bgp
*bgp
)
141 struct listnode
*hnode
;
142 struct rfapi_descriptor
*rfd
;
144 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
145 assert(!rfd
->import_table
->vpn0_queries
[AFI_IP
]);
146 assert(!rfd
->import_table
->vpn0_queries
[AFI_IP6
]);
150 for (rn
= agg_route_top(
151 rfd
->import_table
->imported_vpn
[AFI_IP
]);
152 rn
; rn
= agg_route_next(rn
)) {
154 assert(!RFAPI_MONITOR_VPN(rn
));
156 for (rn
= agg_route_top(
157 rfd
->import_table
->imported_vpn
[AFI_IP6
]);
158 rn
; rn
= agg_route_next(rn
)) {
160 assert(!RFAPI_MONITOR_VPN(rn
));
166 void rfapiMonitorCheckAttachAllowed(void)
168 struct bgp
*bgp
= bgp_get_default();
169 assert(!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
));
172 void rfapiMonitorExtraFlush(safi_t safi
, struct agg_node
*rn
)
174 struct rfapi_it_extra
*hie
;
175 struct rfapi_monitor_vpn
*v
;
176 struct rfapi_monitor_vpn
*v_next
;
177 struct rfapi_monitor_encap
*e
= NULL
;
178 struct rfapi_monitor_encap
*e_next
= NULL
;
186 hie
= (struct rfapi_it_extra
*)(rn
->aggregate
);
190 for (e
= hie
->u
.encap
.e
; e
; e
= e_next
) {
193 XFREE(MTYPE_RFAPI_MONITOR_ENCAP
, e
);
196 hie
->u
.encap
.e
= NULL
;
200 for (v
= hie
->u
.vpn
.v
; v
; v
= v_next
) {
203 XFREE(MTYPE_RFAPI_MONITOR
, e
);
207 if (hie
->u
.vpn
.e
.source
) {
208 while (!skiplist_delete_first(hie
->u
.vpn
.e
.source
)) {
211 skiplist_free(hie
->u
.vpn
.e
.source
);
212 hie
->u
.vpn
.e
.source
= NULL
;
215 if (hie
->u
.vpn
.idx_rd
) {
216 /* looping through bpi->extra->vnc.import.rd is tbd */
217 while (!skiplist_delete_first(hie
->u
.vpn
.idx_rd
)) {
220 skiplist_free(hie
->u
.vpn
.idx_rd
);
221 hie
->u
.vpn
.idx_rd
= NULL
;
224 if (hie
->u
.vpn
.mon_eth
) {
225 while (!skiplist_delete_first(hie
->u
.vpn
.mon_eth
)) {
228 skiplist_free(hie
->u
.vpn
.mon_eth
);
229 hie
->u
.vpn
.mon_eth
= NULL
;
238 case SAFI_LABELED_UNICAST
:
243 XFREE(MTYPE_RFAPI_IT_EXTRA
, hie
);
244 rn
->aggregate
= NULL
;
249 * If the child lists are empty, release the rfapi_it_extra struct
251 void rfapiMonitorExtraPrune(safi_t safi
, struct agg_node
*rn
)
253 struct rfapi_it_extra
*hie
;
261 hie
= (struct rfapi_it_extra
*)(rn
->aggregate
);
272 if (hie
->u
.vpn
.mon_eth
) {
273 if (skiplist_count(hie
->u
.vpn
.mon_eth
))
275 skiplist_free(hie
->u
.vpn
.mon_eth
);
276 hie
->u
.vpn
.mon_eth
= NULL
;
277 agg_unlock_node(rn
); /* uncount skiplist */
279 if (hie
->u
.vpn
.e
.source
) {
280 if (skiplist_count(hie
->u
.vpn
.e
.source
))
282 skiplist_free(hie
->u
.vpn
.e
.source
);
283 hie
->u
.vpn
.e
.source
= NULL
;
286 if (hie
->u
.vpn
.idx_rd
) {
287 if (skiplist_count(hie
->u
.vpn
.idx_rd
))
289 skiplist_free(hie
->u
.vpn
.idx_rd
);
290 hie
->u
.vpn
.idx_rd
= NULL
;
293 if (hie
->u
.vpn
.mon_eth
) {
294 if (skiplist_count(hie
->u
.vpn
.mon_eth
))
296 skiplist_free(hie
->u
.vpn
.mon_eth
);
297 hie
->u
.vpn
.mon_eth
= NULL
;
306 case SAFI_LABELED_UNICAST
:
311 XFREE(MTYPE_RFAPI_IT_EXTRA
, hie
);
312 rn
->aggregate
= NULL
;
317 * returns locked node
319 struct agg_node
*rfapiMonitorGetAttachNode(struct rfapi_descriptor
*rfd
,
325 if (RFAPI_0_PREFIX(p
)) {
329 afi
= family2afi(p
->family
);
333 * It's possible that even though there is a route at this node,
334 * there are no routes with valid UN addresses (i.e,. with no
335 * valid tunnel routes). Check for that and walk back up the
338 * When the outer loop completes, the matched node, if any, is
339 * locked (i.e., its reference count has been incremented) to
340 * account for the VPN monitor we are about to attach.
342 * if a monitor is moved to another node, there must be
343 * corresponding unlock/locks
345 for (rn
= agg_node_match(rfd
->import_table
->imported_vpn
[afi
], p
);
348 struct bgp_path_info
*bpi
;
349 struct prefix pfx_dummy
;
351 /* TBD update this code to use new valid_interior_count */
352 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
354 * If there is a cached ENCAP UN address, it's a usable
357 if (bpi
->extra
&& bpi
->extra
->vnc
.import
.un_family
) {
362 * Or if there is a valid Encap Attribute tunnel subtlv
364 * it's a usable VPN route.
366 if (!rfapiGetVncTunnelUnAddr(bpi
->attr
, &pfx_dummy
)) {
374 if ((rn
= agg_node_parent(rn
))) {
380 struct prefix pfx_default
;
382 memset(&pfx_default
, 0, sizeof(pfx_default
));
383 pfx_default
.family
= p
->family
;
385 /* creates default node if none exists, and increments ref count
387 rn
= agg_node_get(rfd
->import_table
->imported_vpn
[afi
],
395 * If this function happens to attach the monitor to a radix tree
396 * node (as opposed to the 0-prefix list), the node pointer is
397 * returned (for the benefit of caller which might like to use it
398 * to generate an immediate query response).
400 static struct agg_node
*rfapiMonitorAttachImport(struct rfapi_descriptor
*rfd
,
401 struct rfapi_monitor_vpn
*m
)
405 rfapiMonitorCheckAttachAllowed();
407 if (RFAPI_0_PREFIX(&m
->p
)) {
409 * Add new monitor entry to vpn0 list
413 afi
= family2afi(m
->p
.family
);
416 m
->next
= rfd
->import_table
->vpn0_queries
[afi
];
417 rfd
->import_table
->vpn0_queries
[afi
] = m
;
418 vnc_zlog_debug_verbose("%s: attached monitor %p to vpn0 list",
424 * Attach new monitor entry to import table node
426 rn
= rfapiMonitorGetAttachNode(rfd
, &m
->p
); /* returns locked rn */
428 m
->next
= RFAPI_MONITOR_VPN(rn
);
429 RFAPI_MONITOR_VPN_W_ALLOC(rn
) = m
;
430 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, 0);
431 vnc_zlog_debug_verbose("%s: attached monitor %p to rn %p", __func__
, m
,
438 * reattach monitors for this HD to import table
440 void rfapiMonitorAttachImportHd(struct rfapi_descriptor
*rfd
)
442 struct agg_node
*mrn
;
446 * No monitors for this HD
451 for (mrn
= agg_route_top(rfd
->mon
); mrn
; mrn
= agg_route_next(mrn
)) {
456 (void)rfapiMonitorAttachImport(
457 rfd
, (struct rfapi_monitor_vpn
*)(mrn
->info
));
462 * Adds a monitor for a query to the NVE descriptor's list
463 * and, if callbacks are enabled, attaches it to the import table.
465 * If we happened to locate the import table radix tree attachment
466 * point, return it so the caller can use it to generate a query
467 * response without repeating the lookup. Note that when callbacks
468 * are disabled, this function will not perform a lookup, and the
469 * caller will have to do its own lookup.
471 struct agg_node
*rfapiMonitorAdd(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
474 struct rfapi_monitor_vpn
*m
;
478 * Initialize nve's monitor list if needed
479 * NB use the same radix tree for IPv4 and IPv6 targets.
480 * The prefix will always have full-length mask (/32, /128)
481 * or be 0/0 so they won't get mixed up.
484 rfd
->mon
= agg_table_init();
486 rn
= agg_node_get(rfd
->mon
, p
);
489 * received this query before, no further action needed
491 rfapiMonitorTimerRestart((struct rfapi_monitor_vpn
*)rn
->info
);
497 * New query for this nve, record it in the HD
500 XCALLOC(MTYPE_RFAPI_MONITOR
, sizeof(struct rfapi_monitor_vpn
));
501 m
= (struct rfapi_monitor_vpn
*)(rn
->info
);
503 prefix_copy(&m
->p
, p
);
505 ++rfd
->monitor_count
;
506 ++bgp
->rfapi
->monitor_count
;
508 rfapiMonitorTimerRestart(m
);
510 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
512 * callbacks turned off, so don't attach monitor to import table
519 * attach to import table
521 return rfapiMonitorAttachImport(rfd
, m
);
525 * returns monitor pointer if found, NULL if not
527 static struct rfapi_monitor_vpn
*
528 rfapiMonitorDetachImport(struct rfapi_monitor_vpn
*m
)
530 struct rfapi_monitor_vpn
*prev
;
531 struct rfapi_monitor_vpn
*this = NULL
;
533 if (RFAPI_0_PREFIX(&m
->p
)) {
537 * 0-prefix monitors are stored in a special list and not
538 * in the import VPN tree
541 afi
= family2afi(m
->p
.family
);
544 if (m
->rfd
->import_table
) {
546 this = m
->rfd
->import_table
->vpn0_queries
[afi
];
547 this; prev
= this, this = this->next
) {
555 ->vpn0_queries
[afi
] =
558 prev
->next
= this->next
;
565 for (prev
= NULL
, this = RFAPI_MONITOR_VPN(m
->node
);
566 this; prev
= this, this = this->next
) {
573 prev
->next
= this->next
;
575 RFAPI_MONITOR_VPN_W_ALLOC(m
->node
) =
578 RFAPI_CHECK_REFCOUNT(m
->node
, SAFI_MPLS_VPN
, 1);
579 agg_unlock_node(m
->node
);
588 void rfapiMonitorDetachImportHd(struct rfapi_descriptor
*rfd
)
595 for (rn
= agg_route_top(rfd
->mon
); rn
; rn
= agg_route_next(rn
)) {
597 rfapiMonitorDetachImport(
598 (struct rfapi_monitor_vpn
*)(rn
->info
));
603 void rfapiMonitorDel(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
607 struct rfapi_monitor_vpn
*m
;
610 rn
= agg_node_get(rfd
->mon
, p
); /* locks node */
616 * remove from import table
618 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
619 rfapiMonitorDetachImport(m
);
622 THREAD_OFF(m
->timer
);
625 * remove from rfd list
627 XFREE(MTYPE_RFAPI_MONITOR
, m
);
629 agg_unlock_node(rn
); /* undo original lock when created */
630 agg_unlock_node(rn
); /* undo lock in agg_node_get */
632 --rfd
->monitor_count
;
633 --bgp
->rfapi
->monitor_count
;
637 * returns count of monitors deleted
639 int rfapiMonitorDelHd(struct rfapi_descriptor
*rfd
)
645 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
647 bgp
= bgp_get_default();
650 for (rn
= agg_route_top(rfd
->mon
); rn
;
651 rn
= agg_route_next(rn
)) {
652 struct rfapi_monitor_vpn
*m
;
653 if ((m
= rn
->info
)) {
654 if (!(bgp
->rfapi_cfg
->flags
655 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
656 rfapiMonitorDetachImport(m
);
659 THREAD_OFF(m
->timer
);
661 XFREE(MTYPE_RFAPI_MONITOR
, m
);
663 agg_unlock_node(rn
); /* undo original lock
666 --rfd
->monitor_count
;
667 --bgp
->rfapi
->monitor_count
;
670 agg_table_finish(rfd
->mon
);
676 struct rfapi_monitor_eth
*mon_eth
;
678 while (!skiplist_first(rfd
->mon_eth
, NULL
, (void **)&mon_eth
)) {
682 if (!(bgp
->rfapi_cfg
->flags
683 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
684 rfapiMonitorEthDetachImport(bgp
, mon_eth
);
687 vnc_zlog_debug_verbose(
688 "%s: callbacks disabled, not attempting to detach mon_eth %p",
693 THREAD_OFF(mon_eth
->timer
);
696 * remove from rfd list
698 rc
= skiplist_delete(rfd
->mon_eth
, mon_eth
, mon_eth
);
701 vnc_zlog_debug_verbose("%s: freeing mon_eth %p",
703 XFREE(MTYPE_RFAPI_MONITOR_ETH
, mon_eth
);
706 --rfd
->monitor_count
;
707 --bgp
->rfapi
->monitor_count
;
709 skiplist_free(rfd
->mon_eth
);
716 void rfapiMonitorResponseRemovalOff(struct bgp
*bgp
)
718 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
) {
721 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
724 void rfapiMonitorResponseRemovalOn(struct bgp
*bgp
)
726 if (!(bgp
->rfapi_cfg
->flags
727 & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
)) {
730 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
733 static void rfapiMonitorTimerExpire(struct thread
*t
)
735 struct rfapi_monitor_vpn
*m
= THREAD_ARG(t
);
737 /* forget reference to thread, it's gone */
740 /* delete the monitor */
741 rfapiMonitorDel(bgp_get_default(), m
->rfd
, &m
->p
);
744 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn
*m
)
746 unsigned long remain
= thread_timer_remain_second(m
->timer
);
748 /* unexpected case, but avoid wraparound problems below */
749 if (remain
> m
->rfd
->response_lifetime
)
752 /* don't restart if we just restarted recently */
753 if (m
->rfd
->response_lifetime
- remain
< 2)
756 THREAD_OFF(m
->timer
);
761 vnc_zlog_debug_verbose(
762 "%s: target %s life %u", __func__
,
763 rfapi_ntop(m
->p
.family
, m
->p
.u
.val
, buf
, BUFSIZ
),
764 m
->rfd
->response_lifetime
);
767 thread_add_timer(bm
->master
, rfapiMonitorTimerExpire
, m
,
768 m
->rfd
->response_lifetime
, &m
->timer
);
772 * called when an updated response is sent to the NVE. Per
773 * ticket 255, restart timers for any monitors that could have
774 * been responsible for the response, i.e., any monitors for
775 * the exact prefix or a parent of it.
777 void rfapiMonitorTimersRestart(struct rfapi_descriptor
*rfd
,
778 const struct prefix
*p
)
782 if (AF_ETHERNET
== p
->family
) {
783 struct rfapi_monitor_eth
*mon_eth
;
791 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon_eth
,
793 rc
== 0; rc
= skiplist_next(rfd
->mon_eth
, NULL
,
794 (void **)&mon_eth
, &cursor
)) {
796 if (!memcmp(mon_eth
->macaddr
.octet
,
797 p
->u
.prefix_eth
.octet
, ETH_ALEN
)) {
799 rfapiMonitorEthTimerRestart(mon_eth
);
804 for (rn
= agg_route_top(rfd
->mon
); rn
;
805 rn
= agg_route_next(rn
)) {
806 struct rfapi_monitor_vpn
*m
;
807 const struct prefix
*p_node
;
809 if (!((m
= rn
->info
)))
812 p_node
= agg_node_get_prefix(m
->node
);
813 /* NB order of test is significant ! */
814 if (!m
->node
|| prefix_match(p_node
, p
)) {
815 rfapiMonitorTimerRestart(m
);
822 * Find monitors at this node and all its parents. Call
823 * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
825 void rfapiMonitorItNodeChanged(
826 struct rfapi_import_table
*import_table
, struct agg_node
*it_node
,
827 struct rfapi_monitor_vpn
*monitor_list
) /* for base it node, NULL=all */
829 struct skiplist
*nves_seen
;
830 struct agg_node
*rn
= it_node
;
831 struct bgp
*bgp
= bgp_get_default();
832 const struct prefix
*p
= agg_node_get_prefix(rn
);
833 afi_t afi
= family2afi(p
->family
);
836 assert(import_table
);
838 nves_seen
= skiplist_new(0, NULL
, NULL
);
841 vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%pFX",
842 __func__
, import_table
, it_node
, &it_node
->p
);
845 if (AFI_L2VPN
== afi
) {
846 struct rfapi_monitor_eth
*m
;
851 if ((sl
= RFAPI_MONITOR_ETH(rn
))) {
854 rc
= skiplist_next(sl
, NULL
, (void **)&m
, &cursor
);
855 !rc
; rc
= skiplist_next(sl
, NULL
, (void **)&m
,
858 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
860 * Haven't done this NVE yet. Add to
863 assert(!skiplist_insert(nves_seen
,
869 rfapiRibUpdatePendingNode(
870 bgp
, m
->rfd
, import_table
,
872 m
->rfd
->response_lifetime
);
879 struct rfapi_monitor_vpn
*m
;
884 m
= RFAPI_MONITOR_VPN(rn
);
889 * If we have reached the root node (parent==NULL) and
891 * are no routes here (info==NULL), and the IT node that
892 * changed was not the root node (it_node->parent !=
894 * then any monitors at this node are here because they
896 * no match at all. Therefore, do not send route updates
898 * because we haven't sent them an initial route.
900 if (!agg_node_parent(rn
) && !rn
->info
904 for (; m
; m
= m
->next
) {
906 if (RFAPI_0_PREFIX(&m
->p
)) {
907 /* shouldn't happen, but be safe */
910 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
912 * Haven't done this NVE yet. Add to
915 assert(!skiplist_insert(nves_seen
,
918 vnc_zlog_debug_verbose(
919 "%s: update rfd %p attached to pfx %pRN (targ=%pFX)",
920 __func__
, m
->rfd
, m
->node
,
926 rfapiRibUpdatePendingNode(
927 bgp
, m
->rfd
, import_table
,
929 m
->rfd
->response_lifetime
);
932 rn
= agg_node_parent(rn
);
934 m
= RFAPI_MONITOR_VPN(rn
);
939 * All-routes L2 monitors
941 if (AFI_L2VPN
== afi
) {
942 struct rfapi_monitor_eth
*e
;
945 vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
949 for (e
= import_table
->eth0_queries
; e
; e
= e
->next
) {
951 vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
954 if (skiplist_search(nves_seen
, e
->rfd
, NULL
)) {
956 * Haven't done this NVE yet. Add to "seen"
959 assert(!skiplist_insert(nves_seen
, e
->rfd
,
966 vnc_zlog_debug_verbose(
967 "%s: found L2 all-routes monitor %p",
970 rfapiRibUpdatePendingNode(
971 bgp
, e
->rfd
, import_table
, it_node
,
972 e
->rfd
->response_lifetime
);
976 struct rfapi_monitor_vpn
*m
;
979 * All-routes IPv4. IPv6 monitors
981 for (m
= import_table
->vpn0_queries
[afi
]; m
; m
= m
->next
) {
982 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
984 * Haven't done this NVE yet. Add to "seen"
987 assert(!skiplist_insert(nves_seen
, m
->rfd
,
993 rfapiRibUpdatePendingNode(
994 bgp
, m
->rfd
, import_table
, it_node
,
995 m
->rfd
->response_lifetime
);
1000 skiplist_free(nves_seen
);
1004 * For the listed monitors, update new node and its subtree, but
1005 * omit old node and its subtree
1007 void rfapiMonitorMovedUp(struct rfapi_import_table
*import_table
,
1008 struct agg_node
*old_node
, struct agg_node
*new_node
,
1009 struct rfapi_monitor_vpn
*monitor_list
)
1011 struct bgp
*bgp
= bgp_get_default();
1012 struct rfapi_monitor_vpn
*m
;
1016 assert(new_node
!= old_node
);
1019 * If new node is 0/0 and there is no route there, don't
1020 * generate an update because it will not contain any
1021 * routes including the target.
1023 if (!new_node
->parent
&& !new_node
->info
) {
1024 vnc_zlog_debug_verbose(
1025 "%s: new monitor at 0/0 and no routes, no updates",
1030 for (m
= monitor_list
; m
; m
= m
->next
) {
1031 rfapiRibUpdatePendingNode(bgp
, m
->rfd
, import_table
, new_node
,
1032 m
->rfd
->response_lifetime
);
1033 rfapiRibUpdatePendingNodeSubtree(bgp
, m
->rfd
, import_table
,
1035 m
->rfd
->response_lifetime
);
1039 static void rfapiMonitorEthTimerExpire(struct thread
*t
)
1041 struct rfapi_monitor_eth
*m
= THREAD_ARG(t
);
1043 /* forget reference to thread, it's gone */
1046 /* delete the monitor */
1047 rfapiMonitorEthDel(bgp_get_default(), m
->rfd
, &m
->macaddr
,
1052 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth
*m
)
1054 unsigned long remain
= thread_timer_remain_second(m
->timer
);
1056 /* unexpected case, but avoid wraparound problems below */
1057 if (remain
> m
->rfd
->response_lifetime
)
1060 /* don't restart if we just restarted recently */
1061 if (m
->rfd
->response_lifetime
- remain
< 2)
1064 THREAD_OFF(m
->timer
);
1069 vnc_zlog_debug_verbose(
1070 "%s: target %s life %u", __func__
,
1071 rfapiEthAddr2Str(&m
->macaddr
, buf
, BUFSIZ
),
1072 m
->rfd
->response_lifetime
);
1075 thread_add_timer(bm
->master
, rfapiMonitorEthTimerExpire
, m
,
1076 m
->rfd
->response_lifetime
, &m
->timer
);
1079 static int mon_eth_cmp(const void *a
, const void *b
)
1081 const struct rfapi_monitor_eth
*m1
;
1082 const struct rfapi_monitor_eth
*m2
;
1086 m1
= (struct rfapi_monitor_eth
*)a
;
1087 m2
= (struct rfapi_monitor_eth
*)b
;
1090 * compare ethernet addresses
1092 for (i
= 0; i
< ETH_ALEN
; ++i
) {
1093 if (m1
->macaddr
.octet
[i
] != m2
->macaddr
.octet
[i
])
1094 return (m1
->macaddr
.octet
[i
] - m2
->macaddr
.octet
[i
]);
1100 return (m1
->logical_net_id
- m2
->logical_net_id
);
1103 static void rfapiMonitorEthAttachImport(
1104 struct rfapi_import_table
*it
,
1105 struct agg_node
*rn
, /* it node attach point if non-0 */
1106 struct rfapi_monitor_eth
*mon
) /* monitor struct to attach */
1108 struct skiplist
*sl
;
1111 vnc_zlog_debug_verbose("%s: it=%p", __func__
, it
);
1113 rfapiMonitorCheckAttachAllowed();
1115 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1117 * These go on a different list
1119 mon
->next
= it
->eth0_queries
;
1120 it
->eth0_queries
= mon
;
1122 vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
1130 vnc_zlog_debug_verbose("%s: rn is null!", __func__
);
1136 * Get sl to attach to
1138 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
);
1140 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
) =
1141 skiplist_new(0, NULL
, NULL
);
1142 agg_lock_node(rn
); /* count skiplist mon_eth */
1146 vnc_zlog_debug_verbose(
1147 "%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__
,
1148 rn
, rn
->lock
, sl
, mon
);
1151 rc
= skiplist_insert(sl
, (void *)mon
, (void *)mon
);
1154 /* count eth monitor */
1159 * reattach monitors for this HD to import table
1161 static void rfapiMonitorEthAttachImportHd(struct bgp
*bgp
,
1162 struct rfapi_descriptor
*rfd
)
1165 struct rfapi_monitor_eth
*mon
;
1168 if (!rfd
->mon_eth
) {
1170 * No monitors for this HD
1176 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
);
1178 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
)) {
1180 struct rfapi_import_table
*it
;
1181 struct prefix pfx_mac_buf
;
1182 struct agg_node
*rn
;
1184 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1187 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1188 pfx_mac_buf
.family
= AF_ETHERNET
;
1189 pfx_mac_buf
.prefixlen
= 48;
1190 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1192 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1195 (void)rfapiMonitorEthAttachImport(it
, rn
, mon
);
1199 static void rfapiMonitorEthDetachImport(
1201 struct rfapi_monitor_eth
*mon
) /* monitor struct to detach */
1203 struct rfapi_import_table
*it
;
1204 struct prefix pfx_mac_buf
;
1205 struct skiplist
*sl
;
1206 struct agg_node
*rn
;
1209 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1212 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1213 struct rfapi_monitor_eth
*prev
;
1214 struct rfapi_monitor_eth
*this = NULL
;
1216 for (prev
= NULL
, this = it
->eth0_queries
; this;
1217 prev
= this, this = this->next
) {
1224 it
->eth0_queries
= this->next
;
1226 prev
->next
= this->next
;
1230 vnc_zlog_debug_verbose(
1231 "%s: it=%p, LNI=%d, detached eth0 mon %p", __func__
, it
,
1232 mon
->logical_net_id
, mon
);
1237 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1238 pfx_mac_buf
.family
= AF_ETHERNET
;
1239 pfx_mac_buf
.prefixlen
= 48;
1240 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1242 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1246 * Get sl to detach from
1248 sl
= RFAPI_MONITOR_ETH(rn
);
1250 vnc_zlog_debug_verbose(
1251 "%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%pFX, LNI=%d, detaching eth mon %p",
1252 __func__
, it
, rn
, rn
->lock
, sl
, agg_node_get_prefix(rn
),
1253 mon
->logical_net_id
, mon
);
1258 rc
= skiplist_delete(sl
, (void *)mon
, (void *)mon
);
1261 /* uncount eth monitor */
1262 agg_unlock_node(rn
);
1265 struct agg_node
*rfapiMonitorEthAdd(struct bgp
*bgp
,
1266 struct rfapi_descriptor
*rfd
,
1267 struct ethaddr
*macaddr
,
1268 uint32_t logical_net_id
)
1271 struct rfapi_monitor_eth mon_buf
;
1272 struct rfapi_monitor_eth
*val
;
1273 struct rfapi_import_table
*it
;
1274 struct agg_node
*rn
= NULL
;
1275 struct prefix pfx_mac_buf
;
1277 if (!rfd
->mon_eth
) {
1278 rfd
->mon_eth
= skiplist_new(0, mon_eth_cmp
, NULL
);
1281 it
= rfapiMacImportTableGet(bgp
, logical_net_id
);
1285 * Get route node in import table. Here is where we attach the
1288 * Look it up now because we return it to caller regardless of
1289 * whether we create a new monitor or not.
1291 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1292 pfx_mac_buf
.family
= AF_ETHERNET
;
1293 pfx_mac_buf
.prefixlen
= 48;
1294 pfx_mac_buf
.u
.prefix_eth
= *macaddr
;
1296 if (!RFAPI_0_ETHERADDR(macaddr
)) {
1297 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1301 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1303 mon_buf
.macaddr
= *macaddr
;
1304 mon_buf
.logical_net_id
= logical_net_id
;
1309 vnc_zlog_debug_verbose(
1310 "%s: LNI=%d: rfd=%p, pfx=%s", __func__
, logical_net_id
,
1311 rfd
, rfapi_ntop(pfx_mac_buf
.family
, pfx_mac_buf
.u
.val
,
1319 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1322 * Found monitor - we have seen this query before
1325 vnc_zlog_debug_verbose(
1326 "%s: already present in rfd->mon_eth, not adding",
1328 rfapiMonitorEthTimerRestart(val
);
1335 val
= XCALLOC(MTYPE_RFAPI_MONITOR_ETH
,
1336 sizeof(struct rfapi_monitor_eth
));
1340 ++rfd
->monitor_count
;
1341 ++bgp
->rfapi
->monitor_count
;
1343 rc
= skiplist_insert(rfd
->mon_eth
, val
, val
);
1346 vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
1347 __func__
, rfd
, val
, rc
);
1355 rfapiMonitorEthTimerRestart(val
);
1357 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1359 * callbacks turned off, so don't attach monitor to import table
1362 vnc_zlog_debug_verbose(
1363 "%s: callbacks turned off, not attaching mon_eth %p to import table",
1370 * attach to import table
1372 rfapiMonitorEthAttachImport(it
, rn
, val
);
1377 void rfapiMonitorEthDel(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1378 struct ethaddr
*macaddr
, uint32_t logical_net_id
)
1380 struct rfapi_monitor_eth
*val
;
1381 struct rfapi_monitor_eth mon_buf
;
1384 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
1386 assert(rfd
->mon_eth
);
1388 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1389 mon_buf
.macaddr
= *macaddr
;
1390 mon_buf
.logical_net_id
= logical_net_id
;
1392 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1396 * remove from import table
1398 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1399 rfapiMonitorEthDetachImport(bgp
, val
);
1402 THREAD_OFF(val
->timer
);
1405 * remove from rfd list
1407 rc
= skiplist_delete(rfd
->mon_eth
, val
, val
);
1411 vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__
, val
);
1413 XFREE(MTYPE_RFAPI_MONITOR_ETH
, val
);
1415 --rfd
->monitor_count
;
1416 --bgp
->rfapi
->monitor_count
;
1420 void rfapiMonitorCallbacksOff(struct bgp
*bgp
)
1422 struct rfapi_import_table
*it
;
1424 struct agg_table
*rt
;
1425 struct agg_node
*rn
;
1428 struct rfapi
*h
= bgp
->rfapi
;
1430 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1436 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1439 vnc_zlog_debug_verbose("%s: turned off callbacks", __func__
);
1445 * detach monitors from import VPN tables. The monitors
1446 * will still be linked in per-nve monitor lists.
1448 for (it
= h
->imports
; it
; it
= it
->next
) {
1449 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
1451 struct rfapi_monitor_vpn
*m
;
1452 struct rfapi_monitor_vpn
*next
;
1454 rt
= it
->imported_vpn
[afi
];
1456 for (rn
= agg_route_top(rt
); rn
;
1457 rn
= agg_route_next(rn
)) {
1458 m
= RFAPI_MONITOR_VPN(rn
);
1459 if (RFAPI_MONITOR_VPN(rn
))
1460 RFAPI_MONITOR_VPN_W_ALLOC(rn
) = NULL
;
1461 for (; m
; m
= next
) {
1464 NULL
; /* gratuitous safeness */
1466 agg_unlock_node(rn
); /* uncount */
1470 for (m
= it
->vpn0_queries
[afi
]; m
; m
= next
) {
1472 m
->next
= NULL
; /* gratuitous safeness */
1475 it
->vpn0_queries
[afi
] = NULL
; /* detach first monitor */
1480 * detach monitors from import Eth tables. The monitors
1481 * will still be linked in per-nve monitor lists.
1485 * Loop over ethernet import tables
1488 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
);
1490 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
)) {
1491 struct rfapi_monitor_eth
*e
;
1492 struct rfapi_monitor_eth
*enext
;
1495 * The actual route table
1497 rt
= it
->imported_vpn
[AFI_L2VPN
];
1500 * Find non-0 monitors (i.e., actual addresses, not FTD
1503 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
1504 struct skiplist
*sl
;
1506 sl
= RFAPI_MONITOR_ETH(rn
);
1507 while (!skiplist_delete_first(sl
)) {
1508 agg_unlock_node(rn
); /* uncount monitor */
1513 * Find 0-monitors (FTD queries)
1515 for (e
= it
->eth0_queries
; e
; e
= enext
) {
1517 vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
1521 e
->next
= NULL
; /* gratuitous safeness */
1523 it
->eth0_queries
= NULL
; /* detach first monitor */
1527 void rfapiMonitorCallbacksOn(struct bgp
*bgp
)
1529 struct listnode
*hnode
;
1530 struct rfapi_descriptor
*rfd
;
1532 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1534 * Already on. It's important that we don't try to reattach
1535 * monitors that are already attached because, in the interest
1536 * of performance, there is no checking at the lower level
1537 * whether a monitor is already attached. It leads to
1538 * corrupted chains (e.g., looped pointers)
1542 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1544 vnc_zlog_debug_verbose("%s: turned on callbacks", __func__
);
1546 if (bgp
->rfapi
== NULL
)
1552 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
1554 rfapiMonitorAttachImportHd(rfd
);
1555 rfapiMonitorEthAttachImportHd(bgp
, rfd
);