]>
Commit | Line | Data |
---|---|---|
361b5843 | 1 | /* |
2 | * pim_bsm.c: PIM BSM handling routines | |
3 | * | |
4 | * Copyright (C) 2018-19 Vmware, Inc. | |
5 | * Saravanan K | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; see the file COPYING; if not, write to the | |
19 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
20 | * MA 02110-1301 USA | |
21 | */ | |
22 | #include "if.h" | |
23 | #include "pimd.h" | |
24 | #include "pim_iface.h" | |
361b5843 | 25 | #include "pim_instance.h" |
26 | #include "pim_rpf.h" | |
27 | #include "pim_hello.h" | |
28 | #include "pim_pim.h" | |
29 | #include "pim_nht.h" | |
30 | #include "pim_bsm.h" | |
31 | #include "pim_time.h" | |
32 | ||
33 | /* Functions forward declaration */ | |
34 | static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout); | |
a5164e97 | 35 | static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time); |
36 | static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp, | |
37 | int hold_time); | |
23255dfd | 38 | |
39 | /* Memory Types */ | |
40 | DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info") | |
41 | DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info") | |
42 | DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info") | |
43 | DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet") | |
361b5843 | 44 | |
16c926c8 | 45 | /* pim_bsm_write_config - Write the interface pim bsm configuration.*/ |
d0e418b4 | 46 | void pim_bsm_write_config(struct vty *vty, struct interface *ifp) |
16c926c8 | 47 | { |
48 | struct pim_interface *pim_ifp = ifp->info; | |
49 | ||
50 | if (pim_ifp) { | |
51 | if (!pim_ifp->bsm_enable) | |
52 | vty_out(vty, " no ip pim bsm\n"); | |
53 | if (!pim_ifp->ucast_bsm_accept) | |
54 | vty_out(vty, " no ip pim unicast-bsm\n"); | |
55 | } | |
56 | } | |
57 | ||
d0e418b4 | 58 | static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node) |
361b5843 | 59 | { |
60 | if (bsgrp_node->bsrp_list) | |
61 | list_delete(&bsgrp_node->bsrp_list); | |
62 | if (bsgrp_node->partial_bsrp_list) | |
63 | list_delete(&bsgrp_node->partial_bsrp_list); | |
361b5843 | 64 | XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node); |
65 | } | |
66 | ||
c295e391 | 67 | static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp) |
68 | { | |
69 | struct route_node *rn; | |
70 | ||
71 | rn = route_node_lookup(rt, grp); | |
72 | if (rn) { | |
73 | rn->info = NULL; | |
74 | route_unlock_node(rn); | |
75 | route_unlock_node(rn); | |
76 | } | |
77 | } | |
78 | ||
361b5843 | 79 | static void pim_bsm_node_free(struct bsm_info *bsm) |
80 | { | |
81 | if (bsm->bsm) | |
82 | XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm); | |
83 | XFREE(MTYPE_PIM_BSM_INFO, bsm); | |
84 | } | |
85 | ||
23255dfd | 86 | static int pim_on_bs_timer(struct thread *t) |
87 | { | |
c843f56d | 88 | struct route_node *rn; |
89 | struct bsm_scope *scope; | |
90 | struct bsgrp_node *bsgrp_node; | |
91 | struct bsm_rpinfo *bsrp; | |
92 | struct prefix nht_p; | |
93 | char buf[PREFIX2STR_BUFFER]; | |
94 | bool is_bsr_tracking = true; | |
95 | ||
96 | scope = THREAD_ARG(t); | |
97 | THREAD_OFF(scope->bs_timer); | |
98 | ||
99 | if (PIM_DEBUG_BSM) | |
100 | zlog_debug("%s: Bootstrap Timer expired for scope: %d", | |
101 | __PRETTY_FUNCTION__, scope->sz_id); | |
102 | ||
103 | /* Remove next hop tracking for the bsr */ | |
104 | nht_p.family = AF_INET; | |
105 | nht_p.prefixlen = IPV4_MAX_BITLEN; | |
106 | nht_p.u.prefix4 = scope->current_bsr; | |
107 | if (PIM_DEBUG_BSM) { | |
108 | prefix2str(&nht_p, buf, sizeof(buf)); | |
109 | zlog_debug("%s: Deregister BSR addr %s with Zebra NHT", | |
110 | __PRETTY_FUNCTION__, buf); | |
111 | } | |
112 | pim_delete_tracked_nexthop(scope->pim, &nht_p, NULL, NULL, | |
113 | is_bsr_tracking); | |
114 | ||
115 | /* Reset scope zone data */ | |
116 | scope->accept_nofwd_bsm = false; | |
117 | scope->state = ACCEPT_ANY; | |
118 | scope->current_bsr.s_addr = INADDR_ANY; | |
119 | scope->current_bsr_prio = 0; | |
120 | scope->current_bsr_first_ts = 0; | |
121 | scope->current_bsr_last_ts = 0; | |
122 | scope->bsm_frag_tag = 0; | |
123 | list_delete_all_node(scope->bsm_list); | |
124 | ||
125 | for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) { | |
126 | ||
127 | bsgrp_node = (struct bsgrp_node *)rn->info; | |
128 | if (!bsgrp_node) { | |
129 | if (PIM_DEBUG_BSM) | |
130 | zlog_debug("%s: bsgrp_node is null", | |
131 | __PRETTY_FUNCTION__); | |
132 | continue; | |
133 | } | |
134 | /* Give grace time for rp to continue for another hold time */ | |
135 | if ((bsgrp_node->bsrp_list) && (bsgrp_node->bsrp_list->count)) { | |
136 | bsrp = listnode_head(bsgrp_node->bsrp_list); | |
137 | pim_g2rp_timer_restart(bsrp, bsrp->rp_holdtime); | |
138 | } | |
139 | /* clear pending list */ | |
140 | if ((bsgrp_node->partial_bsrp_list) | |
141 | && (bsgrp_node->partial_bsrp_list->count)) { | |
142 | list_delete_all_node(bsgrp_node->partial_bsrp_list); | |
143 | bsgrp_node->pend_rp_cnt = 0; | |
144 | } | |
145 | } | |
23255dfd | 146 | return 0; |
147 | } | |
148 | ||
149 | static void pim_bs_timer_stop(struct bsm_scope *scope) | |
150 | { | |
151 | if (PIM_DEBUG_BSM) | |
152 | zlog_debug("%s : BS timer being stopped of sz: %d", | |
153 | __PRETTY_FUNCTION__, scope->sz_id); | |
154 | THREAD_OFF(scope->bs_timer); | |
155 | } | |
156 | ||
157 | static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout) | |
158 | { | |
159 | if (!scope) { | |
160 | if (PIM_DEBUG_BSM) | |
161 | zlog_debug("%s : Invalid scope(NULL).", | |
162 | __PRETTY_FUNCTION__); | |
163 | return; | |
164 | } | |
165 | THREAD_OFF(scope->bs_timer); | |
166 | if (PIM_DEBUG_BSM) | |
167 | zlog_debug("%s : starting bs timer for scope %d with timeout %d secs", | |
168 | __PRETTY_FUNCTION__, scope->sz_id, bs_timeout); | |
169 | thread_add_timer(router->master, pim_on_bs_timer, scope, bs_timeout, | |
170 | &scope->bs_timer); | |
171 | } | |
172 | ||
361b5843 | 173 | void pim_bsm_proc_init(struct pim_instance *pim) |
174 | { | |
175 | memset(&pim->global_scope, 0, sizeof(struct bsm_scope)); | |
176 | ||
177 | pim->global_scope.sz_id = PIM_GBL_SZ_ID; | |
178 | pim->global_scope.bsrp_table = route_table_init(); | |
179 | pim->global_scope.accept_nofwd_bsm = true; | |
180 | pim->global_scope.state = NO_INFO; | |
181 | pim->global_scope.pim = pim; | |
182 | pim->global_scope.bsm_list = list_new(); | |
183 | pim->global_scope.bsm_list->del = (void (*)(void *))pim_bsm_node_free; | |
184 | pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME); | |
185 | } | |
186 | ||
187 | void pim_bsm_proc_free(struct pim_instance *pim) | |
188 | { | |
189 | struct route_node *rn; | |
190 | struct bsgrp_node *bsgrp; | |
191 | ||
192 | pim_bs_timer_stop(&pim->global_scope); | |
193 | ||
194 | if (pim->global_scope.bsm_list) | |
195 | list_delete(&pim->global_scope.bsm_list); | |
196 | ||
d0e418b4 | 197 | for (rn = route_top(pim->global_scope.bsrp_table); rn; |
198 | rn = route_next(rn)) { | |
361b5843 | 199 | bsgrp = rn->info; |
200 | if (!bsgrp) | |
201 | continue; | |
202 | pim_free_bsgrp_data(bsgrp); | |
203 | } | |
204 | ||
205 | if (pim->global_scope.bsrp_table) | |
206 | route_table_finish(pim->global_scope.bsrp_table); | |
207 | } | |
208 | ||
c295e391 | 209 | static bool is_hold_time_elapsed(void *data) |
210 | { | |
211 | struct bsm_rpinfo *bsrp; | |
212 | ||
213 | bsrp = data; | |
214 | ||
215 | if (bsrp->elapse_time < bsrp->rp_holdtime) | |
216 | return false; | |
217 | else | |
218 | return true; | |
219 | } | |
220 | ||
a5164e97 | 221 | static int pim_on_g2rp_timer(struct thread *t) |
222 | { | |
c295e391 | 223 | struct bsm_rpinfo *bsrp; |
224 | struct bsm_rpinfo *bsrp_node; | |
225 | struct bsgrp_node *bsgrp_node; | |
226 | struct listnode *bsrp_ln; | |
227 | struct pim_instance *pim; | |
228 | struct rp_info *rp_info; | |
229 | struct route_node *rn; | |
230 | uint16_t elapse; | |
231 | struct in_addr bsrp_addr; | |
232 | ||
233 | bsrp = THREAD_ARG(t); | |
234 | THREAD_OFF(bsrp->g2rp_timer); | |
235 | bsgrp_node = bsrp->bsgrp_node; | |
236 | ||
237 | /* elapse time is the hold time of expired node */ | |
238 | elapse = bsrp->rp_holdtime; | |
239 | bsrp_addr = bsrp->rp_address; | |
240 | ||
241 | /* update elapse for all bsrp nodes */ | |
242 | for (ALL_LIST_ELEMENTS_RO(bsgrp_node->bsrp_list, bsrp_ln, bsrp_node)) | |
243 | bsrp_node->elapse_time += elapse; | |
244 | ||
245 | /* remove the expired nodes from the list */ | |
246 | list_filter_out_nodes(bsgrp_node->bsrp_list, is_hold_time_elapsed); | |
247 | ||
248 | /* Get the next elected rp node */ | |
249 | bsrp = listnode_head(bsgrp_node->bsrp_list); | |
250 | pim = bsgrp_node->scope->pim; | |
251 | rn = route_node_lookup(pim->rp_table, &bsgrp_node->group); | |
252 | ||
253 | if (!rn) { | |
254 | zlog_warn("%s: Route node doesn't exist", __PRETTY_FUNCTION__); | |
255 | return 0; | |
256 | } | |
257 | ||
258 | rp_info = (struct rp_info *)rn->info; | |
259 | ||
260 | if (!rp_info) { | |
261 | route_unlock_node(rn); | |
262 | return 0; | |
263 | } | |
264 | ||
265 | if (rp_info->rp_src != RP_SRC_STATIC) { | |
266 | /* If new rp available, change it else delete the existing */ | |
267 | if (bsrp) { | |
268 | bsrp_addr = bsrp->rp_address; | |
269 | pim_g2rp_timer_start( | |
270 | bsrp, (bsrp->rp_holdtime - bsrp->elapse_time)); | |
271 | pim_rp_change(pim, bsrp_addr, bsgrp_node->group, | |
272 | RP_SRC_BSR); | |
273 | } else { | |
274 | pim_rp_del(pim, bsrp_addr, bsgrp_node->group, NULL, | |
275 | RP_SRC_BSR); | |
276 | } | |
277 | } | |
278 | ||
279 | if ((!bsgrp_node->bsrp_list->count) | |
280 | && (!bsgrp_node->partial_bsrp_list->count)) { | |
281 | pim_free_bsgrp_node(pim->global_scope.bsrp_table, | |
282 | &bsgrp_node->group); | |
283 | pim_free_bsgrp_data(bsgrp_node); | |
284 | } | |
285 | ||
a5164e97 | 286 | return 0; |
287 | } | |
288 | ||
289 | static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time) | |
290 | { | |
291 | if (!bsrp) { | |
292 | if (PIM_DEBUG_BSM) | |
293 | zlog_debug("%s : Invalid brsp(NULL).", | |
294 | __PRETTY_FUNCTION__); | |
295 | return; | |
296 | } | |
297 | THREAD_OFF(bsrp->g2rp_timer); | |
298 | if (PIM_DEBUG_BSM) { | |
299 | char buf[48]; | |
300 | ||
301 | zlog_debug( | |
302 | "%s : starting g2rp timer for grp: %s - rp: %s with timeout %d secs(Actual Hold time : %d secs)", | |
303 | __PRETTY_FUNCTION__, | |
304 | prefix2str(&bsrp->bsgrp_node->group, buf, 48), | |
305 | inet_ntoa(bsrp->rp_address), hold_time, | |
306 | bsrp->rp_holdtime); | |
307 | } | |
308 | ||
309 | thread_add_timer(router->master, pim_on_g2rp_timer, bsrp, hold_time, | |
310 | &bsrp->g2rp_timer); | |
311 | } | |
312 | ||
313 | static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp, | |
314 | int hold_time) | |
315 | { | |
316 | pim_g2rp_timer_start(bsrp, hold_time); | |
317 | } | |
318 | ||
d0e418b4 | 319 | struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope, |
320 | struct prefix *grp) | |
321 | { | |
322 | struct route_node *rn; | |
323 | struct bsgrp_node *bsgrp; | |
324 | ||
325 | rn = route_node_lookup(scope->bsrp_table, grp); | |
326 | if (!rn) { | |
327 | if (PIM_DEBUG_BSM) | |
328 | zlog_debug("%s: Route node doesn't exist for the group", | |
329 | __PRETTY_FUNCTION__); | |
330 | return NULL; | |
331 | } | |
332 | bsgrp = rn->info; | |
333 | route_unlock_node(rn); | |
334 | ||
335 | return bsgrp; | |
336 | } |