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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
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
) {
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
,
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
)
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
)
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
)
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
,
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
)
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 on_trace(__PRETTY_FUNCTION__
, ifp
, src_addr
);
168 ++pim_ifp
->pim_ifstat_hello_recv
;
173 zassert(tlv_buf_size
>= 0);
175 tlv_pastend
= tlv_buf
+ tlv_buf_size
;
177 while (tlv_curr
< tlv_pastend
) {
178 uint16_t option_type
;
180 int remain
= tlv_pastend
- tlv_curr
;
182 if (remain
< PIM_TLV_MIN_SIZE
) {
184 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
185 zlog_warn("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
187 remain
, PIM_TLV_MIN_SIZE
,
189 FREE_ADDR_LIST_THEN_RETURN(-1);
192 option_type
= PIM_TLV_GET_TYPE(tlv_curr
);
193 tlv_curr
+= PIM_TLV_TYPE_SIZE
;
194 option_len
= PIM_TLV_GET_LENGTH(tlv_curr
);
195 tlv_curr
+= PIM_TLV_LENGTH_SIZE
;
197 if ((tlv_curr
+ option_len
) > tlv_pastend
) {
199 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
200 zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
202 option_type
, option_len
, tlv_pastend
- tlv_curr
,
204 FREE_ADDR_LIST_THEN_RETURN(-2);
207 if (PIM_DEBUG_PIM_TRACE
|| PIM_DEBUG_PIM_HELLO
) {
209 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
210 zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
213 option_type
, option_len
,
217 switch (option_type
) {
218 case PIM_MSG_OPTION_TYPE_HOLDTIME
:
219 if (pim_tlv_parse_holdtime(ifp
->name
, src_addr
,
221 &hello_option_holdtime
,
224 FREE_ADDR_LIST_THEN_RETURN(-3);
227 case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
:
228 if (pim_tlv_parse_lan_prune_delay(ifp
->name
, src_addr
,
230 &hello_option_propagation_delay
,
231 &hello_option_override_interval
,
234 FREE_ADDR_LIST_THEN_RETURN(-4);
237 case PIM_MSG_OPTION_TYPE_DR_PRIORITY
:
238 if (pim_tlv_parse_dr_priority(ifp
->name
, src_addr
,
240 &hello_option_dr_priority
,
243 FREE_ADDR_LIST_THEN_RETURN(-5);
246 case PIM_MSG_OPTION_TYPE_GENERATION_ID
:
247 if (pim_tlv_parse_generation_id(ifp
->name
, src_addr
,
249 &hello_option_generation_id
,
252 FREE_ADDR_LIST_THEN_RETURN(-6);
255 case PIM_MSG_OPTION_TYPE_ADDRESS_LIST
:
256 if (pim_tlv_parse_addr_list(ifp
->name
, src_addr
,
258 &hello_option_addr_list
,
264 case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH
:
265 if (PIM_DEBUG_PIM_TRACE
|| PIM_DEBUG_PIM_HELLO
) {
267 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
268 zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
270 option_type
, option_len
,
277 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
278 zlog_warn("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
280 option_type
, option_len
,
285 tlv_curr
+= option_len
;
289 Check received PIM hello options
292 if (PIM_DEBUG_PIM_TRACE
) {
293 tlv_trace_uint16(__PRETTY_FUNCTION__
, "holdtime",
295 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
),
296 hello_option_holdtime
);
297 tlv_trace_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
299 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
300 hello_option_propagation_delay
);
301 tlv_trace_uint16(__PRETTY_FUNCTION__
, "override_interval",
303 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
304 hello_option_override_interval
);
305 tlv_trace_bool(__PRETTY_FUNCTION__
, "can_disable_join_suppression",
307 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
308 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
));
309 tlv_trace_uint32(__PRETTY_FUNCTION__
, "dr_priority",
311 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
),
312 hello_option_dr_priority
);
313 tlv_trace_uint32_hex(__PRETTY_FUNCTION__
, "generation_id",
315 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
),
316 hello_option_generation_id
);
317 tlv_trace_list(__PRETTY_FUNCTION__
, "address_list",
319 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
),
320 hello_option_addr_list
);
323 if (!PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
325 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
326 zlog_warn("%s: PIM hello missing holdtime from %s on interface %s",
335 neigh
= pim_neighbor_find(ifp
, src_addr
);
337 /* Add as new neighbor */
339 neigh
= pim_neighbor_add(ifp
, src_addr
,
341 hello_option_holdtime
,
342 hello_option_propagation_delay
,
343 hello_option_override_interval
,
344 hello_option_dr_priority
,
345 hello_option_generation_id
,
346 hello_option_addr_list
);
349 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
350 zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
353 FREE_ADDR_LIST_THEN_RETURN(-8);
356 /* actual addr list has been saved under neighbor */
361 Received generation ID ?
364 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
)) {
365 /* GenID mismatch ? */
366 if (!PIM_OPTION_IS_SET(neigh
->hello_options
, PIM_OPTION_MASK_GENERATION_ID
) ||
367 (hello_option_generation_id
!= neigh
->generation_id
)) {
371 pim_upstream_rpf_genid_changed(neigh
->source_addr
);
373 /* GenID mismatch, then replace neighbor */
375 if (PIM_DEBUG_PIM_TRACE
) {
377 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
378 zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
380 hello_option_generation_id
,
381 neigh
->generation_id
,
385 pim_upstream_rpf_genid_changed(neigh
->source_addr
);
387 pim_neighbor_delete(ifp
, neigh
, "GenID mismatch");
388 neigh
= pim_neighbor_add(ifp
, src_addr
,
390 hello_option_holdtime
,
391 hello_option_propagation_delay
,
392 hello_option_override_interval
,
393 hello_option_dr_priority
,
394 hello_option_generation_id
,
395 hello_option_addr_list
);
398 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
399 zlog_warn("%s: failure re-creating PIM neighbor %s on interface %s",
402 FREE_ADDR_LIST_THEN_RETURN(-9);
404 /* actual addr list is saved under neighbor */
407 } /* GenId mismatch: replace neighbor */
409 } /* GenId received */
412 Update existing neighbor
415 pim_neighbor_update(neigh
,
417 hello_option_holdtime
,
418 hello_option_dr_priority
,
419 hello_option_addr_list
);
420 /* actual addr list is saved under neighbor */
424 int pim_hello_build_tlv(const char *ifname
,
425 uint8_t *tlv_buf
, int tlv_buf_size
,
427 uint32_t dr_priority
,
428 uint32_t generation_id
,
429 uint16_t propagation_delay
,
430 uint16_t override_interval
,
431 int can_disable_join_suppression
,
432 struct list
*ifconnected
)
434 uint8_t *curr
= tlv_buf
;
435 uint8_t *pastend
= tlv_buf
+ tlv_buf_size
;
443 curr
= pim_tlv_append_uint16(curr
,
445 PIM_MSG_OPTION_TYPE_HOLDTIME
,
448 zlog_warn("%s: could not set PIM hello Holdtime option for interface %s",
449 __PRETTY_FUNCTION__
, ifname
);
453 /* LAN Prune Delay */
454 tmp
= pim_tlv_append_2uint16(curr
,
456 PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
,
460 zlog_warn("%s: could not set PIM LAN Prune Delay option for interface %s",
461 __PRETTY_FUNCTION__
, ifname
);
464 if (can_disable_join_suppression
) {
465 *((uint8_t*)(curr
) + 4) |= 0x80; /* enable T bit */
470 curr
= pim_tlv_append_uint32(curr
,
472 PIM_MSG_OPTION_TYPE_DR_PRIORITY
,
475 zlog_warn("%s: could not set PIM hello DR Priority option for interface %s",
476 __PRETTY_FUNCTION__
, ifname
);
481 curr
= pim_tlv_append_uint32(curr
,
483 PIM_MSG_OPTION_TYPE_GENERATION_ID
,
486 zlog_warn("%s: could not set PIM hello Generation ID option for interface %s",
487 __PRETTY_FUNCTION__
, ifname
);
491 /* Secondary Address List */
493 curr
= pim_tlv_append_addrlist_ucast(curr
,
497 zlog_warn("%s: could not set PIM hello Secondary Address List option for interface %s",
498 __PRETTY_FUNCTION__
, ifname
);
503 return curr
- tlv_buf
;
507 RFC 4601: 4.3.1. Sending Hello Messages
509 Thus, if a router needs to send a Join/Prune or Assert message on an
510 interface on which it has not yet sent a Hello message with the
511 currently configured IP address, then it MUST immediately send the
512 relevant Hello message without waiting for the Hello Timer to
513 expire, followed by the Join/Prune or Assert message.
515 void pim_hello_require(struct interface
*ifp
)
517 struct pim_interface
*pim_ifp
;
525 if (pim_ifp
->pim_ifstat_hello_sent
)
528 pim_hello_restart_now(ifp
); /* Send hello and restart timer */