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