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