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