]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_zebra.c
Merge pull request #10621 from donaldsharp/cov_fun
[mirror_frr.git] / pimd / pim_zebra.c
CommitLineData
12e41d03 1/*
896014f4
DL
2 * PIM for Quagga
3 * Copyright (C) 2008 Everton da Silva Marques
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
12e41d03
DL
19
20#include <zebra.h>
21
12e41d03
DL
22#include "if.h"
23#include "log.h"
24#include "prefix.h"
25#include "zclient.h"
26#include "stream.h"
27#include "network.h"
dfe43e25
DW
28#include "vty.h"
29#include "plist.h"
ba4eb1bc 30#include "lib/bfd.h"
12e41d03
DL
31
32#include "pimd.h"
33#include "pim_pim.h"
34#include "pim_zebra.h"
35#include "pim_iface.h"
36#include "pim_str.h"
37#include "pim_oil.h"
38#include "pim_rpf.h"
39#include "pim_time.h"
40#include "pim_join.h"
41#include "pim_zlookup.h"
42#include "pim_ifchannel.h"
8f5f5e91 43#include "pim_rp.h"
2560106c 44#include "pim_igmpv3.h"
982bff89 45#include "pim_jp_agg.h"
1bc98276 46#include "pim_nht.h"
15a5dafe 47#include "pim_ssm.h"
af7b561b 48#include "pim_vxlan.h"
46c2687c 49#include "pim_mlag.h"
12e41d03
DL
50
51#undef PIM_DEBUG_IFADDR_DUMP
52#define PIM_DEBUG_IFADDR_DUMP
53
36b5b98f 54struct zclient *zclient;
38f4935a 55
12e41d03 56
12e41d03 57/* Router-id update message from zebra. */
121f9dee 58static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
12e41d03 59{
d62a17ae 60 struct prefix router_id;
12e41d03 61
d62a17ae 62 zebra_router_id_update_read(zclient->ibuf, &router_id);
12e41d03 63
d62a17ae 64 return 0;
12e41d03
DL
65}
66
121f9dee 67static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
ee568318
DS
68{
69 struct interface *ifp;
70 vrf_id_t new_vrf_id;
71
72 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
73 &new_vrf_id);
74 if (!ifp)
75 return 0;
76
77 if (PIM_DEBUG_ZEBRA)
15569c58
DA
78 zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name,
79 vrf_id, new_vrf_id);
ee568318 80
a36898e7 81 if_update_to_new_vrf(ifp, new_vrf_id);
ee568318
DS
82
83 return 0;
84}
85
12e41d03
DL
86#ifdef PIM_DEBUG_IFADDR_DUMP
87static void dump_if_address(struct interface *ifp)
88{
d62a17ae 89 struct connected *ifc;
90 struct listnode *node;
91
5e81f5dd
DS
92 zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__,
93 ifp->name);
d62a17ae 94
95 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
96 struct prefix *p = ifc->address;
97
98 if (p->family != AF_INET)
99 continue;
100
ee2bbf7c
MS
101 zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__,
102 __func__, ifp->name, &p->u.prefix4,
d62a17ae 103 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
104 ? "secondary"
105 : "primary");
106 }
12e41d03
DL
107}
108#endif
109
121f9dee 110static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
12e41d03 111{
d62a17ae 112 struct connected *c;
113 struct prefix *p;
114 struct pim_interface *pim_ifp;
26bb1fd5 115 struct pim_instance *pim;
d62a17ae 116
117 /*
118 zebra api notifies address adds/dels events by using the same call
119 interface_add_read below, see comments in lib/zclient.c
120
121 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
122 will add address to interface list by calling
123 connected_add_by_prefix()
124 */
121f9dee 125 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
d62a17ae 126 if (!c)
127 return 0;
128
129 pim_ifp = c->ifp->info;
130 p = c->address;
131
132 if (PIM_DEBUG_ZEBRA) {
2dbe669b
DA
133 zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
134 __func__, c->ifp->name, vrf_id, p, c->flags,
996c9314
LB
135 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
136 ? "secondary"
137 : "primary");
d62a17ae 138
12e41d03 139#ifdef PIM_DEBUG_IFADDR_DUMP
d62a17ae 140 dump_if_address(c->ifp);
12e41d03 141#endif
d62a17ae 142 }
12e41d03 143
034db86b
DL
144 if (p->family != PIM_AF)
145 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
146 else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
147 /* trying to add primary address? */
148 pim_addr primary_addr = pim_find_primary_addr(c->ifp);
149 pim_addr addr = pim_addr_from_prefix(p);
150
151 if (pim_addr_cmp(primary_addr, addr)) {
2dbe669b 152 if (PIM_DEBUG_ZEBRA)
d62a17ae 153 zlog_warn(
2dbe669b
DA
154 "%s: %s : forcing secondary flag on %pFX",
155 __func__, c->ifp->name, p);
d62a17ae 156 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
157 }
158 }
12e41d03 159
d62a17ae 160 pim_if_addr_add(c);
26bb1fd5
DS
161 if (pim_ifp) {
162 pim = pim_get_pim_instance(vrf_id);
163 pim_ifp->pim = pim;
164
d62a17ae 165 pim_rp_check_on_if_add(pim_ifp);
26bb1fd5 166 }
12e41d03 167
d62a17ae 168 if (if_is_loopback(c->ifp)) {
4bb0e8f0 169 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
d62a17ae 170 struct interface *ifp;
d8424057 171
451fda4f 172 FOR_ALL_INTERFACES (vrf, ifp) {
d62a17ae 173 if (!if_is_loopback(ifp) && if_is_operative(ifp))
174 pim_if_addr_add_all(ifp);
175 }
176 }
d8424057 177
d62a17ae 178 return 0;
12e41d03
DL
179}
180
121f9dee 181static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
12e41d03 182{
d62a17ae 183 struct connected *c;
184 struct prefix *p;
fec883d9 185 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
819f099b
DS
186 struct pim_instance *pim;
187
188 if (!vrf)
189 return 0;
190 pim = vrf->info;
d62a17ae 191
192 /*
193 zebra api notifies address adds/dels events by using the same call
194 interface_add_read below, see comments in lib/zclient.c
195
196 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
197 will remove address from interface list by calling
198 connected_delete_by_prefix()
199 */
121f9dee 200 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
d62a17ae 201 if (!c)
202 return 0;
203
204 p = c->address;
205 if (p->family == AF_INET) {
206 if (PIM_DEBUG_ZEBRA) {
d62a17ae 207 zlog_debug(
2dbe669b
DA
208 "%s: %s(%u) disconnected IP address %pFX flags %u %s",
209 __func__, c->ifp->name, vrf_id, p, c->flags,
d62a17ae 210 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
211 ? "secondary"
212 : "primary");
6233f087 213
12e41d03 214#ifdef PIM_DEBUG_IFADDR_DUMP
d62a17ae 215 dump_if_address(c->ifp);
12e41d03 216#endif
d62a17ae 217 }
12e41d03 218
d62a17ae 219 pim_if_addr_del(c, 0);
fec883d9
DS
220 pim_rp_setup(pim);
221 pim_i_am_rp_re_evaluate(pim);
d62a17ae 222 }
6233f087 223
721c0857 224 connected_free(&c);
d62a17ae 225 return 0;
12e41d03
DL
226}
227
74389231
DS
228void pim_zebra_update_all_interfaces(struct pim_instance *pim)
229{
230 struct interface *ifp;
231
232 FOR_ALL_INTERFACES (pim->vrf, ifp) {
233 struct pim_interface *pim_ifp = ifp->info;
234 struct pim_iface_upstream_switch *us;
235 struct listnode *node;
236
237 if (!pim_ifp)
238 continue;
239
240 for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node,
241 us)) {
242 struct pim_rpf rpf;
243
244 rpf.source_nexthop.interface = ifp;
245 rpf.rpf_addr.u.prefix4 = us->address;
246 pim_joinprune_send(&rpf, us->us);
247 pim_jp_agg_clear_group(us->us);
248 }
249 }
250}
251
cc67ccf9
DS
252void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
253 struct pim_upstream *up,
254 struct pim_rpf *old)
255{
1250cb5d
SP
256 if (old->source_nexthop.interface) {
257 struct pim_neighbor *nbr;
cc67ccf9 258
9bb93fa0
DL
259 nbr = pim_neighbor_find_prefix(old->source_nexthop.interface,
260 &old->rpf_addr);
1250cb5d 261 if (nbr)
c5cdf069 262 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
cc67ccf9 263
cc67ccf9 264 /*
1250cb5d
SP
265 * We have detected a case where we might need
266 * to rescan the inherited o_list so do it.
cc67ccf9 267 */
1250cb5d
SP
268 if (up->channel_oil->oil_inherited_rescan) {
269 pim_upstream_inherited_olist_decide(pim, up);
270 up->channel_oil->oil_inherited_rescan = 0;
271 }
cc67ccf9 272
1250cb5d
SP
273 if (up->join_state == PIM_UPSTREAM_JOINED) {
274 /*
275 * If we come up real fast we can be here
276 * where the mroute has not been installed
277 * so install it.
278 */
279 if (!up->channel_oil->installed)
69e3538c 280 pim_upstream_mroute_add(up->channel_oil,
15569c58 281 __func__);
1250cb5d
SP
282
283 /*
284 * RFC 4601: 4.5.7. Sending (S,G)
285 * Join/Prune Messages
286 *
287 * Transitions from Joined State
288 *
289 * RPF'(S,G) changes not due to an Assert
290 *
291 * The upstream (S,G) state machine remains
292 * in Joined state. Send Join(S,G) to the new
293 * upstream neighbor, which is the new value
294 * of RPF'(S,G). Send Prune(S,G) to the old
295 * upstream neighbor, which is the old value
296 * of RPF'(S,G). Set the Join Timer (JT) to
297 * expire after t_periodic seconds.
298 */
299 pim_jp_agg_switch_interface(old, &up->rpf, up);
300
301 pim_upstream_join_timer_restart(up, old);
302 } /* up->join_state == PIM_UPSTREAM_JOINED */
303 }
304
305 else {
cc67ccf9 306 /*
1250cb5d
SP
307 * We have detected a case where we might need
308 * to rescan the inherited o_list so do it.
cc67ccf9 309 */
1250cb5d
SP
310 if (up->channel_oil->oil_inherited_rescan) {
311 pim_upstream_inherited_olist_decide(pim, up);
312 up->channel_oil->oil_inherited_rescan = 0;
313 }
cc67ccf9 314
db431af2
AK
315 if (up->join_state == PIM_UPSTREAM_JOINED)
316 pim_jp_agg_switch_interface(old, &up->rpf, up);
317
1250cb5d 318 if (!up->channel_oil->installed)
15569c58 319 pim_upstream_mroute_add(up->channel_oil, __func__);
1250cb5d 320 }
cc67ccf9 321
1250cb5d
SP
322 /* FIXME can join_desired actually be changed by pim_rpf_update()
323 * returning PIM_RPF_CHANGED ?
324 */
cc67ccf9
DS
325 pim_upstream_update_join_desired(pim, up);
326}
327
121f9dee 328static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
af7b561b
AK
329{
330 struct stream *s;
331 struct pim_instance *pim;
6fff2cc6
DL
332 pim_sgaddr sg;
333 size_t prefixlen;
af7b561b
AK
334
335 pim = pim_get_pim_instance(vrf_id);
336 if (!pim)
337 return 0;
338
339 s = zclient->ibuf;
340
6fff2cc6 341 prefixlen = stream_getl(s);
c631920c
DL
342 stream_get(&sg.src, s, prefixlen);
343 stream_get(&sg.grp, s, prefixlen);
af7b561b 344
9bace5c2
DL
345 if (PIM_DEBUG_ZEBRA)
346 zlog_debug("%u:recv SG %s %pSG", vrf_id,
347 (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg);
af7b561b 348
121f9dee 349 if (cmd == ZEBRA_VXLAN_SG_ADD)
af7b561b
AK
350 pim_vxlan_sg_add(pim, &sg);
351 else
352 pim_vxlan_sg_del(pim, &sg);
353
354 return 0;
355}
356
ecbbc3a7
AK
357static void pim_zebra_vxlan_replay(void)
358{
359 struct stream *s = NULL;
360
361 /* Check socket. */
362 if (!zclient || zclient->sock < 0)
363 return;
364
365 s = zclient->obuf;
366 stream_reset(s);
367
368 zclient_create_header(s, ZEBRA_VXLAN_SG_REPLAY, VRF_DEFAULT);
369 stream_putw_at(s, 0, stream_get_endp(s));
370
371 zclient_send_message(zclient);
372}
373
da11e325 374void pim_scan_oil(struct pim_instance *pim)
8a67a996 375{
d62a17ae 376 struct channel_oil *c_oil;
d62a17ae 377
bfc92019
DS
378 pim->scan_oil_last = pim_time_monotonic_sec();
379 ++pim->scan_oil_events;
d62a17ae 380
7315ecda 381 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
7984af18 382 pim_upstream_mroute_iif_update(c_oil, __func__);
12e41d03
DL
383}
384
385static int on_rpf_cache_refresh(struct thread *t)
386{
da11e325
DS
387 struct pim_instance *pim = THREAD_ARG(t);
388
d62a17ae 389 /* update kernel multicast forwarding cache (MFC) */
da11e325 390 pim_scan_oil(pim);
12e41d03 391
bfc92019
DS
392 pim->rpf_cache_refresh_last = pim_time_monotonic_sec();
393 ++pim->rpf_cache_refresh_events;
12e41d03 394
d62a17ae 395 // It is called as part of pim_neighbor_add
396 // pim_rp_setup ();
397 return 0;
12e41d03
DL
398}
399
da11e325 400void sched_rpf_cache_refresh(struct pim_instance *pim)
12e41d03 401{
bfc92019 402 ++pim->rpf_cache_refresh_requests;
12e41d03 403
bfc92019 404 pim_rpf_set_refresh_time(pim);
e71bf8f7 405
da11e325 406 if (pim->rpf_cache_refresher) {
d62a17ae 407 /* Refresh timer is already running */
408 return;
409 }
12e41d03 410
d62a17ae 411 /* Start refresh timer */
12e41d03 412
d62a17ae 413 if (PIM_DEBUG_ZEBRA) {
15569c58 414 zlog_debug("%s: triggering %ld msec timer", __func__,
da03883e 415 router->rpf_cache_refresh_delay_msec);
d62a17ae 416 }
12e41d03 417
36417fcc 418 thread_add_timer_msec(router->master, on_rpf_cache_refresh, pim,
da03883e 419 router->rpf_cache_refresh_delay_msec,
da11e325 420 &pim->rpf_cache_refresher);
12e41d03
DL
421}
422
d62a17ae 423static void pim_zebra_connected(struct zclient *zclient)
48e8451b 424{
d62a17ae 425 /* Send the client registration */
0945d5ed 426 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
ba4eb1bc 427
4dfe9ad2 428 zclient_send_reg_requests(zclient, router->vrf_id);
ecbbc3a7
AK
429
430 /* request for VxLAN BUM group addresses */
431 pim_zebra_vxlan_replay();
48e8451b 432}
8711a53d 433
ac567a6f
DS
434static void pim_zebra_capabilities(struct zclient_capabilities *cap)
435{
05ca004b 436 router->mlag_role = cap->role;
ac567a6f
DS
437}
438
a243d1db
DL
439static zclient_handler *const pim_handlers[] = {
440 [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
441 [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
442 [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
443 [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
444 [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
445
446 [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
447 [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
448
449 [ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up,
450 [ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down,
451 [ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg,
452};
453
eb05883f 454void pim_zebra_init(void)
12e41d03 455{
d62a17ae 456 /* Socket for receiving updates from Zebra daemon */
a243d1db
DL
457 zclient = zclient_new(router->master, &zclient_options_default,
458 pim_handlers, array_size(pim_handlers));
d62a17ae 459
ac567a6f 460 zclient->zebra_capabilities = pim_zebra_capabilities;
d62a17ae 461 zclient->zebra_connected = pim_zebra_connected;
d62a17ae 462
342213ea 463 zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
d62a17ae 464 if (PIM_DEBUG_PIM_TRACE) {
15569c58 465 zlog_notice("%s: zclient socket initialized", __func__);
d62a17ae 466 }
467
468 zclient_lookup_new();
12e41d03
DL
469}
470
6f932b0c 471void igmp_anysource_forward_start(struct pim_instance *pim,
a16db099 472 struct gm_group *group)
12e41d03 473{
51700107 474 struct gm_source *source;
d62a17ae 475 struct in_addr src_addr = {.s_addr = 0};
476 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
df5dfb77
DL
477 assert(group->group_filtermode_isexcl);
478 assert(listcount(group->group_source_list) < 1);
d62a17ae 479
5421bf8f 480 source = igmp_get_source_by_addr(group, src_addr, NULL);
d62a17ae 481 if (!source) {
15569c58 482 zlog_warn("%s: Failure to create * source", __func__);
d62a17ae 483 return;
484 }
485
6f932b0c 486 igmp_source_forward_start(pim, source);
12e41d03
DL
487}
488
a16db099 489void igmp_anysource_forward_stop(struct gm_group *group)
12e41d03 490{
51700107 491 struct gm_source *source;
d62a17ae 492 struct in_addr star = {.s_addr = 0};
12e41d03 493
d62a17ae 494 source = igmp_find_source_by_addr(group, star);
495 if (source)
496 igmp_source_forward_stop(source);
12e41d03
DL
497}
498
6f439a70 499static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
51700107 500 struct gm_source *source)
15a5dafe 501{
6fff2cc6 502 pim_sgaddr sg;
a16db099 503 struct gm_group *group = source->source_group;
d62a17ae 504 struct pim_ifchannel *ch;
505
506 if ((source->source_addr.s_addr != INADDR_ANY)
507 || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
508 return;
509
6fff2cc6 510 memset(&sg, 0, sizeof(sg));
d62a17ae 511 sg.src = source->source_addr;
512 sg.grp = group->group_addr;
513
dda4d23c 514 ch = pim_ifchannel_find(group->interface, &sg);
6f439a70 515 if (pim_is_grp_ssm(pim, group->group_addr)) {
d62a17ae 516 /* If SSM group withdraw local membership */
517 if (ch
518 && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
519 if (PIM_DEBUG_PIM_EVENTS)
98a81d2b
DL
520 zlog_debug("local membership del for %pSG as G is now SSM",
521 &sg);
a1a4295a
DL
522 pim_ifchannel_local_membership_del(group->interface,
523 &sg);
d62a17ae 524 }
525 } else {
526 /* If ASM group add local membership */
527 if (!ch
528 || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
529 if (PIM_DEBUG_PIM_EVENTS)
98a81d2b
DL
530 zlog_debug("local membership add for %pSG as G is now ASM",
531 &sg);
d62a17ae 532 pim_ifchannel_local_membership_add(
a1a4295a 533 group->interface, &sg, false /*is_vxlan*/);
d62a17ae 534 }
535 }
15a5dafe 536}
537
5d59e408 538void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
15a5dafe 539{
d62a17ae 540 struct interface *ifp;
541
5d59e408
DS
542 FOR_ALL_INTERFACES (pim->vrf, ifp) {
543 struct pim_interface *pim_ifp = ifp->info;
dda4d23c 544 struct listnode *grpnode;
a16db099 545 struct gm_group *grp;
c29fec4d 546 struct pim_ifchannel *ch, *ch_temp;
5d59e408
DS
547
548 if (!pim_ifp)
d62a17ae 549 continue;
550
dda4d23c 551 /* scan igmp groups */
18adcff1 552 for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
29e58225 553 grp)) {
dda4d23c 554 struct listnode *srcnode;
51700107 555 struct gm_source *src;
dda4d23c
DL
556
557 /* scan group sources */
558 for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
559 srcnode, src)) {
560 igmp_source_forward_reevaluate_one(pim, src);
c29fec4d
SG
561 } /* scan group sources */
562 } /* scan igmp groups */
563
564 RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
565 ch_temp) {
566 if (pim_is_grp_ssm(pim, ch->sg.grp)) {
2a27f13b 567 if (pim_addr_is_any(ch->sg.src))
c29fec4d
SG
568 pim_ifchannel_delete(ch);
569 }
570 }
571 } /* scan interfaces */
15a5dafe 572}
573
6f932b0c 574void igmp_source_forward_start(struct pim_instance *pim,
51700107 575 struct gm_source *source)
12e41d03 576{
75c61a18 577 struct pim_interface *pim_oif;
a16db099 578 struct gm_group *group;
6fff2cc6 579 pim_sgaddr sg;
d62a17ae 580 int result;
581 int input_iface_vif_index = 0;
582
6fff2cc6 583 memset(&sg, 0, sizeof(sg));
d62a17ae 584 sg.src = source->source_addr;
585 sg.grp = source->source_group->group_addr;
586
587 if (PIM_DEBUG_IGMP_TRACE) {
98a81d2b 588 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
a1a4295a
DL
589 source->source_group->interface->name,
590 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
d62a17ae 591 }
592
593 /* Prevent IGMP interface from installing multicast route multiple
594 times */
595 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
596 return;
8711a53d 597 }
d62a17ae 598
599 group = source->source_group;
dda4d23c 600 pim_oif = group->interface->info;
75c61a18
DS
601 if (!pim_oif) {
602 if (PIM_DEBUG_IGMP_TRACE) {
15569c58
DA
603 zlog_debug("%s: multicast not enabled on oif=%s ?",
604 __func__,
dda4d23c 605 source->source_group->interface->name);
75c61a18
DS
606 }
607 return;
608 }
d62a17ae 609
610 if (!source->source_channel_oil) {
c631920c 611 pim_addr vif_source;
d1a1b09c 612 struct prefix src, grp;
d62a17ae 613 struct pim_nexthop nexthop;
614 struct pim_upstream *up = NULL;
615
6f932b0c 616 if (!pim_rp_set_upstream_addr(pim, &vif_source,
732c209c
SP
617 source->source_addr, sg.grp)) {
618 /*Create a dummy channel oil */
15569c58
DA
619 source->source_channel_oil =
620 pim_channel_oil_add(pim, &sg, __func__);
732c209c 621 }
d62a17ae 622
732c209c 623 else {
c631920c
DL
624 pim_addr_to_prefix(&src, vif_source); // RP or Src addr
625 pim_addr_to_prefix(&grp, sg.grp);
732c209c 626
43763b11
DS
627 up = pim_upstream_find(pim, &sg);
628 if (up) {
629 memcpy(&nexthop, &up->rpf.source_nexthop,
630 sizeof(struct pim_nexthop));
631 pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
632 &grp, 0);
633 if (nexthop.interface)
634 input_iface_vif_index =
d62a17ae 635 pim_if_find_vifindex_by_ifindex(
43763b11
DS
636 pim,
637 nexthop.interface->ifindex);
732c209c
SP
638 } else
639 input_iface_vif_index =
43763b11
DS
640 pim_ecmp_fib_lookup_if_vif_index(
641 pim, &src, &grp);
d62a17ae 642
c631920c
DL
643 if (PIM_DEBUG_ZEBRA)
644 zlog_debug(
645 "%s: NHT %pSG vif_source %pPAs vif_index:%d ",
646 __func__, &sg, &vif_source,
647 input_iface_vif_index);
d62a17ae 648
732c209c
SP
649 if (input_iface_vif_index < 1) {
650 if (PIM_DEBUG_IGMP_TRACE) {
651 char source_str[INET_ADDRSTRLEN];
652 pim_inet4_dump("<source?>",
653 source->source_addr,
654 source_str, sizeof(source_str));
655 zlog_debug(
15569c58
DA
656 "%s %s: could not find input interface for source %s",
657 __FILE__, __func__, source_str);
732c209c
SP
658 }
659 source->source_channel_oil =
15569c58 660 pim_channel_oil_add(pim, &sg, __func__);
732c209c
SP
661 }
662
663 else {
664 /*
665 * Protect IGMP against adding looped MFC
666 * entries created by both source and receiver
667 * attached to the same interface. See TODO
50d06d9e 668 * T22. Block only when the intf is non DR
669 * DR must create upstream.
732c209c 670 */
50d06d9e 671 if ((input_iface_vif_index ==
672 pim_oif->mroute_vif_index) &&
673 !(PIM_I_am_DR(pim_oif))) {
732c209c
SP
674 /* ignore request for looped MFC entry
675 */
676 if (PIM_DEBUG_IGMP_TRACE) {
98a81d2b
DL
677 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
678 __func__,
679 &sg,
680 source->source_group
681 ->interface->name,
682 input_iface_vif_index);
732c209c
SP
683 }
684 return;
685 }
686
687 source->source_channel_oil =
15569c58 688 pim_channel_oil_add(pim, &sg, __func__);
732c209c
SP
689 if (!source->source_channel_oil) {
690 if (PIM_DEBUG_IGMP_TRACE) {
98a81d2b
DL
691 zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
692 __FILE__, __func__,
693 &sg);
732c209c
SP
694 }
695 return;
696 }
d62a17ae 697 }
d62a17ae 698 }
8711a53d 699 }
d62a17ae 700
ac6ebcb0 701 if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
8e389ea9 702 result = pim_channel_add_oif(source->source_channel_oil,
dda4d23c 703 group->interface,
1b249e70 704 PIM_OIF_FLAG_PROTO_IGMP, __func__);
8e389ea9
DS
705 if (result) {
706 if (PIM_DEBUG_MROUTE) {
707 zlog_warn("%s: add_oif() failed with return=%d",
708 __func__, result);
709 }
710 return;
d62a17ae 711 }
8e389ea9 712 } else {
90a084e4 713 if (PIM_DEBUG_IGMP_TRACE)
98a81d2b
DL
714 zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
715 __func__, &sg,
716 group->interface->name);
b96892db 717
75c61a18 718 return;
90a084e4 719 }
d62a17ae 720 /*
721 Feed IGMPv3-gathered local membership information into PIM
722 per-interface (S,G) state.
723 */
a1a4295a 724 if (!pim_ifchannel_local_membership_add(group->interface, &sg,
448139e7 725 false /*is_vxlan*/)) {
d62a17ae 726 if (PIM_DEBUG_MROUTE)
98a81d2b
DL
727 zlog_warn("%s: Failure to add local membership for %pSG",
728 __func__, &sg);
b96892db
DS
729
730 pim_channel_del_oif(source->source_channel_oil,
a1a4295a
DL
731 group->interface, PIM_OIF_FLAG_PROTO_IGMP,
732 __func__);
d62a17ae 733 return;
734 }
735
736 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
12e41d03
DL
737}
738
739/*
740 igmp_source_forward_stop: stop fowarding, but keep the source
741 igmp_source_delete: stop fowarding, and delete the source
742 */
51700107 743void igmp_source_forward_stop(struct gm_source *source)
12e41d03 744{
a16db099 745 struct gm_group *group;
6fff2cc6 746 pim_sgaddr sg;
d62a17ae 747 int result;
748
6fff2cc6 749 memset(&sg, 0, sizeof(sg));
d62a17ae 750 sg.src = source->source_addr;
751 sg.grp = source->source_group->group_addr;
752
753 if (PIM_DEBUG_IGMP_TRACE) {
98a81d2b 754 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
a1a4295a
DL
755 source->source_group->interface->name,
756 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
d62a17ae 757 }
758
759 /* Prevent IGMP interface from removing multicast route multiple
760 times */
761 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
762 return;
763 }
764
765 group = source->source_group;
766
767 /*
768 It appears that in certain circumstances that
769 igmp_source_forward_stop is called when IGMP forwarding
770 was not enabled in oif_flags for this outgoing interface.
771 Possibly because of multiple calls. When that happens, we
772 enter the below if statement and this function returns early
773 which in turn triggers the calling function to assert.
774 Making the call to pim_channel_del_oif and ignoring the return code
775 fixes the issue without ill effect, similar to
776 pim_forward_stop below.
777 */
778 result = pim_channel_del_oif(source->source_channel_oil,
a1a4295a
DL
779 group->interface, PIM_OIF_FLAG_PROTO_IGMP,
780 __func__);
d62a17ae 781 if (result) {
782 if (PIM_DEBUG_IGMP_TRACE)
783 zlog_debug(
784 "%s: pim_channel_del_oif() failed with return=%d",
785 __func__, result);
786 return;
787 }
788
789 /*
790 Feed IGMPv3-gathered local membership information into PIM
791 per-interface (S,G) state.
792 */
dda4d23c 793 pim_ifchannel_local_membership_del(group->interface, &sg);
d62a17ae 794
795 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
12e41d03
DL
796}
797
798void pim_forward_start(struct pim_ifchannel *ch)
799{
d62a17ae 800 struct pim_upstream *up = ch->upstream;
9443810e 801 uint32_t mask = 0;
d62a17ae 802
8e8be741
DL
803 if (PIM_DEBUG_PIM_TRACE)
804 zlog_debug("%s: (S,G)=%pSG oif=%s (%pI4)", __func__, &ch->sg,
805 ch->interface->name, &up->upstream_addr);
d62a17ae 806
9443810e 807 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
d62a17ae 808 mask = PIM_OIF_FLAG_PROTO_IGMP;
809
9443810e
SP
810 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
811 mask |= PIM_OIF_FLAG_PROTO_PIM;
812
1b249e70
AK
813 pim_channel_add_oif(up->channel_oil, ch->interface,
814 mask, __func__);
12e41d03
DL
815}
816
86696f7b 817void pim_forward_stop(struct pim_ifchannel *ch)
12e41d03 818{
d62a17ae 819 struct pim_upstream *up = ch->upstream;
12e41d03 820
d62a17ae 821 if (PIM_DEBUG_PIM_TRACE) {
86696f7b 822 zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
15569c58 823 __func__, ch->sg_str, ch->interface->name,
86696f7b 824 up->channel_oil->installed);
d62a17ae 825 }
12e41d03 826
2164ed5d
DS
827 /*
828 * If a channel is being removed, check to see if we still need
829 * to inherit the interface. If so make sure it is added in
830 */
831 if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
832 pim_channel_add_oif(up->channel_oil, ch->interface,
1b249e70 833 PIM_OIF_FLAG_PROTO_PIM, __func__);
2164ed5d
DS
834 else
835 pim_channel_del_oif(up->channel_oil, ch->interface,
1b249e70 836 PIM_OIF_FLAG_PROTO_PIM, __func__);
12e41d03 837}
8799b66b 838
d62a17ae 839void pim_zebra_zclient_update(struct vty *vty)
8799b66b 840{
d62a17ae 841 vty_out(vty, "Zclient update socket: ");
842
843 if (zclient) {
844 vty_out(vty, "%d failures=%d\n", zclient->sock, zclient->fail);
845 } else {
846 vty_out(vty, "<null zclient>\n");
847 }
8799b66b 848}
1bc98276 849
d62a17ae 850struct zclient *pim_zebra_zclient_get(void)
1bc98276 851{
d62a17ae 852 if (zclient)
853 return zclient;
854 else
855 return NULL;
1bc98276 856}
ddbf3e60
DS
857
858void pim_zebra_interface_set_master(struct interface *vrf,
859 struct interface *ifp)
860{
861 zclient_interface_set_master(zclient, vrf, ifp);
862}