]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_iface.c
pimd: Trust the compiler
[mirror_frr.git] / pimd / pim_iface.c
CommitLineData
12e41d03
DL
1/*
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
12e41d03
DL
18*/
19
20#include <zebra.h>
21
22#include "if.h"
23#include "log.h"
24#include "vty.h"
25#include "memory.h"
26#include "prefix.h"
469351b3 27#include "vrf.h"
9f0edbc9 28#include "linklist.h"
7176984f 29#include "plist.h"
12e41d03
DL
30
31#include "pimd.h"
32#include "pim_iface.h"
33#include "pim_igmp.h"
34#include "pim_mroute.h"
35#include "pim_oil.h"
36#include "pim_str.h"
37#include "pim_pim.h"
38#include "pim_neighbor.h"
39#include "pim_ifchannel.h"
12e41d03
DL
40#include "pim_sock.h"
41#include "pim_time.h"
42#include "pim_ssmpingd.h"
7176984f 43#include "pim_rp.h"
12e41d03 44
c992c9a0 45struct interface *pim_regiface = NULL;
ea4a71fc 46struct list *pim_ifchannel_list = NULL;
dc0665f1 47static int pim_iface_vif_index[MAXVIFS];
c992c9a0 48
12e41d03
DL
49static void pim_if_igmp_join_del_all(struct interface *ifp);
50
ea4a71fc
DS
51void
52pim_if_init (void)
53{
dc0665f1
DS
54 int i;
55
56 for (i = 0; i < MAXVIFS; i++)
57 pim_iface_vif_index[i] = 0;
58
ea4a71fc
DS
59 vrf_iflist_create(VRF_DEFAULT);
60 pim_ifchannel_list = list_new();
61 pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
62}
63
64void
65pim_if_terminate (void)
66{
67 if (pim_ifchannel_list)
68 list_free (pim_ifchannel_list);
69}
70
71static void *if_list_clean(struct pim_interface *pim_ifp)
72{
73 if (pim_ifp->igmp_join_list) {
74 list_delete(pim_ifp->igmp_join_list);
75 }
76
77 if (pim_ifp->igmp_socket_list) {
78 list_delete(pim_ifp->igmp_socket_list);
79 }
80
81 if (pim_ifp->pim_neighbor_list) {
82 list_delete(pim_ifp->pim_neighbor_list);
83 }
84
85 if (pim_ifp->pim_ifchannel_list) {
86 list_delete(pim_ifp->pim_ifchannel_list);
87 }
88
89 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
90
91 return 0;
92}
93
12e41d03
DL
94struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
95{
96 struct pim_interface *pim_ifp;
97
98 zassert(ifp);
99 zassert(!ifp->info);
100
36d9e7dc 101 pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
12e41d03 102 if (!pim_ifp) {
36d9e7dc 103 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
12e41d03
DL
104 return 0;
105 }
106
107 pim_ifp->options = 0;
108 pim_ifp->mroute_vif_index = -1;
109
b05b72e8 110 pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
12e41d03
DL
111 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
112 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
113 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
114 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
115
116 /*
117 RFC 3376: 8.3. Query Response Interval
118 The number of seconds represented by the [Query Response Interval]
119 must be less than the [Query Interval].
120 */
121 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
122
123 if (pim)
124 PIM_IF_DO_PIM(pim_ifp->options);
125 if (igmp)
126 PIM_IF_DO_IGMP(pim_ifp->options);
127
12e41d03 128 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
12e41d03 129
59ba0ac3
DS
130 pim_ifp->igmp_join_list = NULL;
131 pim_ifp->igmp_socket_list = NULL;
132 pim_ifp->pim_neighbor_list = NULL;
133 pim_ifp->pim_ifchannel_list = NULL;
e4cc0185 134 pim_ifp->pim_generation_id = 0;
12e41d03
DL
135
136 /* list of struct igmp_sock */
137 pim_ifp->igmp_socket_list = list_new();
138 if (!pim_ifp->igmp_socket_list) {
139 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
140 __FILE__, __PRETTY_FUNCTION__);
141 return if_list_clean(pim_ifp);
142 }
143 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
144
145 /* list of struct pim_neighbor */
146 pim_ifp->pim_neighbor_list = list_new();
147 if (!pim_ifp->pim_neighbor_list) {
148 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
149 __FILE__, __PRETTY_FUNCTION__);
150 return if_list_clean(pim_ifp);
151 }
152 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
153
154 /* list of struct pim_ifchannel */
155 pim_ifp->pim_ifchannel_list = list_new();
156 if (!pim_ifp->pim_ifchannel_list) {
157 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
158 __FILE__, __PRETTY_FUNCTION__);
159 return if_list_clean(pim_ifp);
160 }
161 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
bbd64ce1 162 pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
12e41d03
DL
163
164 ifp->info = pim_ifp;
165
166 pim_sock_reset(ifp);
167
12e41d03
DL
168 if (PIM_MROUTE_IS_ENABLED) {
169 pim_if_add_vif(ifp);
170 }
171
172 return pim_ifp;
173}
174
175void pim_if_delete(struct interface *ifp)
176{
177 struct pim_interface *pim_ifp;
178
179 zassert(ifp);
180 pim_ifp = ifp->info;
181 zassert(pim_ifp);
182
183 if (pim_ifp->igmp_join_list) {
184 pim_if_igmp_join_del_all(ifp);
185 }
12e41d03 186
cb24fec4
DS
187 pim_ifchannel_delete_all (ifp);
188 igmp_sock_delete_all (ifp);
12e41d03 189
cb24fec4 190 pim_neighbor_delete_all (ifp, "Interface removed from configuration");
12e41d03
DL
191
192 if (PIM_MROUTE_IS_ENABLED) {
193 pim_if_del_vif(ifp);
194 }
195
196 list_delete(pim_ifp->igmp_socket_list);
197 list_delete(pim_ifp->pim_neighbor_list);
198 list_delete(pim_ifp->pim_ifchannel_list);
199
200 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
201
59ba0ac3 202 ifp->info = NULL;
12e41d03
DL
203}
204
205void pim_if_update_could_assert(struct interface *ifp)
206{
207 struct pim_interface *pim_ifp;
208 struct listnode *node;
209 struct listnode *next_node;
210 struct pim_ifchannel *ch;
211
212 pim_ifp = ifp->info;
213 zassert(pim_ifp);
214
215 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
216 pim_ifchannel_update_could_assert(ch);
217 }
218}
219
220static void pim_if_update_my_assert_metric(struct interface *ifp)
221{
222 struct pim_interface *pim_ifp;
223 struct listnode *node;
224 struct listnode *next_node;
225 struct pim_ifchannel *ch;
226
227 pim_ifp = ifp->info;
228 zassert(pim_ifp);
229
230 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
231 pim_ifchannel_update_my_assert_metric(ch);
232 }
233}
234
235static void pim_addr_change(struct interface *ifp)
236{
237 struct pim_interface *pim_ifp;
238
239 pim_ifp = ifp->info;
240 zassert(pim_ifp);
241
242 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
243 pim_if_update_join_desired(pim_ifp); /* depends on DR */
244 pim_if_update_could_assert(ifp); /* depends on DR */
245 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
246 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
247
248 /*
249 RFC 4601: 4.3.1. Sending Hello Messages
250
251 1) Before an interface goes down or changes primary IP address, a
252 Hello message with a zero HoldTime should be sent immediately
253 (with the old IP address if the IP address changed).
254 -- FIXME See CAVEAT C13
255
256 2) After an interface has changed its IP address, it MUST send a
257 Hello message with its new IP address.
258 -- DONE below
259
260 3) If an interface changes one of its secondary IP addresses, a
261 Hello message with an updated Address_List option and a non-zero
262 HoldTime should be sent immediately.
263 -- FIXME See TODO T31
264 */
265 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
266 if (pim_ifp->pim_sock_fd < 0)
267 return;
268 pim_hello_restart_now(ifp); /* send hello and restart timer */
269}
270
12e41d03
DL
271static int detect_primary_address_change(struct interface *ifp,
272 int force_prim_as_any,
273 const char *caller)
274{
4763cd0e 275 struct pim_interface *pim_ifp = ifp->info;
12e41d03
DL
276 struct in_addr new_prim_addr;
277 int changed;
278
12e41d03
DL
279 if (force_prim_as_any)
280 new_prim_addr = qpim_inaddr_any;
281 else
282 new_prim_addr = pim_find_primary_addr(ifp);
283
284 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
285
286 if (PIM_DEBUG_ZEBRA) {
eaa54bdb
DW
287 char new_prim_str[INET_ADDRSTRLEN];
288 char old_prim_str[INET_ADDRSTRLEN];
12e41d03
DL
289 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
290 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
291 zlog_debug("%s: old=%s new=%s on interface %s: %s",
292 __PRETTY_FUNCTION__,
293 old_prim_str, new_prim_str, ifp->name,
294 changed ? "changed" : "unchanged");
295 }
296
297 if (changed) {
12e41d03 298 pim_ifp->primary_address = new_prim_addr;
12e41d03
DL
299 }
300
301 return changed;
302}
303
7176984f 304static int pim_sec_addr_comp(const void *p1, const void *p2)
305{
306 const struct pim_secondary_addr *sec1 = p1;
307 const struct pim_secondary_addr *sec2 = p2;
308
309 if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
310 return -1;
311
312 if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
313 return 1;
314
315 return 0;
316}
317
318static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
319{
320 XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
321}
322
323static struct pim_secondary_addr *
324pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
325{
326 struct pim_secondary_addr *sec_addr;
327 struct listnode *node;
328
329 if (!pim_ifp->sec_addr_list) {
330 return NULL;
331 }
332
333 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
334 if (sec_addr->addr.s_addr == addr.s_addr) {
335 return sec_addr;
336 }
337 }
338
339 return NULL;
340}
341
342static void pim_sec_addr_del(struct pim_interface *pim_ifp,
343 struct pim_secondary_addr *sec_addr)
344{
345 listnode_delete(pim_ifp->sec_addr_list, sec_addr);
346 pim_sec_addr_free(sec_addr);
347}
348
349static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
350{
351 int changed = 0;
352 struct pim_secondary_addr *sec_addr;
353
354 sec_addr = pim_sec_addr_find(pim_ifp, addr);
355 if (sec_addr) {
356 sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
357 return changed;
358 }
359
360 if (!pim_ifp->sec_addr_list) {
361 pim_ifp->sec_addr_list = list_new();
362 pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
363 pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
364 }
365
366 sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
367 if (!sec_addr) {
368 if (list_isempty(pim_ifp->sec_addr_list)) {
369 list_free(pim_ifp->sec_addr_list);
370 pim_ifp->sec_addr_list = NULL;
371 }
372 return changed;
373 }
374
375 changed = 1;
376 sec_addr->addr = addr;
377 listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
378
379 return changed;
380}
381
382static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
383{
384 int changed = 0;
385
386 if (!pim_ifp->sec_addr_list) {
387 return changed;
388 }
389 if (!list_isempty(pim_ifp->sec_addr_list)) {
390 changed = 1;
391 /* remove all nodes and free up the list itself */
392 list_delete_all_node(pim_ifp->sec_addr_list);
393 list_free(pim_ifp->sec_addr_list);
394 pim_ifp->sec_addr_list = NULL;
395 }
396
397 return changed;
398}
399
400static int pim_sec_addr_update(struct interface *ifp)
401{
402 struct pim_interface *pim_ifp = ifp->info;
403 struct connected *ifc;
404 struct listnode *node;
405 struct listnode *nextnode;
406 struct pim_secondary_addr *sec_addr;
407 int changed = 0;
408
409 if (pim_ifp->sec_addr_list) {
410 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
411 sec_addr->flags |= PIM_SEC_ADDRF_STALE;
412 }
413 }
414
415 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
416 struct prefix *p = ifc->address;
417
418 if (p->family != AF_INET) {
419 continue;
420 }
421
422 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
423 continue;
424 }
425
426 if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
427 /* don't add the primary address into the secondary address list */
428 continue;
429 }
430
431 if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
432 changed = 1;
433 }
434 }
435
436 if (pim_ifp->sec_addr_list) {
437 /* Drop stale entries */
438 for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
439 if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
440 pim_sec_addr_del(pim_ifp, sec_addr);
441 changed = 1;
442 }
443 }
444
445 /* If the list went empty free it up */
446 if (list_isempty(pim_ifp->sec_addr_list)) {
447 list_free(pim_ifp->sec_addr_list);
448 pim_ifp->sec_addr_list = NULL;
449 }
450 }
451
452 return changed;
453}
454
4763cd0e 455static int detect_secondary_address_change(struct interface *ifp,
7176984f 456 int force_prim_as_any,
12e41d03
DL
457 const char *caller)
458{
4763cd0e 459 struct pim_interface *pim_ifp = ifp->info;
7176984f 460 int changed = 0;
12e41d03 461
7176984f 462 if (force_prim_as_any) {
463 /* if primary address is being forced to zero just flush the
464 * secondary address list */
4763cd0e 465 changed = pim_sec_addr_del_all(pim_ifp);
7176984f 466 } else {
467 /* re-evaluate the secondary address list */
468 changed = pim_sec_addr_update(ifp);
469 }
470
4763cd0e 471 return changed;
472}
473
474static void detect_address_change(struct interface *ifp,
475 int force_prim_as_any,
476 const char *caller)
477{
478 int changed = 0;
479 struct pim_interface *pim_ifp;
12e41d03 480
4763cd0e 481 pim_ifp = ifp->info;
482 if (!pim_ifp)
12e41d03 483 return;
4763cd0e 484
485 if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
486 changed = 1;
12e41d03
DL
487 }
488
4763cd0e 489 if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
490 changed = 1;
491 }
492
493
494 if (changed) {
495 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
496 return;
497 }
498
499 pim_addr_change(ifp);
12e41d03
DL
500 }
501
4763cd0e 502 /* XXX: if we have unnumbered interfaces we need to run detect address
503 * address change on all of them when the lo address changes */
12e41d03
DL
504}
505
4763cd0e 506int pim_update_source_set(struct interface *ifp, struct in_addr source)
12e41d03 507{
4763cd0e 508 struct pim_interface *pim_ifp = ifp->info;
12e41d03 509
4763cd0e 510 if (!pim_ifp) {
511 return PIM_IFACE_NOT_FOUND;
12e41d03
DL
512 }
513
4763cd0e 514 if (pim_ifp->update_source.s_addr == source.s_addr) {
515 return PIM_UPDATE_SOURCE_DUP;
516 }
517
518 pim_ifp->update_source = source;
519 detect_address_change(ifp, 0 /* force_prim_as_any */,
520 __PRETTY_FUNCTION__);
521
522 return PIM_SUCCESS;
12e41d03
DL
523}
524
525void pim_if_addr_add(struct connected *ifc)
526{
527 struct pim_interface *pim_ifp;
528 struct interface *ifp;
529 struct in_addr ifaddr;
530
531 zassert(ifc);
532
533 ifp = ifc->ifp;
534 zassert(ifp);
535 pim_ifp = ifp->info;
536 if (!pim_ifp)
537 return;
538
539 if (!if_is_operative(ifp))
540 return;
541
7adf0260 542 if (PIM_DEBUG_ZEBRA) {
12e41d03
DL
543 char buf[BUFSIZ];
544 prefix2str(ifc->address, buf, BUFSIZ);
545 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
546 __PRETTY_FUNCTION__,
547 ifp->name, ifp->ifindex, buf,
548 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
549 "secondary" : "primary");
550 }
551
552 ifaddr = ifc->address->u.prefix4;
553
554 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
555
556 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
557 struct igmp_sock *igmp;
558
559 /* lookup IGMP socket */
560 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
561 ifaddr);
562 if (!igmp) {
563 /* if addr new, add IGMP socket */
564 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
565 }
566 } /* igmp */
567
568 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
569
570 /* Interface has a valid primary address ? */
571 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
572
573 /* Interface has a valid socket ? */
574 if (pim_ifp->pim_sock_fd < 0) {
575 if (pim_sock_add(ifp)) {
576 zlog_warn("Failure creating PIM socket for interface %s",
577 ifp->name);
578 }
579 }
580
581 }
582 } /* pim */
583
584 if (PIM_MROUTE_IS_ENABLED) {
585 /*
586 PIM or IGMP is enabled on interface, and there is at least one
587 address assigned, then try to create a vif_index.
588 */
589 if (pim_ifp->mroute_vif_index < 0) {
590 pim_if_add_vif(ifp);
591 }
c8507a16 592 pim_ifchannel_scan_forward_start (ifp);
12e41d03
DL
593 }
594}
595
596static void pim_if_addr_del_igmp(struct connected *ifc)
597{
598 struct pim_interface *pim_ifp = ifc->ifp->info;
599 struct igmp_sock *igmp;
600 struct in_addr ifaddr;
601
602 if (ifc->address->family != AF_INET) {
603 /* non-IPv4 address */
604 return;
605 }
606
607 if (!pim_ifp) {
608 /* IGMP not enabled on interface */
609 return;
610 }
611
612 ifaddr = ifc->address->u.prefix4;
613
614 /* lookup IGMP socket */
615 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
616 ifaddr);
617 if (igmp) {
618 /* if addr found, del IGMP socket */
619 igmp_sock_delete(igmp);
620 }
621}
622
623static void pim_if_addr_del_pim(struct connected *ifc)
624{
625 struct pim_interface *pim_ifp = ifc->ifp->info;
626
627 if (ifc->address->family != AF_INET) {
628 /* non-IPv4 address */
629 return;
630 }
631
632 if (!pim_ifp) {
633 /* PIM not enabled on interface */
634 return;
635 }
636
637 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
638 /* Interface keeps a valid primary address */
639 return;
640 }
641
642 if (pim_ifp->pim_sock_fd < 0) {
643 /* Interface does not hold a valid socket any longer */
644 return;
645 }
646
647 /*
648 pim_sock_delete() closes the socket, stops read and timer threads,
649 and kills all neighbors.
650 */
651 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
652}
653
654void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
655{
656 struct interface *ifp;
657
658 zassert(ifc);
659 ifp = ifc->ifp;
660 zassert(ifp);
661
7adf0260 662 if (PIM_DEBUG_ZEBRA) {
12e41d03
DL
663 char buf[BUFSIZ];
664 prefix2str(ifc->address, buf, BUFSIZ);
665 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
666 __PRETTY_FUNCTION__,
667 ifp->name, ifp->ifindex, buf,
668 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
669 "secondary" : "primary");
670 }
671
672 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
673
674 pim_if_addr_del_igmp(ifc);
675 pim_if_addr_del_pim(ifc);
676}
677
678void pim_if_addr_add_all(struct interface *ifp)
679{
680 struct connected *ifc;
681 struct listnode *node;
682 struct listnode *nextnode;
d8424057
DS
683 int v4_addrs = 0;
684 int v6_addrs = 0;
7176984f 685 struct pim_interface *pim_ifp = ifp->info;
686
12e41d03
DL
687
688 /* PIM/IGMP enabled ? */
7176984f 689 if (!pim_ifp)
12e41d03
DL
690 return;
691
692 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
693 struct prefix *p = ifc->address;
694
695 if (p->family != AF_INET)
d8424057
DS
696 {
697 v6_addrs++;
698 continue;
699 }
12e41d03 700
d8424057 701 v4_addrs++;
12e41d03
DL
702 pim_if_addr_add(ifc);
703 }
d8424057
DS
704
705 if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
706 {
7176984f 707 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
d8424057
DS
708
709 /* Interface has a valid primary address ? */
710 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
711
712 /* Interface has a valid socket ? */
713 if (pim_ifp->pim_sock_fd < 0) {
714 if (pim_sock_add(ifp)) {
715 zlog_warn("Failure creating PIM socket for interface %s",
716 ifp->name);
717 }
718 }
719
720 }
721 } /* pim */
722 }
ef71d1f8
DS
723 if (PIM_MROUTE_IS_ENABLED) {
724 /*
725 * PIM or IGMP is enabled on interface, and there is at least one
726 * address assigned, then try to create a vif_index.
727 */
728 if (pim_ifp->mroute_vif_index < 0) {
729 pim_if_add_vif(ifp);
730 }
731 pim_ifchannel_scan_forward_start (ifp);
732 }
733
da3dcffb 734 pim_rp_setup();
7176984f 735 pim_rp_check_on_if_add(pim_ifp);
12e41d03
DL
736}
737
738void pim_if_addr_del_all(struct interface *ifp)
739{
740 struct connected *ifc;
741 struct listnode *node;
742 struct listnode *nextnode;
743
744 /* PIM/IGMP enabled ? */
745 if (!ifp->info)
746 return;
747
748 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
749 struct prefix *p = ifc->address;
750
751 if (p->family != AF_INET)
752 continue;
753
754 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
755 }
da3dcffb
DS
756
757 pim_rp_setup();
7176984f 758 pim_i_am_rp_re_evaluate();
12e41d03
DL
759}
760
761void pim_if_addr_del_all_igmp(struct interface *ifp)
762{
763 struct connected *ifc;
764 struct listnode *node;
765 struct listnode *nextnode;
766
767 /* PIM/IGMP enabled ? */
768 if (!ifp->info)
769 return;
770
771 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
772 struct prefix *p = ifc->address;
773
774 if (p->family != AF_INET)
775 continue;
776
777 pim_if_addr_del_igmp(ifc);
778 }
779}
780
781void pim_if_addr_del_all_pim(struct interface *ifp)
782{
783 struct connected *ifc;
784 struct listnode *node;
785 struct listnode *nextnode;
786
787 /* PIM/IGMP enabled ? */
788 if (!ifp->info)
789 return;
790
791 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
792 struct prefix *p = ifc->address;
793
794 if (p->family != AF_INET)
795 continue;
796
797 pim_if_addr_del_pim(ifc);
798 }
799}
800
89f1d91e
DS
801struct in_addr
802pim_find_primary_addr (struct interface *ifp)
12e41d03
DL
803{
804 struct connected *ifc;
805 struct listnode *node;
806 struct in_addr addr;
d8424057
DS
807 int v4_addrs = 0;
808 int v6_addrs = 0;
4763cd0e 809 struct pim_interface *pim_ifp = ifp->info;
810
811 if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
812 return pim_ifp->update_source;
813 }
12e41d03
DL
814
815 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
816 struct prefix *p = ifc->address;
d8424057 817
12e41d03 818 if (p->family != AF_INET)
d8424057
DS
819 {
820 v6_addrs++;
821 continue;
822 }
12e41d03
DL
823
824 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
825 zlog_warn("%s: null IPv4 address connected to interface %s",
826 __PRETTY_FUNCTION__, ifp->name);
827 continue;
828 }
829
d8424057
DS
830 v4_addrs++;
831
12e41d03
DL
832 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
833 continue;
834
835 return p->u.prefix4;
836 }
837
d8424057
DS
838 /*
839 * If we have no v4_addrs and v6 is configured
840 * We probably are using unnumbered
841 * So let's grab the loopbacks v4 address
842 * and use that as the primary address
843 */
844 if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
845 {
846 struct interface *lo_ifp;
847 lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
848 if (lo_ifp)
849 return pim_find_primary_addr (lo_ifp);
850 }
851
12e41d03
DL
852 addr.s_addr = PIM_NET_INADDR_ANY;
853
854 return addr;
855}
856
9df99407 857static int
744d91b3
DS
858pim_iface_next_vif_index (struct interface *ifp)
859{
dc0665f1 860 int i;
744d91b3
DS
861 /*
862 * The pimreg vif is always going to be in index 0
863 * of the table.
864 */
865 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
866 return 0;
867
dc0665f1
DS
868 for (i = 1 ; i < MAXVIFS; i++)
869 {
870 if (pim_iface_vif_index[i] == 0)
871 return i;
872 }
873 return MAXVIFS;
744d91b3
DS
874}
875
12e41d03
DL
876/*
877 pim_if_add_vif() uses ifindex as vif_index
878
879 see also pim_if_find_vifindex_by_ifindex()
880 */
881int pim_if_add_vif(struct interface *ifp)
882{
883 struct pim_interface *pim_ifp = ifp->info;
884 struct in_addr ifaddr;
b3f2bf7c 885 unsigned char flags = 0;
12e41d03
DL
886
887 zassert(pim_ifp);
888
889 if (pim_ifp->mroute_vif_index > 0) {
890 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
891 __PRETTY_FUNCTION__,
892 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
893 return -1;
894 }
895
e34a317a 896 if (ifp->ifindex < 0) {
12e41d03
DL
897 zlog_warn("%s: ifindex=%d < 1 on interface %s",
898 __PRETTY_FUNCTION__,
899 ifp->ifindex, ifp->name);
900 return -2;
901 }
902
12e41d03 903 ifaddr = pim_ifp->primary_address;
c992c9a0 904 if (ifp->ifindex != PIM_OIF_PIM_REGISTER_VIF && PIM_INADDR_IS_ANY(ifaddr)) {
12e41d03
DL
905 zlog_warn("%s: could not get address for interface %s ifindex=%d",
906 __PRETTY_FUNCTION__,
907 ifp->name, ifp->ifindex);
908 return -4;
909 }
910
744d91b3
DS
911 pim_ifp->mroute_vif_index = pim_iface_next_vif_index (ifp);
912
913 if (pim_ifp->mroute_vif_index >= MAXVIFS)
914 {
915 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
916 __PRETTY_FUNCTION__,
917 MAXVIFS, ifp->name);
918 return -3;
919 }
920
b3f2bf7c
RW
921 if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
922 flags = VIFF_REGISTER;
923#ifdef VIFF_USE_IFINDEX
924 else
925 flags = VIFF_USE_IFINDEX;
926#endif
927
744d91b3 928 if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
12e41d03
DL
929 /* pim_mroute_add_vif reported error */
930 return -5;
931 }
932
dc0665f1 933 pim_iface_vif_index[pim_ifp->mroute_vif_index] = 1;
12e41d03
DL
934 return 0;
935}
936
12e41d03
DL
937int pim_if_del_vif(struct interface *ifp)
938{
939 struct pim_interface *pim_ifp = ifp->info;
12e41d03
DL
940
941 if (pim_ifp->mroute_vif_index < 1) {
942 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
943 __PRETTY_FUNCTION__,
944 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
945 return -1;
946 }
947
429a291b 948 pim_mroute_del_vif(pim_ifp->mroute_vif_index);
12e41d03
DL
949
950 /*
dc0665f1 951 Update vif_index
12e41d03 952 */
dc0665f1 953 pim_iface_vif_index[pim_ifp->mroute_vif_index] = 0;
12e41d03
DL
954
955 pim_ifp->mroute_vif_index = -1;
956
12e41d03
DL
957 return 0;
958}
959
960void pim_if_add_vif_all()
961{
962 struct listnode *ifnode;
963 struct listnode *ifnextnode;
964 struct interface *ifp;
965
469351b3 966 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
967 if (!ifp->info)
968 continue;
969
970 pim_if_add_vif(ifp);
971 }
972}
973
974void pim_if_del_vif_all()
975{
976 struct listnode *ifnode;
977 struct listnode *ifnextnode;
978 struct interface *ifp;
979
469351b3 980 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
981 if (!ifp->info)
982 continue;
983
984 pim_if_del_vif(ifp);
985 }
986}
987
b892f1dd 988struct interface *pim_if_find_by_vif_index(ifindex_t vif_index)
12e41d03
DL
989{
990 struct listnode *ifnode;
991 struct interface *ifp;
992
ae90dfbb
DS
993 if (vif_index == 0)
994 return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT);
995
469351b3 996 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
12e41d03
DL
997 if (ifp->info) {
998 struct pim_interface *pim_ifp;
999 pim_ifp = ifp->info;
b892f1dd 1000
12e41d03
DL
1001 if (vif_index == pim_ifp->mroute_vif_index)
1002 return ifp;
1003 }
1004 }
1005
1006 return 0;
1007}
1008
1009/*
1010 pim_if_add_vif() uses ifindex as vif_index
1011 */
b892f1dd 1012int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
12e41d03 1013{
ae90dfbb
DS
1014 struct pim_interface *pim_ifp;
1015 struct interface *ifp;
1016
1017 ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
28185336 1018 if (!ifp || !ifp->info)
ae90dfbb 1019 return -1;
28185336 1020 pim_ifp = ifp->info;
ae90dfbb
DS
1021
1022 return pim_ifp->mroute_vif_index;
12e41d03
DL
1023}
1024
1025int pim_if_lan_delay_enabled(struct interface *ifp)
1026{
1027 struct pim_interface *pim_ifp;
1028
1029 pim_ifp = ifp->info;
1030 zassert(pim_ifp);
1031 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
1032
1033 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
1034}
1035
1036uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1037{
1038 if (pim_if_lan_delay_enabled(ifp)) {
1039 struct pim_interface *pim_ifp;
1040 pim_ifp = ifp->info;
1041 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1042 }
1043 else {
1044 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1045 }
1046}
1047
1048uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1049{
1050 if (pim_if_lan_delay_enabled(ifp)) {
1051 struct pim_interface *pim_ifp;
1052 pim_ifp = ifp->info;
1053 return pim_ifp->pim_neighbors_highest_override_interval_msec;
1054 }
1055 else {
1056 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1057 }
1058}
1059
1060int pim_if_t_override_msec(struct interface *ifp)
1061{
1062 int effective_override_interval_msec;
1063 int t_override_msec;
1064
1065 effective_override_interval_msec =
1066 pim_if_effective_override_interval_msec(ifp);
1067
60b40924 1068 t_override_msec = random() % (effective_override_interval_msec + 1);
12e41d03
DL
1069
1070 return t_override_msec;
1071}
1072
1073uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1074{
1075 return pim_if_effective_propagation_delay_msec(ifp) +
1076 pim_if_effective_override_interval_msec(ifp);
1077}
1078
1079/*
1080 RFC 4601: 4.1.6. State Summarization Macros
1081
1082 The function NBR( I, A ) uses information gathered through PIM Hello
1083 messages to map the IP address A of a directly connected PIM
1084 neighbor router on interface I to the primary IP address of the same
1085 router (Section 4.3.4). The primary IP address of a neighbor is the
1086 address that it uses as the source of its PIM Hello messages.
1087*/
1088struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
1089 struct in_addr addr)
1090{
1091 struct listnode *neighnode;
1092 struct pim_neighbor *neigh;
1093 struct pim_interface *pim_ifp;
1094
1095 zassert(ifp);
1096
1097 pim_ifp = ifp->info;
1098 if (!pim_ifp) {
1099 zlog_warn("%s: multicast not enabled on interface %s",
1100 __PRETTY_FUNCTION__,
1101 ifp->name);
1102 return 0;
1103 }
1104
1105 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
1106
1107 /* primary address ? */
1108 if (neigh->source_addr.s_addr == addr.s_addr)
1109 return neigh;
1110
1111 /* secondary address ? */
1112 if (pim_neighbor_find_secondary(neigh, addr))
1113 return neigh;
1114 }
1115
1116 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 1117 char addr_str[INET_ADDRSTRLEN];
12e41d03
DL
1118 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
1119 zlog_debug("%s: neighbor not found for address %s on interface %s",
1120 __PRETTY_FUNCTION__,
1121 addr_str, ifp->name);
1122 }
1123
ff67a923 1124 return NULL;
12e41d03
DL
1125}
1126
1127long pim_if_t_suppressed_msec(struct interface *ifp)
1128{
1129 struct pim_interface *pim_ifp;
1130 long t_suppressed_msec;
60b40924 1131 uint32_t ramount = 0;
12e41d03
DL
1132
1133 pim_ifp = ifp->info;
1134 zassert(pim_ifp);
1135
1136 /* join suppression disabled ? */
1137 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
1138 return 0;
1139
1140 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
60b40924
DS
1141 ramount = 1100 + (random() % (1400 - 1100 + 1));
1142 t_suppressed_msec = qpim_t_periodic * ramount;
12e41d03
DL
1143
1144 return t_suppressed_msec;
1145}
1146
1147static void igmp_join_free(struct igmp_join *ij)
1148{
1149 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
1150}
1151
1152static struct igmp_join *igmp_join_find(struct list *join_list,
1153 struct in_addr group_addr,
1154 struct in_addr source_addr)
1155{
1156 struct listnode *node;
1157 struct igmp_join *ij;
1158
1159 zassert(join_list);
1160
1161 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
1162 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
1163 (source_addr.s_addr == ij->source_addr.s_addr))
1164 return ij;
1165 }
1166
1167 return 0;
1168}
1169
1170static int igmp_join_sock(const char *ifname,
b892f1dd 1171 ifindex_t ifindex,
12e41d03
DL
1172 struct in_addr group_addr,
1173 struct in_addr source_addr)
1174{
1175 int join_fd;
1176
1177 join_fd = pim_socket_raw(IPPROTO_IGMP);
1178 if (join_fd < 0) {
1179 return -1;
1180 }
1181
1182 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
1183 close(join_fd);
1184 return -2;
1185 }
1186
1187 return join_fd;
1188}
1189
1190static struct igmp_join *igmp_join_new(struct interface *ifp,
1191 struct in_addr group_addr,
1192 struct in_addr source_addr)
1193{
1194 struct pim_interface *pim_ifp;
1195 struct igmp_join *ij;
1196 int join_fd;
1197
1198 pim_ifp = ifp->info;
1199 zassert(pim_ifp);
1200
1201 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
1202 if (join_fd < 0) {
eaa54bdb
DW
1203 char group_str[INET_ADDRSTRLEN];
1204 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1205 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1206 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1207 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1208 __PRETTY_FUNCTION__,
1209 group_str, source_str, ifp->name);
1210 return 0;
1211 }
1212
36d9e7dc 1213 ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
12e41d03 1214 if (!ij) {
eaa54bdb
DW
1215 char group_str[INET_ADDRSTRLEN];
1216 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1217 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1218 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
36d9e7dc 1219 zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
12e41d03
DL
1220 __PRETTY_FUNCTION__,
1221 sizeof(*ij), group_str, source_str, ifp->name);
1222 close(join_fd);
1223 return 0;
1224 }
1225
1226 ij->sock_fd = join_fd;
1227 ij->group_addr = group_addr;
1228 ij->source_addr = source_addr;
1229 ij->sock_creation = pim_time_monotonic_sec();
1230
1231 listnode_add(pim_ifp->igmp_join_list, ij);
1232
1233 return ij;
1234}
1235
1236int pim_if_igmp_join_add(struct interface *ifp,
1237 struct in_addr group_addr,
1238 struct in_addr source_addr)
1239{
1240 struct pim_interface *pim_ifp;
1241 struct igmp_join *ij;
1242
1243 pim_ifp = ifp->info;
1244 if (!pim_ifp) {
1245 zlog_warn("%s: multicast not enabled on interface %s",
1246 __PRETTY_FUNCTION__,
1247 ifp->name);
1248 return -1;
1249 }
1250
1251 if (!pim_ifp->igmp_join_list) {
1252 pim_ifp->igmp_join_list = list_new();
1253 if (!pim_ifp->igmp_join_list) {
1254 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1255 __FILE__, __PRETTY_FUNCTION__);
1256 return -2;
1257 }
1258 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1259 }
1260
1261 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1262 if (ij) {
eaa54bdb
DW
1263 char group_str[INET_ADDRSTRLEN];
1264 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1265 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1266 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1267 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1268 __PRETTY_FUNCTION__,
1269 group_str, source_str, ifp->name);
1270 return -3;
1271 }
1272
1273 ij = igmp_join_new(ifp, group_addr, source_addr);
1274 if (!ij) {
eaa54bdb
DW
1275 char group_str[INET_ADDRSTRLEN];
1276 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1277 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1278 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1279 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1280 __PRETTY_FUNCTION__,
1281 group_str, source_str, ifp->name);
1282 return -4;
1283 }
1284
7adf0260 1285 if (PIM_DEBUG_IGMP_EVENTS) {
eaa54bdb
DW
1286 char group_str[INET_ADDRSTRLEN];
1287 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1288 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1289 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1290 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
7adf0260
DS
1291 __PRETTY_FUNCTION__,
1292 source_str, group_str, ifp->name);
12e41d03
DL
1293 }
1294
1295 return 0;
1296}
1297
1298
1299
1300int pim_if_igmp_join_del(struct interface *ifp,
1301 struct in_addr group_addr,
1302 struct in_addr source_addr)
1303{
1304 struct pim_interface *pim_ifp;
1305 struct igmp_join *ij;
1306
1307 pim_ifp = ifp->info;
1308 if (!pim_ifp) {
1309 zlog_warn("%s: multicast not enabled on interface %s",
1310 __PRETTY_FUNCTION__,
1311 ifp->name);
1312 return -1;
1313 }
1314
1315 if (!pim_ifp->igmp_join_list) {
1316 zlog_warn("%s: no IGMP join on interface %s",
1317 __PRETTY_FUNCTION__,
1318 ifp->name);
1319 return -2;
1320 }
1321
1322 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1323 if (!ij) {
eaa54bdb
DW
1324 char group_str[INET_ADDRSTRLEN];
1325 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1326 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1327 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1328 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1329 __PRETTY_FUNCTION__,
1330 group_str, source_str, ifp->name);
1331 return -3;
1332 }
1333
1334 if (close(ij->sock_fd)) {
eaa54bdb
DW
1335 char group_str[INET_ADDRSTRLEN];
1336 char source_str[INET_ADDRSTRLEN];
12e41d03
DL
1337 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1338 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1339 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1340 __PRETTY_FUNCTION__,
3d7765d7 1341 ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
12e41d03
DL
1342 /* warning only */
1343 }
1344 listnode_delete(pim_ifp->igmp_join_list, ij);
1345 igmp_join_free(ij);
1346 if (listcount(pim_ifp->igmp_join_list) < 1) {
1347 list_delete(pim_ifp->igmp_join_list);
1348 pim_ifp->igmp_join_list = 0;
1349 }
1350
1351 return 0;
1352}
1353
1354static void pim_if_igmp_join_del_all(struct interface *ifp)
1355{
1356 struct pim_interface *pim_ifp;
1357 struct listnode *node;
1358 struct listnode *nextnode;
1359 struct igmp_join *ij;
1360
1361 pim_ifp = ifp->info;
1362 if (!pim_ifp) {
1363 zlog_warn("%s: multicast not enabled on interface %s",
1364 __PRETTY_FUNCTION__,
1365 ifp->name);
1366 return;
1367 }
1368
1369 if (!pim_ifp->igmp_join_list)
1370 return;
1371
1372 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1373 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1374}
1375
1376/*
1377 RFC 4601
1378
1379 Transitions from "I am Assert Loser" State
1380
1381 Current Winner's GenID Changes or NLT Expires
1382
1383 The Neighbor Liveness Timer associated with the current winner
1384 expires or we receive a Hello message from the current winner
1385 reporting a different GenID from the one it previously reported.
1386 This indicates that the current winner's interface or router has
1387 gone down (and may have come back up), and so we must assume it no
1388 longer knows it was the winner.
1389 */
1390void pim_if_assert_on_neighbor_down(struct interface *ifp,
1391 struct in_addr neigh_addr)
1392{
1393 struct pim_interface *pim_ifp;
1394 struct listnode *node;
1395 struct listnode *next_node;
1396 struct pim_ifchannel *ch;
1397
1398 pim_ifp = ifp->info;
1399 zassert(pim_ifp);
1400
1401 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1402 /* Is (S,G,I) assert loser ? */
1403 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1404 continue;
1405 /* Dead neighbor was winner ? */
1406 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1407 continue;
1408
1409 assert_action_a5(ch);
1410 }
1411}
1412
1413void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1414{
1415 struct listnode *ch_node;
1416 struct pim_ifchannel *ch;
1417
1418 /* clear off flag from interface's upstreams */
1419 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1420 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1421 }
1422
1423 /* scan per-interface (S,G,I) state on this I interface */
1424 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1425 struct pim_upstream *up = ch->upstream;
1426
1427 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1428 continue;
1429
1430 /* update join_desired for the global (S,G) state */
1431 pim_upstream_update_join_desired(up);
1432 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1433 }
1434}
1435
1436void pim_if_update_assert_tracking_desired(struct interface *ifp)
1437{
1438 struct pim_interface *pim_ifp;
1439 struct listnode *node;
1440 struct listnode *next_node;
1441 struct pim_ifchannel *ch;
1442
1443 pim_ifp = ifp->info;
1444 if (!pim_ifp)
1445 return;
1446
1447 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1448 pim_ifchannel_update_assert_tracking_desired(ch);
1449 }
1450}
c992c9a0
DS
1451
1452/*
1453 * PIM wants to have an interface pointer for everything it does.
1454 * The pimreg is a special interface that we have that is not
1455 * quite an inteface but a VIF is created for it.
1456 */
1457void pim_if_create_pimreg (void)
1458{
1459 if (!pim_regiface) {
1460 pim_regiface = if_create("pimreg", strlen("pimreg"));
1461 pim_regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1462
1463 pim_if_new(pim_regiface, 0, 0);
1464 }
1465}
3565202d
DS
1466
1467int
1468pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
1469{
1470 struct listnode *cnode;
1471 struct connected *c;
1472 struct prefix p;
1473
1474 p.family = AF_INET;
1475 p.u.prefix4 = src;
1476 p.prefixlen = IPV4_MAX_BITLEN;
1477
1478 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
1479 {
1480 if ((c->address->family == AF_INET) &&
1481 prefix_match (CONNECTED_PREFIX (c), &p))
1482 {
1483 return 1;
1484 }
1485 }
1486
1487 return 0;
1488}
9f0edbc9
DS
1489
1490struct interface *
1491pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
1492{
1493 struct listnode *ifnode;
1494 struct interface *ifp;
1495
1496 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
1497 {
1498 if (pim_if_connected_to_source (ifp, src) && ifp->info)
1499 return ifp;
1500 }
1501 return NULL;
1502}