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