blob: 930dad00bb2c948d2b2d575a5683cf7bee8157e9 [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"
Everton Marques871dbcf2009-08-11 15:43:05 -030039#include "pim_sock.h"
Everton Marques567f9272010-02-19 19:07:00 -020040#include "pim_time.h"
Everton Marques96f91ae2009-10-07 18:41:45 -030041#include "pim_ssmpingd.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030042
43static void pim_if_igmp_join_del_all(struct interface *ifp);
44
Everton Marques871dbcf2009-08-11 15:43:05 -030045static void *if_list_clean(struct pim_interface *pim_ifp)
46{
47 if (pim_ifp->igmp_join_list) {
48 list_delete(pim_ifp->igmp_join_list);
49 }
50
51 if (pim_ifp->igmp_socket_list) {
52 list_delete(pim_ifp->igmp_socket_list);
53 }
54
55 if (pim_ifp->pim_neighbor_list) {
56 list_delete(pim_ifp->pim_neighbor_list);
57 }
58
59 if (pim_ifp->pim_ifchannel_list) {
60 list_delete(pim_ifp->pim_ifchannel_list);
61 }
62
63 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
64
65 return 0;
66}
67
68struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
69{
70 struct pim_interface *pim_ifp;
71
72 zassert(ifp);
73 zassert(!ifp->info);
74
75 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
76 if (!pim_ifp) {
David Lamparter5c697982012-02-16 04:47:56 +010077 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
Everton Marques871dbcf2009-08-11 15:43:05 -030078 return 0;
79 }
80
81 pim_ifp->options = 0;
82 pim_ifp->mroute_vif_index = -1;
83
Leonard Herve236b0152009-08-11 15:51:52 -030084 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
85 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
86 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
87 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
Everton Marques871dbcf2009-08-11 15:43:05 -030088
89 /*
90 RFC 3376: 8.3. Query Response Interval
91 The number of seconds represented by the [Query Response Interval]
92 must be less than the [Query Interval].
93 */
94 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
95
96 if (pim)
97 PIM_IF_DO_PIM(pim_ifp->options);
98 if (igmp)
99 PIM_IF_DO_IGMP(pim_ifp->options);
100
101#if 0
102 /* FIXME: Should join? */
103 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
104#endif
105
106 pim_ifp->igmp_join_list = 0;
107 pim_ifp->igmp_socket_list = 0;
108 pim_ifp->pim_neighbor_list = 0;
109 pim_ifp->pim_ifchannel_list = 0;
110
111 /* list of struct igmp_sock */
112 pim_ifp->igmp_socket_list = list_new();
113 if (!pim_ifp->igmp_socket_list) {
114 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
115 __FILE__, __PRETTY_FUNCTION__);
116 return if_list_clean(pim_ifp);
117 }
118 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
119
120 /* list of struct pim_neighbor */
121 pim_ifp->pim_neighbor_list = list_new();
122 if (!pim_ifp->pim_neighbor_list) {
123 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
124 __FILE__, __PRETTY_FUNCTION__);
125 return if_list_clean(pim_ifp);
126 }
127 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
128
129 /* list of struct pim_ifchannel */
130 pim_ifp->pim_ifchannel_list = list_new();
131 if (!pim_ifp->pim_ifchannel_list) {
132 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
133 __FILE__, __PRETTY_FUNCTION__);
134 return if_list_clean(pim_ifp);
135 }
136 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
137
138 ifp->info = pim_ifp;
139
140 pim_sock_reset(ifp);
141
142 zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
143
144 if (PIM_MROUTE_IS_ENABLED) {
145 pim_if_add_vif(ifp);
146 }
147
148 return pim_ifp;
149}
150
151void pim_if_delete(struct interface *ifp)
152{
153 struct pim_interface *pim_ifp;
154
155 zassert(ifp);
156 pim_ifp = ifp->info;
157 zassert(pim_ifp);
158
159 if (pim_ifp->igmp_join_list) {
160 pim_if_igmp_join_del_all(ifp);
161 }
162 zassert(!pim_ifp->igmp_join_list);
163
164 zassert(pim_ifp->igmp_socket_list);
165 zassert(!listcount(pim_ifp->igmp_socket_list));
166
167 zassert(pim_ifp->pim_neighbor_list);
168 zassert(!listcount(pim_ifp->pim_neighbor_list));
169
170 zassert(pim_ifp->pim_ifchannel_list);
171 zassert(!listcount(pim_ifp->pim_ifchannel_list));
172
173 if (PIM_MROUTE_IS_ENABLED) {
174 pim_if_del_vif(ifp);
175 }
176
177 list_delete(pim_ifp->igmp_socket_list);
178 list_delete(pim_ifp->pim_neighbor_list);
179 list_delete(pim_ifp->pim_ifchannel_list);
180
181 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
182
183 ifp->info = 0;
184}
185
186void pim_if_update_could_assert(struct interface *ifp)
187{
188 struct pim_interface *pim_ifp;
189 struct listnode *node;
190 struct listnode *next_node;
191 struct pim_ifchannel *ch;
192
193 pim_ifp = ifp->info;
194 zassert(pim_ifp);
195
196 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
197 pim_ifchannel_update_could_assert(ch);
198 }
199}
200
201static void pim_if_update_my_assert_metric(struct interface *ifp)
202{
203 struct pim_interface *pim_ifp;
204 struct listnode *node;
205 struct listnode *next_node;
206 struct pim_ifchannel *ch;
207
208 pim_ifp = ifp->info;
209 zassert(pim_ifp);
210
211 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
212 pim_ifchannel_update_my_assert_metric(ch);
213 }
214}
215
216static void pim_addr_change(struct interface *ifp)
217{
218 struct pim_interface *pim_ifp;
219
220 pim_ifp = ifp->info;
221 zassert(pim_ifp);
222
Everton Marques777fe1f2014-02-14 14:16:07 -0200223 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
Everton Marques871dbcf2009-08-11 15:43:05 -0300224 pim_if_update_join_desired(pim_ifp); /* depends on DR */
225 pim_if_update_could_assert(ifp); /* depends on DR */
226 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
227 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
228
229 /*
230 RFC 4601: 4.3.1. Sending Hello Messages
231
232 1) Before an interface goes down or changes primary IP address, a
233 Hello message with a zero HoldTime should be sent immediately
234 (with the old IP address if the IP address changed).
235 -- FIXME See CAVEAT C13
236
237 2) After an interface has changed its IP address, it MUST send a
238 Hello message with its new IP address.
239 -- DONE below
240
241 3) If an interface changes one of its secondary IP addresses, a
242 Hello message with an updated Address_List option and a non-zero
243 HoldTime should be sent immediately.
244 -- FIXME See TODO T31
245 */
246 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
247 if (pim_ifp->pim_sock_fd < 0)
248 return;
249 pim_hello_restart_now(ifp); /* send hello and restart timer */
250}
251
Everton Marques8852dba2014-08-28 16:02:11 -0300252static int detect_primary_address_change(struct interface *ifp,
253 int force_prim_as_any,
254 const char *caller)
Everton Marques871dbcf2009-08-11 15:43:05 -0300255{
256 struct pim_interface *pim_ifp;
257 struct in_addr new_prim_addr;
Everton Marques306c99e2014-07-16 15:51:37 -0300258 int changed;
Everton Marques871dbcf2009-08-11 15:43:05 -0300259
260 pim_ifp = ifp->info;
261 if (!pim_ifp)
Everton Marques8852dba2014-08-28 16:02:11 -0300262 return 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300263
Everton Marquesb2402972014-09-22 18:29:29 -0300264 if (force_prim_as_any)
265 new_prim_addr = qpim_inaddr_any;
266 else
267 new_prim_addr = pim_find_primary_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300268
Everton Marques306c99e2014-07-16 15:51:37 -0300269 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
270
Everton Marques871dbcf2009-08-11 15:43:05 -0300271 if (PIM_DEBUG_ZEBRA) {
272 char new_prim_str[100];
273 char old_prim_str[100];
274 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
275 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
Everton Marques306c99e2014-07-16 15:51:37 -0300276 zlog_debug("%s: old=%s new=%s on interface %s: %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300277 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300278 old_prim_str, new_prim_str, ifp->name,
279 changed ? "changed" : "unchanged");
Everton Marques871dbcf2009-08-11 15:43:05 -0300280 }
281
Everton Marques306c99e2014-07-16 15:51:37 -0300282 if (changed) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300283 pim_ifp->primary_address = new_prim_addr;
284
Donald Sharpa6a11762015-10-02 12:27:27 -0400285 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
286 return changed;
287 }
288
289 pim_addr_change(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300290 }
Everton Marques8852dba2014-08-28 16:02:11 -0300291
292 return changed;
293}
294
295static void detect_secondary_address_change(struct interface *ifp,
296 const char *caller)
297{
298 struct pim_interface *pim_ifp;
299 int changed;
300
301 pim_ifp = ifp->info;
302 if (!pim_ifp)
303 return;
304
305 changed = 1; /* true */
Donald Sharpa6a11762015-10-02 12:27:27 -0400306 if (PIM_DEBUG_ZEBRA)
307 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
308 __PRETTY_FUNCTION__, ifp->name);
Everton Marques8852dba2014-08-28 16:02:11 -0300309
310 if (!changed) {
311 return;
312 }
313
314 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
315 return;
316 }
317
318 pim_addr_change(ifp);
319}
320
321static void detect_address_change(struct interface *ifp,
322 int force_prim_as_any,
323 const char *caller)
324{
325 int prim_changed;
326
327 prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
328 if (prim_changed) {
329 /* no need to detect secondary change because
330 the reaction would be the same */
331 return;
332 }
333
334 detect_secondary_address_change(ifp, caller);
Everton Marques871dbcf2009-08-11 15:43:05 -0300335}
336
337void pim_if_addr_add(struct connected *ifc)
338{
339 struct pim_interface *pim_ifp;
340 struct interface *ifp;
341 struct in_addr ifaddr;
342
343 zassert(ifc);
344
345 ifp = ifc->ifp;
346 zassert(ifp);
347 pim_ifp = ifp->info;
348 if (!pim_ifp)
349 return;
350
351 if (!if_is_operative(ifp))
352 return;
353
Donald Sharpf3734dd2015-09-30 10:22:46 -0400354 if (PIM_DEBUG_ZEBRA) {
Everton Marques306c99e2014-07-16 15:51:37 -0300355 char buf[BUFSIZ];
356 prefix2str(ifc->address, buf, BUFSIZ);
Everton Marques85385f72015-01-19 18:25:45 -0200357 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
Everton Marques306c99e2014-07-16 15:51:37 -0300358 __PRETTY_FUNCTION__,
Everton Marques85385f72015-01-19 18:25:45 -0200359 ifp->name, ifp->ifindex, buf,
Everton Marques306c99e2014-07-16 15:51:37 -0300360 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
361 "secondary" : "primary");
362 }
363
Everton Marques871dbcf2009-08-11 15:43:05 -0300364 ifaddr = ifc->address->u.prefix4;
365
Everton Marques8852dba2014-08-28 16:02:11 -0300366 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300367
368 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
369 struct igmp_sock *igmp;
370
371 /* lookup IGMP socket */
372 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
373 ifaddr);
374 if (!igmp) {
375 /* if addr new, add IGMP socket */
376 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
377 }
378 } /* igmp */
379
380 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
381
382 /* Interface has a valid primary address ? */
383 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
384
385 /* Interface has a valid socket ? */
386 if (pim_ifp->pim_sock_fd < 0) {
387 if (pim_sock_add(ifp)) {
388 zlog_warn("Failure creating PIM socket for interface %s",
389 ifp->name);
390 }
391 }
392
393 }
394 } /* pim */
395
396 if (PIM_MROUTE_IS_ENABLED) {
397 /*
398 PIM or IGMP is enabled on interface, and there is at least one
399 address assigned, then try to create a vif_index.
400 */
401 if (pim_ifp->mroute_vif_index < 0) {
402 pim_if_add_vif(ifp);
403 }
404 }
405}
406
407static void pim_if_addr_del_igmp(struct connected *ifc)
408{
409 struct pim_interface *pim_ifp = ifc->ifp->info;
410 struct igmp_sock *igmp;
411 struct in_addr ifaddr;
412
413 if (ifc->address->family != AF_INET) {
414 /* non-IPv4 address */
415 return;
416 }
417
418 if (!pim_ifp) {
419 /* IGMP not enabled on interface */
420 return;
421 }
422
423 ifaddr = ifc->address->u.prefix4;
424
425 /* lookup IGMP socket */
426 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
427 ifaddr);
428 if (igmp) {
429 /* if addr found, del IGMP socket */
430 igmp_sock_delete(igmp);
431 }
432}
433
434static void pim_if_addr_del_pim(struct connected *ifc)
435{
436 struct pim_interface *pim_ifp = ifc->ifp->info;
437
438 if (ifc->address->family != AF_INET) {
439 /* non-IPv4 address */
440 return;
441 }
442
443 if (!pim_ifp) {
444 /* PIM not enabled on interface */
445 return;
446 }
447
448 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
449 /* Interface keeps a valid primary address */
450 return;
451 }
452
453 if (pim_ifp->pim_sock_fd < 0) {
454 /* Interface does not hold a valid socket any longer */
455 return;
456 }
457
458 /*
459 pim_sock_delete() closes the socket, stops read and timer threads,
460 and kills all neighbors.
461 */
462 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
463}
464
Everton Marquesb2402972014-09-22 18:29:29 -0300465void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
Everton Marques871dbcf2009-08-11 15:43:05 -0300466{
467 struct interface *ifp;
468
469 zassert(ifc);
470 ifp = ifc->ifp;
471 zassert(ifp);
472
Donald Sharpf3734dd2015-09-30 10:22:46 -0400473 if (PIM_DEBUG_ZEBRA) {
Everton Marques306c99e2014-07-16 15:51:37 -0300474 char buf[BUFSIZ];
475 prefix2str(ifc->address, buf, BUFSIZ);
Everton Marques85385f72015-01-19 18:25:45 -0200476 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
Everton Marques306c99e2014-07-16 15:51:37 -0300477 __PRETTY_FUNCTION__,
Everton Marques85385f72015-01-19 18:25:45 -0200478 ifp->name, ifp->ifindex, buf,
Everton Marques306c99e2014-07-16 15:51:37 -0300479 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
480 "secondary" : "primary");
481 }
482
Everton Marques8852dba2014-08-28 16:02:11 -0300483 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300484
485 pim_if_addr_del_igmp(ifc);
486 pim_if_addr_del_pim(ifc);
487}
488
489void pim_if_addr_add_all(struct interface *ifp)
490{
491 struct connected *ifc;
492 struct listnode *node;
493 struct listnode *nextnode;
494
495 /* PIM/IGMP enabled ? */
496 if (!ifp->info)
497 return;
498
499 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
500 struct prefix *p = ifc->address;
501
502 if (p->family != AF_INET)
503 continue;
504
505 pim_if_addr_add(ifc);
506 }
507}
508
509void pim_if_addr_del_all(struct interface *ifp)
510{
511 struct connected *ifc;
512 struct listnode *node;
513 struct listnode *nextnode;
514
515 /* PIM/IGMP enabled ? */
516 if (!ifp->info)
517 return;
518
519 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
520 struct prefix *p = ifc->address;
521
522 if (p->family != AF_INET)
523 continue;
524
Everton Marquesb2402972014-09-22 18:29:29 -0300525 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
Everton Marques871dbcf2009-08-11 15:43:05 -0300526 }
527}
528
529void pim_if_addr_del_all_igmp(struct interface *ifp)
530{
531 struct connected *ifc;
532 struct listnode *node;
533 struct listnode *nextnode;
534
535 /* PIM/IGMP enabled ? */
536 if (!ifp->info)
537 return;
538
539 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
540 struct prefix *p = ifc->address;
541
542 if (p->family != AF_INET)
543 continue;
544
545 pim_if_addr_del_igmp(ifc);
546 }
547}
548
549void pim_if_addr_del_all_pim(struct interface *ifp)
550{
551 struct connected *ifc;
552 struct listnode *node;
553 struct listnode *nextnode;
554
555 /* PIM/IGMP enabled ? */
556 if (!ifp->info)
557 return;
558
559 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
560 struct prefix *p = ifc->address;
561
562 if (p->family != AF_INET)
563 continue;
564
565 pim_if_addr_del_pim(ifc);
566 }
567}
568
Everton Marques306c99e2014-07-16 15:51:37 -0300569static struct in_addr find_first_nonsec_addr(struct interface *ifp)
Everton Marques871dbcf2009-08-11 15:43:05 -0300570{
571 struct connected *ifc;
572 struct listnode *node;
573 struct in_addr addr;
574
575 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
576 struct prefix *p = ifc->address;
577
578 if (p->family != AF_INET)
579 continue;
580
581 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
582 zlog_warn("%s: null IPv4 address connected to interface %s",
583 __PRETTY_FUNCTION__, ifp->name);
584 continue;
585 }
586
Everton Marques075ac8d2014-09-24 15:18:37 -0300587 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
Everton Marques306c99e2014-07-16 15:51:37 -0300588 continue;
589
Everton Marques871dbcf2009-08-11 15:43:05 -0300590 return p->u.prefix4;
591 }
592
593 addr.s_addr = PIM_NET_INADDR_ANY;
594
595 return addr;
596}
597
598struct in_addr pim_find_primary_addr(struct interface *ifp)
599{
Everton Marques306c99e2014-07-16 15:51:37 -0300600 return find_first_nonsec_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300601}
602
603/*
604 pim_if_add_vif() uses ifindex as vif_index
605
606 see also pim_if_find_vifindex_by_ifindex()
607 */
608int pim_if_add_vif(struct interface *ifp)
609{
610 struct pim_interface *pim_ifp = ifp->info;
611 struct in_addr ifaddr;
612
613 zassert(pim_ifp);
614
615 if (pim_ifp->mroute_vif_index > 0) {
616 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
617 __PRETTY_FUNCTION__,
618 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
619 return -1;
620 }
621
622 if (ifp->ifindex < 1) {
623 zlog_warn("%s: ifindex=%d < 1 on interface %s",
624 __PRETTY_FUNCTION__,
625 ifp->ifindex, ifp->name);
626 return -2;
627 }
628
629 if (ifp->ifindex >= MAXVIFS) {
630 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
631 __PRETTY_FUNCTION__,
632 ifp->ifindex, MAXVIFS, ifp->name);
633 return -3;
634 }
635
636 ifaddr = pim_ifp->primary_address;
637 if (PIM_INADDR_IS_ANY(ifaddr)) {
638 zlog_warn("%s: could not get address for interface %s ifindex=%d",
639 __PRETTY_FUNCTION__,
640 ifp->name, ifp->ifindex);
641 return -4;
642 }
643
644 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
645 /* pim_mroute_add_vif reported error */
646 return -5;
647 }
648
649 pim_ifp->mroute_vif_index = ifp->ifindex;
650
651 /*
652 Update highest vif_index
653 */
654 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
655 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
656 }
657
658 return 0;
659}
660
661static int iflist_find_highest_vif_index()
662{
663 struct listnode *ifnode;
664 struct interface *ifp;
665 struct pim_interface *pim_ifp;
666 int highest_vif_index = -1;
667
668 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
669 pim_ifp = ifp->info;
670 if (!pim_ifp)
671 continue;
672
673 if (pim_ifp->mroute_vif_index > highest_vif_index) {
674 highest_vif_index = pim_ifp->mroute_vif_index;
675 }
676 }
677
678 return highest_vif_index;
679}
680
681int pim_if_del_vif(struct interface *ifp)
682{
683 struct pim_interface *pim_ifp = ifp->info;
684 int old_vif_index;
685
686 if (pim_ifp->mroute_vif_index < 1) {
687 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
688 __PRETTY_FUNCTION__,
689 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
690 return -1;
691 }
692
693 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
694 /* pim_mroute_del_vif reported error */
695 return -2;
696 }
697
698 /*
699 Update highest vif_index
700 */
701
702 /* save old vif_index in order to compare with highest below */
703 old_vif_index = pim_ifp->mroute_vif_index;
704
705 pim_ifp->mroute_vif_index = -1;
706
707 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
708 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
709 }
710
711 return 0;
712}
713
714void pim_if_add_vif_all()
715{
716 struct listnode *ifnode;
717 struct listnode *ifnextnode;
718 struct interface *ifp;
719
720 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
721 if (!ifp->info)
722 continue;
723
724 pim_if_add_vif(ifp);
725 }
726}
727
728void pim_if_del_vif_all()
729{
730 struct listnode *ifnode;
731 struct listnode *ifnextnode;
732 struct interface *ifp;
733
734 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
735 if (!ifp->info)
736 continue;
737
738 pim_if_del_vif(ifp);
739 }
740}
741
742struct interface *pim_if_find_by_vif_index(int vif_index)
743{
744 struct listnode *ifnode;
745 struct interface *ifp;
746
747 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
748 if (ifp->info) {
749 struct pim_interface *pim_ifp;
750 pim_ifp = ifp->info;
751 if (vif_index == pim_ifp->mroute_vif_index)
752 return ifp;
753 }
754 }
755
756 return 0;
757}
758
759/*
760 pim_if_add_vif() uses ifindex as vif_index
761 */
762int pim_if_find_vifindex_by_ifindex(int ifindex)
763{
764 return ifindex;
765}
766
767int pim_if_lan_delay_enabled(struct interface *ifp)
768{
769 struct pim_interface *pim_ifp;
770
771 pim_ifp = ifp->info;
772 zassert(pim_ifp);
773 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
774
775 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
776}
777
778uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
779{
780 if (pim_if_lan_delay_enabled(ifp)) {
781 struct pim_interface *pim_ifp;
782 pim_ifp = ifp->info;
783 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
784 }
785 else {
786 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
787 }
788}
789
790uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
791{
792 if (pim_if_lan_delay_enabled(ifp)) {
793 struct pim_interface *pim_ifp;
794 pim_ifp = ifp->info;
795 return pim_ifp->pim_neighbors_highest_override_interval_msec;
796 }
797 else {
798 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
799 }
800}
801
802int pim_if_t_override_msec(struct interface *ifp)
803{
804 int effective_override_interval_msec;
805 int t_override_msec;
806
807 effective_override_interval_msec =
808 pim_if_effective_override_interval_msec(ifp);
809
Donald Sharp77162682015-06-19 19:26:18 -0400810 t_override_msec = random() % (effective_override_interval_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300811
812 return t_override_msec;
813}
814
815uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
816{
817 return pim_if_effective_propagation_delay_msec(ifp) +
818 pim_if_effective_override_interval_msec(ifp);
819}
820
821/*
822 RFC 4601: 4.1.6. State Summarization Macros
823
824 The function NBR( I, A ) uses information gathered through PIM Hello
825 messages to map the IP address A of a directly connected PIM
826 neighbor router on interface I to the primary IP address of the same
827 router (Section 4.3.4). The primary IP address of a neighbor is the
828 address that it uses as the source of its PIM Hello messages.
829*/
830struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
831 struct in_addr addr)
832{
833 struct listnode *neighnode;
834 struct pim_neighbor *neigh;
835 struct pim_interface *pim_ifp;
836
837 zassert(ifp);
838
839 pim_ifp = ifp->info;
840 if (!pim_ifp) {
841 zlog_warn("%s: multicast not enabled on interface %s",
842 __PRETTY_FUNCTION__,
843 ifp->name);
844 return 0;
845 }
846
847 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
848
849 /* primary address ? */
850 if (neigh->source_addr.s_addr == addr.s_addr)
851 return neigh;
852
853 /* secondary address ? */
854 if (pim_neighbor_find_secondary(neigh, addr))
855 return neigh;
856 }
857
858 if (PIM_DEBUG_PIM_TRACE) {
859 char addr_str[100];
860 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
861 zlog_debug("%s: neighbor not found for address %s on interface %s",
862 __PRETTY_FUNCTION__,
863 addr_str, ifp->name);
864 }
865
866 return 0;
867}
868
869long pim_if_t_suppressed_msec(struct interface *ifp)
870{
871 struct pim_interface *pim_ifp;
872 long t_suppressed_msec;
Donald Sharp77162682015-06-19 19:26:18 -0400873 uint32_t ramount = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300874
875 pim_ifp = ifp->info;
876 zassert(pim_ifp);
877
878 /* join suppression disabled ? */
879 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
880 return 0;
881
882 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
Donald Sharp77162682015-06-19 19:26:18 -0400883 ramount = 1100 + (random() % (1400 - 1100 + 1));
884 t_suppressed_msec = qpim_t_periodic * ramount;
Everton Marques871dbcf2009-08-11 15:43:05 -0300885
886 return t_suppressed_msec;
887}
888
889static void igmp_join_free(struct igmp_join *ij)
890{
891 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
892}
893
894static struct igmp_join *igmp_join_find(struct list *join_list,
895 struct in_addr group_addr,
896 struct in_addr source_addr)
897{
898 struct listnode *node;
899 struct igmp_join *ij;
900
901 zassert(join_list);
902
903 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
904 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
905 (source_addr.s_addr == ij->source_addr.s_addr))
906 return ij;
907 }
908
909 return 0;
910}
911
912static int igmp_join_sock(const char *ifname,
913 int ifindex,
914 struct in_addr group_addr,
915 struct in_addr source_addr)
916{
917 int join_fd;
918
919 join_fd = pim_socket_raw(IPPROTO_IGMP);
920 if (join_fd < 0) {
921 return -1;
922 }
923
924 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
925 close(join_fd);
926 return -2;
927 }
928
929 return join_fd;
930}
931
932static struct igmp_join *igmp_join_new(struct interface *ifp,
933 struct in_addr group_addr,
934 struct in_addr source_addr)
935{
936 struct pim_interface *pim_ifp;
937 struct igmp_join *ij;
938 int join_fd;
939
940 pim_ifp = ifp->info;
941 zassert(pim_ifp);
942
943 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
944 if (join_fd < 0) {
945 char group_str[100];
946 char source_str[100];
947 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
948 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
949 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
950 __PRETTY_FUNCTION__,
951 group_str, source_str, ifp->name);
952 return 0;
953 }
954
955 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
956 if (!ij) {
957 char group_str[100];
958 char source_str[100];
959 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
960 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
David Lamparter5c697982012-02-16 04:47:56 +0100961 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300962 __PRETTY_FUNCTION__,
963 sizeof(*ij), group_str, source_str, ifp->name);
964 close(join_fd);
965 return 0;
966 }
967
Everton Marques567f9272010-02-19 19:07:00 -0200968 ij->sock_fd = join_fd;
969 ij->group_addr = group_addr;
970 ij->source_addr = source_addr;
971 ij->sock_creation = pim_time_monotonic_sec();
Everton Marques871dbcf2009-08-11 15:43:05 -0300972
973 listnode_add(pim_ifp->igmp_join_list, ij);
974
975 return ij;
976}
977
978int pim_if_igmp_join_add(struct interface *ifp,
979 struct in_addr group_addr,
980 struct in_addr source_addr)
981{
982 struct pim_interface *pim_ifp;
983 struct igmp_join *ij;
984
985 pim_ifp = ifp->info;
986 if (!pim_ifp) {
987 zlog_warn("%s: multicast not enabled on interface %s",
988 __PRETTY_FUNCTION__,
989 ifp->name);
990 return -1;
991 }
992
993 if (!pim_ifp->igmp_join_list) {
994 pim_ifp->igmp_join_list = list_new();
995 if (!pim_ifp->igmp_join_list) {
996 zlog_err("%s %s: failure: igmp_join_list=list_new()",
997 __FILE__, __PRETTY_FUNCTION__);
998 return -2;
999 }
1000 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1001 }
1002
1003 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1004 if (ij) {
1005 char group_str[100];
1006 char source_str[100];
1007 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1008 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1009 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1010 __PRETTY_FUNCTION__,
1011 group_str, source_str, ifp->name);
1012 return -3;
1013 }
1014
1015 ij = igmp_join_new(ifp, group_addr, source_addr);
1016 if (!ij) {
1017 char group_str[100];
1018 char source_str[100];
1019 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1020 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1021 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1022 __PRETTY_FUNCTION__,
1023 group_str, source_str, ifp->name);
1024 return -4;
1025 }
1026
Donald Sharpf3734dd2015-09-30 10:22:46 -04001027 if (PIM_DEBUG_IGMP_EVENTS) {
Everton Marques567f9272010-02-19 19:07:00 -02001028 char group_str[100];
1029 char source_str[100];
1030 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1031 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
Everton Marques9986fb32010-02-22 09:09:09 -03001032 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
Donald Sharpf3734dd2015-09-30 10:22:46 -04001033 __PRETTY_FUNCTION__,
1034 source_str, group_str, ifp->name);
Everton Marques567f9272010-02-19 19:07:00 -02001035 }
1036
Everton Marques871dbcf2009-08-11 15:43:05 -03001037 return 0;
1038}
1039
1040
1041
1042int pim_if_igmp_join_del(struct interface *ifp,
1043 struct in_addr group_addr,
1044 struct in_addr source_addr)
1045{
1046 struct pim_interface *pim_ifp;
1047 struct igmp_join *ij;
1048
1049 pim_ifp = ifp->info;
1050 if (!pim_ifp) {
1051 zlog_warn("%s: multicast not enabled on interface %s",
1052 __PRETTY_FUNCTION__,
1053 ifp->name);
1054 return -1;
1055 }
1056
1057 if (!pim_ifp->igmp_join_list) {
1058 zlog_warn("%s: no IGMP join on interface %s",
1059 __PRETTY_FUNCTION__,
1060 ifp->name);
1061 return -2;
1062 }
1063
1064 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1065 if (!ij) {
1066 char group_str[100];
1067 char source_str[100];
1068 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1069 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1070 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1071 __PRETTY_FUNCTION__,
1072 group_str, source_str, ifp->name);
1073 return -3;
1074 }
1075
1076 if (close(ij->sock_fd)) {
1077 int e = errno;
1078 char group_str[100];
1079 char source_str[100];
1080 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1081 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1082 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1083 __PRETTY_FUNCTION__,
Everton Marquese96f0af2009-08-11 15:48:02 -03001084 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -03001085 /* warning only */
1086 }
1087 listnode_delete(pim_ifp->igmp_join_list, ij);
1088 igmp_join_free(ij);
1089 if (listcount(pim_ifp->igmp_join_list) < 1) {
1090 list_delete(pim_ifp->igmp_join_list);
1091 pim_ifp->igmp_join_list = 0;
1092 }
1093
1094 return 0;
1095}
1096
1097static void pim_if_igmp_join_del_all(struct interface *ifp)
1098{
1099 struct pim_interface *pim_ifp;
1100 struct listnode *node;
1101 struct listnode *nextnode;
1102 struct igmp_join *ij;
1103
1104 pim_ifp = ifp->info;
1105 if (!pim_ifp) {
1106 zlog_warn("%s: multicast not enabled on interface %s",
1107 __PRETTY_FUNCTION__,
1108 ifp->name);
1109 return;
1110 }
1111
1112 if (!pim_ifp->igmp_join_list)
1113 return;
1114
1115 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1116 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1117}
1118
1119/*
1120 RFC 4601
1121
1122 Transitions from "I am Assert Loser" State
1123
1124 Current Winner's GenID Changes or NLT Expires
1125
1126 The Neighbor Liveness Timer associated with the current winner
1127 expires or we receive a Hello message from the current winner
1128 reporting a different GenID from the one it previously reported.
1129 This indicates that the current winner's interface or router has
1130 gone down (and may have come back up), and so we must assume it no
1131 longer knows it was the winner.
1132 */
1133void pim_if_assert_on_neighbor_down(struct interface *ifp,
1134 struct in_addr neigh_addr)
1135{
1136 struct pim_interface *pim_ifp;
1137 struct listnode *node;
1138 struct listnode *next_node;
1139 struct pim_ifchannel *ch;
1140
1141 pim_ifp = ifp->info;
1142 zassert(pim_ifp);
1143
1144 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1145 /* Is (S,G,I) assert loser ? */
1146 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1147 continue;
1148 /* Dead neighbor was winner ? */
1149 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1150 continue;
1151
1152 assert_action_a5(ch);
1153 }
1154}
1155
1156void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1157{
1158 struct listnode *ch_node;
1159 struct pim_ifchannel *ch;
1160
1161 /* clear off flag from interface's upstreams */
1162 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1163 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1164 }
1165
1166 /* scan per-interface (S,G,I) state on this I interface */
1167 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1168 struct pim_upstream *up = ch->upstream;
1169
1170 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1171 continue;
1172
1173 /* update join_desired for the global (S,G) state */
1174 pim_upstream_update_join_desired(up);
1175 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1176 }
1177}
1178
1179void pim_if_update_assert_tracking_desired(struct interface *ifp)
1180{
1181 struct pim_interface *pim_ifp;
1182 struct listnode *node;
1183 struct listnode *next_node;
1184 struct pim_ifchannel *ch;
1185
1186 pim_ifp = ifp->info;
1187 if (!pim_ifp)
1188 return;
1189
1190 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1191 pim_ifchannel_update_assert_tracking_desired(ch);
1192 }
1193}