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