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