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