]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_iface.c
pimd: Rework pim to handle changes between us and upstream
[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 $QuaggaId: $Format:%an, %ai, %h$ $
20 */
21
22 #include <zebra.h>
23
24 #include "if.h"
25 #include "log.h"
26 #include "vty.h"
27 #include "memory.h"
28 #include "prefix.h"
29 #include "vrf.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_rand.h"
41 #include "pim_sock.h"
42 #include "pim_time.h"
43 #include "pim_ssmpingd.h"
44
45 static void pim_if_igmp_join_del_all(struct interface *ifp);
46
47 void pim_if_init()
48 {
49 vrf_iflist_create(VRF_DEFAULT);
50 }
51
52 static void *if_list_clean(struct pim_interface *pim_ifp)
53 {
54 if (pim_ifp->igmp_join_list) {
55 list_delete(pim_ifp->igmp_join_list);
56 }
57
58 if (pim_ifp->igmp_socket_list) {
59 list_delete(pim_ifp->igmp_socket_list);
60 }
61
62 if (pim_ifp->pim_neighbor_list) {
63 list_delete(pim_ifp->pim_neighbor_list);
64 }
65
66 if (pim_ifp->pim_ifchannel_list) {
67 list_delete(pim_ifp->pim_ifchannel_list);
68 }
69
70 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
71
72 return 0;
73 }
74
75 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
76 {
77 struct pim_interface *pim_ifp;
78
79 zassert(ifp);
80 zassert(!ifp->info);
81
82 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
83 if (!pim_ifp) {
84 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
85 return 0;
86 }
87
88 pim_ifp->options = 0;
89 pim_ifp->mroute_vif_index = -1;
90
91 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
92 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
93 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
94 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
95
96 /*
97 RFC 3376: 8.3. Query Response Interval
98 The number of seconds represented by the [Query Response Interval]
99 must be less than the [Query Interval].
100 */
101 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
102
103 if (pim)
104 PIM_IF_DO_PIM(pim_ifp->options);
105 if (igmp)
106 PIM_IF_DO_IGMP(pim_ifp->options);
107
108 #if 0
109 /* FIXME: Should join? */
110 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
111 #endif
112
113 pim_ifp->igmp_join_list = 0;
114 pim_ifp->igmp_socket_list = 0;
115 pim_ifp->pim_neighbor_list = 0;
116 pim_ifp->pim_ifchannel_list = 0;
117
118 /* list of struct igmp_sock */
119 pim_ifp->igmp_socket_list = list_new();
120 if (!pim_ifp->igmp_socket_list) {
121 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
122 __FILE__, __PRETTY_FUNCTION__);
123 return if_list_clean(pim_ifp);
124 }
125 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
126
127 /* list of struct pim_neighbor */
128 pim_ifp->pim_neighbor_list = list_new();
129 if (!pim_ifp->pim_neighbor_list) {
130 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
131 __FILE__, __PRETTY_FUNCTION__);
132 return if_list_clean(pim_ifp);
133 }
134 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
135
136 /* list of struct pim_ifchannel */
137 pim_ifp->pim_ifchannel_list = list_new();
138 if (!pim_ifp->pim_ifchannel_list) {
139 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
140 __FILE__, __PRETTY_FUNCTION__);
141 return if_list_clean(pim_ifp);
142 }
143 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
144
145 ifp->info = pim_ifp;
146
147 pim_sock_reset(ifp);
148
149 zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
150
151 if (PIM_MROUTE_IS_ENABLED) {
152 pim_if_add_vif(ifp);
153 }
154
155 return pim_ifp;
156 }
157
158 void pim_if_delete(struct interface *ifp)
159 {
160 struct pim_interface *pim_ifp;
161
162 zassert(ifp);
163 pim_ifp = ifp->info;
164 zassert(pim_ifp);
165
166 if (pim_ifp->igmp_join_list) {
167 pim_if_igmp_join_del_all(ifp);
168 }
169 zassert(!pim_ifp->igmp_join_list);
170
171 zassert(pim_ifp->igmp_socket_list);
172 zassert(!listcount(pim_ifp->igmp_socket_list));
173
174 zassert(pim_ifp->pim_neighbor_list);
175 zassert(!listcount(pim_ifp->pim_neighbor_list));
176
177 zassert(pim_ifp->pim_ifchannel_list);
178 zassert(!listcount(pim_ifp->pim_ifchannel_list));
179
180 if (PIM_MROUTE_IS_ENABLED) {
181 pim_if_del_vif(ifp);
182 }
183
184 list_delete(pim_ifp->igmp_socket_list);
185 list_delete(pim_ifp->pim_neighbor_list);
186 list_delete(pim_ifp->pim_ifchannel_list);
187
188 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
189
190 ifp->info = 0;
191 }
192
193 void pim_if_update_could_assert(struct interface *ifp)
194 {
195 struct pim_interface *pim_ifp;
196 struct listnode *node;
197 struct listnode *next_node;
198 struct pim_ifchannel *ch;
199
200 pim_ifp = ifp->info;
201 zassert(pim_ifp);
202
203 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
204 pim_ifchannel_update_could_assert(ch);
205 }
206 }
207
208 static void pim_if_update_my_assert_metric(struct interface *ifp)
209 {
210 struct pim_interface *pim_ifp;
211 struct listnode *node;
212 struct listnode *next_node;
213 struct pim_ifchannel *ch;
214
215 pim_ifp = ifp->info;
216 zassert(pim_ifp);
217
218 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
219 pim_ifchannel_update_my_assert_metric(ch);
220 }
221 }
222
223 static void pim_addr_change(struct interface *ifp)
224 {
225 struct pim_interface *pim_ifp;
226
227 pim_ifp = ifp->info;
228 zassert(pim_ifp);
229
230 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
231 pim_if_update_join_desired(pim_ifp); /* depends on DR */
232 pim_if_update_could_assert(ifp); /* depends on DR */
233 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
234 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
235
236 /*
237 RFC 4601: 4.3.1. Sending Hello Messages
238
239 1) Before an interface goes down or changes primary IP address, a
240 Hello message with a zero HoldTime should be sent immediately
241 (with the old IP address if the IP address changed).
242 -- FIXME See CAVEAT C13
243
244 2) After an interface has changed its IP address, it MUST send a
245 Hello message with its new IP address.
246 -- DONE below
247
248 3) If an interface changes one of its secondary IP addresses, a
249 Hello message with an updated Address_List option and a non-zero
250 HoldTime should be sent immediately.
251 -- FIXME See TODO T31
252 */
253 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
254 if (pim_ifp->pim_sock_fd < 0)
255 return;
256 pim_hello_restart_now(ifp); /* send hello and restart timer */
257 }
258
259 static void on_primary_address_change(struct interface *ifp,
260 const char *caller,
261 struct in_addr old_addr,
262 struct in_addr new_addr)
263 {
264 struct pim_interface *pim_ifp;
265
266 {
267 char old_str[100];
268 char new_str[100];
269 pim_inet4_dump("<old?>", old_addr, old_str, sizeof(old_str));
270 pim_inet4_dump("<new?>", new_addr, new_str, sizeof(new_str));
271 zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
272 __PRETTY_FUNCTION__, caller,
273 old_str, new_str, ifp->name);
274 }
275
276 pim_ifp = ifp->info;
277 if (!pim_ifp) {
278 return;
279 }
280
281 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
282 return;
283 }
284
285 pim_addr_change(ifp);
286 }
287
288 static int detect_primary_address_change(struct interface *ifp,
289 int force_prim_as_any,
290 const char *caller)
291 {
292 struct pim_interface *pim_ifp;
293 struct in_addr new_prim_addr;
294 int changed;
295
296 pim_ifp = ifp->info;
297 if (!pim_ifp)
298 return 0;
299
300 if (force_prim_as_any)
301 new_prim_addr = qpim_inaddr_any;
302 else
303 new_prim_addr = pim_find_primary_addr(ifp);
304
305 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
306
307 if (PIM_DEBUG_ZEBRA) {
308 char new_prim_str[100];
309 char old_prim_str[100];
310 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
311 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
312 zlog_debug("%s: old=%s new=%s on interface %s: %s",
313 __PRETTY_FUNCTION__,
314 old_prim_str, new_prim_str, ifp->name,
315 changed ? "changed" : "unchanged");
316 }
317
318 if (changed) {
319 struct in_addr old_addr = pim_ifp->primary_address;
320 pim_ifp->primary_address = new_prim_addr;
321
322 on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
323 }
324
325 return changed;
326 }
327
328 static void detect_secondary_address_change(struct interface *ifp,
329 const char *caller)
330 {
331 struct pim_interface *pim_ifp;
332 int changed;
333
334 pim_ifp = ifp->info;
335 if (!pim_ifp)
336 return;
337
338 changed = 1; /* true */
339 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
340 __PRETTY_FUNCTION__, ifp->name);
341
342 if (PIM_DEBUG_ZEBRA) {
343 zlog_debug("%s: on interface %s: %s",
344 __PRETTY_FUNCTION__,
345 ifp->name, changed ? "changed" : "unchanged");
346 }
347
348 if (!changed) {
349 return;
350 }
351
352 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
353 return;
354 }
355
356 pim_addr_change(ifp);
357 }
358
359 static void detect_address_change(struct interface *ifp,
360 int force_prim_as_any,
361 const char *caller)
362 {
363 int prim_changed;
364
365 prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
366 if (prim_changed) {
367 /* no need to detect secondary change because
368 the reaction would be the same */
369 return;
370 }
371
372 detect_secondary_address_change(ifp, caller);
373 }
374
375 void pim_if_addr_add(struct connected *ifc)
376 {
377 struct pim_interface *pim_ifp;
378 struct interface *ifp;
379 struct in_addr ifaddr;
380
381 zassert(ifc);
382
383 ifp = ifc->ifp;
384 zassert(ifp);
385 pim_ifp = ifp->info;
386 if (!pim_ifp)
387 return;
388
389 if (!if_is_operative(ifp))
390 return;
391
392 /* if (PIM_DEBUG_ZEBRA) */ {
393 char buf[BUFSIZ];
394 prefix2str(ifc->address, buf, BUFSIZ);
395 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
396 __PRETTY_FUNCTION__,
397 ifp->name, ifp->ifindex, buf,
398 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
399 "secondary" : "primary");
400 }
401
402 ifaddr = ifc->address->u.prefix4;
403
404 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
405
406 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
407 struct igmp_sock *igmp;
408
409 /* lookup IGMP socket */
410 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
411 ifaddr);
412 if (!igmp) {
413 /* if addr new, add IGMP socket */
414 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
415 }
416 } /* igmp */
417
418 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
419
420 /* Interface has a valid primary address ? */
421 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
422
423 /* Interface has a valid socket ? */
424 if (pim_ifp->pim_sock_fd < 0) {
425 if (pim_sock_add(ifp)) {
426 zlog_warn("Failure creating PIM socket for interface %s",
427 ifp->name);
428 }
429 }
430
431 }
432 } /* pim */
433
434 if (PIM_MROUTE_IS_ENABLED) {
435 /*
436 PIM or IGMP is enabled on interface, and there is at least one
437 address assigned, then try to create a vif_index.
438 */
439 if (pim_ifp->mroute_vif_index < 0) {
440 pim_if_add_vif(ifp);
441 }
442 }
443 }
444
445 static void pim_if_addr_del_igmp(struct connected *ifc)
446 {
447 struct pim_interface *pim_ifp = ifc->ifp->info;
448 struct igmp_sock *igmp;
449 struct in_addr ifaddr;
450
451 if (ifc->address->family != AF_INET) {
452 /* non-IPv4 address */
453 return;
454 }
455
456 if (!pim_ifp) {
457 /* IGMP not enabled on interface */
458 return;
459 }
460
461 ifaddr = ifc->address->u.prefix4;
462
463 /* lookup IGMP socket */
464 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
465 ifaddr);
466 if (igmp) {
467 /* if addr found, del IGMP socket */
468 igmp_sock_delete(igmp);
469 }
470 }
471
472 static void pim_if_addr_del_pim(struct connected *ifc)
473 {
474 struct pim_interface *pim_ifp = ifc->ifp->info;
475
476 if (ifc->address->family != AF_INET) {
477 /* non-IPv4 address */
478 return;
479 }
480
481 if (!pim_ifp) {
482 /* PIM not enabled on interface */
483 return;
484 }
485
486 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
487 /* Interface keeps a valid primary address */
488 return;
489 }
490
491 if (pim_ifp->pim_sock_fd < 0) {
492 /* Interface does not hold a valid socket any longer */
493 return;
494 }
495
496 /*
497 pim_sock_delete() closes the socket, stops read and timer threads,
498 and kills all neighbors.
499 */
500 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
501 }
502
503 void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
504 {
505 struct interface *ifp;
506
507 zassert(ifc);
508 ifp = ifc->ifp;
509 zassert(ifp);
510
511 /* if (PIM_DEBUG_ZEBRA) */ {
512 char buf[BUFSIZ];
513 prefix2str(ifc->address, buf, BUFSIZ);
514 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
515 __PRETTY_FUNCTION__,
516 ifp->name, ifp->ifindex, buf,
517 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
518 "secondary" : "primary");
519 }
520
521 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
522
523 pim_if_addr_del_igmp(ifc);
524 pim_if_addr_del_pim(ifc);
525 }
526
527 void pim_if_addr_add_all(struct interface *ifp)
528 {
529 struct connected *ifc;
530 struct listnode *node;
531 struct listnode *nextnode;
532
533 /* PIM/IGMP enabled ? */
534 if (!ifp->info)
535 return;
536
537 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
538 struct prefix *p = ifc->address;
539
540 if (p->family != AF_INET)
541 continue;
542
543 pim_if_addr_add(ifc);
544 }
545 }
546
547 void pim_if_addr_del_all(struct interface *ifp)
548 {
549 struct connected *ifc;
550 struct listnode *node;
551 struct listnode *nextnode;
552
553 /* PIM/IGMP enabled ? */
554 if (!ifp->info)
555 return;
556
557 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
558 struct prefix *p = ifc->address;
559
560 if (p->family != AF_INET)
561 continue;
562
563 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
564 }
565 }
566
567 void pim_if_addr_del_all_igmp(struct interface *ifp)
568 {
569 struct connected *ifc;
570 struct listnode *node;
571 struct listnode *nextnode;
572
573 /* PIM/IGMP enabled ? */
574 if (!ifp->info)
575 return;
576
577 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
578 struct prefix *p = ifc->address;
579
580 if (p->family != AF_INET)
581 continue;
582
583 pim_if_addr_del_igmp(ifc);
584 }
585 }
586
587 void pim_if_addr_del_all_pim(struct interface *ifp)
588 {
589 struct connected *ifc;
590 struct listnode *node;
591 struct listnode *nextnode;
592
593 /* PIM/IGMP enabled ? */
594 if (!ifp->info)
595 return;
596
597 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
598 struct prefix *p = ifc->address;
599
600 if (p->family != AF_INET)
601 continue;
602
603 pim_if_addr_del_pim(ifc);
604 }
605 }
606
607 static struct in_addr find_first_nonsec_addr(struct interface *ifp)
608 {
609 struct connected *ifc;
610 struct listnode *node;
611 struct in_addr addr;
612
613 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
614 struct prefix *p = ifc->address;
615
616 if (p->family != AF_INET)
617 continue;
618
619 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
620 zlog_warn("%s: null IPv4 address connected to interface %s",
621 __PRETTY_FUNCTION__, ifp->name);
622 continue;
623 }
624
625 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
626 continue;
627
628 return p->u.prefix4;
629 }
630
631 addr.s_addr = PIM_NET_INADDR_ANY;
632
633 return addr;
634 }
635
636 struct in_addr pim_find_primary_addr(struct interface *ifp)
637 {
638 return find_first_nonsec_addr(ifp);
639 }
640
641 /*
642 pim_if_add_vif() uses ifindex as vif_index
643
644 see also pim_if_find_vifindex_by_ifindex()
645 */
646 int pim_if_add_vif(struct interface *ifp)
647 {
648 struct pim_interface *pim_ifp = ifp->info;
649 struct in_addr ifaddr;
650
651 zassert(pim_ifp);
652
653 if (pim_ifp->mroute_vif_index > 0) {
654 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
655 __PRETTY_FUNCTION__,
656 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
657 return -1;
658 }
659
660 if (ifp->ifindex < 1) {
661 zlog_warn("%s: ifindex=%d < 1 on interface %s",
662 __PRETTY_FUNCTION__,
663 ifp->ifindex, ifp->name);
664 return -2;
665 }
666
667 if (ifp->ifindex >= MAXVIFS) {
668 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
669 __PRETTY_FUNCTION__,
670 ifp->ifindex, MAXVIFS, ifp->name);
671 return -3;
672 }
673
674 ifaddr = pim_ifp->primary_address;
675 if (PIM_INADDR_IS_ANY(ifaddr)) {
676 zlog_warn("%s: could not get address for interface %s ifindex=%d",
677 __PRETTY_FUNCTION__,
678 ifp->name, ifp->ifindex);
679 return -4;
680 }
681
682 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
683 /* pim_mroute_add_vif reported error */
684 return -5;
685 }
686
687 pim_ifp->mroute_vif_index = ifp->ifindex;
688
689 /*
690 Update highest vif_index
691 */
692 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
693 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
694 }
695
696 return 0;
697 }
698
699 static int iflist_find_highest_vif_index()
700 {
701 struct listnode *ifnode;
702 struct interface *ifp;
703 struct pim_interface *pim_ifp;
704 int highest_vif_index = -1;
705
706 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
707 pim_ifp = ifp->info;
708 if (!pim_ifp)
709 continue;
710
711 if (pim_ifp->mroute_vif_index > highest_vif_index) {
712 highest_vif_index = pim_ifp->mroute_vif_index;
713 }
714 }
715
716 return highest_vif_index;
717 }
718
719 int pim_if_del_vif(struct interface *ifp)
720 {
721 struct pim_interface *pim_ifp = ifp->info;
722 int old_vif_index;
723
724 if (pim_ifp->mroute_vif_index < 1) {
725 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
726 __PRETTY_FUNCTION__,
727 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
728 return -1;
729 }
730
731 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
732 /* pim_mroute_del_vif reported error */
733 return -2;
734 }
735
736 /*
737 Update highest vif_index
738 */
739
740 /* save old vif_index in order to compare with highest below */
741 old_vif_index = pim_ifp->mroute_vif_index;
742
743 pim_ifp->mroute_vif_index = -1;
744
745 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
746 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
747 }
748
749 return 0;
750 }
751
752 void pim_if_add_vif_all()
753 {
754 struct listnode *ifnode;
755 struct listnode *ifnextnode;
756 struct interface *ifp;
757
758 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
759 if (!ifp->info)
760 continue;
761
762 pim_if_add_vif(ifp);
763 }
764 }
765
766 void pim_if_del_vif_all()
767 {
768 struct listnode *ifnode;
769 struct listnode *ifnextnode;
770 struct interface *ifp;
771
772 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
773 if (!ifp->info)
774 continue;
775
776 pim_if_del_vif(ifp);
777 }
778 }
779
780 struct interface *pim_if_find_by_vif_index(int vif_index)
781 {
782 struct listnode *ifnode;
783 struct interface *ifp;
784
785 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
786 if (ifp->info) {
787 struct pim_interface *pim_ifp;
788 pim_ifp = ifp->info;
789 if (vif_index == pim_ifp->mroute_vif_index)
790 return ifp;
791 }
792 }
793
794 return 0;
795 }
796
797 /*
798 pim_if_add_vif() uses ifindex as vif_index
799 */
800 int pim_if_find_vifindex_by_ifindex(int ifindex)
801 {
802 return ifindex;
803 }
804
805 int pim_if_lan_delay_enabled(struct interface *ifp)
806 {
807 struct pim_interface *pim_ifp;
808
809 pim_ifp = ifp->info;
810 zassert(pim_ifp);
811 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
812
813 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
814 }
815
816 uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
817 {
818 if (pim_if_lan_delay_enabled(ifp)) {
819 struct pim_interface *pim_ifp;
820 pim_ifp = ifp->info;
821 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
822 }
823 else {
824 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
825 }
826 }
827
828 uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
829 {
830 if (pim_if_lan_delay_enabled(ifp)) {
831 struct pim_interface *pim_ifp;
832 pim_ifp = ifp->info;
833 return pim_ifp->pim_neighbors_highest_override_interval_msec;
834 }
835 else {
836 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
837 }
838 }
839
840 int pim_if_t_override_msec(struct interface *ifp)
841 {
842 int effective_override_interval_msec;
843 int t_override_msec;
844
845 effective_override_interval_msec =
846 pim_if_effective_override_interval_msec(ifp);
847
848 t_override_msec = pim_rand_next(0, effective_override_interval_msec);
849
850 return t_override_msec;
851 }
852
853 uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
854 {
855 return pim_if_effective_propagation_delay_msec(ifp) +
856 pim_if_effective_override_interval_msec(ifp);
857 }
858
859 /*
860 RFC 4601: 4.1.6. State Summarization Macros
861
862 The function NBR( I, A ) uses information gathered through PIM Hello
863 messages to map the IP address A of a directly connected PIM
864 neighbor router on interface I to the primary IP address of the same
865 router (Section 4.3.4). The primary IP address of a neighbor is the
866 address that it uses as the source of its PIM Hello messages.
867 */
868 struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
869 struct in_addr addr)
870 {
871 struct listnode *neighnode;
872 struct pim_neighbor *neigh;
873 struct pim_interface *pim_ifp;
874
875 zassert(ifp);
876
877 pim_ifp = ifp->info;
878 if (!pim_ifp) {
879 zlog_warn("%s: multicast not enabled on interface %s",
880 __PRETTY_FUNCTION__,
881 ifp->name);
882 return 0;
883 }
884
885 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
886
887 /* primary address ? */
888 if (neigh->source_addr.s_addr == addr.s_addr)
889 return neigh;
890
891 /* secondary address ? */
892 if (pim_neighbor_find_secondary(neigh, addr))
893 return neigh;
894 }
895
896 if (PIM_DEBUG_PIM_TRACE) {
897 char addr_str[100];
898 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
899 zlog_debug("%s: neighbor not found for address %s on interface %s",
900 __PRETTY_FUNCTION__,
901 addr_str, ifp->name);
902 }
903
904 return 0;
905 }
906
907 long pim_if_t_suppressed_msec(struct interface *ifp)
908 {
909 struct pim_interface *pim_ifp;
910 long t_suppressed_msec;
911
912 pim_ifp = ifp->info;
913 zassert(pim_ifp);
914
915 /* join suppression disabled ? */
916 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
917 return 0;
918
919 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
920
921 t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400);
922
923 return t_suppressed_msec;
924 }
925
926 static void igmp_join_free(struct igmp_join *ij)
927 {
928 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
929 }
930
931 static struct igmp_join *igmp_join_find(struct list *join_list,
932 struct in_addr group_addr,
933 struct in_addr source_addr)
934 {
935 struct listnode *node;
936 struct igmp_join *ij;
937
938 zassert(join_list);
939
940 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
941 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
942 (source_addr.s_addr == ij->source_addr.s_addr))
943 return ij;
944 }
945
946 return 0;
947 }
948
949 static int igmp_join_sock(const char *ifname,
950 int ifindex,
951 struct in_addr group_addr,
952 struct in_addr source_addr)
953 {
954 int join_fd;
955
956 join_fd = pim_socket_raw(IPPROTO_IGMP);
957 if (join_fd < 0) {
958 return -1;
959 }
960
961 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
962 close(join_fd);
963 return -2;
964 }
965
966 return join_fd;
967 }
968
969 static struct igmp_join *igmp_join_new(struct interface *ifp,
970 struct in_addr group_addr,
971 struct in_addr source_addr)
972 {
973 struct pim_interface *pim_ifp;
974 struct igmp_join *ij;
975 int join_fd;
976
977 pim_ifp = ifp->info;
978 zassert(pim_ifp);
979
980 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
981 if (join_fd < 0) {
982 char group_str[100];
983 char source_str[100];
984 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
985 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
986 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
987 __PRETTY_FUNCTION__,
988 group_str, source_str, ifp->name);
989 return 0;
990 }
991
992 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
993 if (!ij) {
994 char group_str[100];
995 char source_str[100];
996 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
997 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
998 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
999 __PRETTY_FUNCTION__,
1000 sizeof(*ij), group_str, source_str, ifp->name);
1001 close(join_fd);
1002 return 0;
1003 }
1004
1005 ij->sock_fd = join_fd;
1006 ij->group_addr = group_addr;
1007 ij->source_addr = source_addr;
1008 ij->sock_creation = pim_time_monotonic_sec();
1009
1010 listnode_add(pim_ifp->igmp_join_list, ij);
1011
1012 return ij;
1013 }
1014
1015 int pim_if_igmp_join_add(struct interface *ifp,
1016 struct in_addr group_addr,
1017 struct in_addr source_addr)
1018 {
1019 struct pim_interface *pim_ifp;
1020 struct igmp_join *ij;
1021
1022 pim_ifp = ifp->info;
1023 if (!pim_ifp) {
1024 zlog_warn("%s: multicast not enabled on interface %s",
1025 __PRETTY_FUNCTION__,
1026 ifp->name);
1027 return -1;
1028 }
1029
1030 if (!pim_ifp->igmp_join_list) {
1031 pim_ifp->igmp_join_list = list_new();
1032 if (!pim_ifp->igmp_join_list) {
1033 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1034 __FILE__, __PRETTY_FUNCTION__);
1035 return -2;
1036 }
1037 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1038 }
1039
1040 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1041 if (ij) {
1042 char group_str[100];
1043 char source_str[100];
1044 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1045 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1046 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1047 __PRETTY_FUNCTION__,
1048 group_str, source_str, ifp->name);
1049 return -3;
1050 }
1051
1052 ij = igmp_join_new(ifp, group_addr, source_addr);
1053 if (!ij) {
1054 char group_str[100];
1055 char source_str[100];
1056 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1057 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1058 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1059 __PRETTY_FUNCTION__,
1060 group_str, source_str, ifp->name);
1061 return -4;
1062 }
1063
1064 {
1065 char group_str[100];
1066 char source_str[100];
1067 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1068 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1069 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1070 __PRETTY_FUNCTION__,
1071 source_str, group_str, ifp->name);
1072 }
1073
1074 return 0;
1075 }
1076
1077
1078
1079 int pim_if_igmp_join_del(struct interface *ifp,
1080 struct in_addr group_addr,
1081 struct in_addr source_addr)
1082 {
1083 struct pim_interface *pim_ifp;
1084 struct igmp_join *ij;
1085
1086 pim_ifp = ifp->info;
1087 if (!pim_ifp) {
1088 zlog_warn("%s: multicast not enabled on interface %s",
1089 __PRETTY_FUNCTION__,
1090 ifp->name);
1091 return -1;
1092 }
1093
1094 if (!pim_ifp->igmp_join_list) {
1095 zlog_warn("%s: no IGMP join on interface %s",
1096 __PRETTY_FUNCTION__,
1097 ifp->name);
1098 return -2;
1099 }
1100
1101 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1102 if (!ij) {
1103 char group_str[100];
1104 char source_str[100];
1105 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1106 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1107 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1108 __PRETTY_FUNCTION__,
1109 group_str, source_str, ifp->name);
1110 return -3;
1111 }
1112
1113 if (close(ij->sock_fd)) {
1114 int e = errno;
1115 char group_str[100];
1116 char source_str[100];
1117 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1118 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1119 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1120 __PRETTY_FUNCTION__,
1121 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
1122 /* warning only */
1123 }
1124 listnode_delete(pim_ifp->igmp_join_list, ij);
1125 igmp_join_free(ij);
1126 if (listcount(pim_ifp->igmp_join_list) < 1) {
1127 list_delete(pim_ifp->igmp_join_list);
1128 pim_ifp->igmp_join_list = 0;
1129 }
1130
1131 return 0;
1132 }
1133
1134 static void pim_if_igmp_join_del_all(struct interface *ifp)
1135 {
1136 struct pim_interface *pim_ifp;
1137 struct listnode *node;
1138 struct listnode *nextnode;
1139 struct igmp_join *ij;
1140
1141 pim_ifp = ifp->info;
1142 if (!pim_ifp) {
1143 zlog_warn("%s: multicast not enabled on interface %s",
1144 __PRETTY_FUNCTION__,
1145 ifp->name);
1146 return;
1147 }
1148
1149 if (!pim_ifp->igmp_join_list)
1150 return;
1151
1152 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1153 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1154 }
1155
1156 /*
1157 RFC 4601
1158
1159 Transitions from "I am Assert Loser" State
1160
1161 Current Winner's GenID Changes or NLT Expires
1162
1163 The Neighbor Liveness Timer associated with the current winner
1164 expires or we receive a Hello message from the current winner
1165 reporting a different GenID from the one it previously reported.
1166 This indicates that the current winner's interface or router has
1167 gone down (and may have come back up), and so we must assume it no
1168 longer knows it was the winner.
1169 */
1170 void pim_if_assert_on_neighbor_down(struct interface *ifp,
1171 struct in_addr neigh_addr)
1172 {
1173 struct pim_interface *pim_ifp;
1174 struct listnode *node;
1175 struct listnode *next_node;
1176 struct pim_ifchannel *ch;
1177
1178 pim_ifp = ifp->info;
1179 zassert(pim_ifp);
1180
1181 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1182 /* Is (S,G,I) assert loser ? */
1183 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1184 continue;
1185 /* Dead neighbor was winner ? */
1186 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1187 continue;
1188
1189 assert_action_a5(ch);
1190 }
1191 }
1192
1193 void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1194 {
1195 struct listnode *ch_node;
1196 struct pim_ifchannel *ch;
1197
1198 /* clear off flag from interface's upstreams */
1199 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1200 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1201 }
1202
1203 /* scan per-interface (S,G,I) state on this I interface */
1204 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1205 struct pim_upstream *up = ch->upstream;
1206
1207 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1208 continue;
1209
1210 /* update join_desired for the global (S,G) state */
1211 pim_upstream_update_join_desired(up);
1212 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1213 }
1214 }
1215
1216 void pim_if_update_assert_tracking_desired(struct interface *ifp)
1217 {
1218 struct pim_interface *pim_ifp;
1219 struct listnode *node;
1220 struct listnode *next_node;
1221 struct pim_ifchannel *ch;
1222
1223 pim_ifp = ifp->info;
1224 if (!pim_ifp)
1225 return;
1226
1227 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1228 pim_ifchannel_update_assert_tracking_desired(ch);
1229 }
1230 }