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
22 * File: rfapi_monitor.c
25 /* TBD remove unneeded includes */
27 #include "lib/zebra.h"
28 #include "lib/prefix.h"
29 #include "lib/agg_table.h"
31 #include "lib/memory.h"
33 #include "lib/table.h"
34 #include "lib/skiplist.h"
36 #include "bgpd/bgpd.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/rfapi/rfapi.h"
43 #include "bgpd/rfapi/rfapi_import.h"
44 #include "bgpd/rfapi/vnc_import_bgp.h"
45 #include "bgpd/rfapi/rfapi_private.h"
46 #include "bgpd/rfapi/rfapi_monitor.h"
47 #include "bgpd/rfapi/rfapi_vty.h"
48 #include "bgpd/rfapi/rfapi_rib.h"
49 #include "bgpd/rfapi/vnc_debug.h"
51 #define DEBUG_L2_EXTRA 0
52 #define DEBUG_DUP_CHECK 0
53 #define DEBUG_ETH_SL 0
55 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn
*m
);
57 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth
*m
);
60 * Forward declarations
62 static void rfapiMonitorEthDetachImport(struct bgp
*bgp
,
63 struct rfapi_monitor_eth
*mon
);
67 * Debug function, special case
69 void rfapiMonitorEthSlCheck(struct agg_node
*rn
, const char *tag1
,
72 struct agg_node
*rn_saved
= NULL
;
73 static struct skiplist
*sl_saved
= NULL
;
79 if (rn_saved
&& (rn
!= rn_saved
))
85 sl
= RFAPI_MONITOR_ETH(rn
);
87 vnc_zlog_debug_verbose(
88 "%s[%s%s]: rn=%p, rn->lock=%d, old sl=%p, new sl=%p",
89 __func__
, (tag1
? tag1
: ""), (tag2
? tag2
: ""), rn
,
90 rn
->lock
, sl_saved
, sl
);
97 * Debugging function that aborts when it finds monitors whose
98 * "next" pointer * references themselves
100 void rfapiMonitorLoopCheck(struct rfapi_monitor_vpn
*mchain
)
102 struct rfapi_monitor_vpn
*m
;
104 for (m
= mchain
; m
; m
= m
->next
)
105 assert(m
!= m
->next
);
110 * Debugging code: see if a monitor is mentioned more than once
111 * in a HD's monitor list
113 void rfapiMonitorDupCheck(struct bgp
*bgp
)
115 struct listnode
*hnode
;
116 struct rfapi_descriptor
*rfd
;
118 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
119 struct agg_node
*mrn
;
124 for (mrn
= agg_route_top(rfd
->mon
); mrn
;
125 mrn
= agg_route_next(mrn
)) {
126 struct rfapi_monitor_vpn
*m
;
127 for (m
= (struct rfapi_monitor_vpn
*)(mrn
->info
); m
;
133 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
134 struct agg_node
*mrn
;
139 for (mrn
= agg_route_top(rfd
->mon
); mrn
;
140 mrn
= agg_route_next(mrn
)) {
141 struct rfapi_monitor_vpn
*m
;
143 for (m
= (struct rfapi_monitor_vpn
*)(mrn
->info
); m
;
145 assert(++m
->dcount
== 1);
152 void rfapiMonitorCleanCheck(struct bgp
*bgp
)
154 struct listnode
*hnode
;
155 struct rfapi_descriptor
*rfd
;
157 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
158 assert(!rfd
->import_table
->vpn0_queries
[AFI_IP
]);
159 assert(!rfd
->import_table
->vpn0_queries
[AFI_IP6
]);
163 for (rn
= agg_route_top(
164 rfd
->import_table
->imported_vpn
[AFI_IP
]);
165 rn
; rn
= agg_route_next(rn
)) {
167 assert(!RFAPI_MONITOR_VPN(rn
));
169 for (rn
= agg_route_top(
170 rfd
->import_table
->imported_vpn
[AFI_IP6
]);
171 rn
; rn
= agg_route_next(rn
)) {
173 assert(!RFAPI_MONITOR_VPN(rn
));
179 void rfapiMonitorCheckAttachAllowed(void)
181 struct bgp
*bgp
= bgp_get_default();
182 assert(!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
));
185 void rfapiMonitorExtraFlush(safi_t safi
, struct agg_node
*rn
)
187 struct rfapi_it_extra
*hie
;
188 struct rfapi_monitor_vpn
*v
;
189 struct rfapi_monitor_vpn
*v_next
;
190 struct rfapi_monitor_encap
*e
= NULL
;
191 struct rfapi_monitor_encap
*e_next
= NULL
;
199 hie
= (struct rfapi_it_extra
*)(rn
->aggregate
);
203 for (e
= hie
->u
.encap
.e
; e
; e
= e_next
) {
206 XFREE(MTYPE_RFAPI_MONITOR_ENCAP
, e
);
209 hie
->u
.encap
.e
= NULL
;
213 for (v
= hie
->u
.vpn
.v
; v
; v
= v_next
) {
216 XFREE(MTYPE_RFAPI_MONITOR
, e
);
220 if (hie
->u
.vpn
.e
.source
) {
221 while (!skiplist_delete_first(hie
->u
.vpn
.e
.source
)) {
224 skiplist_free(hie
->u
.vpn
.e
.source
);
225 hie
->u
.vpn
.e
.source
= NULL
;
228 if (hie
->u
.vpn
.idx_rd
) {
229 /* looping through bpi->extra->vnc.import.rd is tbd */
230 while (!skiplist_delete_first(hie
->u
.vpn
.idx_rd
)) {
233 skiplist_free(hie
->u
.vpn
.idx_rd
);
234 hie
->u
.vpn
.idx_rd
= NULL
;
237 if (hie
->u
.vpn
.mon_eth
) {
238 while (!skiplist_delete_first(hie
->u
.vpn
.mon_eth
)) {
241 skiplist_free(hie
->u
.vpn
.mon_eth
);
242 hie
->u
.vpn
.mon_eth
= NULL
;
250 XFREE(MTYPE_RFAPI_IT_EXTRA
, hie
);
251 rn
->aggregate
= NULL
;
256 * If the child lists are empty, release the rfapi_it_extra struct
258 void rfapiMonitorExtraPrune(safi_t safi
, struct agg_node
*rn
)
260 struct rfapi_it_extra
*hie
;
268 hie
= (struct rfapi_it_extra
*)(rn
->aggregate
);
279 if (hie
->u
.vpn
.mon_eth
) {
280 if (skiplist_count(hie
->u
.vpn
.mon_eth
))
282 skiplist_free(hie
->u
.vpn
.mon_eth
);
283 hie
->u
.vpn
.mon_eth
= NULL
;
284 agg_unlock_node(rn
); /* uncount skiplist */
286 if (hie
->u
.vpn
.e
.source
) {
287 if (skiplist_count(hie
->u
.vpn
.e
.source
))
289 skiplist_free(hie
->u
.vpn
.e
.source
);
290 hie
->u
.vpn
.e
.source
= NULL
;
293 if (hie
->u
.vpn
.idx_rd
) {
294 if (skiplist_count(hie
->u
.vpn
.idx_rd
))
296 skiplist_free(hie
->u
.vpn
.idx_rd
);
297 hie
->u
.vpn
.idx_rd
= NULL
;
300 if (hie
->u
.vpn
.mon_eth
) {
301 if (skiplist_count(hie
->u
.vpn
.mon_eth
))
303 skiplist_free(hie
->u
.vpn
.mon_eth
);
304 hie
->u
.vpn
.mon_eth
= NULL
;
312 XFREE(MTYPE_RFAPI_IT_EXTRA
, hie
);
313 rn
->aggregate
= NULL
;
318 * returns locked node
320 struct agg_node
*rfapiMonitorGetAttachNode(struct rfapi_descriptor
*rfd
,
326 if (RFAPI_0_PREFIX(p
)) {
330 afi
= family2afi(p
->family
);
334 * It's possible that even though there is a route at this node,
335 * there are no routes with valid UN addresses (i.e,. with no
336 * valid tunnel routes). Check for that and walk back up the
339 * When the outer loop completes, the matched node, if any, is
340 * locked (i.e., its reference count has been incremented) to
341 * account for the VPN monitor we are about to attach.
343 * if a monitor is moved to another node, there must be
344 * corresponding unlock/locks
346 for (rn
= agg_node_match(rfd
->import_table
->imported_vpn
[afi
], p
);
349 struct bgp_path_info
*bpi
;
350 struct prefix pfx_dummy
;
352 /* TBD update this code to use new valid_interior_count */
353 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
355 * If there is a cached ENCAP UN address, it's a usable
358 if (bpi
->extra
&& bpi
->extra
->vnc
.import
.un_family
) {
363 * Or if there is a valid Encap Attribute tunnel subtlv
365 * it's a usable VPN route.
367 if (!rfapiGetVncTunnelUnAddr(bpi
->attr
, &pfx_dummy
)) {
375 if ((rn
= agg_node_parent(rn
))) {
381 struct prefix pfx_default
;
383 memset(&pfx_default
, 0, sizeof(pfx_default
));
384 pfx_default
.family
= p
->family
;
386 /* creates default node if none exists, and increments ref count
388 rn
= agg_node_get(rfd
->import_table
->imported_vpn
[afi
],
396 * If this function happens to attach the monitor to a radix tree
397 * node (as opposed to the 0-prefix list), the node pointer is
398 * returned (for the benefit of caller which might like to use it
399 * to generate an immediate query response).
401 static struct agg_node
*rfapiMonitorAttachImport(struct rfapi_descriptor
*rfd
,
402 struct rfapi_monitor_vpn
*m
)
406 rfapiMonitorCheckAttachAllowed();
408 if (RFAPI_0_PREFIX(&m
->p
)) {
410 * Add new monitor entry to vpn0 list
414 afi
= family2afi(m
->p
.family
);
417 m
->next
= rfd
->import_table
->vpn0_queries
[afi
];
418 rfd
->import_table
->vpn0_queries
[afi
] = m
;
419 vnc_zlog_debug_verbose("%s: attached monitor %p to vpn0 list",
425 * Attach new monitor entry to import table node
427 rn
= rfapiMonitorGetAttachNode(rfd
, &m
->p
); /* returns locked rn */
429 m
->next
= RFAPI_MONITOR_VPN(rn
);
430 RFAPI_MONITOR_VPN_W_ALLOC(rn
) = m
;
431 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, 0);
432 vnc_zlog_debug_verbose("%s: attached monitor %p to rn %p", __func__
, m
,
439 * reattach monitors for this HD to import table
441 void rfapiMonitorAttachImportHd(struct rfapi_descriptor
*rfd
)
443 struct agg_node
*mrn
;
447 * No monitors for this HD
452 for (mrn
= agg_route_top(rfd
->mon
); mrn
; mrn
= agg_route_next(mrn
)) {
457 (void)rfapiMonitorAttachImport(
458 rfd
, (struct rfapi_monitor_vpn
*)(mrn
->info
));
463 * Adds a monitor for a query to the NVE descriptor's list
464 * and, if callbacks are enabled, attaches it to the import table.
466 * If we happened to locate the import table radix tree attachment
467 * point, return it so the caller can use it to generate a query
468 * response without repeating the lookup. Note that when callbacks
469 * are disabled, this function will not perform a lookup, and the
470 * caller will have to do its own lookup.
472 struct agg_node
*rfapiMonitorAdd(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
475 struct rfapi_monitor_vpn
*m
;
479 * Initialize nve's monitor list if needed
480 * NB use the same radix tree for IPv4 and IPv6 targets.
481 * The prefix will always have full-length mask (/32, /128)
482 * or be 0/0 so they won't get mixed up.
485 rfd
->mon
= agg_table_init();
487 rn
= agg_node_get(rfd
->mon
, p
);
490 * received this query before, no further action needed
492 rfapiMonitorTimerRestart((struct rfapi_monitor_vpn
*)rn
->info
);
498 * New query for this nve, record it in the HD
501 XCALLOC(MTYPE_RFAPI_MONITOR
, sizeof(struct rfapi_monitor_vpn
));
502 m
= (struct rfapi_monitor_vpn
*)(rn
->info
);
504 prefix_copy(&m
->p
, p
);
506 ++rfd
->monitor_count
;
507 ++bgp
->rfapi
->monitor_count
;
509 rfapiMonitorTimerRestart(m
);
511 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
513 * callbacks turned off, so don't attach monitor to import table
520 * attach to import table
522 return rfapiMonitorAttachImport(rfd
, m
);
526 * returns monitor pointer if found, NULL if not
528 static struct rfapi_monitor_vpn
*
529 rfapiMonitorDetachImport(struct rfapi_monitor_vpn
*m
)
531 struct rfapi_monitor_vpn
*prev
;
532 struct rfapi_monitor_vpn
*this = NULL
;
534 if (RFAPI_0_PREFIX(&m
->p
)) {
538 * 0-prefix monitors are stored in a special list and not
539 * in the import VPN tree
542 afi
= family2afi(m
->p
.family
);
545 if (m
->rfd
->import_table
) {
547 this = m
->rfd
->import_table
->vpn0_queries
[afi
];
548 this; prev
= this, this = this->next
) {
556 ->vpn0_queries
[afi
] =
559 prev
->next
= this->next
;
566 for (prev
= NULL
, this = RFAPI_MONITOR_VPN(m
->node
);
567 this; prev
= this, this = this->next
) {
574 prev
->next
= this->next
;
576 RFAPI_MONITOR_VPN_W_ALLOC(m
->node
) =
579 RFAPI_CHECK_REFCOUNT(m
->node
, SAFI_MPLS_VPN
, 1);
580 agg_unlock_node(m
->node
);
589 void rfapiMonitorDetachImportHd(struct rfapi_descriptor
*rfd
)
596 for (rn
= agg_route_top(rfd
->mon
); rn
; rn
= agg_route_next(rn
)) {
598 rfapiMonitorDetachImport(
599 (struct rfapi_monitor_vpn
*)(rn
->info
));
604 void rfapiMonitorDel(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
608 struct rfapi_monitor_vpn
*m
;
611 rn
= agg_node_get(rfd
->mon
, p
); /* locks node */
617 * remove from import table
619 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
620 rfapiMonitorDetachImport(m
);
623 thread_cancel(&m
->timer
);
626 * remove from rfd list
628 XFREE(MTYPE_RFAPI_MONITOR
, m
);
630 agg_unlock_node(rn
); /* undo original lock when created */
631 agg_unlock_node(rn
); /* undo lock in agg_node_get */
633 --rfd
->monitor_count
;
634 --bgp
->rfapi
->monitor_count
;
638 * returns count of monitors deleted
640 int rfapiMonitorDelHd(struct rfapi_descriptor
*rfd
)
646 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
648 bgp
= bgp_get_default();
651 for (rn
= agg_route_top(rfd
->mon
); rn
;
652 rn
= agg_route_next(rn
)) {
653 struct rfapi_monitor_vpn
*m
;
654 if ((m
= rn
->info
)) {
655 if (!(bgp
->rfapi_cfg
->flags
656 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
657 rfapiMonitorDetachImport(m
);
660 thread_cancel(&m
->timer
);
662 XFREE(MTYPE_RFAPI_MONITOR
, m
);
664 agg_unlock_node(rn
); /* undo original lock
667 --rfd
->monitor_count
;
668 --bgp
->rfapi
->monitor_count
;
671 agg_table_finish(rfd
->mon
);
677 struct rfapi_monitor_eth
*mon_eth
;
679 while (!skiplist_first(rfd
->mon_eth
, NULL
, (void **)&mon_eth
)) {
683 if (!(bgp
->rfapi_cfg
->flags
684 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
685 rfapiMonitorEthDetachImport(bgp
, mon_eth
);
688 vnc_zlog_debug_verbose(
689 "%s: callbacks disabled, not attempting to detach mon_eth %p",
694 thread_cancel(&mon_eth
->timer
);
697 * remove from rfd list
699 rc
= skiplist_delete(rfd
->mon_eth
, mon_eth
, mon_eth
);
702 vnc_zlog_debug_verbose("%s: freeing mon_eth %p",
704 XFREE(MTYPE_RFAPI_MONITOR_ETH
, mon_eth
);
707 --rfd
->monitor_count
;
708 --bgp
->rfapi
->monitor_count
;
710 skiplist_free(rfd
->mon_eth
);
717 void rfapiMonitorResponseRemovalOff(struct bgp
*bgp
)
719 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
) {
722 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
725 void rfapiMonitorResponseRemovalOn(struct bgp
*bgp
)
727 if (!(bgp
->rfapi_cfg
->flags
728 & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
)) {
731 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
734 static void rfapiMonitorTimerExpire(struct thread
*t
)
736 struct rfapi_monitor_vpn
*m
= t
->arg
;
738 /* forget reference to thread, it's gone */
741 /* delete the monitor */
742 rfapiMonitorDel(bgp_get_default(), m
->rfd
, &m
->p
);
745 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn
*m
)
748 unsigned long remain
= thread_timer_remain_second(m
->timer
);
750 /* unexpected case, but avoid wraparound problems below */
751 if (remain
> m
->rfd
->response_lifetime
)
754 /* don't restart if we just restarted recently */
755 if (m
->rfd
->response_lifetime
- remain
< 2)
758 thread_cancel(&m
->timer
);
764 vnc_zlog_debug_verbose(
765 "%s: target %s life %u", __func__
,
766 rfapi_ntop(m
->p
.family
, m
->p
.u
.val
, buf
, BUFSIZ
),
767 m
->rfd
->response_lifetime
);
770 thread_add_timer(bm
->master
, rfapiMonitorTimerExpire
, m
,
771 m
->rfd
->response_lifetime
, &m
->timer
);
775 * called when an updated response is sent to the NVE. Per
776 * ticket 255, restart timers for any monitors that could have
777 * been responsible for the response, i.e., any monitors for
778 * the exact prefix or a parent of it.
780 void rfapiMonitorTimersRestart(struct rfapi_descriptor
*rfd
,
781 const struct prefix
*p
)
785 if (AF_ETHERNET
== p
->family
) {
786 struct rfapi_monitor_eth
*mon_eth
;
794 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon_eth
,
796 rc
== 0; rc
= skiplist_next(rfd
->mon_eth
, NULL
,
797 (void **)&mon_eth
, &cursor
)) {
799 if (!memcmp(mon_eth
->macaddr
.octet
,
800 p
->u
.prefix_eth
.octet
, ETH_ALEN
)) {
802 rfapiMonitorEthTimerRestart(mon_eth
);
807 for (rn
= agg_route_top(rfd
->mon
); rn
;
808 rn
= agg_route_next(rn
)) {
809 struct rfapi_monitor_vpn
*m
;
810 const struct prefix
*p_node
;
812 if (!((m
= rn
->info
)))
815 p_node
= agg_node_get_prefix(m
->node
);
816 /* NB order of test is significant ! */
817 if (!m
->node
|| prefix_match(p_node
, p
)) {
818 rfapiMonitorTimerRestart(m
);
825 * Find monitors at this node and all its parents. Call
826 * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
828 void rfapiMonitorItNodeChanged(
829 struct rfapi_import_table
*import_table
, struct agg_node
*it_node
,
830 struct rfapi_monitor_vpn
*monitor_list
) /* for base it node, NULL=all */
832 struct skiplist
*nves_seen
;
833 struct agg_node
*rn
= it_node
;
834 struct bgp
*bgp
= bgp_get_default();
835 const struct prefix
*p
= agg_node_get_prefix(rn
);
836 afi_t afi
= family2afi(p
->family
);
839 assert(import_table
);
841 nves_seen
= skiplist_new(0, NULL
, NULL
);
844 vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%pFX",
845 __func__
, import_table
, it_node
, &it_node
->p
);
848 if (AFI_L2VPN
== afi
) {
849 struct rfapi_monitor_eth
*m
;
854 if ((sl
= RFAPI_MONITOR_ETH(rn
))) {
857 rc
= skiplist_next(sl
, NULL
, (void **)&m
, &cursor
);
858 !rc
; rc
= skiplist_next(sl
, NULL
, (void **)&m
,
861 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
863 * Haven't done this NVE yet. Add to
866 assert(!skiplist_insert(nves_seen
,
872 rfapiRibUpdatePendingNode(
873 bgp
, m
->rfd
, import_table
,
875 m
->rfd
->response_lifetime
);
882 struct rfapi_monitor_vpn
*m
;
887 m
= RFAPI_MONITOR_VPN(rn
);
892 * If we have reached the root node (parent==NULL) and
894 * are no routes here (info==NULL), and the IT node that
895 * changed was not the root node (it_node->parent !=
897 * then any monitors at this node are here because they
899 * no match at all. Therefore, do not send route updates
901 * because we haven't sent them an initial route.
903 if (!agg_node_parent(rn
) && !rn
->info
907 for (; m
; m
= m
->next
) {
909 if (RFAPI_0_PREFIX(&m
->p
)) {
910 /* shouldn't happen, but be safe */
913 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
915 * Haven't done this NVE yet. Add to
918 assert(!skiplist_insert(nves_seen
,
921 vnc_zlog_debug_verbose(
922 "%s: update rfd %p attached to pfx %pRN (targ=%pFX)",
923 __func__
, m
->rfd
, m
->node
,
929 rfapiRibUpdatePendingNode(
930 bgp
, m
->rfd
, import_table
,
932 m
->rfd
->response_lifetime
);
935 rn
= agg_node_parent(rn
);
937 m
= RFAPI_MONITOR_VPN(rn
);
942 * All-routes L2 monitors
944 if (AFI_L2VPN
== afi
) {
945 struct rfapi_monitor_eth
*e
;
948 vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
952 for (e
= import_table
->eth0_queries
; e
; e
= e
->next
) {
954 vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
957 if (skiplist_search(nves_seen
, e
->rfd
, NULL
)) {
959 * Haven't done this NVE yet. Add to "seen"
962 assert(!skiplist_insert(nves_seen
, e
->rfd
,
969 vnc_zlog_debug_verbose(
970 "%s: found L2 all-routes monitor %p",
973 rfapiRibUpdatePendingNode(
974 bgp
, e
->rfd
, import_table
, it_node
,
975 e
->rfd
->response_lifetime
);
979 struct rfapi_monitor_vpn
*m
;
982 * All-routes IPv4. IPv6 monitors
984 for (m
= import_table
->vpn0_queries
[afi
]; m
; m
= m
->next
) {
985 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
987 * Haven't done this NVE yet. Add to "seen"
990 assert(!skiplist_insert(nves_seen
, m
->rfd
,
996 rfapiRibUpdatePendingNode(
997 bgp
, m
->rfd
, import_table
, it_node
,
998 m
->rfd
->response_lifetime
);
1003 skiplist_free(nves_seen
);
1007 * For the listed monitors, update new node and its subtree, but
1008 * omit old node and its subtree
1010 void rfapiMonitorMovedUp(struct rfapi_import_table
*import_table
,
1011 struct agg_node
*old_node
, struct agg_node
*new_node
,
1012 struct rfapi_monitor_vpn
*monitor_list
)
1014 struct bgp
*bgp
= bgp_get_default();
1015 struct rfapi_monitor_vpn
*m
;
1019 assert(new_node
!= old_node
);
1022 * If new node is 0/0 and there is no route there, don't
1023 * generate an update because it will not contain any
1024 * routes including the target.
1026 if (!new_node
->parent
&& !new_node
->info
) {
1027 vnc_zlog_debug_verbose(
1028 "%s: new monitor at 0/0 and no routes, no updates",
1033 for (m
= monitor_list
; m
; m
= m
->next
) {
1034 rfapiRibUpdatePendingNode(bgp
, m
->rfd
, import_table
, new_node
,
1035 m
->rfd
->response_lifetime
);
1036 rfapiRibUpdatePendingNodeSubtree(bgp
, m
->rfd
, import_table
,
1038 m
->rfd
->response_lifetime
);
1042 static void rfapiMonitorEthTimerExpire(struct thread
*t
)
1044 struct rfapi_monitor_eth
*m
= t
->arg
;
1046 /* forget reference to thread, it's gone */
1049 /* delete the monitor */
1050 rfapiMonitorEthDel(bgp_get_default(), m
->rfd
, &m
->macaddr
,
1055 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth
*m
)
1058 unsigned long remain
= thread_timer_remain_second(m
->timer
);
1060 /* unexpected case, but avoid wraparound problems below */
1061 if (remain
> m
->rfd
->response_lifetime
)
1064 /* don't restart if we just restarted recently */
1065 if (m
->rfd
->response_lifetime
- remain
< 2)
1068 thread_cancel(&m
->timer
);
1074 vnc_zlog_debug_verbose(
1075 "%s: target %s life %u", __func__
,
1076 rfapiEthAddr2Str(&m
->macaddr
, buf
, BUFSIZ
),
1077 m
->rfd
->response_lifetime
);
1080 thread_add_timer(bm
->master
, rfapiMonitorEthTimerExpire
, m
,
1081 m
->rfd
->response_lifetime
, &m
->timer
);
1084 static int mon_eth_cmp(const void *a
, const void *b
)
1086 const struct rfapi_monitor_eth
*m1
;
1087 const struct rfapi_monitor_eth
*m2
;
1091 m1
= (struct rfapi_monitor_eth
*)a
;
1092 m2
= (struct rfapi_monitor_eth
*)b
;
1095 * compare ethernet addresses
1097 for (i
= 0; i
< ETH_ALEN
; ++i
) {
1098 if (m1
->macaddr
.octet
[i
] != m2
->macaddr
.octet
[i
])
1099 return (m1
->macaddr
.octet
[i
] - m2
->macaddr
.octet
[i
]);
1105 return (m1
->logical_net_id
- m2
->logical_net_id
);
1108 static void rfapiMonitorEthAttachImport(
1109 struct rfapi_import_table
*it
,
1110 struct agg_node
*rn
, /* it node attach point if non-0 */
1111 struct rfapi_monitor_eth
*mon
) /* monitor struct to attach */
1113 struct skiplist
*sl
;
1116 vnc_zlog_debug_verbose("%s: it=%p", __func__
, it
);
1118 rfapiMonitorCheckAttachAllowed();
1120 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1122 * These go on a different list
1124 mon
->next
= it
->eth0_queries
;
1125 it
->eth0_queries
= mon
;
1127 vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
1135 vnc_zlog_debug_verbose("%s: rn is null!", __func__
);
1141 * Get sl to attach to
1143 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
);
1145 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
) =
1146 skiplist_new(0, NULL
, NULL
);
1147 agg_lock_node(rn
); /* count skiplist mon_eth */
1151 vnc_zlog_debug_verbose(
1152 "%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__
,
1153 rn
, rn
->lock
, sl
, mon
);
1156 rc
= skiplist_insert(sl
, (void *)mon
, (void *)mon
);
1159 /* count eth monitor */
1164 * reattach monitors for this HD to import table
1166 static void rfapiMonitorEthAttachImportHd(struct bgp
*bgp
,
1167 struct rfapi_descriptor
*rfd
)
1170 struct rfapi_monitor_eth
*mon
;
1173 if (!rfd
->mon_eth
) {
1175 * No monitors for this HD
1181 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
);
1183 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
)) {
1185 struct rfapi_import_table
*it
;
1186 struct prefix pfx_mac_buf
;
1187 struct agg_node
*rn
;
1189 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1192 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1193 pfx_mac_buf
.family
= AF_ETHERNET
;
1194 pfx_mac_buf
.prefixlen
= 48;
1195 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1197 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1200 (void)rfapiMonitorEthAttachImport(it
, rn
, mon
);
1204 static void rfapiMonitorEthDetachImport(
1206 struct rfapi_monitor_eth
*mon
) /* monitor struct to detach */
1208 struct rfapi_import_table
*it
;
1209 struct prefix pfx_mac_buf
;
1210 struct skiplist
*sl
;
1211 struct agg_node
*rn
;
1214 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1217 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1218 struct rfapi_monitor_eth
*prev
;
1219 struct rfapi_monitor_eth
*this = NULL
;
1221 for (prev
= NULL
, this = it
->eth0_queries
; this;
1222 prev
= this, this = this->next
) {
1229 it
->eth0_queries
= this->next
;
1231 prev
->next
= this->next
;
1235 vnc_zlog_debug_verbose(
1236 "%s: it=%p, LNI=%d, detached eth0 mon %p", __func__
, it
,
1237 mon
->logical_net_id
, mon
);
1242 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1243 pfx_mac_buf
.family
= AF_ETHERNET
;
1244 pfx_mac_buf
.prefixlen
= 48;
1245 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1247 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1251 * Get sl to detach from
1253 sl
= RFAPI_MONITOR_ETH(rn
);
1255 vnc_zlog_debug_verbose(
1256 "%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%pFX, LNI=%d, detaching eth mon %p",
1257 __func__
, it
, rn
, rn
->lock
, sl
, agg_node_get_prefix(rn
),
1258 mon
->logical_net_id
, mon
);
1263 rc
= skiplist_delete(sl
, (void *)mon
, (void *)mon
);
1266 /* uncount eth monitor */
1267 agg_unlock_node(rn
);
1270 struct agg_node
*rfapiMonitorEthAdd(struct bgp
*bgp
,
1271 struct rfapi_descriptor
*rfd
,
1272 struct ethaddr
*macaddr
,
1273 uint32_t logical_net_id
)
1276 struct rfapi_monitor_eth mon_buf
;
1277 struct rfapi_monitor_eth
*val
;
1278 struct rfapi_import_table
*it
;
1279 struct agg_node
*rn
= NULL
;
1280 struct prefix pfx_mac_buf
;
1282 if (!rfd
->mon_eth
) {
1283 rfd
->mon_eth
= skiplist_new(0, mon_eth_cmp
, NULL
);
1286 it
= rfapiMacImportTableGet(bgp
, logical_net_id
);
1290 * Get route node in import table. Here is where we attach the
1293 * Look it up now because we return it to caller regardless of
1294 * whether we create a new monitor or not.
1296 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1297 pfx_mac_buf
.family
= AF_ETHERNET
;
1298 pfx_mac_buf
.prefixlen
= 48;
1299 pfx_mac_buf
.u
.prefix_eth
= *macaddr
;
1301 if (!RFAPI_0_ETHERADDR(macaddr
)) {
1302 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1306 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1308 mon_buf
.macaddr
= *macaddr
;
1309 mon_buf
.logical_net_id
= logical_net_id
;
1314 vnc_zlog_debug_verbose(
1315 "%s: LNI=%d: rfd=%p, pfx=%s", __func__
, logical_net_id
,
1316 rfd
, rfapi_ntop(pfx_mac_buf
.family
, pfx_mac_buf
.u
.val
,
1324 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1327 * Found monitor - we have seen this query before
1330 vnc_zlog_debug_verbose(
1331 "%s: already present in rfd->mon_eth, not adding",
1333 rfapiMonitorEthTimerRestart(val
);
1340 val
= XCALLOC(MTYPE_RFAPI_MONITOR_ETH
,
1341 sizeof(struct rfapi_monitor_eth
));
1345 ++rfd
->monitor_count
;
1346 ++bgp
->rfapi
->monitor_count
;
1348 rc
= skiplist_insert(rfd
->mon_eth
, val
, val
);
1351 vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
1352 __func__
, rfd
, val
, rc
);
1360 rfapiMonitorEthTimerRestart(val
);
1362 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1364 * callbacks turned off, so don't attach monitor to import table
1367 vnc_zlog_debug_verbose(
1368 "%s: callbacks turned off, not attaching mon_eth %p to import table",
1375 * attach to import table
1377 rfapiMonitorEthAttachImport(it
, rn
, val
);
1382 void rfapiMonitorEthDel(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1383 struct ethaddr
*macaddr
, uint32_t logical_net_id
)
1385 struct rfapi_monitor_eth
*val
;
1386 struct rfapi_monitor_eth mon_buf
;
1389 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
1391 assert(rfd
->mon_eth
);
1393 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1394 mon_buf
.macaddr
= *macaddr
;
1395 mon_buf
.logical_net_id
= logical_net_id
;
1397 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1401 * remove from import table
1403 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1404 rfapiMonitorEthDetachImport(bgp
, val
);
1407 thread_cancel(&val
->timer
);
1410 * remove from rfd list
1412 rc
= skiplist_delete(rfd
->mon_eth
, val
, val
);
1416 vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__
, val
);
1418 XFREE(MTYPE_RFAPI_MONITOR_ETH
, val
);
1420 --rfd
->monitor_count
;
1421 --bgp
->rfapi
->monitor_count
;
1425 void rfapiMonitorCallbacksOff(struct bgp
*bgp
)
1427 struct rfapi_import_table
*it
;
1429 struct agg_table
*rt
;
1430 struct agg_node
*rn
;
1433 struct rfapi
*h
= bgp
->rfapi
;
1435 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1441 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1444 vnc_zlog_debug_verbose("%s: turned off callbacks", __func__
);
1450 * detach monitors from import VPN tables. The monitors
1451 * will still be linked in per-nve monitor lists.
1453 for (it
= h
->imports
; it
; it
= it
->next
) {
1454 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
1456 struct rfapi_monitor_vpn
*m
;
1457 struct rfapi_monitor_vpn
*next
;
1459 rt
= it
->imported_vpn
[afi
];
1461 for (rn
= agg_route_top(rt
); rn
;
1462 rn
= agg_route_next(rn
)) {
1463 m
= RFAPI_MONITOR_VPN(rn
);
1464 if (RFAPI_MONITOR_VPN(rn
))
1465 RFAPI_MONITOR_VPN_W_ALLOC(rn
) = NULL
;
1466 for (; m
; m
= next
) {
1469 NULL
; /* gratuitous safeness */
1471 agg_unlock_node(rn
); /* uncount */
1475 for (m
= it
->vpn0_queries
[afi
]; m
; m
= next
) {
1477 m
->next
= NULL
; /* gratuitous safeness */
1480 it
->vpn0_queries
[afi
] = NULL
; /* detach first monitor */
1485 * detach monitors from import Eth tables. The monitors
1486 * will still be linked in per-nve monitor lists.
1490 * Loop over ethernet import tables
1493 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
);
1495 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
)) {
1496 struct rfapi_monitor_eth
*e
;
1497 struct rfapi_monitor_eth
*enext
;
1500 * The actual route table
1502 rt
= it
->imported_vpn
[AFI_L2VPN
];
1505 * Find non-0 monitors (i.e., actual addresses, not FTD
1508 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
1509 struct skiplist
*sl
;
1511 sl
= RFAPI_MONITOR_ETH(rn
);
1512 while (!skiplist_delete_first(sl
)) {
1513 agg_unlock_node(rn
); /* uncount monitor */
1518 * Find 0-monitors (FTD queries)
1520 for (e
= it
->eth0_queries
; e
; e
= enext
) {
1522 vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
1526 e
->next
= NULL
; /* gratuitous safeness */
1528 it
->eth0_queries
= NULL
; /* detach first monitor */
1532 void rfapiMonitorCallbacksOn(struct bgp
*bgp
)
1534 struct listnode
*hnode
;
1535 struct rfapi_descriptor
*rfd
;
1537 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1539 * Already on. It's important that we don't try to reattach
1540 * monitors that are already attached because, in the interest
1541 * of performance, there is no checking at the lower level
1542 * whether a monitor is already attached. It leads to
1543 * corrupted chains (e.g., looped pointers)
1547 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1549 vnc_zlog_debug_verbose("%s: turned on callbacks", __func__
);
1551 if (bgp
->rfapi
== NULL
)
1557 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
1559 rfapiMonitorAttachImportHd(rfd
);
1560 rfapiMonitorEthAttachImportHd(bgp
, rfd
);