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