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