blob: 8ceecf853fd030fc44dd9980dfe8fbbfe8b7dcff [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;
276
277 if (pim_ifp) {
278 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
279 pim_addr_change(ifp);
280 }
281 }
282}
283
284static void detect_primary_address_change(struct interface *ifp,
285 const char *caller)
286{
287 struct pim_interface *pim_ifp;
288 struct in_addr new_prim_addr;
Everton Marques306c99e2014-07-16 15:51:37 -0300289 int changed;
Everton Marques871dbcf2009-08-11 15:43:05 -0300290
291 pim_ifp = ifp->info;
292 if (!pim_ifp)
293 return;
294
295 new_prim_addr = pim_find_primary_addr(ifp);
296
Everton Marques306c99e2014-07-16 15:51:37 -0300297 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
298
Everton Marques871dbcf2009-08-11 15:43:05 -0300299 if (PIM_DEBUG_ZEBRA) {
300 char new_prim_str[100];
301 char old_prim_str[100];
302 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
303 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
Everton Marques306c99e2014-07-16 15:51:37 -0300304 zlog_debug("%s: old=%s new=%s on interface %s: %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300305 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300306 old_prim_str, new_prim_str, ifp->name,
307 changed ? "changed" : "unchanged");
Everton Marques871dbcf2009-08-11 15:43:05 -0300308 }
309
Everton Marques306c99e2014-07-16 15:51:37 -0300310 if (changed) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300311 struct in_addr old_addr = pim_ifp->primary_address;
312 pim_ifp->primary_address = new_prim_addr;
313
314 on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
315 }
316}
317
318void pim_if_addr_add(struct connected *ifc)
319{
320 struct pim_interface *pim_ifp;
321 struct interface *ifp;
322 struct in_addr ifaddr;
323
324 zassert(ifc);
325
326 ifp = ifc->ifp;
327 zassert(ifp);
328 pim_ifp = ifp->info;
329 if (!pim_ifp)
330 return;
331
332 if (!if_is_operative(ifp))
333 return;
334
Everton Marques306c99e2014-07-16 15:51:37 -0300335 if (PIM_DEBUG_ZEBRA) {
336 char buf[BUFSIZ];
337 prefix2str(ifc->address, buf, BUFSIZ);
338 zlog_debug("%s: %s connected IP address %s %s",
339 __PRETTY_FUNCTION__,
340 ifp->name, buf,
341 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
342 "secondary" : "primary");
343 }
344
Everton Marques871dbcf2009-08-11 15:43:05 -0300345 ifaddr = ifc->address->u.prefix4;
346
347 detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
348
349 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
350 struct igmp_sock *igmp;
351
352 /* lookup IGMP socket */
353 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
354 ifaddr);
355 if (!igmp) {
356 /* if addr new, add IGMP socket */
357 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
358 }
359 } /* igmp */
360
361 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
362
363 /* Interface has a valid primary address ? */
364 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
365
366 /* Interface has a valid socket ? */
367 if (pim_ifp->pim_sock_fd < 0) {
368 if (pim_sock_add(ifp)) {
369 zlog_warn("Failure creating PIM socket for interface %s",
370 ifp->name);
371 }
372 }
373
374 }
375 } /* pim */
376
377 if (PIM_MROUTE_IS_ENABLED) {
378 /*
379 PIM or IGMP is enabled on interface, and there is at least one
380 address assigned, then try to create a vif_index.
381 */
382 if (pim_ifp->mroute_vif_index < 0) {
383 pim_if_add_vif(ifp);
384 }
385 }
386}
387
388static void pim_if_addr_del_igmp(struct connected *ifc)
389{
390 struct pim_interface *pim_ifp = ifc->ifp->info;
391 struct igmp_sock *igmp;
392 struct in_addr ifaddr;
393
394 if (ifc->address->family != AF_INET) {
395 /* non-IPv4 address */
396 return;
397 }
398
399 if (!pim_ifp) {
400 /* IGMP not enabled on interface */
401 return;
402 }
403
404 ifaddr = ifc->address->u.prefix4;
405
406 /* lookup IGMP socket */
407 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
408 ifaddr);
409 if (igmp) {
410 /* if addr found, del IGMP socket */
411 igmp_sock_delete(igmp);
412 }
413}
414
415static void pim_if_addr_del_pim(struct connected *ifc)
416{
417 struct pim_interface *pim_ifp = ifc->ifp->info;
418
419 if (ifc->address->family != AF_INET) {
420 /* non-IPv4 address */
421 return;
422 }
423
424 if (!pim_ifp) {
425 /* PIM not enabled on interface */
426 return;
427 }
428
429 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
430 /* Interface keeps a valid primary address */
431 return;
432 }
433
434 if (pim_ifp->pim_sock_fd < 0) {
435 /* Interface does not hold a valid socket any longer */
436 return;
437 }
438
439 /*
440 pim_sock_delete() closes the socket, stops read and timer threads,
441 and kills all neighbors.
442 */
443 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
444}
445
446void pim_if_addr_del(struct connected *ifc)
447{
448 struct interface *ifp;
449
450 zassert(ifc);
451 ifp = ifc->ifp;
452 zassert(ifp);
453
Everton Marques306c99e2014-07-16 15:51:37 -0300454 if (PIM_DEBUG_ZEBRA) {
455 char buf[BUFSIZ];
456 prefix2str(ifc->address, buf, BUFSIZ);
457 zlog_debug("%s: %s disconnected IP address %s %s",
458 __PRETTY_FUNCTION__,
459 ifp->name, buf,
460 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
461 "secondary" : "primary");
462 }
463
Everton Marques871dbcf2009-08-11 15:43:05 -0300464 detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
465
466 pim_if_addr_del_igmp(ifc);
467 pim_if_addr_del_pim(ifc);
468}
469
470void pim_if_addr_add_all(struct interface *ifp)
471{
472 struct connected *ifc;
473 struct listnode *node;
474 struct listnode *nextnode;
475
476 /* PIM/IGMP enabled ? */
477 if (!ifp->info)
478 return;
479
480 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
481 struct prefix *p = ifc->address;
482
483 if (p->family != AF_INET)
484 continue;
485
486 pim_if_addr_add(ifc);
487 }
488}
489
490void pim_if_addr_del_all(struct interface *ifp)
491{
492 struct connected *ifc;
493 struct listnode *node;
494 struct listnode *nextnode;
495
496 /* PIM/IGMP enabled ? */
497 if (!ifp->info)
498 return;
499
500 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
501 struct prefix *p = ifc->address;
502
503 if (p->family != AF_INET)
504 continue;
505
506 pim_if_addr_del(ifc);
507 }
508}
509
510void pim_if_addr_del_all_igmp(struct interface *ifp)
511{
512 struct connected *ifc;
513 struct listnode *node;
514 struct listnode *nextnode;
515
516 /* PIM/IGMP enabled ? */
517 if (!ifp->info)
518 return;
519
520 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
521 struct prefix *p = ifc->address;
522
523 if (p->family != AF_INET)
524 continue;
525
526 pim_if_addr_del_igmp(ifc);
527 }
528}
529
530void pim_if_addr_del_all_pim(struct interface *ifp)
531{
532 struct connected *ifc;
533 struct listnode *node;
534 struct listnode *nextnode;
535
536 /* PIM/IGMP enabled ? */
537 if (!ifp->info)
538 return;
539
540 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
541 struct prefix *p = ifc->address;
542
543 if (p->family != AF_INET)
544 continue;
545
546 pim_if_addr_del_pim(ifc);
547 }
548}
549
Everton Marques306c99e2014-07-16 15:51:37 -0300550static struct in_addr find_first_nonsec_addr(struct interface *ifp)
Everton Marques871dbcf2009-08-11 15:43:05 -0300551{
552 struct connected *ifc;
553 struct listnode *node;
554 struct in_addr addr;
555
556 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
557 struct prefix *p = ifc->address;
558
559 if (p->family != AF_INET)
560 continue;
561
562 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
563 zlog_warn("%s: null IPv4 address connected to interface %s",
564 __PRETTY_FUNCTION__, ifp->name);
565 continue;
566 }
567
Everton Marques075ac8d2014-09-24 15:18:37 -0300568 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
Everton Marques306c99e2014-07-16 15:51:37 -0300569 continue;
570
Everton Marques871dbcf2009-08-11 15:43:05 -0300571 return p->u.prefix4;
572 }
573
574 addr.s_addr = PIM_NET_INADDR_ANY;
575
576 return addr;
577}
578
579struct in_addr pim_find_primary_addr(struct interface *ifp)
580{
Everton Marques306c99e2014-07-16 15:51:37 -0300581 return find_first_nonsec_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300582}
583
584/*
585 pim_if_add_vif() uses ifindex as vif_index
586
587 see also pim_if_find_vifindex_by_ifindex()
588 */
589int pim_if_add_vif(struct interface *ifp)
590{
591 struct pim_interface *pim_ifp = ifp->info;
592 struct in_addr ifaddr;
593
594 zassert(pim_ifp);
595
596 if (pim_ifp->mroute_vif_index > 0) {
597 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
598 __PRETTY_FUNCTION__,
599 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
600 return -1;
601 }
602
603 if (ifp->ifindex < 1) {
604 zlog_warn("%s: ifindex=%d < 1 on interface %s",
605 __PRETTY_FUNCTION__,
606 ifp->ifindex, ifp->name);
607 return -2;
608 }
609
610 if (ifp->ifindex >= MAXVIFS) {
611 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
612 __PRETTY_FUNCTION__,
613 ifp->ifindex, MAXVIFS, ifp->name);
614 return -3;
615 }
616
617 ifaddr = pim_ifp->primary_address;
618 if (PIM_INADDR_IS_ANY(ifaddr)) {
619 zlog_warn("%s: could not get address for interface %s ifindex=%d",
620 __PRETTY_FUNCTION__,
621 ifp->name, ifp->ifindex);
622 return -4;
623 }
624
625 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
626 /* pim_mroute_add_vif reported error */
627 return -5;
628 }
629
630 pim_ifp->mroute_vif_index = ifp->ifindex;
631
632 /*
633 Update highest vif_index
634 */
635 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
636 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
637 }
638
639 return 0;
640}
641
642static int iflist_find_highest_vif_index()
643{
644 struct listnode *ifnode;
645 struct interface *ifp;
646 struct pim_interface *pim_ifp;
647 int highest_vif_index = -1;
648
649 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
650 pim_ifp = ifp->info;
651 if (!pim_ifp)
652 continue;
653
654 if (pim_ifp->mroute_vif_index > highest_vif_index) {
655 highest_vif_index = pim_ifp->mroute_vif_index;
656 }
657 }
658
659 return highest_vif_index;
660}
661
662int pim_if_del_vif(struct interface *ifp)
663{
664 struct pim_interface *pim_ifp = ifp->info;
665 int old_vif_index;
666
667 if (pim_ifp->mroute_vif_index < 1) {
668 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
669 __PRETTY_FUNCTION__,
670 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
671 return -1;
672 }
673
674 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
675 /* pim_mroute_del_vif reported error */
676 return -2;
677 }
678
679 /*
680 Update highest vif_index
681 */
682
683 /* save old vif_index in order to compare with highest below */
684 old_vif_index = pim_ifp->mroute_vif_index;
685
686 pim_ifp->mroute_vif_index = -1;
687
688 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
689 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
690 }
691
692 return 0;
693}
694
695void pim_if_add_vif_all()
696{
697 struct listnode *ifnode;
698 struct listnode *ifnextnode;
699 struct interface *ifp;
700
701 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
702 if (!ifp->info)
703 continue;
704
705 pim_if_add_vif(ifp);
706 }
707}
708
709void pim_if_del_vif_all()
710{
711 struct listnode *ifnode;
712 struct listnode *ifnextnode;
713 struct interface *ifp;
714
715 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
716 if (!ifp->info)
717 continue;
718
719 pim_if_del_vif(ifp);
720 }
721}
722
723struct interface *pim_if_find_by_vif_index(int vif_index)
724{
725 struct listnode *ifnode;
726 struct interface *ifp;
727
728 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
729 if (ifp->info) {
730 struct pim_interface *pim_ifp;
731 pim_ifp = ifp->info;
732 if (vif_index == pim_ifp->mroute_vif_index)
733 return ifp;
734 }
735 }
736
737 return 0;
738}
739
740/*
741 pim_if_add_vif() uses ifindex as vif_index
742 */
743int pim_if_find_vifindex_by_ifindex(int ifindex)
744{
745 return ifindex;
746}
747
748int pim_if_lan_delay_enabled(struct interface *ifp)
749{
750 struct pim_interface *pim_ifp;
751
752 pim_ifp = ifp->info;
753 zassert(pim_ifp);
754 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
755
756 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
757}
758
759uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
760{
761 if (pim_if_lan_delay_enabled(ifp)) {
762 struct pim_interface *pim_ifp;
763 pim_ifp = ifp->info;
764 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
765 }
766 else {
767 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
768 }
769}
770
771uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
772{
773 if (pim_if_lan_delay_enabled(ifp)) {
774 struct pim_interface *pim_ifp;
775 pim_ifp = ifp->info;
776 return pim_ifp->pim_neighbors_highest_override_interval_msec;
777 }
778 else {
779 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
780 }
781}
782
783int pim_if_t_override_msec(struct interface *ifp)
784{
785 int effective_override_interval_msec;
786 int t_override_msec;
787
788 effective_override_interval_msec =
789 pim_if_effective_override_interval_msec(ifp);
790
791 t_override_msec = pim_rand_next(0, effective_override_interval_msec);
792
793 return t_override_msec;
794}
795
796uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
797{
798 return pim_if_effective_propagation_delay_msec(ifp) +
799 pim_if_effective_override_interval_msec(ifp);
800}
801
802/*
803 RFC 4601: 4.1.6. State Summarization Macros
804
805 The function NBR( I, A ) uses information gathered through PIM Hello
806 messages to map the IP address A of a directly connected PIM
807 neighbor router on interface I to the primary IP address of the same
808 router (Section 4.3.4). The primary IP address of a neighbor is the
809 address that it uses as the source of its PIM Hello messages.
810*/
811struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
812 struct in_addr addr)
813{
814 struct listnode *neighnode;
815 struct pim_neighbor *neigh;
816 struct pim_interface *pim_ifp;
817
818 zassert(ifp);
819
820 pim_ifp = ifp->info;
821 if (!pim_ifp) {
822 zlog_warn("%s: multicast not enabled on interface %s",
823 __PRETTY_FUNCTION__,
824 ifp->name);
825 return 0;
826 }
827
828 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
829
830 /* primary address ? */
831 if (neigh->source_addr.s_addr == addr.s_addr)
832 return neigh;
833
834 /* secondary address ? */
835 if (pim_neighbor_find_secondary(neigh, addr))
836 return neigh;
837 }
838
839 if (PIM_DEBUG_PIM_TRACE) {
840 char addr_str[100];
841 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
842 zlog_debug("%s: neighbor not found for address %s on interface %s",
843 __PRETTY_FUNCTION__,
844 addr_str, ifp->name);
845 }
846
847 return 0;
848}
849
850long pim_if_t_suppressed_msec(struct interface *ifp)
851{
852 struct pim_interface *pim_ifp;
853 long t_suppressed_msec;
854
855 pim_ifp = ifp->info;
856 zassert(pim_ifp);
857
858 /* join suppression disabled ? */
859 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
860 return 0;
861
862 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
863
864 t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400);
865
866 return t_suppressed_msec;
867}
868
869static void igmp_join_free(struct igmp_join *ij)
870{
871 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
872}
873
874static struct igmp_join *igmp_join_find(struct list *join_list,
875 struct in_addr group_addr,
876 struct in_addr source_addr)
877{
878 struct listnode *node;
879 struct igmp_join *ij;
880
881 zassert(join_list);
882
883 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
884 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
885 (source_addr.s_addr == ij->source_addr.s_addr))
886 return ij;
887 }
888
889 return 0;
890}
891
892static int igmp_join_sock(const char *ifname,
893 int ifindex,
894 struct in_addr group_addr,
895 struct in_addr source_addr)
896{
897 int join_fd;
898
899 join_fd = pim_socket_raw(IPPROTO_IGMP);
900 if (join_fd < 0) {
901 return -1;
902 }
903
904 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
905 close(join_fd);
906 return -2;
907 }
908
909 return join_fd;
910}
911
912static struct igmp_join *igmp_join_new(struct interface *ifp,
913 struct in_addr group_addr,
914 struct in_addr source_addr)
915{
916 struct pim_interface *pim_ifp;
917 struct igmp_join *ij;
918 int join_fd;
919
920 pim_ifp = ifp->info;
921 zassert(pim_ifp);
922
923 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
924 if (join_fd < 0) {
925 char group_str[100];
926 char source_str[100];
927 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
928 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
929 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
930 __PRETTY_FUNCTION__,
931 group_str, source_str, ifp->name);
932 return 0;
933 }
934
935 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
936 if (!ij) {
937 char group_str[100];
938 char source_str[100];
939 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
940 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
David Lamparter5c697982012-02-16 04:47:56 +0100941 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300942 __PRETTY_FUNCTION__,
943 sizeof(*ij), group_str, source_str, ifp->name);
944 close(join_fd);
945 return 0;
946 }
947
Everton Marques567f9272010-02-19 19:07:00 -0200948 ij->sock_fd = join_fd;
949 ij->group_addr = group_addr;
950 ij->source_addr = source_addr;
951 ij->sock_creation = pim_time_monotonic_sec();
Everton Marques871dbcf2009-08-11 15:43:05 -0300952
953 listnode_add(pim_ifp->igmp_join_list, ij);
954
955 return ij;
956}
957
958int pim_if_igmp_join_add(struct interface *ifp,
959 struct in_addr group_addr,
960 struct in_addr source_addr)
961{
962 struct pim_interface *pim_ifp;
963 struct igmp_join *ij;
964
965 pim_ifp = ifp->info;
966 if (!pim_ifp) {
967 zlog_warn("%s: multicast not enabled on interface %s",
968 __PRETTY_FUNCTION__,
969 ifp->name);
970 return -1;
971 }
972
973 if (!pim_ifp->igmp_join_list) {
974 pim_ifp->igmp_join_list = list_new();
975 if (!pim_ifp->igmp_join_list) {
976 zlog_err("%s %s: failure: igmp_join_list=list_new()",
977 __FILE__, __PRETTY_FUNCTION__);
978 return -2;
979 }
980 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
981 }
982
983 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
984 if (ij) {
985 char group_str[100];
986 char source_str[100];
987 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
988 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
989 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
990 __PRETTY_FUNCTION__,
991 group_str, source_str, ifp->name);
992 return -3;
993 }
994
995 ij = igmp_join_new(ifp, group_addr, source_addr);
996 if (!ij) {
997 char group_str[100];
998 char source_str[100];
999 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1000 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1001 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1002 __PRETTY_FUNCTION__,
1003 group_str, source_str, ifp->name);
1004 return -4;
1005 }
1006
Everton Marques567f9272010-02-19 19:07:00 -02001007 {
1008 char group_str[100];
1009 char source_str[100];
1010 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1011 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
Everton Marques9986fb32010-02-22 09:09:09 -03001012 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1013 __PRETTY_FUNCTION__,
1014 source_str, group_str, ifp->name);
Everton Marques567f9272010-02-19 19:07:00 -02001015 }
1016
Everton Marques871dbcf2009-08-11 15:43:05 -03001017 return 0;
1018}
1019
1020
1021
1022int pim_if_igmp_join_del(struct interface *ifp,
1023 struct in_addr group_addr,
1024 struct in_addr source_addr)
1025{
1026 struct pim_interface *pim_ifp;
1027 struct igmp_join *ij;
1028
1029 pim_ifp = ifp->info;
1030 if (!pim_ifp) {
1031 zlog_warn("%s: multicast not enabled on interface %s",
1032 __PRETTY_FUNCTION__,
1033 ifp->name);
1034 return -1;
1035 }
1036
1037 if (!pim_ifp->igmp_join_list) {
1038 zlog_warn("%s: no IGMP join on interface %s",
1039 __PRETTY_FUNCTION__,
1040 ifp->name);
1041 return -2;
1042 }
1043
1044 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1045 if (!ij) {
1046 char group_str[100];
1047 char source_str[100];
1048 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1049 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1050 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1051 __PRETTY_FUNCTION__,
1052 group_str, source_str, ifp->name);
1053 return -3;
1054 }
1055
1056 if (close(ij->sock_fd)) {
1057 int e = errno;
1058 char group_str[100];
1059 char source_str[100];
1060 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1061 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1062 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1063 __PRETTY_FUNCTION__,
Everton Marquese96f0af2009-08-11 15:48:02 -03001064 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -03001065 /* warning only */
1066 }
1067 listnode_delete(pim_ifp->igmp_join_list, ij);
1068 igmp_join_free(ij);
1069 if (listcount(pim_ifp->igmp_join_list) < 1) {
1070 list_delete(pim_ifp->igmp_join_list);
1071 pim_ifp->igmp_join_list = 0;
1072 }
1073
1074 return 0;
1075}
1076
1077static void pim_if_igmp_join_del_all(struct interface *ifp)
1078{
1079 struct pim_interface *pim_ifp;
1080 struct listnode *node;
1081 struct listnode *nextnode;
1082 struct igmp_join *ij;
1083
1084 pim_ifp = ifp->info;
1085 if (!pim_ifp) {
1086 zlog_warn("%s: multicast not enabled on interface %s",
1087 __PRETTY_FUNCTION__,
1088 ifp->name);
1089 return;
1090 }
1091
1092 if (!pim_ifp->igmp_join_list)
1093 return;
1094
1095 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1096 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1097}
1098
1099/*
1100 RFC 4601
1101
1102 Transitions from "I am Assert Loser" State
1103
1104 Current Winner's GenID Changes or NLT Expires
1105
1106 The Neighbor Liveness Timer associated with the current winner
1107 expires or we receive a Hello message from the current winner
1108 reporting a different GenID from the one it previously reported.
1109 This indicates that the current winner's interface or router has
1110 gone down (and may have come back up), and so we must assume it no
1111 longer knows it was the winner.
1112 */
1113void pim_if_assert_on_neighbor_down(struct interface *ifp,
1114 struct in_addr neigh_addr)
1115{
1116 struct pim_interface *pim_ifp;
1117 struct listnode *node;
1118 struct listnode *next_node;
1119 struct pim_ifchannel *ch;
1120
1121 pim_ifp = ifp->info;
1122 zassert(pim_ifp);
1123
1124 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1125 /* Is (S,G,I) assert loser ? */
1126 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1127 continue;
1128 /* Dead neighbor was winner ? */
1129 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1130 continue;
1131
1132 assert_action_a5(ch);
1133 }
1134}
1135
1136void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1137{
1138 struct listnode *ch_node;
1139 struct pim_ifchannel *ch;
1140
1141 /* clear off flag from interface's upstreams */
1142 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1143 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1144 }
1145
1146 /* scan per-interface (S,G,I) state on this I interface */
1147 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1148 struct pim_upstream *up = ch->upstream;
1149
1150 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1151 continue;
1152
1153 /* update join_desired for the global (S,G) state */
1154 pim_upstream_update_join_desired(up);
1155 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1156 }
1157}
1158
1159void pim_if_update_assert_tracking_desired(struct interface *ifp)
1160{
1161 struct pim_interface *pim_ifp;
1162 struct listnode *node;
1163 struct listnode *next_node;
1164 struct pim_ifchannel *ch;
1165
1166 pim_ifp = ifp->info;
1167 if (!pim_ifp)
1168 return;
1169
1170 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1171 pim_ifchannel_update_assert_tracking_desired(ch);
1172 }
1173}