]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_hello.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pimd / pim_hello.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
12e41d03 2/*
896014f4
DL
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
896014f4 5 */
12e41d03
DL
6
7#include <zebra.h>
8
9#include "log.h"
744d91b3 10#include "if.h"
12e41d03
DL
11
12#include "pimd.h"
993e3d8e 13#include "pim_instance.h"
12e41d03
DL
14#include "pim_pim.h"
15#include "pim_str.h"
16#include "pim_tlv.h"
17#include "pim_util.h"
18#include "pim_hello.h"
19#include "pim_iface.h"
20#include "pim_neighbor.h"
21#include "pim_upstream.h"
6bb2ef35 22#include "pim_bsm.h"
12e41d03 23
11928ecf 24static void on_trace(const char *label, struct interface *ifp, pim_addr src)
12e41d03 25{
11928ecf
DL
26 if (PIM_DEBUG_PIM_TRACE)
27 zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name);
12e41d03
DL
28}
29
30static void tlv_trace_bool(const char *label, const char *tlv_name,
11928ecf
DL
31 const char *ifname, pim_addr src_addr, int isset,
32 int value)
12e41d03 33{
11928ecf 34 if (isset)
d62a17ae 35 zlog_debug(
11928ecf
DL
36 "%s: PIM hello option from %pPAs on interface %s: %s=%d",
37 label, &src_addr, ifname, tlv_name, value);
12e41d03
DL
38}
39
40static void tlv_trace_uint16(const char *label, const char *tlv_name,
11928ecf
DL
41 const char *ifname, pim_addr src_addr, int isset,
42 uint16_t value)
12e41d03 43{
11928ecf 44 if (isset)
d62a17ae 45 zlog_debug(
11928ecf
DL
46 "%s: PIM hello option from %pPAs on interface %s: %s=%u",
47 label, &src_addr, ifname, tlv_name, value);
12e41d03
DL
48}
49
50static void tlv_trace_uint32(const char *label, const char *tlv_name,
11928ecf
DL
51 const char *ifname, pim_addr src_addr, int isset,
52 uint32_t value)
12e41d03 53{
11928ecf 54 if (isset)
d62a17ae 55 zlog_debug(
11928ecf
DL
56 "%s: PIM hello option from %pPAs on interface %s: %s=%u",
57 label, &src_addr, ifname, tlv_name, value);
12e41d03
DL
58}
59
60static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
11928ecf 61 const char *ifname, pim_addr src_addr,
12e41d03
DL
62 int isset, uint32_t value)
63{
11928ecf 64 if (isset)
d62a17ae 65 zlog_debug(
11928ecf
DL
66 "%s: PIM hello option from %pPAs on interface %s: %s=%08x",
67 label, &src_addr, ifname, tlv_name, value);
12e41d03
DL
68}
69
12e41d03 70static void tlv_trace_list(const char *label, const char *tlv_name,
11928ecf
DL
71 const char *ifname, pim_addr src_addr, int isset,
72 struct list *addr_list)
12e41d03 73{
11928ecf 74 if (isset)
d62a17ae 75 zlog_debug(
11928ecf
DL
76 "%s: PIM hello option from %pPAs on interface %s: %s size=%d list=%p",
77 label, &src_addr, ifname, tlv_name,
d62a17ae 78 addr_list ? ((int)listcount(addr_list)) : -1,
79 (void *)addr_list);
12e41d03
DL
80}
81
996c9314
LB
82#define FREE_ADDR_LIST \
83 if (hello_option_addr_list) { \
6a154c88 84 list_delete(&hello_option_addr_list); \
d62a17ae 85 }
12e41d03 86
d62a17ae 87#define FREE_ADDR_LIST_THEN_RETURN(code) \
88 { \
89 FREE_ADDR_LIST \
90 return (code); \
91 }
12e41d03 92
11928ecf
DL
93int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf,
94 int tlv_buf_size)
12e41d03 95{
d62a17ae 96 struct pim_interface *pim_ifp;
97 struct pim_neighbor *neigh;
98 uint8_t *tlv_curr;
99 uint8_t *tlv_pastend;
100 pim_hello_options hello_options =
101 0; /* bit array recording options found */
102 uint16_t hello_option_holdtime = 0;
103 uint16_t hello_option_propagation_delay = 0;
104 uint16_t hello_option_override_interval = 0;
105 uint32_t hello_option_dr_priority = 0;
106 uint32_t hello_option_generation_id = 0;
107 struct list *hello_option_addr_list = 0;
108
109 if (PIM_DEBUG_PIM_HELLO)
15569c58 110 on_trace(__func__, ifp, src_addr);
d62a17ae 111
112 pim_ifp = ifp->info;
df5dfb77 113 assert(pim_ifp);
d62a17ae 114
39c2130e 115 if (pim_ifp->pim_passive_enable) {
116 if (PIM_DEBUG_PIM_PACKETS)
117 zlog_debug(
118 "skip receiving PIM message on passive interface %s",
119 ifp->name);
120 return 0;
121 }
122
d62a17ae 123 ++pim_ifp->pim_ifstat_hello_recv;
124
125 /*
126 Parse PIM hello TLVs
127 */
df5dfb77 128 assert(tlv_buf_size >= 0);
d62a17ae 129 tlv_curr = tlv_buf;
130 tlv_pastend = tlv_buf + tlv_buf_size;
131
132 while (tlv_curr < tlv_pastend) {
133 uint16_t option_type;
134 uint16_t option_len;
135 int remain = tlv_pastend - tlv_curr;
136
137 if (remain < PIM_TLV_MIN_SIZE) {
11928ecf 138 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 139 zlog_debug(
11928ecf 140 "%s: short PIM hello TLV size=%d < min=%d from %pPAs on interface %s",
15569c58 141 __func__, remain, PIM_TLV_MIN_SIZE,
11928ecf 142 &src_addr, ifp->name);
d62a17ae 143 FREE_ADDR_LIST_THEN_RETURN(-1);
144 }
145
146 option_type = PIM_TLV_GET_TYPE(tlv_curr);
147 tlv_curr += PIM_TLV_TYPE_SIZE;
148 option_len = PIM_TLV_GET_LENGTH(tlv_curr);
149 tlv_curr += PIM_TLV_LENGTH_SIZE;
150
151 if ((tlv_curr + option_len) > tlv_pastend) {
11928ecf 152 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 153 zlog_debug(
11928ecf 154 "%s: long PIM hello TLV type=%d length=%d > left=%td from %pPAs on interface %s",
15569c58 155 __func__, option_type, option_len,
11928ecf 156 tlv_pastend - tlv_curr, &src_addr,
15569c58 157 ifp->name);
d62a17ae 158 FREE_ADDR_LIST_THEN_RETURN(-2);
159 }
160
11928ecf 161 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 162 zlog_debug(
11928ecf 163 "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %pPAs on %s",
15569c58 164 __func__, remain, option_type, option_len,
11928ecf 165 &src_addr, ifp->name);
d62a17ae 166
167 switch (option_type) {
168 case PIM_MSG_OPTION_TYPE_HOLDTIME:
169 if (pim_tlv_parse_holdtime(ifp->name, src_addr,
170 &hello_options,
171 &hello_option_holdtime,
172 option_len, tlv_curr)) {
173 FREE_ADDR_LIST_THEN_RETURN(-3);
174 }
175 break;
176 case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY:
177 if (pim_tlv_parse_lan_prune_delay(
178 ifp->name, src_addr, &hello_options,
179 &hello_option_propagation_delay,
180 &hello_option_override_interval, option_len,
12e41d03 181 tlv_curr)) {
d62a17ae 182 FREE_ADDR_LIST_THEN_RETURN(-4);
183 }
184 break;
185 case PIM_MSG_OPTION_TYPE_DR_PRIORITY:
186 if (pim_tlv_parse_dr_priority(ifp->name, src_addr,
187 &hello_options,
188 &hello_option_dr_priority,
189 option_len, tlv_curr)) {
190 FREE_ADDR_LIST_THEN_RETURN(-5);
191 }
192 break;
193 case PIM_MSG_OPTION_TYPE_GENERATION_ID:
194 if (pim_tlv_parse_generation_id(
195 ifp->name, src_addr, &hello_options,
196 &hello_option_generation_id, option_len,
197 tlv_curr)) {
198 FREE_ADDR_LIST_THEN_RETURN(-6);
199 }
200 break;
201 case PIM_MSG_OPTION_TYPE_ADDRESS_LIST:
202 if (pim_tlv_parse_addr_list(ifp->name, src_addr,
203 &hello_options,
204 &hello_option_addr_list,
205 option_len, tlv_curr)) {
206 return -7;
207 }
208 break;
209 case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
11928ecf 210 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 211 zlog_debug(
11928ecf 212 "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %pPAs on interface %s",
15569c58 213 __func__, option_type, option_len,
11928ecf 214 &src_addr, ifp->name);
d62a17ae 215 break;
216 default:
11928ecf 217 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 218 zlog_debug(
11928ecf 219 "%s: ignoring unknown PIM hello TLV type=%d length=%d from %pPAs on interface %s",
15569c58 220 __func__, option_type, option_len,
11928ecf 221 &src_addr, ifp->name);
d62a17ae 222 }
223
224 tlv_curr += option_len;
225 }
12e41d03 226
d62a17ae 227 /*
228 Check received PIM hello options
229 */
12e41d03 230
d62a17ae 231 if (PIM_DEBUG_PIM_HELLO) {
15569c58 232 tlv_trace_uint16(__func__, "holdtime", ifp->name, src_addr,
d62a17ae 233 PIM_OPTION_IS_SET(hello_options,
234 PIM_OPTION_MASK_HOLDTIME),
235 hello_option_holdtime);
236 tlv_trace_uint16(
15569c58 237 __func__, "propagation_delay", ifp->name, src_addr,
d62a17ae 238 PIM_OPTION_IS_SET(hello_options,
239 PIM_OPTION_MASK_LAN_PRUNE_DELAY),
240 hello_option_propagation_delay);
241 tlv_trace_uint16(
15569c58 242 __func__, "override_interval", ifp->name, src_addr,
d62a17ae 243 PIM_OPTION_IS_SET(hello_options,
244 PIM_OPTION_MASK_LAN_PRUNE_DELAY),
245 hello_option_override_interval);
246 tlv_trace_bool(
15569c58
DA
247 __func__, "can_disable_join_suppression", ifp->name,
248 src_addr,
d62a17ae 249 PIM_OPTION_IS_SET(hello_options,
250 PIM_OPTION_MASK_LAN_PRUNE_DELAY),
251 PIM_OPTION_IS_SET(
252 hello_options,
253 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION));
15569c58 254 tlv_trace_uint32(__func__, "dr_priority", ifp->name, src_addr,
d62a17ae 255 PIM_OPTION_IS_SET(hello_options,
256 PIM_OPTION_MASK_DR_PRIORITY),
257 hello_option_dr_priority);
258 tlv_trace_uint32_hex(
15569c58 259 __func__, "generation_id", ifp->name, src_addr,
d62a17ae 260 PIM_OPTION_IS_SET(hello_options,
261 PIM_OPTION_MASK_GENERATION_ID),
262 hello_option_generation_id);
15569c58 263 tlv_trace_list(__func__, "address_list", ifp->name, src_addr,
d62a17ae 264 PIM_OPTION_IS_SET(hello_options,
265 PIM_OPTION_MASK_ADDRESS_LIST),
266 hello_option_addr_list);
267 }
12e41d03 268
d62a17ae 269 if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
11928ecf 270 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 271 zlog_debug(
11928ecf
DL
272 "%s: PIM hello missing holdtime from %pPAs on interface %s",
273 __func__, &src_addr, ifp->name);
d62a17ae 274 }
12e41d03 275
d62a17ae 276 /*
277 New neighbor?
278 */
279
3dbf370a 280 neigh = pim_neighbor_find(ifp, src_addr, false);
d62a17ae 281 if (!neigh) {
282 /* Add as new neighbor */
283
284 neigh = pim_neighbor_add(
285 ifp, src_addr, hello_options, hello_option_holdtime,
286 hello_option_propagation_delay,
287 hello_option_override_interval,
288 hello_option_dr_priority, hello_option_generation_id,
289 hello_option_addr_list, PIM_NEIGHBOR_SEND_DELAY);
290 if (!neigh) {
11928ecf 291 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 292 zlog_warn(
11928ecf
DL
293 "%s: failure creating PIM neighbor %pPAs on interface %s",
294 __func__, &src_addr, ifp->name);
d62a17ae 295 FREE_ADDR_LIST_THEN_RETURN(-8);
296 }
6bb2ef35 297 /* Forward BSM if required */
298 if (!pim_bsm_new_nbr_fwd(neigh, ifp)) {
299 if (PIM_DEBUG_PIM_HELLO)
15569c58
DA
300 zlog_debug(
301 "%s: forwarding bsm to new nbr failed",
302 __func__);
6bb2ef35 303 }
d62a17ae 304
305 /* actual addr list has been saved under neighbor */
306 return 0;
aea6cb94 307 }
d62a17ae 308
309 /*
310 Received generation ID ?
311 */
312
313 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) {
314 /* GenID mismatch ? */
315 if (!PIM_OPTION_IS_SET(neigh->hello_options,
316 PIM_OPTION_MASK_GENERATION_ID)
317 || (hello_option_generation_id != neigh->generation_id)) {
318 /* GenID mismatch, then replace neighbor */
319
11928ecf 320 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 321 zlog_debug(
11928ecf 322 "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %pPAs on %s",
15569c58 323 __func__, hello_option_generation_id,
11928ecf 324 neigh->generation_id, &src_addr,
d62a17ae 325 ifp->name);
d62a17ae 326
9b29ea95
DS
327 pim_upstream_rpf_genid_changed(pim_ifp->pim,
328 neigh->source_addr);
d62a17ae 329
330 pim_neighbor_delete(ifp, neigh, "GenID mismatch");
331 neigh = pim_neighbor_add(ifp, src_addr, hello_options,
332 hello_option_holdtime,
333 hello_option_propagation_delay,
334 hello_option_override_interval,
335 hello_option_dr_priority,
336 hello_option_generation_id,
337 hello_option_addr_list,
338 PIM_NEIGHBOR_SEND_NOW);
339 if (!neigh) {
11928ecf 340 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 341 zlog_debug(
11928ecf
DL
342 "%s: failure re-creating PIM neighbor %pPAs on interface %s",
343 __func__, &src_addr, ifp->name);
d62a17ae 344 FREE_ADDR_LIST_THEN_RETURN(-9);
345 }
6bb2ef35 346 /* Forward BSM if required */
347 if (!pim_bsm_new_nbr_fwd(neigh, ifp)) {
348 if (PIM_DEBUG_PIM_HELLO)
15569c58
DA
349 zlog_debug(
350 "%s: forwarding bsm to new nbr failed",
351 __func__);
6bb2ef35 352 }
d62a17ae 353 /* actual addr list is saved under neighbor */
354 return 0;
355
356 } /* GenId mismatch: replace neighbor */
357
358 } /* GenId received */
359
360 /*
361 Update existing neighbor
362 */
363
364 pim_neighbor_update(neigh, hello_options, hello_option_holdtime,
365 hello_option_dr_priority, hello_option_addr_list);
366 /* actual addr list is saved under neighbor */
367 return 0;
12e41d03
DL
368}
369
d62a17ae 370int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
371 int tlv_buf_size, uint16_t holdtime,
372 uint32_t dr_priority, uint32_t generation_id,
373 uint16_t propagation_delay, uint16_t override_interval,
dba78609 374 int can_disable_join_suppression)
12e41d03 375{
d62a17ae 376 uint8_t *curr = tlv_buf;
377 uint8_t *pastend = tlv_buf + tlv_buf_size;
378 uint8_t *tmp;
6ea2a7fb 379#if PIM_IPV == 4
88a3f5e1
DS
380 struct pim_interface *pim_ifp = ifp->info;
381 struct pim_instance *pim = pim_ifp->pim;
6ea2a7fb 382#endif
d62a17ae 383
384 /*
385 * Append options
386 */
387
388 /* Holdtime */
389 curr = pim_tlv_append_uint16(curr, pastend,
390 PIM_MSG_OPTION_TYPE_HOLDTIME, holdtime);
391 if (!curr) {
392 if (PIM_DEBUG_PIM_HELLO) {
393 zlog_debug(
394 "%s: could not set PIM hello Holdtime option for interface %s",
15569c58 395 __func__, ifp->name);
d62a17ae 396 }
397 return -1;
398 }
12e41d03 399
d62a17ae 400 /* LAN Prune Delay */
401 tmp = pim_tlv_append_2uint16(curr, pastend,
402 PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY,
403 propagation_delay, override_interval);
404 if (!tmp) {
405 if (PIM_DEBUG_PIM_HELLO) {
406 zlog_debug(
407 "%s: could not set PIM LAN Prune Delay option for interface %s",
15569c58 408 __func__, ifp->name);
d62a17ae 409 }
410 return -1;
411 }
412 if (can_disable_join_suppression) {
c4efd0f4 413 *(curr + 4) |= 0x80; /* enable T bit */
d62a17ae 414 }
415 curr = tmp;
416
417 /* DR Priority */
418 curr = pim_tlv_append_uint32(
419 curr, pastend, PIM_MSG_OPTION_TYPE_DR_PRIORITY, dr_priority);
420 if (!curr) {
421 if (PIM_DEBUG_PIM_HELLO) {
422 zlog_debug(
423 "%s: could not set PIM hello DR Priority option for interface %s",
15569c58 424 __func__, ifp->name);
d62a17ae 425 }
426 return -2;
427 }
12e41d03 428
d62a17ae 429 /* Generation ID */
430 curr = pim_tlv_append_uint32(curr, pastend,
431 PIM_MSG_OPTION_TYPE_GENERATION_ID,
432 generation_id);
433 if (!curr) {
434 if (PIM_DEBUG_PIM_HELLO) {
435 zlog_debug(
436 "%s: could not set PIM hello Generation ID option for interface %s",
15569c58 437 __func__, ifp->name);
d62a17ae 438 }
439 return -3;
440 }
12e41d03 441
d62a17ae 442 /* Secondary Address List */
443 if (ifp->connected->count) {
6ea2a7fb
SP
444 curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,
445 PIM_AF);
d62a17ae 446 if (!curr) {
447 if (PIM_DEBUG_PIM_HELLO) {
448 zlog_debug(
6ea2a7fb
SP
449 "%s: could not set PIM hello %s Secondary Address List option for interface %s",
450 __func__, PIM_AF_NAME, ifp->name);
d62a17ae 451 }
452 return -4;
453 }
6ea2a7fb 454#if PIM_IPV == 4
88a3f5e1 455 if (pim->send_v6_secondary) {
6ea2a7fb
SP
456 curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,
457 AF_INET6);
d62a17ae 458 if (!curr) {
459 if (PIM_DEBUG_PIM_HELLO) {
460 zlog_debug(
461 "%s: could not sent PIM hello v6 secondary Address List option for interface %s",
15569c58 462 __func__, ifp->name);
d62a17ae 463 }
464 return -4;
465 }
466 }
6ea2a7fb 467#endif
d62a17ae 468 }
12e41d03 469
d62a17ae 470 return curr - tlv_buf;
12e41d03
DL
471}
472
473/*
474 RFC 4601: 4.3.1. Sending Hello Messages
475
476 Thus, if a router needs to send a Join/Prune or Assert message on an
477 interface on which it has not yet sent a Hello message with the
478 currently configured IP address, then it MUST immediately send the
479 relevant Hello message without waiting for the Hello Timer to
480 expire, followed by the Join/Prune or Assert message.
481*/
482void pim_hello_require(struct interface *ifp)
483{
d62a17ae 484 struct pim_interface *pim_ifp;
12e41d03 485
df5dfb77 486 assert(ifp);
12e41d03 487
d62a17ae 488 pim_ifp = ifp->info;
12e41d03 489
df5dfb77 490 assert(pim_ifp);
12e41d03 491
79992e8a 492 if (PIM_IF_FLAG_TEST_HELLO_SENT(pim_ifp->flags))
d62a17ae 493 return;
12e41d03 494
d62a17ae 495 pim_hello_restart_now(ifp); /* Send hello and restart timer */
12e41d03 496}