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