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,
31 #include "pim_hello.h"
32 #include "pim_iface.h"
33 #include "pim_neighbor.h"
34 #include "pim_upstream.h"
36 static void on_trace(const char *label
,
37 struct interface
*ifp
, struct in_addr src
)
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",
43 label
, src_str
, ifp
->name
);
47 static void tlv_trace_bool(const char *label
, const char *tlv_name
,
48 const char *ifname
, struct in_addr src_addr
,
52 char src_str
[INET_ADDRSTRLEN
];
53 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
54 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
61 static void tlv_trace_uint16(const char *label
, const char *tlv_name
,
62 const char *ifname
, struct in_addr src_addr
,
63 int isset
, uint16_t value
)
66 char src_str
[INET_ADDRSTRLEN
];
67 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
68 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
75 static void tlv_trace_uint32(const char *label
, const char *tlv_name
,
76 const char *ifname
, struct in_addr src_addr
,
77 int isset
, uint32_t value
)
80 char src_str
[INET_ADDRSTRLEN
];
81 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
82 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
89 static void tlv_trace_uint32_hex(const char *label
, const char *tlv_name
,
90 const char *ifname
, struct in_addr src_addr
,
91 int isset
, uint32_t value
)
94 char src_str
[INET_ADDRSTRLEN
];
95 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
96 zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
104 static void tlv_trace(const char *label
, const char *tlv_name
,
105 const char *ifname
, struct in_addr src_addr
,
109 char src_str
[INET_ADDRSTRLEN
];
110 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
111 zlog_debug("%s: PIM hello option from %s on interface %s: %s",
119 static void tlv_trace_list(const char *label
, const char *tlv_name
,
120 const char *ifname
, struct in_addr src_addr
,
121 int isset
, struct list
*addr_list
)
124 char src_str
[INET_ADDRSTRLEN
];
125 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
126 zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
130 addr_list
? ((int) listcount(addr_list
)) : -1,
135 #define FREE_ADDR_LIST \
136 if (hello_option_addr_list) { \
137 list_delete(hello_option_addr_list); \
140 #define FREE_ADDR_LIST_THEN_RETURN(code) \
146 int pim_hello_recv(struct interface
*ifp
,
147 struct in_addr src_addr
,
148 uint8_t *tlv_buf
, int tlv_buf_size
)
150 struct pim_interface
*pim_ifp
;
151 struct pim_neighbor
*neigh
;
153 uint8_t *tlv_pastend
;
154 pim_hello_options hello_options
= 0; /* bit array recording options found */
155 uint16_t hello_option_holdtime
= 0;
156 uint16_t hello_option_propagation_delay
= 0;
157 uint16_t hello_option_override_interval
= 0;
158 uint32_t hello_option_dr_priority
= 0;
159 uint32_t hello_option_generation_id
= 0;
160 struct list
*hello_option_addr_list
= 0;
162 if (PIM_DEBUG_PIM_HELLO
)
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
) {
183 if (PIM_DEBUG_PIM_HELLO
) {
184 char src_str
[INET_ADDRSTRLEN
];
185 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
186 zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
188 remain
, PIM_TLV_MIN_SIZE
,
191 FREE_ADDR_LIST_THEN_RETURN(-1);
194 option_type
= PIM_TLV_GET_TYPE(tlv_curr
);
195 tlv_curr
+= PIM_TLV_TYPE_SIZE
;
196 option_len
= PIM_TLV_GET_LENGTH(tlv_curr
);
197 tlv_curr
+= PIM_TLV_LENGTH_SIZE
;
199 if ((tlv_curr
+ option_len
) > tlv_pastend
) {
200 if (PIM_DEBUG_PIM_HELLO
) {
201 char src_str
[INET_ADDRSTRLEN
];
202 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
203 zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
205 option_type
, option_len
, tlv_pastend
- tlv_curr
,
208 FREE_ADDR_LIST_THEN_RETURN(-2);
211 if (PIM_DEBUG_PIM_HELLO
) {
212 char src_str
[INET_ADDRSTRLEN
];
213 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
214 zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
217 option_type
, option_len
,
221 switch (option_type
) {
222 case PIM_MSG_OPTION_TYPE_HOLDTIME
:
223 if (pim_tlv_parse_holdtime(ifp
->name
, src_addr
,
225 &hello_option_holdtime
,
228 FREE_ADDR_LIST_THEN_RETURN(-3);
231 case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
:
232 if (pim_tlv_parse_lan_prune_delay(ifp
->name
, src_addr
,
234 &hello_option_propagation_delay
,
235 &hello_option_override_interval
,
238 FREE_ADDR_LIST_THEN_RETURN(-4);
241 case PIM_MSG_OPTION_TYPE_DR_PRIORITY
:
242 if (pim_tlv_parse_dr_priority(ifp
->name
, src_addr
,
244 &hello_option_dr_priority
,
247 FREE_ADDR_LIST_THEN_RETURN(-5);
250 case PIM_MSG_OPTION_TYPE_GENERATION_ID
:
251 if (pim_tlv_parse_generation_id(ifp
->name
, src_addr
,
253 &hello_option_generation_id
,
256 FREE_ADDR_LIST_THEN_RETURN(-6);
259 case PIM_MSG_OPTION_TYPE_ADDRESS_LIST
:
260 if (pim_tlv_parse_addr_list(ifp
->name
, src_addr
,
262 &hello_option_addr_list
,
268 case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH
:
269 if (PIM_DEBUG_PIM_HELLO
) {
270 char src_str
[INET_ADDRSTRLEN
];
271 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
272 zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
274 option_type
, option_len
,
279 if (PIM_DEBUG_PIM_HELLO
) {
280 char src_str
[INET_ADDRSTRLEN
];
281 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
282 zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
284 option_type
, option_len
,
289 tlv_curr
+= option_len
;
293 Check received PIM hello options
296 if (PIM_DEBUG_PIM_HELLO
) {
297 tlv_trace_uint16(__PRETTY_FUNCTION__
, "holdtime",
299 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
),
300 hello_option_holdtime
);
301 tlv_trace_uint16(__PRETTY_FUNCTION__
, "propagation_delay",
303 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
304 hello_option_propagation_delay
);
305 tlv_trace_uint16(__PRETTY_FUNCTION__
, "override_interval",
307 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
308 hello_option_override_interval
);
309 tlv_trace_bool(__PRETTY_FUNCTION__
, "can_disable_join_suppression",
311 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
),
312 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION
));
313 tlv_trace_uint32(__PRETTY_FUNCTION__
, "dr_priority",
315 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
),
316 hello_option_dr_priority
);
317 tlv_trace_uint32_hex(__PRETTY_FUNCTION__
, "generation_id",
319 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
),
320 hello_option_generation_id
);
321 tlv_trace_list(__PRETTY_FUNCTION__
, "address_list",
323 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_ADDRESS_LIST
),
324 hello_option_addr_list
);
327 if (!PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
328 if (PIM_DEBUG_PIM_HELLO
) {
329 char src_str
[INET_ADDRSTRLEN
];
330 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
331 zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
341 neigh
= pim_neighbor_find(ifp
, src_addr
);
343 /* Add as new neighbor */
345 neigh
= pim_neighbor_add(ifp
, src_addr
,
347 hello_option_holdtime
,
348 hello_option_propagation_delay
,
349 hello_option_override_interval
,
350 hello_option_dr_priority
,
351 hello_option_generation_id
,
352 hello_option_addr_list
,
353 PIM_NEIGHBOR_SEND_DELAY
);
355 if (PIM_DEBUG_PIM_HELLO
) {
356 char src_str
[INET_ADDRSTRLEN
];
357 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
358 zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
362 FREE_ADDR_LIST_THEN_RETURN(-8);
365 /* actual addr list has been saved under neighbor */
370 Received generation ID ?
373 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_GENERATION_ID
)) {
374 /* GenID mismatch ? */
375 if (!PIM_OPTION_IS_SET(neigh
->hello_options
, PIM_OPTION_MASK_GENERATION_ID
) ||
376 (hello_option_generation_id
!= neigh
->generation_id
)) {
377 /* GenID mismatch, then replace neighbor */
379 if (PIM_DEBUG_PIM_HELLO
) {
380 char src_str
[INET_ADDRSTRLEN
];
381 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
382 zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
384 hello_option_generation_id
,
385 neigh
->generation_id
,
389 pim_upstream_rpf_genid_changed(neigh
->source_addr
);
391 pim_neighbor_delete(ifp
, neigh
, "GenID mismatch");
392 neigh
= pim_neighbor_add(ifp
, src_addr
,
394 hello_option_holdtime
,
395 hello_option_propagation_delay
,
396 hello_option_override_interval
,
397 hello_option_dr_priority
,
398 hello_option_generation_id
,
399 hello_option_addr_list
,
400 PIM_NEIGHBOR_SEND_NOW
);
402 if (PIM_DEBUG_PIM_HELLO
) {
403 char src_str
[INET_ADDRSTRLEN
];
404 pim_inet4_dump("<src?>", src_addr
, src_str
, sizeof(src_str
));
405 zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
409 FREE_ADDR_LIST_THEN_RETURN(-9);
411 /* actual addr list is saved under neighbor */
414 } /* GenId mismatch: replace neighbor */
416 } /* GenId received */
419 Update existing neighbor
422 pim_neighbor_update(neigh
,
424 hello_option_holdtime
,
425 hello_option_dr_priority
,
426 hello_option_addr_list
);
427 /* actual addr list is saved under neighbor */
431 int pim_hello_build_tlv(const char *ifname
,
432 uint8_t *tlv_buf
, int tlv_buf_size
,
434 uint32_t dr_priority
,
435 uint32_t generation_id
,
436 uint16_t propagation_delay
,
437 uint16_t override_interval
,
438 int can_disable_join_suppression
,
439 struct list
*ifconnected
)
441 uint8_t *curr
= tlv_buf
;
442 uint8_t *pastend
= tlv_buf
+ tlv_buf_size
;
450 curr
= pim_tlv_append_uint16(curr
,
452 PIM_MSG_OPTION_TYPE_HOLDTIME
,
455 if (PIM_DEBUG_PIM_HELLO
) {
456 zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
457 __PRETTY_FUNCTION__
, ifname
);
462 /* LAN Prune Delay */
463 tmp
= pim_tlv_append_2uint16(curr
,
465 PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY
,
469 if (PIM_DEBUG_PIM_HELLO
) {
470 zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
471 __PRETTY_FUNCTION__
, ifname
);
475 if (can_disable_join_suppression
) {
476 *((uint8_t*)(curr
) + 4) |= 0x80; /* enable T bit */
481 curr
= pim_tlv_append_uint32(curr
,
483 PIM_MSG_OPTION_TYPE_DR_PRIORITY
,
486 if (PIM_DEBUG_PIM_HELLO
) {
487 zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
488 __PRETTY_FUNCTION__
, ifname
);
494 curr
= pim_tlv_append_uint32(curr
,
496 PIM_MSG_OPTION_TYPE_GENERATION_ID
,
499 if (PIM_DEBUG_PIM_HELLO
) {
500 zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
501 __PRETTY_FUNCTION__
, ifname
);
506 /* Secondary Address List */
508 curr
= pim_tlv_append_addrlist_ucast(curr
,
512 if (PIM_DEBUG_PIM_HELLO
) {
513 zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
514 __PRETTY_FUNCTION__
, ifname
);
520 return curr
- tlv_buf
;
524 RFC 4601: 4.3.1. Sending Hello Messages
526 Thus, if a router needs to send a Join/Prune or Assert message on an
527 interface on which it has not yet sent a Hello message with the
528 currently configured IP address, then it MUST immediately send the
529 relevant Hello message without waiting for the Hello Timer to
530 expire, followed by the Join/Prune or Assert message.
532 void pim_hello_require(struct interface
*ifp
)
534 struct pim_interface
*pim_ifp
;
542 if (pim_ifp
->pim_ifstat_hello_sent
)
545 pim_hello_restart_now(ifp
); /* Send hello and restart timer */