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