]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_hello.c
pimd: replace grp_str[100] with grp_str[INET_ADDRSTRLEN]
[mirror_frr.git] / pimd / pim_hello.c
1 /*
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
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,
18 MA 02110-1301 USA
19
20 */
21
22 #include <zebra.h>
23
24 #include "log.h"
25 #include "if.h"
26
27 #include "pimd.h"
28 #include "pim_pim.h"
29 #include "pim_str.h"
30 #include "pim_tlv.h"
31 #include "pim_util.h"
32 #include "pim_hello.h"
33 #include "pim_iface.h"
34 #include "pim_neighbor.h"
35 #include "pim_upstream.h"
36
37 static void on_trace(const char *label,
38 struct interface *ifp, struct in_addr src)
39 {
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);
45 }
46 }
47
48 static void tlv_trace_bool(const char *label, const char *tlv_name,
49 const char *ifname, struct in_addr src_addr,
50 int isset, int value)
51 {
52 if (isset) {
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",
56 label,
57 src_str, ifname,
58 tlv_name, value);
59 }
60 }
61
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)
65 {
66 if (isset) {
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",
70 label,
71 src_str, ifname,
72 tlv_name, value);
73 }
74 }
75
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)
79 {
80 if (isset) {
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",
84 label,
85 src_str, ifname,
86 tlv_name, value);
87 }
88 }
89
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)
93 {
94 if (isset) {
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",
98 label,
99 src_str, ifname,
100 tlv_name, value);
101 }
102 }
103
104 #if 0
105 static void tlv_trace(const char *label, const char *tlv_name,
106 const char *ifname, struct in_addr src_addr,
107 int isset)
108 {
109 if (isset) {
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",
113 label,
114 src_str, ifname,
115 tlv_name);
116 }
117 }
118 #endif
119
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)
123 {
124 if (isset) {
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",
128 label,
129 src_str, ifname,
130 tlv_name,
131 addr_list ? ((int) listcount(addr_list)) : -1,
132 (void *) addr_list);
133 }
134 }
135
136 #define FREE_ADDR_LIST \
137 if (hello_option_addr_list) { \
138 list_delete(hello_option_addr_list); \
139 }
140
141 #define FREE_ADDR_LIST_THEN_RETURN(code) \
142 { \
143 FREE_ADDR_LIST \
144 return (code); \
145 }
146
147 int pim_hello_recv(struct interface *ifp,
148 struct in_addr src_addr,
149 uint8_t *tlv_buf, int tlv_buf_size)
150 {
151 struct pim_interface *pim_ifp;
152 struct pim_neighbor *neigh;
153 uint8_t *tlv_curr;
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;
162
163 if (PIM_DEBUG_PIM_HELLO)
164 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
165
166 pim_ifp = ifp->info;
167 zassert(pim_ifp);
168
169 ++pim_ifp->pim_ifstat_hello_recv;
170
171 /*
172 Parse PIM hello TLVs
173 */
174 zassert(tlv_buf_size >= 0);
175 tlv_curr = tlv_buf;
176 tlv_pastend = tlv_buf + tlv_buf_size;
177
178 while (tlv_curr < tlv_pastend) {
179 uint16_t option_type;
180 uint16_t option_len;
181 int remain = tlv_pastend - tlv_curr;
182
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",
188 __PRETTY_FUNCTION__,
189 remain, PIM_TLV_MIN_SIZE,
190 src_str, ifp->name);
191 }
192 FREE_ADDR_LIST_THEN_RETURN(-1);
193 }
194
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;
199
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",
205 __PRETTY_FUNCTION__,
206 option_type, option_len, tlv_pastend - tlv_curr,
207 src_str, ifp->name);
208 }
209 FREE_ADDR_LIST_THEN_RETURN(-2);
210 }
211
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",
216 __PRETTY_FUNCTION__,
217 remain,
218 option_type, option_len,
219 src_str, ifp->name);
220 }
221
222 switch (option_type) {
223 case PIM_MSG_OPTION_TYPE_HOLDTIME:
224 if (pim_tlv_parse_holdtime(ifp->name, src_addr,
225 &hello_options,
226 &hello_option_holdtime,
227 option_len,
228 tlv_curr)) {
229 FREE_ADDR_LIST_THEN_RETURN(-3);
230 }
231 break;
232 case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY:
233 if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr,
234 &hello_options,
235 &hello_option_propagation_delay,
236 &hello_option_override_interval,
237 option_len,
238 tlv_curr)) {
239 FREE_ADDR_LIST_THEN_RETURN(-4);
240 }
241 break;
242 case PIM_MSG_OPTION_TYPE_DR_PRIORITY:
243 if (pim_tlv_parse_dr_priority(ifp->name, src_addr,
244 &hello_options,
245 &hello_option_dr_priority,
246 option_len,
247 tlv_curr)) {
248 FREE_ADDR_LIST_THEN_RETURN(-5);
249 }
250 break;
251 case PIM_MSG_OPTION_TYPE_GENERATION_ID:
252 if (pim_tlv_parse_generation_id(ifp->name, src_addr,
253 &hello_options,
254 &hello_option_generation_id,
255 option_len,
256 tlv_curr)) {
257 FREE_ADDR_LIST_THEN_RETURN(-6);
258 }
259 break;
260 case PIM_MSG_OPTION_TYPE_ADDRESS_LIST:
261 if (pim_tlv_parse_addr_list(ifp->name, src_addr,
262 &hello_options,
263 &hello_option_addr_list,
264 option_len,
265 tlv_curr)) {
266 return -7;
267 }
268 break;
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",
274 __PRETTY_FUNCTION__,
275 option_type, option_len,
276 src_str, ifp->name);
277 }
278 break;
279 default:
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",
284 __PRETTY_FUNCTION__,
285 option_type, option_len,
286 src_str, ifp->name);
287 }
288 }
289
290 tlv_curr += option_len;
291 }
292
293 /*
294 Check received PIM hello options
295 */
296
297 if (PIM_DEBUG_PIM_HELLO) {
298 tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime",
299 ifp->name, src_addr,
300 PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME),
301 hello_option_holdtime);
302 tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay",
303 ifp->name, src_addr,
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",
307 ifp->name, src_addr,
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",
311 ifp->name, src_addr,
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",
315 ifp->name, src_addr,
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",
319 ifp->name, src_addr,
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",
323 ifp->name, src_addr,
324 PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST),
325 hello_option_addr_list);
326 }
327
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",
333 __PRETTY_FUNCTION__,
334 src_str, ifp->name);
335 }
336 }
337
338 /*
339 New neighbor?
340 */
341
342 neigh = pim_neighbor_find(ifp, src_addr);
343 if (!neigh) {
344 /* Add as new neighbor */
345
346 neigh = pim_neighbor_add(ifp, src_addr,
347 hello_options,
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);
355 if (!neigh) {
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",
360 __PRETTY_FUNCTION__,
361 src_str, ifp->name);
362 }
363 FREE_ADDR_LIST_THEN_RETURN(-8);
364 }
365
366 /* actual addr list has been saved under neighbor */
367 return 0;
368 }
369
370 /*
371 Received generation ID ?
372 */
373
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 */
379
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",
384 __PRETTY_FUNCTION__,
385 hello_option_generation_id,
386 neigh->generation_id,
387 src_str, ifp->name);
388 }
389
390 pim_upstream_rpf_genid_changed(neigh->source_addr);
391
392 pim_neighbor_delete(ifp, neigh, "GenID mismatch");
393 neigh = pim_neighbor_add(ifp, src_addr,
394 hello_options,
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);
402 if (!neigh) {
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",
407 __PRETTY_FUNCTION__,
408 src_str, ifp->name);
409 }
410 FREE_ADDR_LIST_THEN_RETURN(-9);
411 }
412 /* actual addr list is saved under neighbor */
413 return 0;
414
415 } /* GenId mismatch: replace neighbor */
416
417 } /* GenId received */
418
419 /*
420 Update existing neighbor
421 */
422
423 pim_neighbor_update(neigh,
424 hello_options,
425 hello_option_holdtime,
426 hello_option_dr_priority,
427 hello_option_addr_list);
428 /* actual addr list is saved under neighbor */
429 return 0;
430 }
431
432 int pim_hello_build_tlv(const char *ifname,
433 uint8_t *tlv_buf, int tlv_buf_size,
434 uint16_t holdtime,
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)
441 {
442 uint8_t *curr = tlv_buf;
443 uint8_t *pastend = tlv_buf + tlv_buf_size;
444 uint8_t *tmp;
445
446 /*
447 * Append options
448 */
449
450 /* Holdtime */
451 curr = pim_tlv_append_uint16(curr,
452 pastend,
453 PIM_MSG_OPTION_TYPE_HOLDTIME,
454 holdtime);
455 if (!curr) {
456 if (PIM_DEBUG_PIM_HELLO) {
457 zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
458 __PRETTY_FUNCTION__, ifname);
459 }
460 return -1;
461 }
462
463 /* LAN Prune Delay */
464 tmp = pim_tlv_append_2uint16(curr,
465 pastend,
466 PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY,
467 propagation_delay,
468 override_interval);
469 if (!tmp) {
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);
473 }
474 return -1;
475 }
476 if (can_disable_join_suppression) {
477 *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */
478 }
479 curr = tmp;
480
481 /* DR Priority */
482 curr = pim_tlv_append_uint32(curr,
483 pastend,
484 PIM_MSG_OPTION_TYPE_DR_PRIORITY,
485 dr_priority);
486 if (!curr) {
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);
490 }
491 return -2;
492 }
493
494 /* Generation ID */
495 curr = pim_tlv_append_uint32(curr,
496 pastend,
497 PIM_MSG_OPTION_TYPE_GENERATION_ID,
498 generation_id);
499 if (!curr) {
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);
503 }
504 return -3;
505 }
506
507 /* Secondary Address List */
508 if (ifconnected) {
509 curr = pim_tlv_append_addrlist_ucast(curr,
510 pastend,
511 ifconnected);
512 if (!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);
516 }
517 return -4;
518 }
519 }
520
521 return curr - tlv_buf;
522 }
523
524 /*
525 RFC 4601: 4.3.1. Sending Hello Messages
526
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.
532 */
533 void pim_hello_require(struct interface *ifp)
534 {
535 struct pim_interface *pim_ifp;
536
537 zassert(ifp);
538
539 pim_ifp = ifp->info;
540
541 zassert(pim_ifp);
542
543 if (pim_ifp->pim_ifstat_hello_sent)
544 return;
545
546 pim_hello_restart_now(ifp); /* Send hello and restart timer */
547 }