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