3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
32 #include "pim_hello.h"
33 #include "pim_iface.h"
34 #include "pim_neighbor.h"
35 #include "pim_upstream.h"
37 static void on_trace(const char *label
,
38 struct interface
*ifp
, struct in_addr src
)
40 if (PIM_DEBUG_PIM_TRACE
) {
41 char src_str
[INET_ADDRSTRLEN
];
42 pim_inet4_dump("<src?>", src
, src_str
, sizeof(src_str
));
43 zlog_debug("%s: from %s on %s",
44 label
, src_str
, ifp
->name
);
48 static void tlv_trace_bool(const char *label
, const char *tlv_name
,
49 const char *ifname
, struct in_addr src_addr
,
53 char src_str
[INET_ADDRSTRLEN
];
54 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
55 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
62 static void tlv_trace_uint16(const char *label
, const char *tlv_name
,
63 const char *ifname
, struct in_addr src_addr
,
64 int isset
, uint16_t value
)
67 char src_str
[INET_ADDRSTRLEN
];
68 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
69 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
76 static void tlv_trace_uint32(const char *label
, const char *tlv_name
,
77 const char *ifname
, struct in_addr src_addr
,
78 int isset
, uint32_t value
)
81 char src_str
[INET_ADDRSTRLEN
];
82 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
83 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
90 static void tlv_trace_uint32_hex(const char *label
, const char *tlv_name
,
91 const char *ifname
, struct in_addr src_addr
,
92 int isset
, uint32_t value
)
95 char src_str
[INET_ADDRSTRLEN
];
96 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
97 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
105 static void tlv_trace(const char *label
, const char *tlv_name
,
106 const char *ifname
, struct in_addr src_addr
,
110 char src_str
[INET_ADDRSTRLEN
];
111 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
112 zlog_debug("%s: PIM hello option from %s on interface %s: %s",
120 static void tlv_trace_list(const char *label
, const char *tlv_name
,
121 const char *ifname
, struct in_addr src_addr
,
122 int isset
, struct list
*addr_list
)
125 char src_str
[INET_ADDRSTRLEN
];
126 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
127 zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
131 addr_list
? ((int) listcount(addr_list
)) : -1,
136 #define FREE_ADDR_LIST \
137 if (hello_option_addr_list) { \
138 list_delete(hello_option_addr_list); \
141 #define FREE_ADDR_LIST_THEN_RETURN(code) \
147 int pim_hello_recv(struct interface
*ifp
,
148 struct in_addr src_addr
,
149 uint8_t *tlv_buf
, int tlv_buf_size
)
151 struct pim_interface
*pim_ifp
;
152 struct pim_neighbor
*neigh
;
154 uint8_t *tlv_pastend
;
155 pim_hello_options hello_options
= 0; /* bit array recording options found */
156 uint16_t hello_option_holdtime
= 0;
157 uint16_t hello_option_propagation_delay
= 0;
158 uint16_t hello_option_override_interval
= 0;
159 uint32_t hello_option_dr_priority
= 0;
160 uint32_t hello_option_generation_id
= 0;
161 struct list
*hello_option_addr_list
= 0;
163 if (PIM_DEBUG_PIM_HELLO
)
164 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
169 ++pim_ifp
->pim_ifstat_hello_recv
;
174 zassert(tlv_buf_size
>= 0);
176 tlv_pastend
= tlv_buf
+ tlv_buf_size
;
178 while (tlv_curr
< tlv_pastend
) {
179 uint16_t option_type
;
181 int remain
= tlv_pastend
- tlv_curr
;
183 if (remain
< PIM_TLV_MIN_SIZE
) {
184 if (PIM_DEBUG_PIM_HELLO
) {
185 char src_str
[INET_ADDRSTRLEN
];
186 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
187 zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
189 remain
, PIM_TLV_MIN_SIZE
,
192 FREE_ADDR_LIST_THEN_RETURN(-1);
195 option_type
= PIM_TLV_GET_TYPE(tlv_curr
);
196 tlv_curr
+= PIM_TLV_TYPE_SIZE
;
197 option_len
= PIM_TLV_GET_LENGTH(tlv_curr
);
198 tlv_curr
+= PIM_TLV_LENGTH_SIZE
;
200 if ((tlv_curr
+ option_len
) > tlv_pastend
) {
201 if (PIM_DEBUG_PIM_HELLO
) {
202 char src_str
[INET_ADDRSTRLEN
];
203 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
204 zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
206 option_type
, option_len
, tlv_pastend
- tlv_curr
,
209 FREE_ADDR_LIST_THEN_RETURN(-2);
212 if (PIM_DEBUG_PIM_HELLO
) {
213 char src_str
[INET_ADDRSTRLEN
];
214 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
215 zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
218 option_type
, option_len
,
222 switch (option_type
) {
223 case PIM_MSG_OPTION_TYPE_HOLDTIME
:
224 if (pim_tlv_parse_holdtime(ifp
->name
, src_addr
,
226 &hello_option_holdtime
,
229 FREE_ADDR_LIST_THEN_RETURN(-3);
232 case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
:
233 if (pim_tlv_parse_lan_prune_delay(ifp
->name
, src_addr
,
235 &hello_option_propagation_delay
,
236 &hello_option_override_interval
,
239 FREE_ADDR_LIST_THEN_RETURN(-4);
242 case PIM_MSG_OPTION_TYPE_DR_PRIORITY
:
243 if (pim_tlv_parse_dr_priority(ifp
->name
, src_addr
,
245 &hello_option_dr_priority
,
248 FREE_ADDR_LIST_THEN_RETURN(-5);
251 case PIM_MSG_OPTION_TYPE_GENERATION_ID
:
252 if (pim_tlv_parse_generation_id(ifp
->name
, src_addr
,
254 &hello_option_generation_id
,
257 FREE_ADDR_LIST_THEN_RETURN(-6);
260 case PIM_MSG_OPTION_TYPE_ADDRESS_LIST
:
261 if (pim_tlv_parse_addr_list(ifp
->name
, src_addr
,
263 &hello_option_addr_list
,
269 case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH
:
270 if (PIM_DEBUG_PIM_HELLO
) {
271 char src_str
[INET_ADDRSTRLEN
];
272 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
273 zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
275 option_type
, option_len
,
280 if (PIM_DEBUG_PIM_HELLO
) {
281 char src_str
[INET_ADDRSTRLEN
];
282 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
283 zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
285 option_type
, option_len
,
290 tlv_curr
+= option_len
;
294 Check received PIM hello options
297 if (PIM_DEBUG_PIM_HELLO
) {
298 tlv_trace_uint16(__PRETTY_FUNCTION__
, "holdtime",
300 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
),
301 hello_option_holdtime
);
302 tlv_trace_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
304 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
305 hello_option_propagation_delay
);
306 tlv_trace_uint16(__PRETTY_FUNCTION__
, "override_interval",
308 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
309 hello_option_override_interval
);
310 tlv_trace_bool(__PRETTY_FUNCTION__
, "can_disable_join_suppression",
312 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
313 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
));
314 tlv_trace_uint32(__PRETTY_FUNCTION__
, "dr_priority",
316 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
),
317 hello_option_dr_priority
);
318 tlv_trace_uint32_hex(__PRETTY_FUNCTION__
, "generation_id",
320 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
),
321 hello_option_generation_id
);
322 tlv_trace_list(__PRETTY_FUNCTION__
, "address_list",
324 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
),
325 hello_option_addr_list
);
328 if (!PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
329 if (PIM_DEBUG_PIM_HELLO
) {
330 char src_str
[INET_ADDRSTRLEN
];
331 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
332 zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
342 neigh
= pim_neighbor_find(ifp
, src_addr
);
344 /* Add as new neighbor */
346 neigh
= pim_neighbor_add(ifp
, src_addr
,
348 hello_option_holdtime
,
349 hello_option_propagation_delay
,
350 hello_option_override_interval
,
351 hello_option_dr_priority
,
352 hello_option_generation_id
,
353 hello_option_addr_list
,
354 PIM_NEIGHBOR_SEND_DELAY
);
356 if (PIM_DEBUG_PIM_HELLO
) {
357 char src_str
[INET_ADDRSTRLEN
];
358 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
359 zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
363 FREE_ADDR_LIST_THEN_RETURN(-8);
366 /* actual addr list has been saved under neighbor */
371 Received generation ID ?
374 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
)) {
375 /* GenID mismatch ? */
376 if (!PIM_OPTION_IS_SET(neigh
->hello_options
, PIM_OPTION_MASK_GENERATION_ID
) ||
377 (hello_option_generation_id
!= neigh
->generation_id
)) {
378 /* GenID mismatch, then replace neighbor */
380 if (PIM_DEBUG_PIM_HELLO
) {
381 char src_str
[INET_ADDRSTRLEN
];
382 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
383 zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
385 hello_option_generation_id
,
386 neigh
->generation_id
,
390 pim_upstream_rpf_genid_changed(neigh
->source_addr
);
392 pim_neighbor_delete(ifp
, neigh
, "GenID mismatch");
393 neigh
= pim_neighbor_add(ifp
, src_addr
,
395 hello_option_holdtime
,
396 hello_option_propagation_delay
,
397 hello_option_override_interval
,
398 hello_option_dr_priority
,
399 hello_option_generation_id
,
400 hello_option_addr_list
,
401 PIM_NEIGHBOR_SEND_NOW
);
403 if (PIM_DEBUG_PIM_HELLO
) {
404 char src_str
[INET_ADDRSTRLEN
];
405 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
406 zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
410 FREE_ADDR_LIST_THEN_RETURN(-9);
412 /* actual addr list is saved under neighbor */
415 } /* GenId mismatch: replace neighbor */
417 } /* GenId received */
420 Update existing neighbor
423 pim_neighbor_update(neigh
,
425 hello_option_holdtime
,
426 hello_option_dr_priority
,
427 hello_option_addr_list
);
428 /* actual addr list is saved under neighbor */
432 int pim_hello_build_tlv(const char *ifname
,
433 uint8_t *tlv_buf
, int tlv_buf_size
,
435 uint32_t dr_priority
,
436 uint32_t generation_id
,
437 uint16_t propagation_delay
,
438 uint16_t override_interval
,
439 int can_disable_join_suppression
,
440 struct list
*ifconnected
)
442 uint8_t *curr
= tlv_buf
;
443 uint8_t *pastend
= tlv_buf
+ tlv_buf_size
;
451 curr
= pim_tlv_append_uint16(curr
,
453 PIM_MSG_OPTION_TYPE_HOLDTIME
,
456 if (PIM_DEBUG_PIM_HELLO
) {
457 zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
458 __PRETTY_FUNCTION__
, ifname
);
463 /* LAN Prune Delay */
464 tmp
= pim_tlv_append_2uint16(curr
,
466 PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
,
470 if (PIM_DEBUG_PIM_HELLO
) {
471 zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
472 __PRETTY_FUNCTION__
, ifname
);
476 if (can_disable_join_suppression
) {
477 *((uint8_t*)(curr
) + 4) |= 0x80; /* enable T bit */
482 curr
= pim_tlv_append_uint32(curr
,
484 PIM_MSG_OPTION_TYPE_DR_PRIORITY
,
487 if (PIM_DEBUG_PIM_HELLO
) {
488 zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
489 __PRETTY_FUNCTION__
, ifname
);
495 curr
= pim_tlv_append_uint32(curr
,
497 PIM_MSG_OPTION_TYPE_GENERATION_ID
,
500 if (PIM_DEBUG_PIM_HELLO
) {
501 zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
502 __PRETTY_FUNCTION__
, ifname
);
507 /* Secondary Address List */
509 curr
= pim_tlv_append_addrlist_ucast(curr
,
513 if (PIM_DEBUG_PIM_HELLO
) {
514 zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
515 __PRETTY_FUNCTION__
, ifname
);
521 return curr
- tlv_buf
;
525 RFC 4601: 4.3.1. Sending Hello Messages
527 Thus, if a router needs to send a Join/Prune or Assert message on an
528 interface on which it has not yet sent a Hello message with the
529 currently configured IP address, then it MUST immediately send the
530 relevant Hello message without waiting for the Hello Timer to
531 expire, followed by the Join/Prune or Assert message.
533 void pim_hello_require(struct interface
*ifp
)
535 struct pim_interface
*pim_ifp
;
543 if (pim_ifp
->pim_ifstat_hello_sent
)
546 pim_hello_restart_now(ifp
); /* Send hello and restart timer */