Line data Source code
1 : /*
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 : */
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"
26 : #include "vrf.h"
27 : #include "linklist.h"
28 : #include "plist.h"
29 : #include "hash.h"
30 : #include "ferr.h"
31 : #include "network.h"
32 :
33 : #include "pimd.h"
34 : #include "pim_instance.h"
35 : #include "pim_zebra.h"
36 : #include "pim_iface.h"
37 : #include "pim_igmp.h"
38 : #include "pim_mroute.h"
39 : #include "pim_oil.h"
40 : #include "pim_str.h"
41 : #include "pim_pim.h"
42 : #include "pim_neighbor.h"
43 : #include "pim_ifchannel.h"
44 : #include "pim_sock.h"
45 : #include "pim_time.h"
46 : #include "pim_ssmpingd.h"
47 : #include "pim_rp.h"
48 : #include "pim_nht.h"
49 : #include "pim_jp_agg.h"
50 : #include "pim_igmp_join.h"
51 : #include "pim_vxlan.h"
52 :
53 : #include "pim6_mld.h"
54 :
55 : #if PIM_IPV == 4
56 : static void pim_if_igmp_join_del_all(struct interface *ifp);
57 : static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
58 : struct in_addr group_addr, struct in_addr source_addr,
59 : struct pim_interface *pim_ifp);
60 : #endif
61 :
62 4 : void pim_if_init(struct pim_instance *pim)
63 : {
64 4 : int i;
65 :
66 132 : for (i = 0; i < MAXVIFS; i++)
67 128 : pim->iface_vif_index[i] = 0;
68 4 : }
69 :
70 4 : void pim_if_terminate(struct pim_instance *pim)
71 : {
72 4 : struct interface *ifp;
73 :
74 22 : FOR_ALL_INTERFACES (pim->vrf, ifp) {
75 14 : struct pim_interface *pim_ifp = ifp->info;
76 :
77 14 : if (!pim_ifp)
78 4 : continue;
79 :
80 10 : pim_if_delete(ifp);
81 : }
82 4 : return;
83 : }
84 :
85 0 : static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
86 : {
87 0 : XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
88 0 : }
89 :
90 : __attribute__((unused))
91 0 : static int pim_sec_addr_comp(const void *p1, const void *p2)
92 : {
93 0 : const struct pim_secondary_addr *sec1 = p1;
94 0 : const struct pim_secondary_addr *sec2 = p2;
95 :
96 0 : if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6)
97 : return -1;
98 :
99 0 : if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET)
100 : return 1;
101 :
102 0 : if (sec1->addr.family == AF_INET) {
103 0 : if (ntohl(sec1->addr.u.prefix4.s_addr)
104 0 : < ntohl(sec2->addr.u.prefix4.s_addr))
105 : return -1;
106 :
107 0 : if (ntohl(sec1->addr.u.prefix4.s_addr)
108 0 : > ntohl(sec2->addr.u.prefix4.s_addr))
109 0 : return 1;
110 : } else {
111 0 : return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6,
112 : sizeof(struct in6_addr));
113 : }
114 :
115 : return 0;
116 : }
117 :
118 10 : struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
119 : bool ispimreg, bool is_vxlan_term)
120 : {
121 10 : struct pim_interface *pim_ifp;
122 :
123 10 : assert(ifp);
124 10 : assert(!ifp->info);
125 :
126 10 : pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
127 :
128 10 : pim_ifp->pim = ifp->vrf->info;
129 10 : pim_ifp->mroute_vif_index = -1;
130 :
131 10 : pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
132 10 : pim_ifp->mld_version = MLD_DEFAULT_VERSION;
133 10 : pim_ifp->gm_default_robustness_variable =
134 : GM_DEFAULT_ROBUSTNESS_VARIABLE;
135 10 : pim_ifp->gm_default_query_interval = GM_GENERAL_QUERY_INTERVAL;
136 10 : pim_ifp->gm_query_max_response_time_dsec =
137 : GM_QUERY_MAX_RESPONSE_TIME_DSEC;
138 10 : pim_ifp->gm_specific_query_max_response_time_dsec =
139 : GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
140 10 : pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE;
141 :
142 : /* BSM config on interface: true by default */
143 10 : pim_ifp->bsm_enable = true;
144 10 : pim_ifp->ucast_bsm_accept = true;
145 10 : pim_ifp->am_i_dr = false;
146 :
147 : /*
148 : RFC 3376: 8.3. Query Response Interval
149 : The number of seconds represented by the [Query Response Interval]
150 : must be less than the [Query Interval].
151 : */
152 10 : assert(pim_ifp->gm_query_max_response_time_dsec <
153 : pim_ifp->gm_default_query_interval);
154 :
155 10 : pim_ifp->pim_enable = pim;
156 10 : pim_ifp->pim_passive_enable = false;
157 10 : pim_ifp->gm_enable = gm;
158 :
159 10 : pim_ifp->gm_join_list = NULL;
160 10 : pim_ifp->pim_neighbor_list = NULL;
161 10 : pim_ifp->upstream_switch_list = NULL;
162 10 : pim_ifp->pim_generation_id = 0;
163 :
164 : /* list of struct gm_sock */
165 10 : pim_igmp_if_init(pim_ifp, ifp);
166 :
167 : /* list of struct pim_neighbor */
168 10 : pim_ifp->pim_neighbor_list = list_new();
169 10 : pim_ifp->pim_neighbor_list->del = (void (*)(void *))pim_neighbor_free;
170 :
171 10 : pim_ifp->upstream_switch_list = list_new();
172 10 : pim_ifp->upstream_switch_list->del =
173 : (void (*)(void *))pim_jp_agg_group_list_free;
174 10 : pim_ifp->upstream_switch_list->cmp = pim_jp_agg_group_list_cmp;
175 :
176 10 : pim_ifp->sec_addr_list = list_new();
177 10 : pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
178 10 : pim_ifp->sec_addr_list->cmp =
179 : (int (*)(void *, void *))pim_sec_addr_comp;
180 :
181 10 : pim_ifp->activeactive = false;
182 :
183 10 : RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
184 :
185 10 : ifp->info = pim_ifp;
186 :
187 10 : pim_sock_reset(ifp);
188 :
189 10 : pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
190 10 : pim_ifp->pim->mcast_if_count++;
191 :
192 10 : return pim_ifp;
193 : }
194 :
195 10 : void pim_if_delete(struct interface *ifp)
196 : {
197 10 : struct pim_interface *pim_ifp;
198 :
199 10 : assert(ifp);
200 10 : pim_ifp = ifp->info;
201 10 : assert(pim_ifp);
202 :
203 10 : pim_ifp->pim->mcast_if_count--;
204 : #if PIM_IPV == 4
205 10 : if (pim_ifp->gm_join_list) {
206 0 : pim_if_igmp_join_del_all(ifp);
207 : }
208 : #endif
209 :
210 10 : pim_ifchannel_delete_all(ifp);
211 : #if PIM_IPV == 4
212 10 : igmp_sock_delete_all(ifp);
213 : #endif
214 10 : if (pim_ifp->pim_sock_fd >= 0)
215 6 : pim_sock_delete(ifp, "Interface removed from configuration");
216 :
217 10 : pim_if_del_vif(ifp);
218 :
219 10 : pim_igmp_if_fini(pim_ifp);
220 :
221 10 : list_delete(&pim_ifp->pim_neighbor_list);
222 10 : list_delete(&pim_ifp->upstream_switch_list);
223 10 : list_delete(&pim_ifp->sec_addr_list);
224 :
225 10 : if (pim_ifp->bfd_config.profile)
226 1 : XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
227 :
228 10 : XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
229 10 : XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
230 :
231 10 : ifp->info = NULL;
232 10 : }
233 :
234 57 : void pim_if_update_could_assert(struct interface *ifp)
235 : {
236 57 : struct pim_interface *pim_ifp;
237 57 : struct pim_ifchannel *ch;
238 :
239 57 : pim_ifp = ifp->info;
240 57 : assert(pim_ifp);
241 :
242 114 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
243 0 : pim_ifchannel_update_could_assert(ch);
244 : }
245 57 : }
246 :
247 27 : static void pim_if_update_my_assert_metric(struct interface *ifp)
248 : {
249 27 : struct pim_interface *pim_ifp;
250 27 : struct pim_ifchannel *ch;
251 :
252 27 : pim_ifp = ifp->info;
253 27 : assert(pim_ifp);
254 :
255 54 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
256 0 : pim_ifchannel_update_my_assert_metric(ch);
257 : }
258 27 : }
259 :
260 27 : static void pim_addr_change(struct interface *ifp)
261 : {
262 27 : struct pim_interface *pim_ifp;
263 :
264 27 : pim_ifp = ifp->info;
265 27 : assert(pim_ifp);
266 :
267 27 : pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes --
268 : Done TODO T30 */
269 27 : pim_if_update_join_desired(pim_ifp); /* depends on DR */
270 27 : pim_if_update_could_assert(ifp); /* depends on DR */
271 27 : pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
272 27 : pim_if_update_assert_tracking_desired(
273 : ifp); /* depends on DR, join_desired */
274 :
275 : /*
276 : RFC 4601: 4.3.1. Sending Hello Messages
277 :
278 : 1) Before an interface goes down or changes primary IP address, a
279 : Hello message with a zero HoldTime should be sent immediately
280 : (with the old IP address if the IP address changed).
281 : -- Done at the caller of the function as new ip already updated here
282 :
283 : 2) After an interface has changed its IP address, it MUST send a
284 : Hello message with its new IP address.
285 : -- DONE below
286 :
287 : 3) If an interface changes one of its secondary IP addresses, a
288 : Hello message with an updated Address_List option and a non-zero
289 : HoldTime should be sent immediately.
290 : -- FIXME See TODO T31
291 : */
292 27 : PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
293 27 : if (pim_ifp->pim_sock_fd < 0)
294 : return;
295 7 : pim_hello_restart_now(ifp); /* send hello and restart timer */
296 : }
297 :
298 95 : static int detect_primary_address_change(struct interface *ifp,
299 : int force_prim_as_any,
300 : const char *caller)
301 : {
302 95 : struct pim_interface *pim_ifp = ifp->info;
303 95 : pim_addr new_prim_addr;
304 95 : int changed;
305 :
306 95 : if (force_prim_as_any)
307 7 : new_prim_addr = PIMADDR_ANY;
308 : else
309 88 : new_prim_addr = pim_find_primary_addr(ifp);
310 :
311 95 : changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address);
312 :
313 95 : if (PIM_DEBUG_ZEBRA)
314 0 : zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s",
315 : __func__, &pim_ifp->primary_address, &new_prim_addr,
316 : ifp->name, changed ? "changed" : "unchanged");
317 :
318 95 : if (changed) {
319 : /* Before updating pim_ifp send Hello time with 0 hold time */
320 27 : if (pim_ifp->pim_enable) {
321 27 : pim_hello_send(ifp, 0 /* zero-sec holdtime */);
322 : }
323 27 : pim_ifp->primary_address = new_prim_addr;
324 : }
325 :
326 95 : return changed;
327 : }
328 :
329 : static struct pim_secondary_addr *
330 0 : pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
331 : {
332 0 : struct pim_secondary_addr *sec_addr;
333 0 : struct listnode *node;
334 :
335 0 : for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
336 0 : if (prefix_cmp(&sec_addr->addr, addr) == 0) {
337 0 : return sec_addr;
338 : }
339 : }
340 :
341 : return NULL;
342 : }
343 :
344 0 : static void pim_sec_addr_del(struct pim_interface *pim_ifp,
345 : struct pim_secondary_addr *sec_addr)
346 : {
347 0 : listnode_delete(pim_ifp->sec_addr_list, sec_addr);
348 0 : pim_sec_addr_free(sec_addr);
349 0 : }
350 :
351 0 : static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
352 : {
353 0 : int changed = 0;
354 0 : struct pim_secondary_addr *sec_addr;
355 :
356 0 : sec_addr = pim_sec_addr_find(pim_ifp, addr);
357 0 : if (sec_addr) {
358 0 : sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
359 0 : return changed;
360 : }
361 :
362 0 : sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
363 :
364 0 : changed = 1;
365 0 : sec_addr->addr = *addr;
366 0 : listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
367 :
368 0 : return changed;
369 : }
370 :
371 7 : static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
372 : {
373 7 : int changed = 0;
374 :
375 7 : if (!list_isempty(pim_ifp->sec_addr_list)) {
376 0 : changed = 1;
377 : /* remove all nodes and free up the list itself */
378 0 : list_delete_all_node(pim_ifp->sec_addr_list);
379 : }
380 :
381 7 : return changed;
382 : }
383 :
384 88 : static int pim_sec_addr_update(struct interface *ifp)
385 : {
386 88 : struct pim_interface *pim_ifp = ifp->info;
387 88 : struct connected *ifc;
388 88 : struct listnode *node;
389 88 : struct listnode *nextnode;
390 88 : struct pim_secondary_addr *sec_addr;
391 88 : int changed = 0;
392 :
393 176 : for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
394 0 : sec_addr->flags |= PIM_SEC_ADDRF_STALE;
395 : }
396 :
397 340 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
398 164 : pim_addr addr = pim_addr_from_prefix(ifc->address);
399 :
400 164 : if (pim_addr_is_any(addr))
401 83 : continue;
402 :
403 81 : if (!pim_addr_cmp(addr, pim_ifp->primary_address)) {
404 : /* don't add the primary address into the secondary
405 : * address list */
406 81 : continue;
407 : }
408 :
409 0 : if (pim_sec_addr_add(pim_ifp, ifc->address)) {
410 164 : changed = 1;
411 : }
412 : }
413 :
414 : /* Drop stale entries */
415 176 : for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode,
416 : sec_addr)) {
417 0 : if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
418 0 : pim_sec_addr_del(pim_ifp, sec_addr);
419 0 : changed = 1;
420 : }
421 : }
422 :
423 88 : return changed;
424 : }
425 :
426 95 : static int detect_secondary_address_change(struct interface *ifp,
427 : int force_prim_as_any,
428 : const char *caller)
429 : {
430 95 : struct pim_interface *pim_ifp = ifp->info;
431 95 : int changed = 0;
432 :
433 95 : if (force_prim_as_any) {
434 : /* if primary address is being forced to zero just flush the
435 : * secondary address list */
436 7 : changed = pim_sec_addr_del_all(pim_ifp);
437 : } else {
438 : /* re-evaluate the secondary address list */
439 88 : changed = pim_sec_addr_update(ifp);
440 : }
441 :
442 95 : return changed;
443 : }
444 :
445 95 : static void detect_address_change(struct interface *ifp, int force_prim_as_any,
446 : const char *caller)
447 : {
448 95 : int changed = 0;
449 95 : struct pim_interface *pim_ifp;
450 :
451 95 : pim_ifp = ifp->info;
452 95 : if (!pim_ifp)
453 : return;
454 :
455 95 : if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
456 27 : changed = 1;
457 : }
458 :
459 95 : if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
460 : changed = 1;
461 : }
462 :
463 :
464 95 : if (changed) {
465 27 : if (!pim_ifp->pim_enable) {
466 : return;
467 : }
468 :
469 27 : pim_addr_change(ifp);
470 : }
471 :
472 : /* XXX: if we have unnumbered interfaces we need to run detect address
473 : * address change on all of them when the lo address changes */
474 : }
475 :
476 0 : int pim_update_source_set(struct interface *ifp, pim_addr source)
477 : {
478 0 : struct pim_interface *pim_ifp = ifp->info;
479 :
480 0 : if (!pim_ifp) {
481 : return PIM_IFACE_NOT_FOUND;
482 : }
483 :
484 0 : if (!pim_addr_cmp(pim_ifp->update_source, source)) {
485 : return PIM_UPDATE_SOURCE_DUP;
486 : }
487 :
488 0 : pim_ifp->update_source = source;
489 0 : detect_address_change(ifp, 0 /* force_prim_as_any */, __func__);
490 :
491 0 : return PIM_SUCCESS;
492 : }
493 :
494 97 : void pim_if_addr_add(struct connected *ifc)
495 : {
496 97 : struct pim_interface *pim_ifp;
497 97 : struct interface *ifp;
498 97 : bool vxlan_term;
499 :
500 97 : assert(ifc);
501 :
502 97 : ifp = ifc->ifp;
503 97 : assert(ifp);
504 97 : pim_ifp = ifp->info;
505 97 : if (!pim_ifp)
506 16 : return;
507 :
508 81 : if (!if_is_operative(ifp))
509 : return;
510 :
511 81 : if (PIM_DEBUG_ZEBRA)
512 0 : zlog_debug("%s: %s ifindex=%d connected IP address %pFX %s",
513 : __func__, ifp->name, ifp->ifindex, ifc->address,
514 : CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
515 : ? "secondary"
516 : : "primary");
517 : #if PIM_IPV != 4
518 : if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
519 : IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
520 : if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
521 : pim_ifp->ll_lowest = ifc->address->u.prefix6;
522 : else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
523 : &pim_ifp->ll_lowest) < 0)
524 : pim_ifp->ll_lowest = ifc->address->u.prefix6;
525 :
526 : if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
527 : &pim_ifp->ll_highest) > 0)
528 : pim_ifp->ll_highest = ifc->address->u.prefix6;
529 :
530 : if (PIM_DEBUG_ZEBRA)
531 : zlog_debug(
532 : "%s: new link-local %pI6, lowest now %pI6, highest %pI6",
533 : ifc->ifp->name, &ifc->address->u.prefix6,
534 : &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
535 : }
536 : #endif
537 :
538 81 : detect_address_change(ifp, 0, __func__);
539 :
540 : // if (ifc->address->family != AF_INET)
541 : // return;
542 :
543 : #if PIM_IPV == 4
544 81 : struct in_addr ifaddr = ifc->address->u.prefix4;
545 :
546 81 : if (pim_ifp->gm_enable) {
547 0 : struct gm_sock *igmp;
548 :
549 : /* lookup IGMP socket */
550 0 : igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
551 : ifaddr);
552 0 : if (!igmp) {
553 : /* if addr new, add IGMP socket */
554 0 : if (ifc->address->family == AF_INET)
555 0 : pim_igmp_sock_add(pim_ifp->gm_socket_list,
556 : ifaddr, ifp, false);
557 0 : } else if (igmp->mtrace_only) {
558 0 : igmp_sock_delete(igmp);
559 0 : pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
560 : false);
561 : }
562 :
563 : /* Replay Static IGMP groups */
564 0 : if (pim_ifp->gm_join_list) {
565 0 : struct listnode *node;
566 0 : struct listnode *nextnode;
567 0 : struct gm_join *ij;
568 0 : int join_fd;
569 :
570 0 : for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node,
571 : nextnode, ij)) {
572 : /* Close socket and reopen with Source and Group
573 : */
574 0 : close(ij->sock_fd);
575 0 : join_fd = igmp_join_sock(
576 0 : ifp->name, ifp->ifindex, ij->group_addr,
577 : ij->source_addr, pim_ifp);
578 0 : if (join_fd < 0) {
579 0 : char group_str[INET_ADDRSTRLEN];
580 0 : char source_str[INET_ADDRSTRLEN];
581 0 : pim_inet4_dump("<grp?>", ij->group_addr,
582 : group_str,
583 : sizeof(group_str));
584 0 : pim_inet4_dump(
585 : "<src?>", ij->source_addr,
586 : source_str, sizeof(source_str));
587 0 : zlog_warn(
588 : "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
589 : __func__, group_str, source_str,
590 : ifp->name);
591 : /* warning only */
592 : } else
593 0 : ij->sock_fd = join_fd;
594 : }
595 : }
596 : } /* igmp */
597 : else {
598 81 : struct gm_sock *igmp;
599 :
600 : /* lookup IGMP socket */
601 81 : igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
602 : ifaddr);
603 81 : if (ifc->address->family == AF_INET) {
604 37 : if (igmp)
605 24 : igmp_sock_delete(igmp);
606 : /* if addr new, add IGMP socket */
607 37 : pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
608 : true);
609 : }
610 : } /* igmp mtrace only */
611 : #endif
612 :
613 81 : if (pim_ifp->pim_enable) {
614 :
615 81 : if (!pim_addr_is_any(pim_ifp->primary_address)) {
616 :
617 : /* Interface has a valid socket ? */
618 81 : if (pim_ifp->pim_sock_fd < 0) {
619 13 : if (pim_sock_add(ifp)) {
620 0 : zlog_warn(
621 : "Failure creating PIM socket for interface %s",
622 : ifp->name);
623 : }
624 : }
625 81 : struct pim_nexthop_cache *pnc = NULL;
626 81 : struct pim_rpf rpf;
627 81 : struct zclient *zclient = NULL;
628 :
629 81 : zclient = pim_zebra_zclient_get();
630 : /* RP config might come prior to (local RP's interface)
631 : IF UP event.
632 : In this case, pnc would not have pim enabled
633 : nexthops.
634 : Once Interface is UP and pim info is available,
635 : reregister
636 : with RNH address to receive update and add the
637 : interface as nexthop. */
638 81 : memset(&rpf, 0, sizeof(struct pim_rpf));
639 81 : rpf.rpf_addr = pim_addr_from_prefix(ifc->address);
640 81 : pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf);
641 81 : if (pnc)
642 0 : pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient,
643 : pnc,
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 81 : if (pim_ifp->mroute_vif_index < 0) {
653 6 : vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
654 6 : pim_if_add_vif(ifp, false, vxlan_term);
655 : }
656 81 : gm_ifp_update(ifp);
657 81 : pim_ifchannel_scan_forward_start(ifp);
658 : }
659 :
660 14 : static void pim_if_addr_del_igmp(struct connected *ifc)
661 : {
662 : #if PIM_IPV == 4
663 14 : struct pim_interface *pim_ifp = ifc->ifp->info;
664 14 : struct gm_sock *igmp;
665 14 : struct in_addr ifaddr;
666 :
667 14 : if (ifc->address->family != AF_INET) {
668 : /* non-IPv4 address */
669 0 : return;
670 : }
671 :
672 14 : if (!pim_ifp) {
673 : /* IGMP not enabled on interface */
674 : return;
675 : }
676 :
677 14 : ifaddr = ifc->address->u.prefix4;
678 :
679 : /* lookup IGMP socket */
680 14 : igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
681 14 : if (igmp) {
682 : /* if addr found, del IGMP socket */
683 7 : igmp_sock_delete(igmp);
684 : }
685 : #endif
686 : }
687 :
688 14 : static void pim_if_addr_del_pim(struct connected *ifc)
689 : {
690 14 : struct pim_interface *pim_ifp = ifc->ifp->info;
691 :
692 14 : if (ifc->address->family != PIM_AF) {
693 : /* non-IPv4 address */
694 : return;
695 : }
696 :
697 14 : if (!pim_ifp) {
698 : /* PIM not enabled on interface */
699 : return;
700 : }
701 :
702 14 : if (!pim_addr_is_any(pim_ifp->primary_address)) {
703 : /* Interface keeps a valid primary address */
704 : return;
705 : }
706 :
707 7 : if (pim_ifp->pim_sock_fd < 0) {
708 : /* Interface does not hold a valid socket any longer */
709 : return;
710 : }
711 :
712 : /*
713 : pim_sock_delete() closes the socket, stops read and timer threads,
714 : and kills all neighbors.
715 : */
716 7 : pim_sock_delete(ifc->ifp,
717 : "last address has been removed from interface");
718 : }
719 :
720 14 : void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
721 : {
722 14 : struct interface *ifp;
723 :
724 14 : assert(ifc);
725 14 : ifp = ifc->ifp;
726 14 : assert(ifp);
727 :
728 14 : if (PIM_DEBUG_ZEBRA)
729 0 : zlog_debug("%s: %s ifindex=%d disconnected IP address %pFX %s",
730 : __func__, ifp->name, ifp->ifindex, ifc->address,
731 : CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
732 : ? "secondary"
733 : : "primary");
734 :
735 : #if PIM_IPV == 6
736 : struct pim_interface *pim_ifp = ifc->ifp->info;
737 :
738 : if (pim_ifp &&
739 : (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
740 : !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
741 : struct listnode *cnode;
742 : struct connected *cc;
743 :
744 : memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
745 : memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
746 :
747 : for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
748 : if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
749 : !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
750 : continue;
751 :
752 : if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
753 : &pim_ifp->ll_lowest) < 0)
754 : pim_ifp->ll_lowest = cc->address->u.prefix6;
755 : if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
756 : &pim_ifp->ll_highest) > 0)
757 : pim_ifp->ll_highest = cc->address->u.prefix6;
758 : }
759 :
760 : if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
761 : memset(&pim_ifp->ll_lowest, 0,
762 : sizeof(pim_ifp->ll_lowest));
763 :
764 : if (PIM_DEBUG_ZEBRA)
765 : zlog_debug(
766 : "%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
767 : ifc->ifp->name, &ifc->address->u.prefix6,
768 : &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
769 :
770 : gm_ifp_update(ifp);
771 : }
772 : #endif
773 :
774 14 : detect_address_change(ifp, force_prim_as_any, __func__);
775 :
776 14 : pim_if_addr_del_igmp(ifc);
777 14 : pim_if_addr_del_pim(ifc);
778 14 : }
779 :
780 49 : void pim_if_addr_add_all(struct interface *ifp)
781 : {
782 49 : struct connected *ifc;
783 49 : struct listnode *node;
784 49 : struct listnode *nextnode;
785 49 : int v4_addrs = 0;
786 49 : int v6_addrs = 0;
787 49 : struct pim_interface *pim_ifp = ifp->info;
788 49 : bool vxlan_term;
789 :
790 :
791 : /* PIM/IGMP enabled ? */
792 49 : if (!pim_ifp)
793 : return;
794 :
795 118 : for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
796 36 : struct prefix *p = ifc->address;
797 :
798 36 : if (p->family != AF_INET)
799 18 : v6_addrs++;
800 : else
801 18 : v4_addrs++;
802 36 : pim_if_addr_add(ifc);
803 : }
804 :
805 41 : if (!v4_addrs && v6_addrs && !if_is_loopback(ifp) &&
806 0 : pim_ifp->pim_enable && !pim_addr_is_any(pim_ifp->primary_address) &&
807 0 : pim_ifp->pim_sock_fd < 0 && pim_sock_add(ifp)) {
808 : /* Interface has a valid primary address ? */
809 : /* Interface has a valid socket ? */
810 0 : zlog_warn("Failure creating PIM socket for interface %s",
811 : ifp->name);
812 : }
813 : /*
814 : * PIM or IGMP/MLD is enabled on interface, and there is at least one
815 : * address assigned, then try to create a vif_index.
816 : */
817 41 : if (pim_ifp->mroute_vif_index < 0) {
818 19 : vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
819 19 : pim_if_add_vif(ifp, false, vxlan_term);
820 : }
821 41 : gm_ifp_update(ifp);
822 41 : pim_ifchannel_scan_forward_start(ifp);
823 :
824 41 : pim_rp_setup(pim_ifp->pim);
825 41 : pim_rp_check_on_if_add(pim_ifp);
826 : }
827 :
828 7 : void pim_if_addr_del_all(struct interface *ifp)
829 : {
830 7 : struct connected *ifc;
831 7 : struct listnode *node;
832 7 : struct listnode *nextnode;
833 7 : struct pim_instance *pim;
834 :
835 7 : pim = ifp->vrf->info;
836 7 : if (!pim)
837 : return;
838 :
839 : /* PIM/IGMP enabled ? */
840 7 : if (!ifp->info)
841 : return;
842 :
843 29 : for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
844 15 : struct prefix *p = ifc->address;
845 :
846 15 : if (p->family != PIM_AF)
847 8 : continue;
848 :
849 7 : pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
850 : }
851 :
852 7 : pim_rp_setup(pim);
853 7 : pim_i_am_rp_re_evaluate(pim);
854 : }
855 :
856 0 : void pim_if_addr_del_all_igmp(struct interface *ifp)
857 : {
858 0 : struct connected *ifc;
859 0 : struct listnode *node;
860 0 : struct listnode *nextnode;
861 :
862 : /* PIM/IGMP enabled ? */
863 0 : if (!ifp->info)
864 : return;
865 :
866 0 : for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
867 0 : struct prefix *p = ifc->address;
868 :
869 0 : if (p->family != AF_INET)
870 0 : continue;
871 :
872 0 : pim_if_addr_del_igmp(ifc);
873 : }
874 : }
875 :
876 125 : pim_addr pim_find_primary_addr(struct interface *ifp)
877 : {
878 132 : struct connected *ifc;
879 132 : struct listnode *node;
880 132 : struct pim_interface *pim_ifp = ifp->info;
881 :
882 132 : if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
883 0 : return pim_ifp->update_source;
884 :
885 : #if PIM_IPV == 6
886 : if (pim_ifp && !pim_addr_is_any(pim_ifp->ll_highest))
887 : return pim_ifp->ll_highest;
888 :
889 : pim_addr best_addr = PIMADDR_ANY;
890 :
891 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
892 : pim_addr addr;
893 :
894 : if (ifc->address->family != AF_INET6)
895 : continue;
896 :
897 : addr = pim_addr_from_prefix(ifc->address);
898 : if (!IN6_IS_ADDR_LINKLOCAL(&addr))
899 : continue;
900 : if (pim_addr_cmp(addr, best_addr) > 0)
901 : best_addr = addr;
902 : }
903 :
904 : return best_addr;
905 : #else
906 132 : int v4_addrs = 0;
907 132 : int v6_addrs = 0;
908 :
909 272 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
910 123 : switch (ifc->address->family) {
911 115 : case AF_INET:
912 115 : v4_addrs++;
913 115 : break;
914 8 : case AF_INET6:
915 8 : v6_addrs++;
916 8 : break;
917 0 : default:
918 0 : continue;
919 : }
920 :
921 123 : if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
922 8 : continue;
923 :
924 115 : if (ifc->address->family != PIM_AF)
925 0 : continue;
926 :
927 115 : return pim_addr_from_prefix(ifc->address);
928 : }
929 :
930 : /*
931 : * If we have no v4_addrs and v6 is configured
932 : * We probably are using unnumbered
933 : * So let's grab the loopbacks v4 address
934 : * and use that as the primary address
935 : */
936 17 : if (!v4_addrs && v6_addrs) {
937 7 : struct interface *lo_ifp;
938 :
939 : // DBS - Come back and check here
940 7 : if (ifp->vrf->vrf_id == VRF_DEFAULT)
941 7 : lo_ifp = if_lookup_by_name("lo", ifp->vrf->vrf_id);
942 : else
943 0 : lo_ifp = if_lookup_by_name(ifp->vrf->name,
944 : ifp->vrf->vrf_id);
945 :
946 7 : if (lo_ifp && (lo_ifp != ifp))
947 : return pim_find_primary_addr(lo_ifp);
948 : }
949 10 : return PIMADDR_ANY;
950 : #endif
951 : }
952 :
953 17 : static int pim_iface_next_vif_index(struct interface *ifp)
954 : {
955 17 : struct pim_interface *pim_ifp = ifp->info;
956 17 : struct pim_instance *pim = pim_ifp->pim;
957 17 : int i;
958 :
959 : /*
960 : * The pimreg vif is always going to be in index 0
961 : * of the table.
962 : */
963 17 : if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
964 : return 0;
965 :
966 19 : for (i = 1; i < MAXVIFS; i++) {
967 19 : if (pim->iface_vif_index[i] == 0)
968 13 : return i;
969 : }
970 : return MAXVIFS;
971 : }
972 :
973 : /*
974 : pim_if_add_vif() uses ifindex as vif_index
975 :
976 : see also pim_if_find_vifindex_by_ifindex()
977 : */
978 35 : int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term)
979 : {
980 35 : struct pim_interface *pim_ifp = ifp->info;
981 35 : pim_addr ifaddr;
982 35 : unsigned char flags = 0;
983 :
984 35 : assert(pim_ifp);
985 :
986 35 : if (pim_ifp->mroute_vif_index > 0) {
987 0 : zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
988 : __func__, pim_ifp->mroute_vif_index, ifp->name,
989 : ifp->ifindex);
990 0 : return -1;
991 : }
992 :
993 35 : if (ifp->ifindex < 0) {
994 0 : zlog_warn("%s: ifindex=%d < 1 on interface %s", __func__,
995 : ifp->ifindex, ifp->name);
996 0 : return -2;
997 : }
998 :
999 35 : ifaddr = pim_ifp->primary_address;
1000 : #if PIM_IPV != 6
1001 : /* IPv6 API is always by interface index */
1002 35 : if (!ispimreg && !is_vxlan_term && pim_addr_is_any(ifaddr)) {
1003 18 : zlog_warn(
1004 : "%s: could not get address for interface %s ifindex=%d",
1005 : __func__, ifp->name, ifp->ifindex);
1006 18 : return -4;
1007 : }
1008 : #endif
1009 :
1010 17 : pim_ifp->mroute_vif_index = pim_iface_next_vif_index(ifp);
1011 :
1012 17 : if (pim_ifp->mroute_vif_index >= MAXVIFS) {
1013 0 : zlog_warn(
1014 : "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
1015 : __func__, MAXVIFS, ifp->name);
1016 0 : return -3;
1017 : }
1018 :
1019 17 : if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
1020 : flags = VIFF_REGISTER;
1021 : #ifdef VIFF_USE_IFINDEX
1022 : else
1023 13 : flags = VIFF_USE_IFINDEX;
1024 : #endif
1025 :
1026 17 : if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
1027 : /* pim_mroute_add_vif reported error */
1028 : return -5;
1029 : }
1030 :
1031 17 : pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
1032 :
1033 17 : if (!ispimreg)
1034 : gm_ifp_update(ifp);
1035 :
1036 : /* if the device qualifies as pim_vxlan iif/oif update vxlan entries */
1037 17 : pim_vxlan_add_vif(ifp);
1038 17 : return 0;
1039 : }
1040 :
1041 17 : int pim_if_del_vif(struct interface *ifp)
1042 : {
1043 17 : struct pim_interface *pim_ifp = ifp->info;
1044 :
1045 17 : if (pim_ifp->mroute_vif_index < 1) {
1046 4 : zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1047 : __func__, pim_ifp->mroute_vif_index, ifp->name,
1048 : ifp->ifindex);
1049 4 : return -1;
1050 : }
1051 :
1052 : /* if the device was a pim_vxlan iif/oif update vxlan mroute entries */
1053 13 : pim_vxlan_del_vif(ifp);
1054 :
1055 13 : gm_ifp_teardown(ifp);
1056 :
1057 13 : pim_mroute_del_vif(ifp);
1058 :
1059 : /*
1060 : Update vif_index
1061 : */
1062 13 : pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0;
1063 :
1064 13 : pim_ifp->mroute_vif_index = -1;
1065 13 : return 0;
1066 : }
1067 :
1068 : // DBS - VRF Revist
1069 0 : struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
1070 : ifindex_t vif_index)
1071 : {
1072 0 : struct interface *ifp;
1073 :
1074 0 : FOR_ALL_INTERFACES (pim->vrf, ifp) {
1075 0 : if (ifp->info) {
1076 0 : struct pim_interface *pim_ifp;
1077 0 : pim_ifp = ifp->info;
1078 :
1079 0 : if (vif_index == pim_ifp->mroute_vif_index)
1080 0 : return ifp;
1081 : }
1082 : }
1083 :
1084 : return 0;
1085 : }
1086 :
1087 : /*
1088 : pim_if_add_vif() uses ifindex as vif_index
1089 : */
1090 0 : int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
1091 : {
1092 0 : struct pim_interface *pim_ifp;
1093 0 : struct interface *ifp;
1094 :
1095 0 : ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
1096 0 : if (!ifp || !ifp->info)
1097 : return -1;
1098 0 : pim_ifp = ifp->info;
1099 :
1100 0 : return pim_ifp->mroute_vif_index;
1101 : }
1102 :
1103 8 : int pim_if_lan_delay_enabled(struct interface *ifp)
1104 : {
1105 8 : struct pim_interface *pim_ifp;
1106 :
1107 8 : pim_ifp = ifp->info;
1108 8 : assert(pim_ifp);
1109 8 : assert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
1110 :
1111 8 : return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
1112 : }
1113 :
1114 0 : uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
1115 : {
1116 0 : if (pim_if_lan_delay_enabled(ifp)) {
1117 0 : struct pim_interface *pim_ifp;
1118 0 : pim_ifp = ifp->info;
1119 0 : return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
1120 : } else {
1121 : return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
1122 : }
1123 : }
1124 :
1125 0 : uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
1126 : {
1127 0 : if (pim_if_lan_delay_enabled(ifp)) {
1128 0 : struct pim_interface *pim_ifp;
1129 0 : pim_ifp = ifp->info;
1130 0 : return pim_ifp->pim_neighbors_highest_override_interval_msec;
1131 : } else {
1132 : return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
1133 : }
1134 : }
1135 :
1136 0 : int pim_if_t_override_msec(struct interface *ifp)
1137 : {
1138 0 : int effective_override_interval_msec;
1139 0 : int t_override_msec;
1140 :
1141 0 : effective_override_interval_msec =
1142 0 : pim_if_effective_override_interval_msec(ifp);
1143 :
1144 0 : t_override_msec =
1145 0 : frr_weak_random() % (effective_override_interval_msec + 1);
1146 :
1147 0 : return t_override_msec;
1148 : }
1149 :
1150 0 : uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
1151 : {
1152 0 : return pim_if_effective_propagation_delay_msec(ifp)
1153 0 : + pim_if_effective_override_interval_msec(ifp);
1154 : }
1155 :
1156 : /*
1157 : RFC 4601: 4.1.6. State Summarization Macros
1158 :
1159 : The function NBR( I, A ) uses information gathered through PIM Hello
1160 : messages to map the IP address A of a directly connected PIM
1161 : neighbor router on interface I to the primary IP address of the same
1162 : router (Section 4.3.4). The primary IP address of a neighbor is the
1163 : address that it uses as the source of its PIM Hello messages.
1164 : */
1165 0 : struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr)
1166 : {
1167 0 : struct listnode *neighnode;
1168 0 : struct pim_neighbor *neigh;
1169 0 : struct pim_interface *pim_ifp;
1170 0 : struct prefix p;
1171 :
1172 0 : assert(ifp);
1173 :
1174 0 : pim_ifp = ifp->info;
1175 0 : if (!pim_ifp) {
1176 0 : zlog_warn("%s: multicast not enabled on interface %s", __func__,
1177 : ifp->name);
1178 0 : return 0;
1179 : }
1180 :
1181 0 : pim_addr_to_prefix(&p, addr);
1182 :
1183 0 : for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
1184 : neigh)) {
1185 :
1186 : /* primary address ? */
1187 0 : if (!pim_addr_cmp(neigh->source_addr, addr))
1188 0 : return neigh;
1189 :
1190 : /* secondary address ? */
1191 0 : if (pim_neighbor_find_secondary(neigh, &p))
1192 0 : return neigh;
1193 : }
1194 :
1195 0 : if (PIM_DEBUG_PIM_TRACE)
1196 0 : zlog_debug(
1197 : "%s: neighbor not found for address %pPA on interface %s",
1198 : __func__, &addr, ifp->name);
1199 :
1200 : return NULL;
1201 : }
1202 :
1203 0 : long pim_if_t_suppressed_msec(struct interface *ifp)
1204 : {
1205 0 : struct pim_interface *pim_ifp;
1206 0 : long t_suppressed_msec;
1207 0 : uint32_t ramount = 0;
1208 :
1209 0 : pim_ifp = ifp->info;
1210 0 : assert(pim_ifp);
1211 :
1212 : /* join suppression disabled ? */
1213 0 : if (pim_ifp->pim_can_disable_join_suppression)
1214 : return 0;
1215 :
1216 : /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1217 0 : ramount = 1100 + (frr_weak_random() % (1400 - 1100 + 1));
1218 0 : t_suppressed_msec = router->t_periodic * ramount;
1219 :
1220 0 : return t_suppressed_msec;
1221 : }
1222 :
1223 : #if PIM_IPV == 4
1224 0 : static void igmp_join_free(struct gm_join *ij)
1225 : {
1226 0 : XFREE(MTYPE_PIM_IGMP_JOIN, ij);
1227 0 : }
1228 :
1229 0 : static struct gm_join *igmp_join_find(struct list *join_list,
1230 : struct in_addr group_addr,
1231 : struct in_addr source_addr)
1232 : {
1233 0 : struct listnode *node;
1234 0 : struct gm_join *ij;
1235 :
1236 0 : assert(join_list);
1237 :
1238 0 : for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
1239 0 : if ((group_addr.s_addr == ij->group_addr.s_addr)
1240 0 : && (source_addr.s_addr == ij->source_addr.s_addr))
1241 0 : return ij;
1242 : }
1243 :
1244 : return 0;
1245 : }
1246 :
1247 0 : static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
1248 : struct in_addr group_addr, struct in_addr source_addr,
1249 : struct pim_interface *pim_ifp)
1250 : {
1251 0 : int join_fd;
1252 :
1253 0 : pim_ifp->igmp_ifstat_joins_sent++;
1254 :
1255 0 : join_fd = pim_socket_raw(IPPROTO_IGMP);
1256 0 : if (join_fd < 0) {
1257 0 : pim_ifp->igmp_ifstat_joins_failed++;
1258 0 : return -1;
1259 : }
1260 :
1261 0 : if (pim_igmp_join_source(join_fd, ifindex, group_addr, source_addr)) {
1262 0 : char group_str[INET_ADDRSTRLEN];
1263 0 : char source_str[INET_ADDRSTRLEN];
1264 0 : pim_inet4_dump("<grp?>", group_addr, group_str,
1265 : sizeof(group_str));
1266 0 : pim_inet4_dump("<src?>", source_addr, source_str,
1267 : sizeof(source_str));
1268 0 : zlog_warn(
1269 : "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
1270 : __func__, join_fd, group_str, source_str, ifindex,
1271 : ifname, errno, safe_strerror(errno));
1272 :
1273 0 : pim_ifp->igmp_ifstat_joins_failed++;
1274 :
1275 0 : close(join_fd);
1276 0 : return -2;
1277 : }
1278 :
1279 : return join_fd;
1280 : }
1281 :
1282 : #if PIM_IPV == 4
1283 0 : static struct gm_join *igmp_join_new(struct interface *ifp,
1284 : struct in_addr group_addr,
1285 : struct in_addr source_addr)
1286 : {
1287 0 : struct pim_interface *pim_ifp;
1288 0 : struct gm_join *ij;
1289 0 : int join_fd;
1290 :
1291 0 : pim_ifp = ifp->info;
1292 0 : assert(pim_ifp);
1293 :
1294 0 : join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
1295 : source_addr, pim_ifp);
1296 0 : if (join_fd < 0) {
1297 0 : char group_str[INET_ADDRSTRLEN];
1298 0 : char source_str[INET_ADDRSTRLEN];
1299 :
1300 0 : pim_inet4_dump("<grp?>", group_addr, group_str,
1301 : sizeof(group_str));
1302 0 : pim_inet4_dump("<src?>", source_addr, source_str,
1303 : sizeof(source_str));
1304 0 : zlog_warn(
1305 : "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1306 : __func__, group_str, source_str, ifp->name);
1307 0 : return 0;
1308 : }
1309 :
1310 0 : ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
1311 :
1312 0 : ij->sock_fd = join_fd;
1313 0 : ij->group_addr = group_addr;
1314 0 : ij->source_addr = source_addr;
1315 0 : ij->sock_creation = pim_time_monotonic_sec();
1316 :
1317 0 : listnode_add(pim_ifp->gm_join_list, ij);
1318 :
1319 0 : return ij;
1320 : }
1321 : #endif /* PIM_IPV == 4 */
1322 :
1323 : #if PIM_IPV == 4
1324 0 : ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
1325 : struct in_addr source_addr)
1326 : {
1327 0 : struct pim_interface *pim_ifp;
1328 0 : struct gm_join *ij;
1329 :
1330 0 : pim_ifp = ifp->info;
1331 0 : if (!pim_ifp) {
1332 0 : return ferr_cfg_invalid("multicast not enabled on interface %s",
1333 : ifp->name);
1334 : }
1335 :
1336 0 : if (!pim_ifp->gm_join_list) {
1337 0 : pim_ifp->gm_join_list = list_new();
1338 0 : pim_ifp->gm_join_list->del = (void (*)(void *))igmp_join_free;
1339 : }
1340 :
1341 0 : ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
1342 :
1343 : /* This interface has already been configured to join this IGMP group
1344 : */
1345 0 : if (ij) {
1346 : return ferr_ok();
1347 : }
1348 :
1349 0 : (void)igmp_join_new(ifp, group_addr, source_addr);
1350 :
1351 0 : if (PIM_DEBUG_GM_EVENTS) {
1352 0 : char group_str[INET_ADDRSTRLEN];
1353 0 : char source_str[INET_ADDRSTRLEN];
1354 0 : pim_inet4_dump("<grp?>", group_addr, group_str,
1355 : sizeof(group_str));
1356 0 : pim_inet4_dump("<src?>", source_addr, source_str,
1357 : sizeof(source_str));
1358 0 : zlog_debug(
1359 : "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1360 : __func__, source_str, group_str, ifp->name);
1361 : }
1362 :
1363 : return ferr_ok();
1364 : }
1365 : #endif /* PIM_IPV == 4 */
1366 :
1367 0 : int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
1368 : struct in_addr source_addr)
1369 : {
1370 0 : struct pim_interface *pim_ifp;
1371 0 : struct gm_join *ij;
1372 :
1373 0 : pim_ifp = ifp->info;
1374 0 : if (!pim_ifp) {
1375 0 : zlog_warn("%s: multicast not enabled on interface %s", __func__,
1376 : ifp->name);
1377 0 : return -1;
1378 : }
1379 :
1380 0 : if (!pim_ifp->gm_join_list) {
1381 0 : zlog_warn("%s: no IGMP join on interface %s", __func__,
1382 : ifp->name);
1383 0 : return -2;
1384 : }
1385 :
1386 0 : ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
1387 0 : if (!ij) {
1388 0 : char group_str[INET_ADDRSTRLEN];
1389 0 : char source_str[INET_ADDRSTRLEN];
1390 0 : pim_inet4_dump("<grp?>", group_addr, group_str,
1391 : sizeof(group_str));
1392 0 : pim_inet4_dump("<src?>", source_addr, source_str,
1393 : sizeof(source_str));
1394 0 : zlog_warn(
1395 : "%s: could not find IGMP group %s source %s on interface %s",
1396 : __func__, group_str, source_str, ifp->name);
1397 0 : return -3;
1398 : }
1399 :
1400 0 : if (close(ij->sock_fd)) {
1401 0 : char group_str[INET_ADDRSTRLEN];
1402 0 : char source_str[INET_ADDRSTRLEN];
1403 0 : pim_inet4_dump("<grp?>", group_addr, group_str,
1404 : sizeof(group_str));
1405 0 : pim_inet4_dump("<src?>", source_addr, source_str,
1406 : sizeof(source_str));
1407 0 : zlog_warn(
1408 : "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1409 : __func__, ij->sock_fd, group_str, source_str, ifp->name,
1410 : errno, safe_strerror(errno));
1411 : /* warning only */
1412 : }
1413 0 : listnode_delete(pim_ifp->gm_join_list, ij);
1414 0 : igmp_join_free(ij);
1415 0 : if (listcount(pim_ifp->gm_join_list) < 1) {
1416 0 : list_delete(&pim_ifp->gm_join_list);
1417 0 : pim_ifp->gm_join_list = 0;
1418 : }
1419 :
1420 : return 0;
1421 : }
1422 :
1423 : __attribute__((unused))
1424 0 : static void pim_if_igmp_join_del_all(struct interface *ifp)
1425 : {
1426 0 : struct pim_interface *pim_ifp;
1427 0 : struct listnode *node;
1428 0 : struct listnode *nextnode;
1429 0 : struct gm_join *ij;
1430 :
1431 0 : pim_ifp = ifp->info;
1432 0 : if (!pim_ifp) {
1433 0 : zlog_warn("%s: multicast not enabled on interface %s", __func__,
1434 : ifp->name);
1435 0 : return;
1436 : }
1437 :
1438 0 : if (!pim_ifp->gm_join_list)
1439 : return;
1440 :
1441 0 : for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
1442 0 : pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1443 : }
1444 : #else /* PIM_IPV != 4 */
1445 : ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
1446 : struct in_addr source_addr)
1447 : {
1448 : return ferr_ok();
1449 : }
1450 :
1451 : int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
1452 : struct in_addr source_addr)
1453 : {
1454 : return 0;
1455 : }
1456 : #endif /* PIM_IPV != 4 */
1457 :
1458 : /*
1459 : RFC 4601
1460 :
1461 : Transitions from "I am Assert Loser" State
1462 :
1463 : Current Winner's GenID Changes or NLT Expires
1464 :
1465 : The Neighbor Liveness Timer associated with the current winner
1466 : expires or we receive a Hello message from the current winner
1467 : reporting a different GenID from the one it previously reported.
1468 : This indicates that the current winner's interface or router has
1469 : gone down (and may have come back up), and so we must assume it no
1470 : longer knows it was the winner.
1471 : */
1472 8 : void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr)
1473 : {
1474 8 : struct pim_interface *pim_ifp;
1475 8 : struct pim_ifchannel *ch;
1476 :
1477 8 : pim_ifp = ifp->info;
1478 8 : assert(pim_ifp);
1479 :
1480 16 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1481 : /* Is (S,G,I) assert loser ? */
1482 0 : if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1483 0 : continue;
1484 : /* Dead neighbor was winner ? */
1485 0 : if (pim_addr_cmp(ch->ifassert_winner, neigh_addr))
1486 0 : continue;
1487 :
1488 0 : assert_action_a5(ch);
1489 : }
1490 8 : }
1491 :
1492 57 : void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1493 : {
1494 57 : struct pim_ifchannel *ch;
1495 :
1496 : /* clear off flag from interface's upstreams */
1497 114 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1498 0 : PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1499 : ch->upstream->flags);
1500 : }
1501 :
1502 : /* scan per-interface (S,G,I) state on this I interface */
1503 114 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1504 0 : struct pim_upstream *up = ch->upstream;
1505 :
1506 0 : if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1507 0 : continue;
1508 :
1509 : /* update join_desired for the global (S,G) state */
1510 0 : pim_upstream_update_join_desired(pim_ifp->pim, up);
1511 0 : PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1512 : }
1513 57 : }
1514 :
1515 57 : void pim_if_update_assert_tracking_desired(struct interface *ifp)
1516 : {
1517 57 : struct pim_interface *pim_ifp;
1518 57 : struct pim_ifchannel *ch;
1519 :
1520 57 : pim_ifp = ifp->info;
1521 57 : if (!pim_ifp)
1522 : return;
1523 :
1524 114 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1525 0 : pim_ifchannel_update_assert_tracking_desired(ch);
1526 : }
1527 : }
1528 :
1529 : /*
1530 : * PIM wants to have an interface pointer for everything it does.
1531 : * The pimreg is a special interface that we have that is not
1532 : * quite an interface but a VIF is created for it.
1533 : */
1534 26 : void pim_if_create_pimreg(struct pim_instance *pim)
1535 : {
1536 26 : char pimreg_name[INTERFACE_NAMSIZ];
1537 :
1538 26 : if (!pim->regiface) {
1539 4 : if (pim->vrf->vrf_id == VRF_DEFAULT)
1540 4 : strlcpy(pimreg_name, PIMREG, sizeof(pimreg_name));
1541 : else
1542 0 : snprintf(pimreg_name, sizeof(pimreg_name), PIMREG "%u",
1543 : pim->vrf->data.l.table_id);
1544 :
1545 8 : pim->regiface = if_get_by_name(pimreg_name, pim->vrf->vrf_id,
1546 4 : pim->vrf->name);
1547 4 : pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
1548 :
1549 4 : pim_if_new(pim->regiface, false, false, true,
1550 : false /*vxlan_term*/);
1551 : /*
1552 : * On vrf moves we delete the interface if there
1553 : * is nothing going on with it. We cannot have
1554 : * the pimregiface deleted.
1555 : */
1556 4 : pim->regiface->configured = true;
1557 :
1558 : }
1559 26 : }
1560 :
1561 35 : struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src)
1562 : {
1563 35 : struct listnode *cnode;
1564 35 : struct connected *c;
1565 35 : struct prefix p;
1566 :
1567 35 : if (!ifp)
1568 : return NULL;
1569 :
1570 35 : pim_addr_to_prefix(&p, src);
1571 :
1572 70 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
1573 35 : if (c->address->family != PIM_AF)
1574 0 : continue;
1575 35 : if (prefix_match(c->address, &p))
1576 35 : return c->address;
1577 0 : if (CONNECTED_PEER(c) && prefix_match(c->destination, &p))
1578 : /* this is not a typo, on PtP we need to return the
1579 : * *local* address that lines up with src.
1580 : */
1581 0 : return c->address;
1582 : }
1583 :
1584 : return NULL;
1585 : }
1586 :
1587 24 : bool pim_if_is_vrf_device(struct interface *ifp)
1588 : {
1589 24 : if (if_is_vrf(ifp))
1590 0 : return true;
1591 :
1592 : return false;
1593 : }
1594 :
1595 0 : int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
1596 : {
1597 0 : struct pim_ifchannel *ch;
1598 0 : int count = 0;
1599 :
1600 0 : RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1601 0 : count++;
1602 : }
1603 :
1604 0 : return count;
1605 : }
1606 :
1607 24 : static int pim_ifp_create(struct interface *ifp)
1608 : {
1609 24 : struct pim_instance *pim;
1610 :
1611 24 : pim = ifp->vrf->info;
1612 24 : if (PIM_DEBUG_ZEBRA) {
1613 0 : zlog_debug(
1614 : "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1615 : __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1616 : ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1617 : ifp->mtu, if_is_operative(ifp));
1618 : }
1619 :
1620 24 : if (if_is_operative(ifp)) {
1621 20 : struct pim_interface *pim_ifp;
1622 :
1623 20 : pim_ifp = ifp->info;
1624 : /*
1625 : * If we have a pim_ifp already and this is an if_add
1626 : * that means that we probably have a vrf move event
1627 : * If that is the case, set the proper vrfness.
1628 : */
1629 20 : if (pim_ifp)
1630 12 : pim_ifp->pim = pim;
1631 20 : pim_if_addr_add_all(ifp);
1632 :
1633 : /*
1634 : * Due to ordering issues based upon when
1635 : * a command is entered we should ensure that
1636 : * the pim reg is created for this vrf if we
1637 : * have configuration for it already.
1638 : *
1639 : * this is a no-op if it's already been done.
1640 : */
1641 20 : pim_if_create_pimreg(pim);
1642 : }
1643 :
1644 : #if PIM_IPV == 4
1645 : /*
1646 : * If we are a vrf device that is up, open up the pim_socket for
1647 : * listening
1648 : * to incoming pim messages irrelevant if the user has configured us
1649 : * for pim or not.
1650 : */
1651 24 : if (pim_if_is_vrf_device(ifp)) {
1652 0 : struct pim_interface *pim_ifp;
1653 :
1654 0 : if (!ifp->info) {
1655 0 : pim_ifp = pim_if_new(ifp, false, false, false,
1656 : false /*vxlan_term*/);
1657 0 : ifp->info = pim_ifp;
1658 : }
1659 :
1660 0 : pim_sock_add(ifp);
1661 : }
1662 :
1663 24 : if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
1664 : sizeof(PIM_VXLAN_TERM_DEV_NAME))) {
1665 0 : if (pim->mcast_if_count < MAXVIFS)
1666 0 : pim_vxlan_add_term_dev(pim, ifp);
1667 : else
1668 0 : zlog_warn(
1669 : "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
1670 : __func__, ifp->name, MAXVIFS);
1671 : }
1672 : #endif
1673 :
1674 24 : return 0;
1675 : }
1676 :
1677 11 : static int pim_ifp_up(struct interface *ifp)
1678 : {
1679 11 : uint32_t table_id;
1680 11 : struct pim_interface *pim_ifp;
1681 11 : struct pim_instance *pim;
1682 :
1683 11 : if (PIM_DEBUG_ZEBRA) {
1684 0 : zlog_debug(
1685 : "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1686 : __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1687 : ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1688 : ifp->mtu, if_is_operative(ifp));
1689 : }
1690 :
1691 11 : pim = ifp->vrf->info;
1692 :
1693 11 : pim_ifp = ifp->info;
1694 : /*
1695 : * If we have a pim_ifp already and this is an if_add
1696 : * that means that we probably have a vrf move event
1697 : * If that is the case, set the proper vrfness.
1698 : */
1699 11 : if (pim_ifp)
1700 11 : pim_ifp->pim = pim;
1701 :
1702 : /*
1703 : pim_if_addr_add_all() suffices for bringing up both IGMP and
1704 : PIM
1705 : */
1706 11 : pim_if_addr_add_all(ifp);
1707 :
1708 : /*
1709 : * If we have a pimreg device callback and it's for a specific
1710 : * table set the master appropriately
1711 : */
1712 11 : if (sscanf(ifp->name, "" PIMREG "%" SCNu32, &table_id) == 1) {
1713 0 : struct vrf *vrf;
1714 0 : RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1715 0 : if ((table_id == vrf->data.l.table_id)
1716 0 : && (ifp->vrf->vrf_id != vrf->vrf_id)) {
1717 0 : struct interface *master = if_lookup_by_name(
1718 0 : vrf->name, vrf->vrf_id);
1719 :
1720 0 : if (!master) {
1721 0 : zlog_debug(
1722 : "%s: Unable to find Master interface for %s",
1723 : __func__, vrf->name);
1724 0 : return 0;
1725 : }
1726 0 : pim_zebra_interface_set_master(master, ifp);
1727 : }
1728 : }
1729 : }
1730 : return 0;
1731 : }
1732 :
1733 7 : static int pim_ifp_down(struct interface *ifp)
1734 : {
1735 7 : if (PIM_DEBUG_ZEBRA) {
1736 0 : zlog_debug(
1737 : "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1738 : __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1739 : ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1740 : ifp->mtu, if_is_operative(ifp));
1741 : }
1742 :
1743 7 : if (!if_is_operative(ifp)) {
1744 7 : pim_ifchannel_delete_all(ifp);
1745 : /*
1746 : pim_if_addr_del_all() suffices for shutting down IGMP,
1747 : but not for shutting down PIM
1748 : */
1749 7 : pim_if_addr_del_all(ifp);
1750 :
1751 : /*
1752 : pim_sock_delete() closes the socket, stops read and timer
1753 : threads,
1754 : and kills all neighbors.
1755 : */
1756 7 : if (ifp->info) {
1757 7 : pim_sock_delete(ifp, "link down");
1758 : }
1759 : }
1760 :
1761 7 : if (ifp->info) {
1762 7 : pim_if_del_vif(ifp);
1763 7 : pim_ifstat_reset(ifp);
1764 : }
1765 :
1766 7 : return 0;
1767 : }
1768 :
1769 0 : static int pim_ifp_destroy(struct interface *ifp)
1770 : {
1771 0 : if (PIM_DEBUG_ZEBRA) {
1772 0 : zlog_debug(
1773 : "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1774 : __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
1775 : ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
1776 : ifp->mtu, if_is_operative(ifp));
1777 : }
1778 :
1779 0 : if (!if_is_operative(ifp))
1780 0 : pim_if_addr_del_all(ifp);
1781 :
1782 : #if PIM_IPV == 4
1783 0 : struct pim_instance *pim;
1784 :
1785 0 : pim = ifp->vrf->info;
1786 0 : if (pim && pim->vxlan.term_if == ifp)
1787 0 : pim_vxlan_del_term_dev(pim);
1788 : #endif
1789 :
1790 0 : return 0;
1791 : }
1792 :
1793 14 : static int pim_if_new_hook(struct interface *ifp)
1794 : {
1795 14 : return 0;
1796 : }
1797 :
1798 14 : static int pim_if_delete_hook(struct interface *ifp)
1799 : {
1800 14 : if (ifp->info)
1801 0 : pim_if_delete(ifp);
1802 :
1803 14 : return 0;
1804 : }
1805 :
1806 4 : void pim_iface_init(void)
1807 : {
1808 4 : hook_register_prio(if_add, 0, pim_if_new_hook);
1809 4 : hook_register_prio(if_del, 0, pim_if_delete_hook);
1810 :
1811 4 : if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down,
1812 : pim_ifp_destroy);
1813 4 : }
|