]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_bsm.c
pimd: PIM Msg header includes N bit as defined by RFC
[mirror_frr.git] / pimd / pim_bsm.c
CommitLineData
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 */
34static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
a5164e97 35static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
36static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
37 int hold_time);
23255dfd 38
39/* Memory Types */
40DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info")
41DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info")
42DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info")
43DEFINE_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 46void 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 58static 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 67static 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 79static 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 86static 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
149static 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
157static 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 173void 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
187void 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 209static 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 221static 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
289static 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
313static 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 319struct 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}