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