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