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