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