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