blob: dc3e9a2bb682286ca26706919ac69b1c9aba14c8 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17 MA 02110-1301 USA
18
19 $QuaggaId: $Format:%an, %ai, %h$ $
20*/
21
22#include <zebra.h>
23
24#include "if.h"
25#include "log.h"
26#include "vty.h"
27#include "memory.h"
28#include "prefix.h"
29
30#include "pimd.h"
31#include "pim_iface.h"
32#include "pim_igmp.h"
33#include "pim_mroute.h"
34#include "pim_oil.h"
35#include "pim_str.h"
36#include "pim_pim.h"
37#include "pim_neighbor.h"
38#include "pim_ifchannel.h"
39#include "pim_rand.h"
40#include "pim_sock.h"
Everton Marques567f9272010-02-19 19:07:00 -020041#include "pim_time.h"
Everton Marques96f91ae2009-10-07 18:41:45 -030042#include "pim_ssmpingd.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030043
44static void pim_if_igmp_join_del_all(struct interface *ifp);
45
Everton Marques871dbcf2009-08-11 15:43:05 -030046static void *if_list_clean(struct pim_interface *pim_ifp)
47{
48 if (pim_ifp->igmp_join_list) {
49 list_delete(pim_ifp->igmp_join_list);
50 }
51
52 if (pim_ifp->igmp_socket_list) {
53 list_delete(pim_ifp->igmp_socket_list);
54 }
55
56 if (pim_ifp->pim_neighbor_list) {
57 list_delete(pim_ifp->pim_neighbor_list);
58 }
59
60 if (pim_ifp->pim_ifchannel_list) {
61 list_delete(pim_ifp->pim_ifchannel_list);
62 }
63
64 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
65
66 return 0;
67}
68
69struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
70{
71 struct pim_interface *pim_ifp;
72
73 zassert(ifp);
74 zassert(!ifp->info);
75
76 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
77 if (!pim_ifp) {
David Lamparter5c697982012-02-16 04:47:56 +010078 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
Everton Marques871dbcf2009-08-11 15:43:05 -030079 return 0;
80 }
81
82 pim_ifp->options = 0;
83 pim_ifp->mroute_vif_index = -1;
84
Leonard Herve236b0152009-08-11 15:51:52 -030085 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
86 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
87 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
88 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
Everton Marques871dbcf2009-08-11 15:43:05 -030089
90 /*
91 RFC 3376: 8.3. Query Response Interval
92 The number of seconds represented by the [Query Response Interval]
93 must be less than the [Query Interval].
94 */
95 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
96
97 if (pim)
98 PIM_IF_DO_PIM(pim_ifp->options);
99 if (igmp)
100 PIM_IF_DO_IGMP(pim_ifp->options);
101
102#if 0
103 /* FIXME: Should join? */
104 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
105#endif
106
107 pim_ifp->igmp_join_list = 0;
108 pim_ifp->igmp_socket_list = 0;
109 pim_ifp->pim_neighbor_list = 0;
110 pim_ifp->pim_ifchannel_list = 0;
111
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
253static void on_primary_address_change(struct interface *ifp,
254 const char *caller,
255 struct in_addr old_addr,
256 struct in_addr new_addr)
257{
258 struct pim_interface *pim_ifp;
259
260 {
261 char old_str[100];
262 char new_str[100];
263 pim_inet4_dump("<old?>", old_addr, old_str, sizeof(old_str));
264 pim_inet4_dump("<new?>", new_addr, new_str, sizeof(new_str));
265 zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
266 __PRETTY_FUNCTION__, caller,
267 old_str, new_str, ifp->name);
268 }
269
270 pim_ifp = ifp->info;
Everton Marques8852dba2014-08-28 16:02:11 -0300271 if (!pim_ifp) {
272 return;
Everton Marques871dbcf2009-08-11 15:43:05 -0300273 }
Everton Marques8852dba2014-08-28 16:02:11 -0300274
275 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
276 return;
277 }
278
279 pim_addr_change(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300280}
281
Everton Marques8852dba2014-08-28 16:02:11 -0300282static int detect_primary_address_change(struct interface *ifp,
283 int force_prim_as_any,
284 const char *caller)
Everton Marques871dbcf2009-08-11 15:43:05 -0300285{
286 struct pim_interface *pim_ifp;
287 struct in_addr new_prim_addr;
Everton Marques306c99e2014-07-16 15:51:37 -0300288 int changed;
Everton Marques871dbcf2009-08-11 15:43:05 -0300289
290 pim_ifp = ifp->info;
291 if (!pim_ifp)
Everton Marques8852dba2014-08-28 16:02:11 -0300292 return 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300293
Everton Marquesb2402972014-09-22 18:29:29 -0300294 if (force_prim_as_any)
295 new_prim_addr = qpim_inaddr_any;
296 else
297 new_prim_addr = pim_find_primary_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300298
Everton Marques306c99e2014-07-16 15:51:37 -0300299 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
300
Everton Marques871dbcf2009-08-11 15:43:05 -0300301 if (PIM_DEBUG_ZEBRA) {
302 char new_prim_str[100];
303 char old_prim_str[100];
304 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
305 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
Everton Marques306c99e2014-07-16 15:51:37 -0300306 zlog_debug("%s: old=%s new=%s on interface %s: %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300307 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300308 old_prim_str, new_prim_str, ifp->name,
309 changed ? "changed" : "unchanged");
Everton Marques871dbcf2009-08-11 15:43:05 -0300310 }
311
Everton Marques306c99e2014-07-16 15:51:37 -0300312 if (changed) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300313 struct in_addr old_addr = pim_ifp->primary_address;
314 pim_ifp->primary_address = new_prim_addr;
315
316 on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
317 }
Everton Marques8852dba2014-08-28 16:02:11 -0300318
319 return changed;
320}
321
322static void detect_secondary_address_change(struct interface *ifp,
323 const char *caller)
324{
325 struct pim_interface *pim_ifp;
326 int changed;
327
328 pim_ifp = ifp->info;
329 if (!pim_ifp)
330 return;
331
332 changed = 1; /* true */
333 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
334 __PRETTY_FUNCTION__, ifp->name);
335
336 if (PIM_DEBUG_ZEBRA) {
337 zlog_debug("%s: on interface %s: %s",
338 __PRETTY_FUNCTION__,
339 ifp->name, changed ? "changed" : "unchanged");
340 }
341
342 if (!changed) {
343 return;
344 }
345
346 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
347 return;
348 }
349
350 pim_addr_change(ifp);
351}
352
353static void detect_address_change(struct interface *ifp,
354 int force_prim_as_any,
355 const char *caller)
356{
357 int prim_changed;
358
359 prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
360 if (prim_changed) {
361 /* no need to detect secondary change because
362 the reaction would be the same */
363 return;
364 }
365
366 detect_secondary_address_change(ifp, caller);
Everton Marques871dbcf2009-08-11 15:43:05 -0300367}
368
369void pim_if_addr_add(struct connected *ifc)
370{
371 struct pim_interface *pim_ifp;
372 struct interface *ifp;
373 struct in_addr ifaddr;
374
375 zassert(ifc);
376
377 ifp = ifc->ifp;
378 zassert(ifp);
379 pim_ifp = ifp->info;
380 if (!pim_ifp)
381 return;
382
383 if (!if_is_operative(ifp))
384 return;
385
Everton Marques85385f72015-01-19 18:25:45 -0200386 /* if (PIM_DEBUG_ZEBRA) */ {
Everton Marques306c99e2014-07-16 15:51:37 -0300387 char buf[BUFSIZ];
388 prefix2str(ifc->address, buf, BUFSIZ);
Everton Marques85385f72015-01-19 18:25:45 -0200389 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
Everton Marques306c99e2014-07-16 15:51:37 -0300390 __PRETTY_FUNCTION__,
Everton Marques85385f72015-01-19 18:25:45 -0200391 ifp->name, ifp->ifindex, buf,
Everton Marques306c99e2014-07-16 15:51:37 -0300392 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
393 "secondary" : "primary");
394 }
395
Everton Marques871dbcf2009-08-11 15:43:05 -0300396 ifaddr = ifc->address->u.prefix4;
397
Everton Marques8852dba2014-08-28 16:02:11 -0300398 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300399
400 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
401 struct igmp_sock *igmp;
402
403 /* lookup IGMP socket */
404 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
405 ifaddr);
406 if (!igmp) {
407 /* if addr new, add IGMP socket */
408 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
409 }
410 } /* igmp */
411
412 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
413
414 /* Interface has a valid primary address ? */
415 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
416
417 /* Interface has a valid socket ? */
418 if (pim_ifp->pim_sock_fd < 0) {
419 if (pim_sock_add(ifp)) {
420 zlog_warn("Failure creating PIM socket for interface %s",
421 ifp->name);
422 }
423 }
424
425 }
426 } /* pim */
427
428 if (PIM_MROUTE_IS_ENABLED) {
429 /*
430 PIM or IGMP is enabled on interface, and there is at least one
431 address assigned, then try to create a vif_index.
432 */
433 if (pim_ifp->mroute_vif_index < 0) {
434 pim_if_add_vif(ifp);
435 }
436 }
437}
438
439static void pim_if_addr_del_igmp(struct connected *ifc)
440{
441 struct pim_interface *pim_ifp = ifc->ifp->info;
442 struct igmp_sock *igmp;
443 struct in_addr ifaddr;
444
445 if (ifc->address->family != AF_INET) {
446 /* non-IPv4 address */
447 return;
448 }
449
450 if (!pim_ifp) {
451 /* IGMP not enabled on interface */
452 return;
453 }
454
455 ifaddr = ifc->address->u.prefix4;
456
457 /* lookup IGMP socket */
458 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
459 ifaddr);
460 if (igmp) {
461 /* if addr found, del IGMP socket */
462 igmp_sock_delete(igmp);
463 }
464}
465
466static void pim_if_addr_del_pim(struct connected *ifc)
467{
468 struct pim_interface *pim_ifp = ifc->ifp->info;
469
470 if (ifc->address->family != AF_INET) {
471 /* non-IPv4 address */
472 return;
473 }
474
475 if (!pim_ifp) {
476 /* PIM not enabled on interface */
477 return;
478 }
479
480 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
481 /* Interface keeps a valid primary address */
482 return;
483 }
484
485 if (pim_ifp->pim_sock_fd < 0) {
486 /* Interface does not hold a valid socket any longer */
487 return;
488 }
489
490 /*
491 pim_sock_delete() closes the socket, stops read and timer threads,
492 and kills all neighbors.
493 */
494 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
495}
496
Everton Marquesb2402972014-09-22 18:29:29 -0300497void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
Everton Marques871dbcf2009-08-11 15:43:05 -0300498{
499 struct interface *ifp;
500
501 zassert(ifc);
502 ifp = ifc->ifp;
503 zassert(ifp);
504
Everton Marques85385f72015-01-19 18:25:45 -0200505 /* if (PIM_DEBUG_ZEBRA) */ {
Everton Marques306c99e2014-07-16 15:51:37 -0300506 char buf[BUFSIZ];
507 prefix2str(ifc->address, buf, BUFSIZ);
Everton Marques85385f72015-01-19 18:25:45 -0200508 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
Everton Marques306c99e2014-07-16 15:51:37 -0300509 __PRETTY_FUNCTION__,
Everton Marques85385f72015-01-19 18:25:45 -0200510 ifp->name, ifp->ifindex, buf,
Everton Marques306c99e2014-07-16 15:51:37 -0300511 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
512 "secondary" : "primary");
513 }
514
Everton Marques8852dba2014-08-28 16:02:11 -0300515 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
Everton Marques871dbcf2009-08-11 15:43:05 -0300516
517 pim_if_addr_del_igmp(ifc);
518 pim_if_addr_del_pim(ifc);
519}
520
521void pim_if_addr_add_all(struct interface *ifp)
522{
523 struct connected *ifc;
524 struct listnode *node;
525 struct listnode *nextnode;
526
527 /* PIM/IGMP enabled ? */
528 if (!ifp->info)
529 return;
530
531 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
532 struct prefix *p = ifc->address;
533
534 if (p->family != AF_INET)
535 continue;
536
537 pim_if_addr_add(ifc);
538 }
539}
540
541void pim_if_addr_del_all(struct interface *ifp)
542{
543 struct connected *ifc;
544 struct listnode *node;
545 struct listnode *nextnode;
546
547 /* PIM/IGMP enabled ? */
548 if (!ifp->info)
549 return;
550
551 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
552 struct prefix *p = ifc->address;
553
554 if (p->family != AF_INET)
555 continue;
556
Everton Marquesb2402972014-09-22 18:29:29 -0300557 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
Everton Marques871dbcf2009-08-11 15:43:05 -0300558 }
559}
560
561void pim_if_addr_del_all_igmp(struct interface *ifp)
562{
563 struct connected *ifc;
564 struct listnode *node;
565 struct listnode *nextnode;
566
567 /* PIM/IGMP enabled ? */
568 if (!ifp->info)
569 return;
570
571 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
572 struct prefix *p = ifc->address;
573
574 if (p->family != AF_INET)
575 continue;
576
577 pim_if_addr_del_igmp(ifc);
578 }
579}
580
581void pim_if_addr_del_all_pim(struct interface *ifp)
582{
583 struct connected *ifc;
584 struct listnode *node;
585 struct listnode *nextnode;
586
587 /* PIM/IGMP enabled ? */
588 if (!ifp->info)
589 return;
590
591 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
592 struct prefix *p = ifc->address;
593
594 if (p->family != AF_INET)
595 continue;
596
597 pim_if_addr_del_pim(ifc);
598 }
599}
600
Everton Marques306c99e2014-07-16 15:51:37 -0300601static struct in_addr find_first_nonsec_addr(struct interface *ifp)
Everton Marques871dbcf2009-08-11 15:43:05 -0300602{
603 struct connected *ifc;
604 struct listnode *node;
605 struct in_addr addr;
606
607 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
608 struct prefix *p = ifc->address;
609
610 if (p->family != AF_INET)
611 continue;
612
613 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
614 zlog_warn("%s: null IPv4 address connected to interface %s",
615 __PRETTY_FUNCTION__, ifp->name);
616 continue;
617 }
618
Everton Marques075ac8d2014-09-24 15:18:37 -0300619 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
Everton Marques306c99e2014-07-16 15:51:37 -0300620 continue;
621
Everton Marques871dbcf2009-08-11 15:43:05 -0300622 return p->u.prefix4;
623 }
624
625 addr.s_addr = PIM_NET_INADDR_ANY;
626
627 return addr;
628}
629
630struct in_addr pim_find_primary_addr(struct interface *ifp)
631{
Everton Marques306c99e2014-07-16 15:51:37 -0300632 return find_first_nonsec_addr(ifp);
Everton Marques871dbcf2009-08-11 15:43:05 -0300633}
634
635/*
636 pim_if_add_vif() uses ifindex as vif_index
637
638 see also pim_if_find_vifindex_by_ifindex()
639 */
640int pim_if_add_vif(struct interface *ifp)
641{
642 struct pim_interface *pim_ifp = ifp->info;
643 struct in_addr ifaddr;
644
645 zassert(pim_ifp);
646
647 if (pim_ifp->mroute_vif_index > 0) {
648 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
649 __PRETTY_FUNCTION__,
650 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
651 return -1;
652 }
653
654 if (ifp->ifindex < 1) {
655 zlog_warn("%s: ifindex=%d < 1 on interface %s",
656 __PRETTY_FUNCTION__,
657 ifp->ifindex, ifp->name);
658 return -2;
659 }
660
661 if (ifp->ifindex >= MAXVIFS) {
662 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
663 __PRETTY_FUNCTION__,
664 ifp->ifindex, MAXVIFS, ifp->name);
665 return -3;
666 }
667
668 ifaddr = pim_ifp->primary_address;
669 if (PIM_INADDR_IS_ANY(ifaddr)) {
670 zlog_warn("%s: could not get address for interface %s ifindex=%d",
671 __PRETTY_FUNCTION__,
672 ifp->name, ifp->ifindex);
673 return -4;
674 }
675
676 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
677 /* pim_mroute_add_vif reported error */
678 return -5;
679 }
680
681 pim_ifp->mroute_vif_index = ifp->ifindex;
682
683 /*
684 Update highest vif_index
685 */
686 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
687 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
688 }
689
690 return 0;
691}
692
693static int iflist_find_highest_vif_index()
694{
695 struct listnode *ifnode;
696 struct interface *ifp;
697 struct pim_interface *pim_ifp;
698 int highest_vif_index = -1;
699
700 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
701 pim_ifp = ifp->info;
702 if (!pim_ifp)
703 continue;
704
705 if (pim_ifp->mroute_vif_index > highest_vif_index) {
706 highest_vif_index = pim_ifp->mroute_vif_index;
707 }
708 }
709
710 return highest_vif_index;
711}
712
713int pim_if_del_vif(struct interface *ifp)
714{
715 struct pim_interface *pim_ifp = ifp->info;
716 int old_vif_index;
717
718 if (pim_ifp->mroute_vif_index < 1) {
719 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
720 __PRETTY_FUNCTION__,
721 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
722 return -1;
723 }
724
725 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
726 /* pim_mroute_del_vif reported error */
727 return -2;
728 }
729
730 /*
731 Update highest vif_index
732 */
733
734 /* save old vif_index in order to compare with highest below */
735 old_vif_index = pim_ifp->mroute_vif_index;
736
737 pim_ifp->mroute_vif_index = -1;
738
739 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
740 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
741 }
742
743 return 0;
744}
745
746void pim_if_add_vif_all()
747{
748 struct listnode *ifnode;
749 struct listnode *ifnextnode;
750 struct interface *ifp;
751
752 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
753 if (!ifp->info)
754 continue;
755
756 pim_if_add_vif(ifp);
757 }
758}
759
760void pim_if_del_vif_all()
761{
762 struct listnode *ifnode;
763 struct listnode *ifnextnode;
764 struct interface *ifp;
765
766 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
767 if (!ifp->info)
768 continue;
769
770 pim_if_del_vif(ifp);
771 }
772}
773
774struct interface *pim_if_find_by_vif_index(int vif_index)
775{
776 struct listnode *ifnode;
777 struct interface *ifp;
778
779 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
780 if (ifp->info) {
781 struct pim_interface *pim_ifp;
782 pim_ifp = ifp->info;
783 if (vif_index == pim_ifp->mroute_vif_index)
784 return ifp;
785 }
786 }
787
788 return 0;
789}
790
791/*
792 pim_if_add_vif() uses ifindex as vif_index
793 */
794int pim_if_find_vifindex_by_ifindex(int ifindex)
795{
796 return ifindex;
797}
798
799int pim_if_lan_delay_enabled(struct interface *ifp)
800{
801 struct pim_interface *pim_ifp;
802
803 pim_ifp = ifp->info;
804 zassert(pim_ifp);
805 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
806
807 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
808}
809
810uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
811{
812 if (pim_if_lan_delay_enabled(ifp)) {
813 struct pim_interface *pim_ifp;
814 pim_ifp = ifp->info;
815 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
816 }
817 else {
818 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
819 }
820}
821
822uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
823{
824 if (pim_if_lan_delay_enabled(ifp)) {
825 struct pim_interface *pim_ifp;
826 pim_ifp = ifp->info;
827 return pim_ifp->pim_neighbors_highest_override_interval_msec;
828 }
829 else {
830 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
831 }
832}
833
834int pim_if_t_override_msec(struct interface *ifp)
835{
836 int effective_override_interval_msec;
837 int t_override_msec;
838
839 effective_override_interval_msec =
840 pim_if_effective_override_interval_msec(ifp);
841
842 t_override_msec = pim_rand_next(0, effective_override_interval_msec);
843
844 return t_override_msec;
845}
846
847uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
848{
849 return pim_if_effective_propagation_delay_msec(ifp) +
850 pim_if_effective_override_interval_msec(ifp);
851}
852
853/*
854 RFC 4601: 4.1.6. State Summarization Macros
855
856 The function NBR( I, A ) uses information gathered through PIM Hello
857 messages to map the IP address A of a directly connected PIM
858 neighbor router on interface I to the primary IP address of the same
859 router (Section 4.3.4). The primary IP address of a neighbor is the
860 address that it uses as the source of its PIM Hello messages.
861*/
862struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
863 struct in_addr addr)
864{
865 struct listnode *neighnode;
866 struct pim_neighbor *neigh;
867 struct pim_interface *pim_ifp;
868
869 zassert(ifp);
870
871 pim_ifp = ifp->info;
872 if (!pim_ifp) {
873 zlog_warn("%s: multicast not enabled on interface %s",
874 __PRETTY_FUNCTION__,
875 ifp->name);
876 return 0;
877 }
878
879 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
880
881 /* primary address ? */
882 if (neigh->source_addr.s_addr == addr.s_addr)
883 return neigh;
884
885 /* secondary address ? */
886 if (pim_neighbor_find_secondary(neigh, addr))
887 return neigh;
888 }
889
890 if (PIM_DEBUG_PIM_TRACE) {
891 char addr_str[100];
892 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
893 zlog_debug("%s: neighbor not found for address %s on interface %s",
894 __PRETTY_FUNCTION__,
895 addr_str, ifp->name);
896 }
897
898 return 0;
899}
900
901long pim_if_t_suppressed_msec(struct interface *ifp)
902{
903 struct pim_interface *pim_ifp;
904 long t_suppressed_msec;
905
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) */
914
915 t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400);
916
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}