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