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