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