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