blob: 770bd4e00077b4a97451a4c3e91edbb9adc86329 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17 MA 02110-1301 USA
18
19 $QuaggaId: $Format:%an, %ai, %h$ $
20*/
21
22#include <zebra.h>
23
24#include "if.h"
25#include "log.h"
26#include "vty.h"
27#include "memory.h"
28#include "prefix.h"
29
30#include "pimd.h"
31#include "pim_iface.h"
32#include "pim_igmp.h"
33#include "pim_mroute.h"
34#include "pim_oil.h"
35#include "pim_str.h"
36#include "pim_pim.h"
37#include "pim_neighbor.h"
38#include "pim_ifchannel.h"
39#include "pim_rand.h"
40#include "pim_sock.h"
Everton Marques567f9272010-02-19 19:07:00 -020041#include "pim_time.h"
Everton Marques96f91ae2009-10-07 18:41:45 -030042#include "pim_ssmpingd.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030043
44static void pim_if_igmp_join_del_all(struct interface *ifp);
45
46void pim_if_init()
47{
48 if_init();
49}
50
51static void *if_list_clean(struct pim_interface *pim_ifp)
52{
53 if (pim_ifp->igmp_join_list) {
54 list_delete(pim_ifp->igmp_join_list);
55 }
56
57 if (pim_ifp->igmp_socket_list) {
58 list_delete(pim_ifp->igmp_socket_list);
59 }
60
61 if (pim_ifp->pim_neighbor_list) {
62 list_delete(pim_ifp->pim_neighbor_list);
63 }
64
65 if (pim_ifp->pim_ifchannel_list) {
66 list_delete(pim_ifp->pim_ifchannel_list);
67 }
68
69 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
70
71 return 0;
72}
73
74struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
75{
76 struct pim_interface *pim_ifp;
77
78 zassert(ifp);
79 zassert(!ifp->info);
80
81 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
82 if (!pim_ifp) {
David Lamparter5c697982012-02-16 04:47:56 +010083 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
Everton Marques871dbcf2009-08-11 15:43:05 -030084 return 0;
85 }
86
87 pim_ifp->options = 0;
88 pim_ifp->mroute_vif_index = -1;
89
Leonard Herve236b0152009-08-11 15:51:52 -030090 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
91 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
92 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
93 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
Everton Marques871dbcf2009-08-11 15:43:05 -030094
95 /*
96 RFC 3376: 8.3. Query Response Interval
97 The number of seconds represented by the [Query Response Interval]
98 must be less than the [Query Interval].
99 */
100 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
101
102 if (pim)
103 PIM_IF_DO_PIM(pim_ifp->options);
104 if (igmp)
105 PIM_IF_DO_IGMP(pim_ifp->options);
106
107#if 0
108 /* FIXME: Should join? */
109 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
110#endif
111
112 pim_ifp->igmp_join_list = 0;
113 pim_ifp->igmp_socket_list = 0;
114 pim_ifp->pim_neighbor_list = 0;
115 pim_ifp->pim_ifchannel_list = 0;
116
117 /* list of struct igmp_sock */
118 pim_ifp->igmp_socket_list = list_new();
119 if (!pim_ifp->igmp_socket_list) {
120 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
121 __FILE__, __PRETTY_FUNCTION__);
122 return if_list_clean(pim_ifp);
123 }
124 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
125
126 /* list of struct pim_neighbor */
127 pim_ifp->pim_neighbor_list = list_new();
128 if (!pim_ifp->pim_neighbor_list) {
129 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
130 __FILE__, __PRETTY_FUNCTION__);
131 return if_list_clean(pim_ifp);
132 }
133 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
134
135 /* list of struct pim_ifchannel */
136 pim_ifp->pim_ifchannel_list = list_new();
137 if (!pim_ifp->pim_ifchannel_list) {
138 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
139 __FILE__, __PRETTY_FUNCTION__);
140 return if_list_clean(pim_ifp);
141 }
142 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
143
144 ifp->info = pim_ifp;
145
146 pim_sock_reset(ifp);
147
148 zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
149
150 if (PIM_MROUTE_IS_ENABLED) {
151 pim_if_add_vif(ifp);
152 }
153
154 return pim_ifp;
155}
156
157void pim_if_delete(struct interface *ifp)
158{
159 struct pim_interface *pim_ifp;
160
161 zassert(ifp);
162 pim_ifp = ifp->info;
163 zassert(pim_ifp);
164
165 if (pim_ifp->igmp_join_list) {
166 pim_if_igmp_join_del_all(ifp);
167 }
168 zassert(!pim_ifp->igmp_join_list);
169
170 zassert(pim_ifp->igmp_socket_list);
171 zassert(!listcount(pim_ifp->igmp_socket_list));
172
173 zassert(pim_ifp->pim_neighbor_list);
174 zassert(!listcount(pim_ifp->pim_neighbor_list));
175
176 zassert(pim_ifp->pim_ifchannel_list);
177 zassert(!listcount(pim_ifp->pim_ifchannel_list));
178
179 if (PIM_MROUTE_IS_ENABLED) {
180 pim_if_del_vif(ifp);
181 }
182
183 list_delete(pim_ifp->igmp_socket_list);
184 list_delete(pim_ifp->pim_neighbor_list);
185 list_delete(pim_ifp->pim_ifchannel_list);
186
187 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
188
189 ifp->info = 0;
190}
191
192void pim_if_update_could_assert(struct interface *ifp)
193{
194 struct pim_interface *pim_ifp;
195 struct listnode *node;
196 struct listnode *next_node;
197 struct pim_ifchannel *ch;
198
199 pim_ifp = ifp->info;
200 zassert(pim_ifp);
201
202 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
203 pim_ifchannel_update_could_assert(ch);
204 }
205}
206
207static void pim_if_update_my_assert_metric(struct interface *ifp)
208{
209 struct pim_interface *pim_ifp;
210 struct listnode *node;
211 struct listnode *next_node;
212 struct pim_ifchannel *ch;
213
214 pim_ifp = ifp->info;
215 zassert(pim_ifp);
216
217 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
218 pim_ifchannel_update_my_assert_metric(ch);
219 }
220}
221
222static void pim_addr_change(struct interface *ifp)
223{
224 struct pim_interface *pim_ifp;
225
226 pim_ifp = ifp->info;
227 zassert(pim_ifp);
228
Everton Marques777fe1f2014-02-14 14:16:07 -0200229 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
Everton Marques871dbcf2009-08-11 15:43:05 -0300230 pim_if_update_join_desired(pim_ifp); /* depends on DR */
231 pim_if_update_could_assert(ifp); /* depends on DR */
232 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
233 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
234
235 /*
236 RFC 4601: 4.3.1. Sending Hello Messages
237
238 1) Before an interface goes down or changes primary IP address, a
239 Hello message with a zero HoldTime should be sent immediately
240 (with the old IP address if the IP address changed).
241 -- FIXME See CAVEAT C13
242
243 2) After an interface has changed its IP address, it MUST send a
244 Hello message with its new IP address.
245 -- DONE below
246
247 3) If an interface changes one of its secondary IP addresses, a
248 Hello message with an updated Address_List option and a non-zero
249 HoldTime should be sent immediately.
250 -- FIXME See TODO T31
251 */
252 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
253 if (pim_ifp->pim_sock_fd < 0)
254 return;
255 pim_hello_restart_now(ifp); /* send hello and restart timer */
256}
257
258static void on_primary_address_change(struct interface *ifp,
259 const char *caller,
260 struct in_addr old_addr,
261 struct in_addr new_addr)
262{
263 struct pim_interface *pim_ifp;
264
265 {
266 char old_str[100];
267 char new_str[100];
268 pim_inet4_dump("<old?>", old_addr, old_str, sizeof(old_str));
269 pim_inet4_dump("<new?>", new_addr, new_str, sizeof(new_str));
270 zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
271 __PRETTY_FUNCTION__, caller,
272 old_str, new_str, ifp->name);
273 }
274
275 pim_ifp = ifp->info;
Everton Marques8852dba2014-08-28 16:02:11 -0300276 if (!pim_ifp) {
277 return;
Everton Marques871dbcf2009-08-11 15:43:05 -0300278 }
Everton Marques8852dba2014-08-28 16:02:11 -0300279
280 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
281 return;
282 }
283
284 pim_addr_change(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300285}
286
Everton Marques8852dba2014-08-28 16:02:11 -0300287static int detect_primary_address_change(struct interface *ifp,
288 int force_prim_as_any,
289 const char *caller)
Everton Marques871dbcf2009-08-11 15:43:05 -0300290{
291 struct pim_interface *pim_ifp;
292 struct in_addr new_prim_addr;
Everton Marques306c99e2014-07-16 15:51:37 -0300293 int changed;
Everton Marques871dbcf2009-08-11 15:43:05 -0300294
295 pim_ifp = ifp->info;
296 if (!pim_ifp)
Everton Marques8852dba2014-08-28 16:02:11 -0300297 return 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300298
Everton Marquesb2402972014-09-22 18:29:29 -0300299 if (force_prim_as_any)
300 new_prim_addr = qpim_inaddr_any;
301 else
302 new_prim_addr = pim_find_primary_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300303
Everton Marques306c99e2014-07-16 15:51:37 -0300304 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
305
Everton Marques871dbcf2009-08-11 15:43:05 -0300306 if (PIM_DEBUG_ZEBRA) {
307 char new_prim_str[100];
308 char old_prim_str[100];
309 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
310 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
Everton Marques306c99e2014-07-16 15:51:37 -0300311 zlog_debug("%s: old=%s new=%s on interface %s: %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300312 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300313 old_prim_str, new_prim_str, ifp->name,
314 changed ? "changed" : "unchanged");
Everton Marques871dbcf2009-08-11 15:43:05 -0300315 }
316
Everton Marques306c99e2014-07-16 15:51:37 -0300317 if (changed) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300318 struct in_addr old_addr = pim_ifp->primary_address;
319 pim_ifp->primary_address = new_prim_addr;
320
321 on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
322 }
Everton Marques8852dba2014-08-28 16:02:11 -0300323
324 return changed;
325}
326
327static void detect_secondary_address_change(struct interface *ifp,
328 const char *caller)
329{
330 struct pim_interface *pim_ifp;
331 int changed;
332
333 pim_ifp = ifp->info;
334 if (!pim_ifp)
335 return;
336
337 changed = 1; /* true */
338 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
339 __PRETTY_FUNCTION__, ifp->name);
340
341 if (PIM_DEBUG_ZEBRA) {
342 zlog_debug("%s: on interface %s: %s",
343 __PRETTY_FUNCTION__,
344 ifp->name, changed ? "changed" : "unchanged");
345 }
346
347 if (!changed) {
348 return;
349 }
350
351 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
352 return;
353 }
354
355 pim_addr_change(ifp);
356}
357
358static void detect_address_change(struct interface *ifp,
359 int force_prim_as_any,
360 const char *caller)
361{
362 int prim_changed;
363
364 prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
365 if (prim_changed) {
366 /* no need to detect secondary change because
367 the reaction would be the same */
368 return;
369 }
370
371 detect_secondary_address_change(ifp, caller);
Everton Marques871dbcf2009-08-11 15:43:05 -0300372}
373
374void pim_if_addr_add(struct connected *ifc)
375{
376 struct pim_interface *pim_ifp;
377 struct interface *ifp;
378 struct in_addr ifaddr;
379
380 zassert(ifc);
381
382 ifp = ifc->ifp;
383 zassert(ifp);
384 pim_ifp = ifp->info;
385 if (!pim_ifp)
386 return;
387
388 if (!if_is_operative(ifp))
389 return;
390
Everton Marques306c99e2014-07-16 15:51:37 -0300391 if (PIM_DEBUG_ZEBRA) {
392 char buf[BUFSIZ];
393 prefix2str(ifc->address, buf, BUFSIZ);
394 zlog_debug("%s: %s connected IP address %s %s",
395 __PRETTY_FUNCTION__,
396 ifp->name, buf,
397 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
398 "secondary" : "primary");
399 }
400
Everton Marques871dbcf2009-08-11 15:43:05 -0300401 ifaddr = ifc->address->u.prefix4;
402
Everton Marques8852dba2014-08-28 16:02:11 -0300403 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300404
405 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
406 struct igmp_sock *igmp;
407
408 /* lookup IGMP socket */
409 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
410 ifaddr);
411 if (!igmp) {
412 /* if addr new, add IGMP socket */
413 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
414 }
415 } /* igmp */
416
417 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
418
419 /* Interface has a valid primary address ? */
420 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
421
422 /* Interface has a valid socket ? */
423 if (pim_ifp->pim_sock_fd < 0) {
424 if (pim_sock_add(ifp)) {
425 zlog_warn("Failure creating PIM socket for interface %s",
426 ifp->name);
427 }
428 }
429
430 }
431 } /* pim */
432
433 if (PIM_MROUTE_IS_ENABLED) {
434 /*
435 PIM or IGMP is enabled on interface, and there is at least one
436 address assigned, then try to create a vif_index.
437 */
438 if (pim_ifp->mroute_vif_index < 0) {
439 pim_if_add_vif(ifp);
440 }
441 }
442}
443
444static void pim_if_addr_del_igmp(struct connected *ifc)
445{
446 struct pim_interface *pim_ifp = ifc->ifp->info;
447 struct igmp_sock *igmp;
448 struct in_addr ifaddr;
449
450 if (ifc->address->family != AF_INET) {
451 /* non-IPv4 address */
452 return;
453 }
454
455 if (!pim_ifp) {
456 /* IGMP not enabled on interface */
457 return;
458 }
459
460 ifaddr = ifc->address->u.prefix4;
461
462 /* lookup IGMP socket */
463 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
464 ifaddr);
465 if (igmp) {
466 /* if addr found, del IGMP socket */
467 igmp_sock_delete(igmp);
468 }
469}
470
471static void pim_if_addr_del_pim(struct connected *ifc)
472{
473 struct pim_interface *pim_ifp = ifc->ifp->info;
474
475 if (ifc->address->family != AF_INET) {
476 /* non-IPv4 address */
477 return;
478 }
479
480 if (!pim_ifp) {
481 /* PIM not enabled on interface */
482 return;
483 }
484
485 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
486 /* Interface keeps a valid primary address */
487 return;
488 }
489
490 if (pim_ifp->pim_sock_fd < 0) {
491 /* Interface does not hold a valid socket any longer */
492 return;
493 }
494
495 /*
496 pim_sock_delete() closes the socket, stops read and timer threads,
497 and kills all neighbors.
498 */
499 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
500}
501
Everton Marquesb2402972014-09-22 18:29:29 -0300502void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
Everton Marques871dbcf2009-08-11 15:43:05 -0300503{
504 struct interface *ifp;
505
506 zassert(ifc);
507 ifp = ifc->ifp;
508 zassert(ifp);
509
Everton Marques306c99e2014-07-16 15:51:37 -0300510 if (PIM_DEBUG_ZEBRA) {
511 char buf[BUFSIZ];
512 prefix2str(ifc->address, buf, BUFSIZ);
513 zlog_debug("%s: %s disconnected IP address %s %s",
514 __PRETTY_FUNCTION__,
515 ifp->name, buf,
516 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
517 "secondary" : "primary");
518 }
519
Everton Marques8852dba2014-08-28 16:02:11 -0300520 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300521
522 pim_if_addr_del_igmp(ifc);
523 pim_if_addr_del_pim(ifc);
524}
525
526void pim_if_addr_add_all(struct interface *ifp)
527{
528 struct connected *ifc;
529 struct listnode *node;
530 struct listnode *nextnode;
531
532 /* PIM/IGMP enabled ? */
533 if (!ifp->info)
534 return;
535
536 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
537 struct prefix *p = ifc->address;
538
539 if (p->family != AF_INET)
540 continue;
541
542 pim_if_addr_add(ifc);
543 }
544}
545
546void pim_if_addr_del_all(struct interface *ifp)
547{
548 struct connected *ifc;
549 struct listnode *node;
550 struct listnode *nextnode;
551
552 /* PIM/IGMP enabled ? */
553 if (!ifp->info)
554 return;
555
556 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
557 struct prefix *p = ifc->address;
558
559 if (p->family != AF_INET)
560 continue;
561
Everton Marquesb2402972014-09-22 18:29:29 -0300562 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
Everton Marques871dbcf2009-08-11 15:43:05 -0300563 }
564}
565
566void pim_if_addr_del_all_igmp(struct interface *ifp)
567{
568 struct connected *ifc;
569 struct listnode *node;
570 struct listnode *nextnode;
571
572 /* PIM/IGMP enabled ? */
573 if (!ifp->info)
574 return;
575
576 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
577 struct prefix *p = ifc->address;
578
579 if (p->family != AF_INET)
580 continue;
581
582 pim_if_addr_del_igmp(ifc);
583 }
584}
585
586void pim_if_addr_del_all_pim(struct interface *ifp)
587{
588 struct connected *ifc;
589 struct listnode *node;
590 struct listnode *nextnode;
591
592 /* PIM/IGMP enabled ? */
593 if (!ifp->info)
594 return;
595
596 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
597 struct prefix *p = ifc->address;
598
599 if (p->family != AF_INET)
600 continue;
601
602 pim_if_addr_del_pim(ifc);
603 }
604}
605
Everton Marques306c99e2014-07-16 15:51:37 -0300606static struct in_addr find_first_nonsec_addr(struct interface *ifp)
Everton Marques871dbcf2009-08-11 15:43:05 -0300607{
608 struct connected *ifc;
609 struct listnode *node;
610 struct in_addr addr;
611
612 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
613 struct prefix *p = ifc->address;
614
615 if (p->family != AF_INET)
616 continue;
617
618 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
619 zlog_warn("%s: null IPv4 address connected to interface %s",
620 __PRETTY_FUNCTION__, ifp->name);
621 continue;
622 }
623
Everton Marques075ac8d2014-09-24 15:18:37 -0300624 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
Everton Marques306c99e2014-07-16 15:51:37 -0300625 continue;
626
Everton Marques871dbcf2009-08-11 15:43:05 -0300627 return p->u.prefix4;
628 }
629
630 addr.s_addr = PIM_NET_INADDR_ANY;
631
632 return addr;
633}
634
635struct in_addr pim_find_primary_addr(struct interface *ifp)
636{
Everton Marques306c99e2014-07-16 15:51:37 -0300637 return find_first_nonsec_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300638}
639
640/*
641 pim_if_add_vif() uses ifindex as vif_index
642
643 see also pim_if_find_vifindex_by_ifindex()
644 */
645int pim_if_add_vif(struct interface *ifp)
646{
647 struct pim_interface *pim_ifp = ifp->info;
648 struct in_addr ifaddr;
649
650 zassert(pim_ifp);
651
652 if (pim_ifp->mroute_vif_index > 0) {
653 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
654 __PRETTY_FUNCTION__,
655 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
656 return -1;
657 }
658
659 if (ifp->ifindex < 1) {
660 zlog_warn("%s: ifindex=%d < 1 on interface %s",
661 __PRETTY_FUNCTION__,
662 ifp->ifindex, ifp->name);
663 return -2;
664 }
665
666 if (ifp->ifindex >= MAXVIFS) {
667 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
668 __PRETTY_FUNCTION__,
669 ifp->ifindex, MAXVIFS, ifp->name);
670 return -3;
671 }
672
673 ifaddr = pim_ifp->primary_address;
674 if (PIM_INADDR_IS_ANY(ifaddr)) {
675 zlog_warn("%s: could not get address for interface %s ifindex=%d",
676 __PRETTY_FUNCTION__,
677 ifp->name, ifp->ifindex);
678 return -4;
679 }
680
681 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
682 /* pim_mroute_add_vif reported error */
683 return -5;
684 }
685
686 pim_ifp->mroute_vif_index = ifp->ifindex;
687
688 /*
689 Update highest vif_index
690 */
691 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
692 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
693 }
694
695 return 0;
696}
697
698static int iflist_find_highest_vif_index()
699{
700 struct listnode *ifnode;
701 struct interface *ifp;
702 struct pim_interface *pim_ifp;
703 int highest_vif_index = -1;
704
705 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
706 pim_ifp = ifp->info;
707 if (!pim_ifp)
708 continue;
709
710 if (pim_ifp->mroute_vif_index > highest_vif_index) {
711 highest_vif_index = pim_ifp->mroute_vif_index;
712 }
713 }
714
715 return highest_vif_index;
716}
717
718int pim_if_del_vif(struct interface *ifp)
719{
720 struct pim_interface *pim_ifp = ifp->info;
721 int old_vif_index;
722
723 if (pim_ifp->mroute_vif_index < 1) {
724 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
725 __PRETTY_FUNCTION__,
726 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
727 return -1;
728 }
729
730 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
731 /* pim_mroute_del_vif reported error */
732 return -2;
733 }
734
735 /*
736 Update highest vif_index
737 */
738
739 /* save old vif_index in order to compare with highest below */
740 old_vif_index = pim_ifp->mroute_vif_index;
741
742 pim_ifp->mroute_vif_index = -1;
743
744 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
745 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
746 }
747
748 return 0;
749}
750
751void pim_if_add_vif_all()
752{
753 struct listnode *ifnode;
754 struct listnode *ifnextnode;
755 struct interface *ifp;
756
757 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
758 if (!ifp->info)
759 continue;
760
761 pim_if_add_vif(ifp);
762 }
763}
764
765void pim_if_del_vif_all()
766{
767 struct listnode *ifnode;
768 struct listnode *ifnextnode;
769 struct interface *ifp;
770
771 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
772 if (!ifp->info)
773 continue;
774
775 pim_if_del_vif(ifp);
776 }
777}
778
779struct interface *pim_if_find_by_vif_index(int vif_index)
780{
781 struct listnode *ifnode;
782 struct interface *ifp;
783
784 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
785 if (ifp->info) {
786 struct pim_interface *pim_ifp;
787 pim_ifp = ifp->info;
788 if (vif_index == pim_ifp->mroute_vif_index)
789 return ifp;
790 }
791 }
792
793 return 0;
794}
795
796/*
797 pim_if_add_vif() uses ifindex as vif_index
798 */
799int pim_if_find_vifindex_by_ifindex(int ifindex)
800{
801 return ifindex;
802}
803
804int pim_if_lan_delay_enabled(struct interface *ifp)
805{
806 struct pim_interface *pim_ifp;
807
808 pim_ifp = ifp->info;
809 zassert(pim_ifp);
810 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
811
812 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
813}
814
815uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
816{
817 if (pim_if_lan_delay_enabled(ifp)) {
818 struct pim_interface *pim_ifp;
819 pim_ifp = ifp->info;
820 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
821 }
822 else {
823 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
824 }
825}
826
827uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
828{
829 if (pim_if_lan_delay_enabled(ifp)) {
830 struct pim_interface *pim_ifp;
831 pim_ifp = ifp->info;
832 return pim_ifp->pim_neighbors_highest_override_interval_msec;
833 }
834 else {
835 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
836 }
837}
838
839int pim_if_t_override_msec(struct interface *ifp)
840{
841 int effective_override_interval_msec;
842 int t_override_msec;
843
844 effective_override_interval_msec =
845 pim_if_effective_override_interval_msec(ifp);
846
847 t_override_msec = pim_rand_next(0, effective_override_interval_msec);
848
849 return t_override_msec;
850}
851
852uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
853{
854 return pim_if_effective_propagation_delay_msec(ifp) +
855 pim_if_effective_override_interval_msec(ifp);
856}
857
858/*
859 RFC 4601: 4.1.6. State Summarization Macros
860
861 The function NBR( I, A ) uses information gathered through PIM Hello
862 messages to map the IP address A of a directly connected PIM
863 neighbor router on interface I to the primary IP address of the same
864 router (Section 4.3.4). The primary IP address of a neighbor is the
865 address that it uses as the source of its PIM Hello messages.
866*/
867struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
868 struct in_addr addr)
869{
870 struct listnode *neighnode;
871 struct pim_neighbor *neigh;
872 struct pim_interface *pim_ifp;
873
874 zassert(ifp);
875
876 pim_ifp = ifp->info;
877 if (!pim_ifp) {
878 zlog_warn("%s: multicast not enabled on interface %s",
879 __PRETTY_FUNCTION__,
880 ifp->name);
881 return 0;
882 }
883
884 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
885
886 /* primary address ? */
887 if (neigh->source_addr.s_addr == addr.s_addr)
888 return neigh;
889
890 /* secondary address ? */
891 if (pim_neighbor_find_secondary(neigh, addr))
892 return neigh;
893 }
894
895 if (PIM_DEBUG_PIM_TRACE) {
896 char addr_str[100];
897 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
898 zlog_debug("%s: neighbor not found for address %s on interface %s",
899 __PRETTY_FUNCTION__,
900 addr_str, ifp->name);
901 }
902
903 return 0;
904}
905
906long pim_if_t_suppressed_msec(struct interface *ifp)
907{
908 struct pim_interface *pim_ifp;
909 long t_suppressed_msec;
910
911 pim_ifp = ifp->info;
912 zassert(pim_ifp);
913
914 /* join suppression disabled ? */
915 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
916 return 0;
917
918 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
919
920 t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400);
921
922 return t_suppressed_msec;
923}
924
925static void igmp_join_free(struct igmp_join *ij)
926{
927 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
928}
929
930static struct igmp_join *igmp_join_find(struct list *join_list,
931 struct in_addr group_addr,
932 struct in_addr source_addr)
933{
934 struct listnode *node;
935 struct igmp_join *ij;
936
937 zassert(join_list);
938
939 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
940 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
941 (source_addr.s_addr == ij->source_addr.s_addr))
942 return ij;
943 }
944
945 return 0;
946}
947
948static int igmp_join_sock(const char *ifname,
949 int ifindex,
950 struct in_addr group_addr,
951 struct in_addr source_addr)
952{
953 int join_fd;
954
955 join_fd = pim_socket_raw(IPPROTO_IGMP);
956 if (join_fd < 0) {
957 return -1;
958 }
959
960 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
961 close(join_fd);
962 return -2;
963 }
964
965 return join_fd;
966}
967
968static struct igmp_join *igmp_join_new(struct interface *ifp,
969 struct in_addr group_addr,
970 struct in_addr source_addr)
971{
972 struct pim_interface *pim_ifp;
973 struct igmp_join *ij;
974 int join_fd;
975
976 pim_ifp = ifp->info;
977 zassert(pim_ifp);
978
979 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
980 if (join_fd < 0) {
981 char group_str[100];
982 char source_str[100];
983 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
984 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
985 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
986 __PRETTY_FUNCTION__,
987 group_str, source_str, ifp->name);
988 return 0;
989 }
990
991 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
992 if (!ij) {
993 char group_str[100];
994 char source_str[100];
995 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
996 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
David Lamparter5c697982012-02-16 04:47:56 +0100997 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300998 __PRETTY_FUNCTION__,
999 sizeof(*ij), group_str, source_str, ifp->name);
1000 close(join_fd);
1001 return 0;
1002 }
1003
Everton Marques567f9272010-02-19 19:07:00 -02001004 ij->sock_fd = join_fd;
1005 ij->group_addr = group_addr;
1006 ij->source_addr = source_addr;
1007 ij->sock_creation = pim_time_monotonic_sec();
Everton Marques871dbcf2009-08-11 15:43:05 -03001008
1009 listnode_add(pim_ifp->igmp_join_list, ij);
1010
1011 return ij;
1012}
1013
1014int pim_if_igmp_join_add(struct interface *ifp,
1015 struct in_addr group_addr,
1016 struct in_addr source_addr)
1017{
1018 struct pim_interface *pim_ifp;
1019 struct igmp_join *ij;
1020
1021 pim_ifp = ifp->info;
1022 if (!pim_ifp) {
1023 zlog_warn("%s: multicast not enabled on interface %s",
1024 __PRETTY_FUNCTION__,
1025 ifp->name);
1026 return -1;
1027 }
1028
1029 if (!pim_ifp->igmp_join_list) {
1030 pim_ifp->igmp_join_list = list_new();
1031 if (!pim_ifp->igmp_join_list) {
1032 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1033 __FILE__, __PRETTY_FUNCTION__);
1034 return -2;
1035 }
1036 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1037 }
1038
1039 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1040 if (ij) {
1041 char group_str[100];
1042 char source_str[100];
1043 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1044 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1045 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1046 __PRETTY_FUNCTION__,
1047 group_str, source_str, ifp->name);
1048 return -3;
1049 }
1050
1051 ij = igmp_join_new(ifp, group_addr, source_addr);
1052 if (!ij) {
1053 char group_str[100];
1054 char source_str[100];
1055 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1056 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1057 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1058 __PRETTY_FUNCTION__,
1059 group_str, source_str, ifp->name);
1060 return -4;
1061 }
1062
Everton Marques567f9272010-02-19 19:07:00 -02001063 {
1064 char group_str[100];
1065 char source_str[100];
1066 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1067 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
Everton Marques9986fb32010-02-22 09:09:09 -03001068 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1069 __PRETTY_FUNCTION__,
1070 source_str, group_str, ifp->name);
Everton Marques567f9272010-02-19 19:07:00 -02001071 }
1072
Everton Marques871dbcf2009-08-11 15:43:05 -03001073 return 0;
1074}
1075
1076
1077
1078int pim_if_igmp_join_del(struct interface *ifp,
1079 struct in_addr group_addr,
1080 struct in_addr source_addr)
1081{
1082 struct pim_interface *pim_ifp;
1083 struct igmp_join *ij;
1084
1085 pim_ifp = ifp->info;
1086 if (!pim_ifp) {
1087 zlog_warn("%s: multicast not enabled on interface %s",
1088 __PRETTY_FUNCTION__,
1089 ifp->name);
1090 return -1;
1091 }
1092
1093 if (!pim_ifp->igmp_join_list) {
1094 zlog_warn("%s: no IGMP join on interface %s",
1095 __PRETTY_FUNCTION__,
1096 ifp->name);
1097 return -2;
1098 }
1099
1100 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1101 if (!ij) {
1102 char group_str[100];
1103 char source_str[100];
1104 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1105 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1106 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1107 __PRETTY_FUNCTION__,
1108 group_str, source_str, ifp->name);
1109 return -3;
1110 }
1111
1112 if (close(ij->sock_fd)) {
1113 int e = errno;
1114 char group_str[100];
1115 char source_str[100];
1116 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1117 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1118 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1119 __PRETTY_FUNCTION__,
Everton Marquese96f0af2009-08-11 15:48:02 -03001120 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -03001121 /* warning only */
1122 }
1123 listnode_delete(pim_ifp->igmp_join_list, ij);
1124 igmp_join_free(ij);
1125 if (listcount(pim_ifp->igmp_join_list) < 1) {
1126 list_delete(pim_ifp->igmp_join_list);
1127 pim_ifp->igmp_join_list = 0;
1128 }
1129
1130 return 0;
1131}
1132
1133static void pim_if_igmp_join_del_all(struct interface *ifp)
1134{
1135 struct pim_interface *pim_ifp;
1136 struct listnode *node;
1137 struct listnode *nextnode;
1138 struct igmp_join *ij;
1139
1140 pim_ifp = ifp->info;
1141 if (!pim_ifp) {
1142 zlog_warn("%s: multicast not enabled on interface %s",
1143 __PRETTY_FUNCTION__,
1144 ifp->name);
1145 return;
1146 }
1147
1148 if (!pim_ifp->igmp_join_list)
1149 return;
1150
1151 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1152 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1153}
1154
1155/*
1156 RFC 4601
1157
1158 Transitions from "I am Assert Loser" State
1159
1160 Current Winner's GenID Changes or NLT Expires
1161
1162 The Neighbor Liveness Timer associated with the current winner
1163 expires or we receive a Hello message from the current winner
1164 reporting a different GenID from the one it previously reported.
1165 This indicates that the current winner's interface or router has
1166 gone down (and may have come back up), and so we must assume it no
1167 longer knows it was the winner.
1168 */
1169void pim_if_assert_on_neighbor_down(struct interface *ifp,
1170 struct in_addr neigh_addr)
1171{
1172 struct pim_interface *pim_ifp;
1173 struct listnode *node;
1174 struct listnode *next_node;
1175 struct pim_ifchannel *ch;
1176
1177 pim_ifp = ifp->info;
1178 zassert(pim_ifp);
1179
1180 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1181 /* Is (S,G,I) assert loser ? */
1182 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1183 continue;
1184 /* Dead neighbor was winner ? */
1185 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1186 continue;
1187
1188 assert_action_a5(ch);
1189 }
1190}
1191
1192void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1193{
1194 struct listnode *ch_node;
1195 struct pim_ifchannel *ch;
1196
1197 /* clear off flag from interface's upstreams */
1198 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1199 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1200 }
1201
1202 /* scan per-interface (S,G,I) state on this I interface */
1203 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1204 struct pim_upstream *up = ch->upstream;
1205
1206 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1207 continue;
1208
1209 /* update join_desired for the global (S,G) state */
1210 pim_upstream_update_join_desired(up);
1211 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1212 }
1213}
1214
1215void pim_if_update_assert_tracking_desired(struct interface *ifp)
1216{
1217 struct pim_interface *pim_ifp;
1218 struct listnode *node;
1219 struct listnode *next_node;
1220 struct pim_ifchannel *ch;
1221
1222 pim_ifp = ifp->info;
1223 if (!pim_ifp)
1224 return;
1225
1226 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1227 pim_ifchannel_update_assert_tracking_desired(ch);
1228 }
1229}