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