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
);
624 thread_cancel(m
->timer
);
629 * remove from rfd list
631 XFREE(MTYPE_RFAPI_MONITOR
, m
);
633 agg_unlock_node(rn
); /* undo original lock when created */
634 agg_unlock_node(rn
); /* undo lock in agg_node_get */
636 --rfd
->monitor_count
;
637 --bgp
->rfapi
->monitor_count
;
641 * returns count of monitors deleted
643 int rfapiMonitorDelHd(struct rfapi_descriptor
*rfd
)
649 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
651 bgp
= bgp_get_default();
654 for (rn
= agg_route_top(rfd
->mon
); rn
;
655 rn
= agg_route_next(rn
)) {
656 struct rfapi_monitor_vpn
*m
;
657 if ((m
= rn
->info
)) {
658 if (!(bgp
->rfapi_cfg
->flags
659 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
660 rfapiMonitorDetachImport(m
);
664 thread_cancel(m
->timer
);
668 XFREE(MTYPE_RFAPI_MONITOR
, m
);
670 agg_unlock_node(rn
); /* undo original lock
673 --rfd
->monitor_count
;
674 --bgp
->rfapi
->monitor_count
;
677 agg_table_finish(rfd
->mon
);
683 struct rfapi_monitor_eth
*mon_eth
;
685 while (!skiplist_first(rfd
->mon_eth
, NULL
, (void **)&mon_eth
)) {
689 if (!(bgp
->rfapi_cfg
->flags
690 & BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
691 rfapiMonitorEthDetachImport(bgp
, mon_eth
);
694 vnc_zlog_debug_verbose(
695 "%s: callbacks disabled, not attempting to detach mon_eth %p",
700 if (mon_eth
->timer
) {
701 thread_cancel(mon_eth
->timer
);
702 mon_eth
->timer
= NULL
;
706 * remove from rfd list
708 rc
= skiplist_delete(rfd
->mon_eth
, mon_eth
, mon_eth
);
711 vnc_zlog_debug_verbose("%s: freeing mon_eth %p",
713 XFREE(MTYPE_RFAPI_MONITOR_ETH
, mon_eth
);
716 --rfd
->monitor_count
;
717 --bgp
->rfapi
->monitor_count
;
719 skiplist_free(rfd
->mon_eth
);
726 void rfapiMonitorResponseRemovalOff(struct bgp
*bgp
)
728 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
) {
731 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
734 void rfapiMonitorResponseRemovalOn(struct bgp
*bgp
)
736 if (!(bgp
->rfapi_cfg
->flags
737 & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
)) {
740 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
;
743 static int rfapiMonitorTimerExpire(struct thread
*t
)
745 struct rfapi_monitor_vpn
*m
= t
->arg
;
747 /* forget reference to thread, it's gone */
750 /* delete the monitor */
751 rfapiMonitorDel(bgp_get_default(), m
->rfd
, &m
->p
);
756 static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn
*m
)
759 unsigned long remain
= thread_timer_remain_second(m
->timer
);
761 /* unexpected case, but avoid wraparound problems below */
762 if (remain
> m
->rfd
->response_lifetime
)
765 /* don't restart if we just restarted recently */
766 if (m
->rfd
->response_lifetime
- remain
< 2)
769 thread_cancel(m
->timer
);
776 vnc_zlog_debug_verbose(
777 "%s: target %s life %u", __func__
,
778 rfapi_ntop(m
->p
.family
, m
->p
.u
.val
, buf
, BUFSIZ
),
779 m
->rfd
->response_lifetime
);
782 thread_add_timer(bm
->master
, rfapiMonitorTimerExpire
, m
,
783 m
->rfd
->response_lifetime
, &m
->timer
);
787 * called when an updated response is sent to the NVE. Per
788 * ticket 255, restart timers for any monitors that could have
789 * been responsible for the response, i.e., any monitors for
790 * the exact prefix or a parent of it.
792 void rfapiMonitorTimersRestart(struct rfapi_descriptor
*rfd
, struct prefix
*p
)
796 if (AF_ETHERNET
== p
->family
) {
797 struct rfapi_monitor_eth
*mon_eth
;
805 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon_eth
,
807 rc
== 0; rc
= skiplist_next(rfd
->mon_eth
, NULL
,
808 (void **)&mon_eth
, &cursor
)) {
810 if (!memcmp(mon_eth
->macaddr
.octet
,
811 p
->u
.prefix_eth
.octet
, ETH_ALEN
)) {
813 rfapiMonitorEthTimerRestart(mon_eth
);
818 for (rn
= agg_route_top(rfd
->mon
); rn
;
819 rn
= agg_route_next(rn
)) {
820 struct rfapi_monitor_vpn
*m
;
822 if (!((m
= rn
->info
)))
825 /* NB order of test is significant ! */
826 if (!m
->node
|| prefix_match(&m
->node
->p
, p
)) {
827 rfapiMonitorTimerRestart(m
);
834 * Find monitors at this node and all its parents. Call
835 * rfapiRibUpdatePendingNode with this node and all corresponding NVEs.
837 void rfapiMonitorItNodeChanged(
838 struct rfapi_import_table
*import_table
, struct agg_node
*it_node
,
839 struct rfapi_monitor_vpn
*monitor_list
) /* for base it node, NULL=all */
841 struct skiplist
*nves_seen
;
842 struct agg_node
*rn
= it_node
;
843 struct bgp
*bgp
= bgp_get_default();
844 afi_t afi
= family2afi(rn
->p
.family
);
846 char buf_prefix
[PREFIX_STRLEN
];
850 assert(import_table
);
852 nves_seen
= skiplist_new(0, NULL
, NULL
);
855 prefix2str(&it_node
->p
, buf_prefix
, sizeof(buf_prefix
));
856 vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%s",
857 __func__
, import_table
, it_node
, buf_prefix
);
860 if (AFI_L2VPN
== afi
) {
861 struct rfapi_monitor_eth
*m
;
866 if ((sl
= RFAPI_MONITOR_ETH(rn
))) {
869 rc
= skiplist_next(sl
, NULL
, (void **)&m
,
871 !rc
; rc
= skiplist_next(sl
, NULL
, (void **)&m
,
874 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
876 * Haven't done this NVE yet. Add to
879 assert(!skiplist_insert(nves_seen
,
885 rfapiRibUpdatePendingNode(
886 bgp
, m
->rfd
, import_table
,
888 m
->rfd
->response_lifetime
);
895 struct rfapi_monitor_vpn
*m
;
900 m
= RFAPI_MONITOR_VPN(rn
);
905 * If we have reached the root node (parent==NULL) and
907 * are no routes here (info==NULL), and the IT node that
908 * changed was not the root node (it_node->parent !=
910 * then any monitors at this node are here because they
912 * no match at all. Therefore, do not send route updates
914 * because we haven't sent them an initial route.
916 if (!agg_node_parent(rn
) && !rn
->info
920 for (; m
; m
= m
->next
) {
922 if (RFAPI_0_PREFIX(&m
->p
)) {
923 /* shouldn't happen, but be safe */
926 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
928 * Haven't done this NVE yet. Add to
931 assert(!skiplist_insert(nves_seen
,
934 char buf_attach_pfx
[PREFIX_STRLEN
];
935 char buf_target_pfx
[PREFIX_STRLEN
];
937 prefix2str(&m
->node
->p
, buf_attach_pfx
,
938 sizeof(buf_attach_pfx
));
939 prefix2str(&m
->p
, buf_target_pfx
,
940 sizeof(buf_target_pfx
));
941 vnc_zlog_debug_verbose(
942 "%s: update rfd %p attached to pfx %s (targ=%s)",
944 buf_attach_pfx
, buf_target_pfx
);
949 rfapiRibUpdatePendingNode(
950 bgp
, m
->rfd
, import_table
,
952 m
->rfd
->response_lifetime
);
955 rn
= agg_node_parent(rn
);
957 m
= RFAPI_MONITOR_VPN(rn
);
962 * All-routes L2 monitors
964 if (AFI_L2VPN
== afi
) {
965 struct rfapi_monitor_eth
*e
;
968 vnc_zlog_debug_verbose("%s: checking L2 all-routes monitors",
972 for (e
= import_table
->eth0_queries
; e
; e
= e
->next
) {
974 vnc_zlog_debug_verbose("%s: checking eth0 mon=%p",
977 if (skiplist_search(nves_seen
, e
->rfd
, NULL
)) {
979 * Haven't done this NVE yet. Add to "seen"
982 assert(!skiplist_insert(nves_seen
, e
->rfd
,
989 vnc_zlog_debug_verbose(
990 "%s: found L2 all-routes monitor %p",
993 rfapiRibUpdatePendingNode(
994 bgp
, e
->rfd
, import_table
, it_node
,
995 e
->rfd
->response_lifetime
);
999 struct rfapi_monitor_vpn
*m
;
1002 * All-routes IPv4. IPv6 monitors
1004 for (m
= import_table
->vpn0_queries
[afi
]; m
; m
= m
->next
) {
1005 if (skiplist_search(nves_seen
, m
->rfd
, NULL
)) {
1007 * Haven't done this NVE yet. Add to "seen"
1010 assert(!skiplist_insert(nves_seen
, m
->rfd
,
1016 rfapiRibUpdatePendingNode(
1017 bgp
, m
->rfd
, import_table
, it_node
,
1018 m
->rfd
->response_lifetime
);
1023 skiplist_free(nves_seen
);
1027 * For the listed monitors, update new node and its subtree, but
1028 * omit old node and its subtree
1030 void rfapiMonitorMovedUp(struct rfapi_import_table
*import_table
,
1031 struct agg_node
*old_node
, struct agg_node
*new_node
,
1032 struct rfapi_monitor_vpn
*monitor_list
)
1034 struct bgp
*bgp
= bgp_get_default();
1035 struct rfapi_monitor_vpn
*m
;
1039 assert(new_node
!= old_node
);
1042 * If new node is 0/0 and there is no route there, don't
1043 * generate an update because it will not contain any
1044 * routes including the target.
1046 if (!new_node
->parent
&& !new_node
->info
) {
1047 vnc_zlog_debug_verbose(
1048 "%s: new monitor at 0/0 and no routes, no updates",
1053 for (m
= monitor_list
; m
; m
= m
->next
) {
1054 rfapiRibUpdatePendingNode(bgp
, m
->rfd
, import_table
, new_node
,
1055 m
->rfd
->response_lifetime
);
1056 rfapiRibUpdatePendingNodeSubtree(bgp
, m
->rfd
, import_table
,
1058 m
->rfd
->response_lifetime
);
1062 static int rfapiMonitorEthTimerExpire(struct thread
*t
)
1064 struct rfapi_monitor_eth
*m
= t
->arg
;
1066 /* forget reference to thread, it's gone */
1069 /* delete the monitor */
1070 rfapiMonitorEthDel(bgp_get_default(), m
->rfd
, &m
->macaddr
,
1076 static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth
*m
)
1079 unsigned long remain
= thread_timer_remain_second(m
->timer
);
1081 /* unexpected case, but avoid wraparound problems below */
1082 if (remain
> m
->rfd
->response_lifetime
)
1085 /* don't restart if we just restarted recently */
1086 if (m
->rfd
->response_lifetime
- remain
< 2)
1089 thread_cancel(m
->timer
);
1096 vnc_zlog_debug_verbose(
1097 "%s: target %s life %u", __func__
,
1098 rfapiEthAddr2Str(&m
->macaddr
, buf
, BUFSIZ
),
1099 m
->rfd
->response_lifetime
);
1102 thread_add_timer(bm
->master
, rfapiMonitorEthTimerExpire
, m
,
1103 m
->rfd
->response_lifetime
, &m
->timer
);
1106 static int mon_eth_cmp(const void *a
, const void *b
)
1108 const struct rfapi_monitor_eth
*m1
;
1109 const struct rfapi_monitor_eth
*m2
;
1113 m1
= (struct rfapi_monitor_eth
*)a
;
1114 m2
= (struct rfapi_monitor_eth
*)b
;
1117 * compare ethernet addresses
1119 for (i
= 0; i
< ETH_ALEN
; ++i
) {
1120 if (m1
->macaddr
.octet
[i
] != m2
->macaddr
.octet
[i
])
1121 return (m1
->macaddr
.octet
[i
] - m2
->macaddr
.octet
[i
]);
1127 return (m1
->logical_net_id
- m2
->logical_net_id
);
1130 static void rfapiMonitorEthAttachImport(
1131 struct rfapi_import_table
*it
,
1132 struct agg_node
*rn
, /* it node attach point if non-0 */
1133 struct rfapi_monitor_eth
*mon
) /* monitor struct to attach */
1135 struct skiplist
*sl
;
1138 vnc_zlog_debug_verbose("%s: it=%p", __func__
, it
);
1140 rfapiMonitorCheckAttachAllowed();
1142 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1144 * These go on a different list
1146 mon
->next
= it
->eth0_queries
;
1147 it
->eth0_queries
= mon
;
1149 vnc_zlog_debug_verbose("%s: attached monitor %p to eth0 list",
1157 vnc_zlog_debug_verbose("%s: rn is null!", __func__
);
1163 * Get sl to attach to
1165 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
);
1167 sl
= RFAPI_MONITOR_ETH_W_ALLOC(rn
) =
1168 skiplist_new(0, NULL
, NULL
);
1169 agg_lock_node(rn
); /* count skiplist mon_eth */
1173 vnc_zlog_debug_verbose(
1174 "%s: rn=%p, rn->lock=%d, sl=%p, attaching eth mon %p", __func__
,
1175 rn
, rn
->lock
, sl
, mon
);
1178 rc
= skiplist_insert(sl
, (void *)mon
, (void *)mon
);
1181 /* count eth monitor */
1186 * reattach monitors for this HD to import table
1188 static void rfapiMonitorEthAttachImportHd(struct bgp
*bgp
,
1189 struct rfapi_descriptor
*rfd
)
1192 struct rfapi_monitor_eth
*mon
;
1195 if (!rfd
->mon_eth
) {
1197 * No monitors for this HD
1203 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
);
1205 rc
= skiplist_next(rfd
->mon_eth
, NULL
, (void **)&mon
, &cursor
)) {
1207 struct rfapi_import_table
*it
;
1208 struct prefix pfx_mac_buf
;
1209 struct agg_node
*rn
;
1211 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1214 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1215 pfx_mac_buf
.family
= AF_ETHERNET
;
1216 pfx_mac_buf
.prefixlen
= 48;
1217 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1219 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1222 (void)rfapiMonitorEthAttachImport(it
, rn
, mon
);
1226 static void rfapiMonitorEthDetachImport(
1228 struct rfapi_monitor_eth
*mon
) /* monitor struct to detach */
1230 struct rfapi_import_table
*it
;
1231 struct prefix pfx_mac_buf
;
1232 struct skiplist
*sl
;
1233 struct agg_node
*rn
;
1236 it
= rfapiMacImportTableGet(bgp
, mon
->logical_net_id
);
1239 if (RFAPI_0_ETHERADDR(&mon
->macaddr
)) {
1240 struct rfapi_monitor_eth
*prev
;
1241 struct rfapi_monitor_eth
*this = NULL
;
1243 for (prev
= NULL
, this = it
->eth0_queries
; this;
1244 prev
= this, this = this->next
) {
1251 it
->eth0_queries
= this->next
;
1253 prev
->next
= this->next
;
1257 vnc_zlog_debug_verbose(
1258 "%s: it=%p, LNI=%d, detached eth0 mon %p", __func__
, it
,
1259 mon
->logical_net_id
, mon
);
1264 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1265 pfx_mac_buf
.family
= AF_ETHERNET
;
1266 pfx_mac_buf
.prefixlen
= 48;
1267 pfx_mac_buf
.u
.prefix_eth
= mon
->macaddr
;
1269 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1273 char buf_prefix
[PREFIX_STRLEN
];
1275 prefix2str(&rn
->p
, buf_prefix
, sizeof(buf_prefix
));
1279 * Get sl to detach from
1281 sl
= RFAPI_MONITOR_ETH(rn
);
1283 vnc_zlog_debug_verbose(
1284 "%s: it=%p, rn=%p, rn->lock=%d, sl=%p, pfx=%s, LNI=%d, detaching eth mon %p",
1285 __func__
, it
, rn
, rn
->lock
, sl
, buf_prefix
, mon
->logical_net_id
,
1291 rc
= skiplist_delete(sl
, (void *)mon
, (void *)mon
);
1294 /* uncount eth monitor */
1295 agg_unlock_node(rn
);
1298 struct agg_node
*rfapiMonitorEthAdd(struct bgp
*bgp
,
1299 struct rfapi_descriptor
*rfd
,
1300 struct ethaddr
*macaddr
,
1301 uint32_t logical_net_id
)
1304 struct rfapi_monitor_eth mon_buf
;
1305 struct rfapi_monitor_eth
*val
;
1306 struct rfapi_import_table
*it
;
1307 struct agg_node
*rn
= NULL
;
1308 struct prefix pfx_mac_buf
;
1310 if (!rfd
->mon_eth
) {
1311 rfd
->mon_eth
= skiplist_new(0, mon_eth_cmp
, NULL
);
1314 it
= rfapiMacImportTableGet(bgp
, logical_net_id
);
1318 * Get route node in import table. Here is where we attach the
1321 * Look it up now because we return it to caller regardless of
1322 * whether we create a new monitor or not.
1324 memset((void *)&pfx_mac_buf
, 0, sizeof(struct prefix
));
1325 pfx_mac_buf
.family
= AF_ETHERNET
;
1326 pfx_mac_buf
.prefixlen
= 48;
1327 pfx_mac_buf
.u
.prefix_eth
= *macaddr
;
1329 if (!RFAPI_0_ETHERADDR(macaddr
)) {
1330 rn
= agg_node_get(it
->imported_vpn
[AFI_L2VPN
], &pfx_mac_buf
);
1334 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1336 mon_buf
.macaddr
= *macaddr
;
1337 mon_buf
.logical_net_id
= logical_net_id
;
1342 vnc_zlog_debug_verbose(
1343 "%s: LNI=%d: rfd=%p, pfx=%s", __func__
, logical_net_id
,
1344 rfd
, rfapi_ntop(pfx_mac_buf
.family
, pfx_mac_buf
.u
.val
,
1352 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1355 * Found monitor - we have seen this query before
1358 vnc_zlog_debug_verbose(
1359 "%s: already present in rfd->mon_eth, not adding",
1361 rfapiMonitorEthTimerRestart(val
);
1368 val
= XCALLOC(MTYPE_RFAPI_MONITOR_ETH
,
1369 sizeof(struct rfapi_monitor_eth
));
1373 ++rfd
->monitor_count
;
1374 ++bgp
->rfapi
->monitor_count
;
1376 rc
= skiplist_insert(rfd
->mon_eth
, val
, val
);
1379 vnc_zlog_debug_verbose("%s: inserted rfd=%p mon_eth=%p, rc=%d",
1380 __func__
, rfd
, val
, rc
);
1388 rfapiMonitorEthTimerRestart(val
);
1390 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1392 * callbacks turned off, so don't attach monitor to import table
1395 vnc_zlog_debug_verbose(
1396 "%s: callbacks turned off, not attaching mon_eth %p to import table",
1403 * attach to import table
1405 rfapiMonitorEthAttachImport(it
, rn
, val
);
1410 void rfapiMonitorEthDel(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
1411 struct ethaddr
*macaddr
, uint32_t logical_net_id
)
1413 struct rfapi_monitor_eth
*val
;
1414 struct rfapi_monitor_eth mon_buf
;
1417 vnc_zlog_debug_verbose("%s: entry rfd=%p", __func__
, rfd
);
1419 assert(rfd
->mon_eth
);
1421 memset((void *)&mon_buf
, 0, sizeof(mon_buf
));
1422 mon_buf
.macaddr
= *macaddr
;
1423 mon_buf
.logical_net_id
= logical_net_id
;
1425 rc
= skiplist_search(rfd
->mon_eth
, (void *)&mon_buf
, (void **)&val
);
1429 * remove from import table
1431 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1432 rfapiMonitorEthDetachImport(bgp
, val
);
1436 thread_cancel(val
->timer
);
1441 * remove from rfd list
1443 rc
= skiplist_delete(rfd
->mon_eth
, val
, val
);
1447 vnc_zlog_debug_verbose("%s: freeing mon_eth %p", __func__
, val
);
1449 XFREE(MTYPE_RFAPI_MONITOR_ETH
, val
);
1451 --rfd
->monitor_count
;
1452 --bgp
->rfapi
->monitor_count
;
1456 void rfapiMonitorCallbacksOff(struct bgp
*bgp
)
1458 struct rfapi_import_table
*it
;
1460 struct agg_table
*rt
;
1461 struct agg_node
*rn
;
1464 struct rfapi
*h
= bgp
->rfapi
;
1466 if (bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
) {
1472 bgp
->rfapi_cfg
->flags
|= BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1475 vnc_zlog_debug_verbose("%s: turned off callbacks", __func__
);
1481 * detach monitors from import VPN tables. The monitors
1482 * will still be linked in per-nve monitor lists.
1484 for (it
= h
->imports
; it
; it
= it
->next
) {
1485 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
1487 struct rfapi_monitor_vpn
*m
;
1488 struct rfapi_monitor_vpn
*next
;
1490 rt
= it
->imported_vpn
[afi
];
1492 for (rn
= agg_route_top(rt
); rn
;
1493 rn
= agg_route_next(rn
)) {
1494 m
= RFAPI_MONITOR_VPN(rn
);
1495 if (RFAPI_MONITOR_VPN(rn
))
1496 RFAPI_MONITOR_VPN_W_ALLOC(rn
) = NULL
;
1497 for (; m
; m
= next
) {
1500 NULL
; /* gratuitous safeness */
1502 agg_unlock_node(rn
); /* uncount */
1506 for (m
= it
->vpn0_queries
[afi
]; m
; m
= next
) {
1508 m
->next
= NULL
; /* gratuitous safeness */
1511 it
->vpn0_queries
[afi
] = NULL
; /* detach first monitor */
1516 * detach monitors from import Eth tables. The monitors
1517 * will still be linked in per-nve monitor lists.
1521 * Loop over ethernet import tables
1524 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
);
1526 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
, &cursor
)) {
1527 struct rfapi_monitor_eth
*e
;
1528 struct rfapi_monitor_eth
*enext
;
1531 * The actual route table
1533 rt
= it
->imported_vpn
[AFI_L2VPN
];
1536 * Find non-0 monitors (i.e., actual addresses, not FTD
1539 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
1540 struct skiplist
*sl
;
1542 sl
= RFAPI_MONITOR_ETH(rn
);
1543 while (!skiplist_delete_first(sl
)) {
1544 agg_unlock_node(rn
); /* uncount monitor */
1549 * Find 0-monitors (FTD queries)
1551 for (e
= it
->eth0_queries
; e
; e
= enext
) {
1553 vnc_zlog_debug_verbose("%s: detaching eth0 mon %p",
1557 e
->next
= NULL
; /* gratuitous safeness */
1559 it
->eth0_queries
= NULL
; /* detach first monitor */
1563 void rfapiMonitorCallbacksOn(struct bgp
*bgp
)
1565 struct listnode
*hnode
;
1566 struct rfapi_descriptor
*rfd
;
1568 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
1570 * Already on. It's important that we don't try to reattach
1571 * monitors that are already attached because, in the interest
1572 * of performance, there is no checking at the lower level
1573 * whether a monitor is already attached. It leads to
1574 * corrupted chains (e.g., looped pointers)
1578 bgp
->rfapi_cfg
->flags
&= ~BGP_VNC_CONFIG_CALLBACK_DISABLE
;
1580 vnc_zlog_debug_verbose("%s: turned on callbacks", __func__
);
1582 if (bgp
->rfapi
== NULL
)
1588 for (ALL_LIST_ELEMENTS_RO(&bgp
->rfapi
->descriptors
, hnode
, rfd
)) {
1590 rfapiMonitorAttachImportHd(rfd
);
1591 rfapiMonitorEthAttachImportHd(bgp
, rfd
);