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