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