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