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