1 /* PIM support for VxLAN BUM flooding
3 * Copyright (C) 2019 Cumulus Networks, Inc.
5 * This file is part of FRR.
7 * FRR is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
12 * FRR is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
31 #include "pim_iface.h"
32 #include "pim_memory.h"
34 #include "pim_register.h"
36 #include "pim_upstream.h"
37 #include "pim_ifchannel.h"
39 #include "pim_zebra.h"
40 #include "pim_vxlan.h"
42 /* pim-vxlan global info */
43 struct pim_vxlan vxlan_info
, *pim_vxlan_p
= &vxlan_info
;
45 static void pim_vxlan_work_timer_setup(bool start
);
46 static void pim_vxlan_set_peerlink_rif(struct pim_instance
*pim
,
47 struct interface
*ifp
);
49 /*************************** vxlan work list **********************************
50 * A work list is maintained for staggered generation of pim null register
51 * messages for vxlan SG entries that are in a reg_join state.
53 * A max of 500 NULL registers are generated at one shot. If paused reg
54 * generation continues on the next second and so on till all register
55 * messages have been sent out. And the process is restarted every 60s.
57 * purpose of this null register generation is to setup the SPT and maintain
58 * independent of the presence of overlay BUM traffic.
59 ****************************************************************************/
60 static void pim_vxlan_do_reg_work(void)
62 struct listnode
*listnode
;
64 struct pim_vxlan_sg
*vxlan_sg
;
69 if (sec_count
> PIM_VXLAN_NULL_REG_INTERVAL
) {
71 listnode
= vxlan_info
.next_work
?
72 vxlan_info
.next_work
:
73 vxlan_info
.work_list
->head
;
74 if (PIM_DEBUG_VXLAN
&& listnode
)
75 zlog_debug("vxlan SG work %s",
76 vxlan_info
.next_work
? "continues" : "starts");
78 listnode
= vxlan_info
.next_work
;
81 for (; listnode
; listnode
= listnode
->next
) {
82 vxlan_sg
= (struct pim_vxlan_sg
*)listnode
->data
;
83 if (vxlan_sg
->up
&& (vxlan_sg
->up
->reg_state
== PIM_REG_JOIN
)) {
85 zlog_debug("vxlan SG %s periodic NULL register",
87 pim_null_register_send(vxlan_sg
->up
);
91 if (work_cnt
> vxlan_info
.max_work_cnt
) {
92 vxlan_info
.next_work
= listnode
->next
;
94 zlog_debug("vxlan SG %d work items proc and pause",
102 zlog_debug("vxlan SG %d work items proc", work_cnt
);
104 vxlan_info
.next_work
= NULL
;
107 /* Staggered work related info is initialized when the first work comes
110 static void pim_vxlan_init_work(void)
112 if (vxlan_info
.flags
& PIM_VXLANF_WORK_INITED
)
115 vxlan_info
.max_work_cnt
= PIM_VXLAN_WORK_MAX
;
116 vxlan_info
.flags
|= PIM_VXLANF_WORK_INITED
;
117 vxlan_info
.work_list
= list_new();
118 pim_vxlan_work_timer_setup(true/* start */);
121 static void pim_vxlan_add_work(struct pim_vxlan_sg
*vxlan_sg
)
123 if (vxlan_sg
->flags
& PIM_VXLAN_SGF_DEL_IN_PROG
) {
125 zlog_debug("vxlan SG %s skip work list; del-in-prog",
130 pim_vxlan_init_work();
132 /* already a part of the work list */
133 if (vxlan_sg
->work_node
)
137 zlog_debug("vxlan SG %s work list add",
139 vxlan_sg
->work_node
= listnode_add(vxlan_info
.work_list
, vxlan_sg
);
140 /* XXX: adjust max_work_cnt if needed */
143 static void pim_vxlan_del_work(struct pim_vxlan_sg
*vxlan_sg
)
145 if (!vxlan_sg
->work_node
)
149 zlog_debug("vxlan SG %s work list del",
152 if (vxlan_sg
->work_node
== vxlan_info
.next_work
)
153 vxlan_info
.next_work
= vxlan_sg
->work_node
->next
;
155 list_delete_node(vxlan_info
.work_list
, vxlan_sg
->work_node
);
156 vxlan_sg
->work_node
= NULL
;
159 void pim_vxlan_update_sg_reg_state(struct pim_instance
*pim
,
160 struct pim_upstream
*up
, bool reg_join
)
162 struct pim_vxlan_sg
*vxlan_sg
;
164 vxlan_sg
= pim_vxlan_sg_find(pim
, &up
->sg
);
168 /* add the vxlan sg entry to a work list for periodic reg joins.
169 * the entry will stay in the list as long as the register state is
173 pim_vxlan_add_work(vxlan_sg
);
175 pim_vxlan_del_work(vxlan_sg
);
178 static int pim_vxlan_work_timer_cb(struct thread
*t
)
180 pim_vxlan_do_reg_work();
181 pim_vxlan_work_timer_setup(true /* start */);
185 /* global 1second timer used for periodic processing */
186 static void pim_vxlan_work_timer_setup(bool start
)
188 THREAD_OFF(vxlan_info
.work_timer
);
190 thread_add_timer(router
->master
, pim_vxlan_work_timer_cb
, NULL
,
191 PIM_VXLAN_WORK_TIME
, &vxlan_info
.work_timer
);
194 /**************************** vxlan origination mroutes ***********************
195 * For every (local-vtep-ip, bum-mcast-grp) registered by evpn an origination
196 * mroute is setup by pimd. The purpose of this mroute is to forward vxlan
197 * encapsulated BUM (broadcast, unknown-unicast and unknown-multicast packets
198 * over the underlay.)
200 * Sample mroute (single VTEP):
201 * (27.0.0.7, 239.1.1.100) Iif: lo Oifs: uplink-1
203 * Sample mroute (anycast VTEP):
204 * (36.0.0.9, 239.1.1.100) Iif: peerlink-3.4094\
205 * Oifs: peerlink-3.4094 uplink-1
206 ***************************************************************************/
207 static void pim_vxlan_orig_mr_up_del(struct pim_vxlan_sg
*vxlan_sg
)
209 struct pim_upstream
*up
= vxlan_sg
->up
;
215 zlog_debug("vxlan SG %s orig mroute-up del",
219 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG
) {
220 /* clear out all the vxlan properties */
221 up
->flags
&= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG
|
222 PIM_UPSTREAM_FLAG_MASK_STATIC_IIF
|
223 PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY
|
224 PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG
|
225 PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA
|
226 PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL
);
228 /* We bring things to a grinding halt by force expirying
229 * the kat. Doing this will also remove the reference we
230 * created as a "vxlan" source and delete the upstream entry
231 * if there are no other references.
233 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up
->flags
)) {
234 THREAD_OFF(up
->t_ka_timer
);
235 up
= pim_upstream_keep_alive_timer_proc(up
);
237 /* this is really unexpected as we force vxlan
238 * origination mroutes active sources but just in
241 up
= pim_upstream_del(vxlan_sg
->pim
, up
,
242 __PRETTY_FUNCTION__
);
244 /* if there are other references register the source
248 pim_rpf_update(vxlan_sg
->pim
, up
, NULL
, __func__
);
252 static void pim_vxlan_orig_mr_up_iif_update(struct pim_vxlan_sg
*vxlan_sg
)
254 /* update MFC with the new IIF */
255 pim_upstream_fill_static_iif(vxlan_sg
->up
, vxlan_sg
->iif
);
256 pim_upstream_mroute_iif_update(vxlan_sg
->up
->channel_oil
, __func__
);
259 zlog_debug("vxlan SG %s orig mroute-up updated with iif %s",
261 vxlan_sg
->iif
?vxlan_sg
->iif
->name
:"-");
265 /* For every VxLAN BUM multicast group we setup a SG-up that has the following
266 * "forced properties" -
267 * 1. Directly connected on a DR interface i.e. we must act as an FHR
268 * 2. We prime the pump i.e. no multicast data is needed to register this
269 * source with the FHR. To do that we send periodic null registers if
270 * the SG entry is in a register-join state. We also prevent expiry of
272 * 3. As this SG is setup without data there is no need to register encapsulate
273 * data traffic. This encapsulation is explicitly skipped for the following
275 * a) Many levels of encapsulation are needed creating MTU disc challenges.
276 * Overlay BUM is encapsulated in a vxlan/UDP/IP header and then
277 * encapsulated again in a pim-register header.
278 * b) On a vxlan-aa setup both switches rx a copy of each BUM packet. if
279 * they both reg encapsulated traffic the RP will accept the duplicates
280 * as there are no RPF checks for this encapsulated data.
281 * a), b) can be workarounded if needed, but there is really no need because
282 * of (2) i.e. the pump is primed without data.
284 static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg
*vxlan_sg
)
286 struct pim_upstream
*up
;
289 struct pim_instance
*pim
= vxlan_sg
->pim
;
297 zlog_debug("vxlan SG %s orig mroute-up add with iif %s",
299 vxlan_sg
->iif
?vxlan_sg
->iif
->name
:"-");
301 PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags
);
302 /* pin the IIF to lo or peerlink-subinterface and disable NHT */
303 PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags
);
304 /* Fake traffic by setting SRC_STREAM and starting KAT */
305 /* We intentionally skip updating ref count for SRC_STREAM/FHR.
306 * Setting SRC_VXLAN should have already created a reference
307 * preventing the entry from being deleted
309 PIM_UPSTREAM_FLAG_SET_FHR(flags
);
310 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags
);
311 /* Force pimreg even if non-DR. This is needed on a MLAG setup for
314 PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags
);
315 /* prevent KAT expiry. we want the MDT setup even if there is no BUM
318 PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags
);
319 /* SPT for vxlan BUM groups is primed and maintained via NULL
320 * registers so there is no need to reg-encapsulate
321 * vxlan-encapsulated overlay data traffic
323 PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags
);
324 /* On a MLAG setup we force a copy to the MLAG peer while also
325 * accepting traffic from the peer. To do this we set peerlink-rif as
326 * the IIF and also add it to the OIL
328 PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags
);
330 /* XXX: todo: defer pim_upstream add if pim is not enabled on the iif */
331 up
= pim_upstream_find(vxlan_sg
->pim
, &vxlan_sg
->sg
);
333 /* if the iif is set to something other than the vxlan_sg->iif
334 * we must dereg the old nexthop and force to new "static"
337 if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up
->flags
)) {
338 nht_p
.family
= AF_INET
;
339 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
340 nht_p
.u
.prefix4
= up
->upstream_addr
;
341 pim_delete_tracked_nexthop(vxlan_sg
->pim
,
342 &nht_p
, up
, NULL
, false);
344 /* We are acting FHR; clear out use_rpt setting if any */
345 pim_upstream_update_use_rpt(up
, false /*update_mroute*/);
346 pim_upstream_ref(up
, flags
, __PRETTY_FUNCTION__
);
348 pim_vxlan_orig_mr_up_iif_update(vxlan_sg
);
349 /* mute pimreg on origination mroutes */
351 pim_channel_update_oif_mute(up
->channel_oil
,
352 pim
->regiface
->info
);
354 up
= pim_upstream_add(vxlan_sg
->pim
, &vxlan_sg
->sg
,
355 vxlan_sg
->iif
, flags
,
356 __PRETTY_FUNCTION__
, NULL
);
362 zlog_debug("vxlan SG %s orig mroute-up add failed",
367 pim_upstream_keep_alive_timer_start(up
, vxlan_sg
->pim
->keep_alive_time
);
369 /* register the source with the RP */
370 if (up
->reg_state
== PIM_REG_NOINFO
) {
371 pim_register_join(up
);
372 pim_null_register_send(up
);
375 /* update the inherited OIL */
376 pim_upstream_inherited_olist(vxlan_sg
->pim
, up
);
377 if (!up
->channel_oil
->installed
)
378 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
381 static void pim_vxlan_orig_mr_oif_add(struct pim_vxlan_sg
*vxlan_sg
)
383 if (!vxlan_sg
->up
|| !vxlan_sg
->orig_oif
)
387 zlog_debug("vxlan SG %s oif %s add",
388 vxlan_sg
->sg_str
, vxlan_sg
->orig_oif
->name
);
390 vxlan_sg
->flags
|= PIM_VXLAN_SGF_OIF_INSTALLED
;
391 pim_channel_add_oif(vxlan_sg
->up
->channel_oil
,
392 vxlan_sg
->orig_oif
, PIM_OIF_FLAG_PROTO_VXLAN
,
396 static void pim_vxlan_orig_mr_oif_del(struct pim_vxlan_sg
*vxlan_sg
)
398 struct interface
*orig_oif
;
400 orig_oif
= vxlan_sg
->orig_oif
;
401 vxlan_sg
->orig_oif
= NULL
;
403 if (!(vxlan_sg
->flags
& PIM_VXLAN_SGF_OIF_INSTALLED
))
407 zlog_debug("vxlan SG %s oif %s del",
408 vxlan_sg
->sg_str
, orig_oif
->name
);
410 vxlan_sg
->flags
&= ~PIM_VXLAN_SGF_OIF_INSTALLED
;
411 pim_channel_del_oif(vxlan_sg
->up
->channel_oil
,
412 orig_oif
, PIM_OIF_FLAG_PROTO_VXLAN
, __func__
);
415 static inline struct interface
*pim_vxlan_orig_mr_oif_get(
416 struct pim_instance
*pim
)
418 return (vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
) ?
419 pim
->vxlan
.peerlink_rif
: NULL
;
422 /* Single VTEPs: IIF for the vxlan-origination-mroutes is lo or vrf-dev (if
423 * the mroute is in a non-default vrf).
424 * Anycast VTEPs: IIF is the MLAG ISL/peerlink.
426 static inline struct interface
*pim_vxlan_orig_mr_iif_get(
427 struct pim_instance
*pim
)
429 return ((vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
) &&
430 pim
->vxlan
.peerlink_rif
) ?
431 pim
->vxlan
.peerlink_rif
: pim
->vxlan
.default_iif
;
434 static bool pim_vxlan_orig_mr_add_is_ok(struct pim_vxlan_sg
*vxlan_sg
)
436 struct pim_interface
*pim_ifp
;
438 vxlan_sg
->iif
= pim_vxlan_orig_mr_iif_get(vxlan_sg
->pim
);
442 pim_ifp
= (struct pim_interface
*)vxlan_sg
->iif
->info
;
443 if (!pim_ifp
|| (pim_ifp
->mroute_vif_index
< 0))
449 static void pim_vxlan_orig_mr_install(struct pim_vxlan_sg
*vxlan_sg
)
451 pim_vxlan_orig_mr_up_add(vxlan_sg
);
453 vxlan_sg
->orig_oif
= pim_vxlan_orig_mr_oif_get(vxlan_sg
->pim
);
454 pim_vxlan_orig_mr_oif_add(vxlan_sg
);
457 static void pim_vxlan_orig_mr_add(struct pim_vxlan_sg
*vxlan_sg
)
459 if (!pim_vxlan_orig_mr_add_is_ok(vxlan_sg
))
463 zlog_debug("vxlan SG %s orig-mr add", vxlan_sg
->sg_str
);
465 pim_vxlan_orig_mr_install(vxlan_sg
);
468 static void pim_vxlan_orig_mr_del(struct pim_vxlan_sg
*vxlan_sg
)
471 zlog_debug("vxlan SG %s orig-mr del", vxlan_sg
->sg_str
);
473 pim_vxlan_orig_mr_oif_del(vxlan_sg
);
474 pim_vxlan_orig_mr_up_del(vxlan_sg
);
477 static void pim_vxlan_orig_mr_iif_update(struct hash_backet
*backet
, void *arg
)
479 struct interface
*ifp
= (struct interface
*)arg
;
480 struct pim_vxlan_sg
*vxlan_sg
= (struct pim_vxlan_sg
*)backet
->data
;
481 struct interface
*old_iif
= vxlan_sg
->iif
;
483 if (!pim_vxlan_is_orig_mroute(vxlan_sg
))
487 zlog_debug("vxlan SG %s iif changed from %s to %s",
489 old_iif
? old_iif
->name
: "-",
490 ifp
? ifp
->name
: "-");
492 if (pim_vxlan_orig_mr_add_is_ok(vxlan_sg
)) {
494 /* upstream exists but iif changed */
495 pim_vxlan_orig_mr_up_iif_update(vxlan_sg
);
498 pim_vxlan_orig_mr_install(vxlan_sg
);
501 pim_vxlan_orig_mr_del(vxlan_sg
);
505 /**************************** vxlan termination mroutes ***********************
506 * For every bum-mcast-grp registered by evpn a *G termination
507 * mroute is setup by pimd. The purpose of this mroute is to pull down vxlan
508 * packets with the bum-mcast-grp dip from the underlay and terminate the
509 * tunnel. This is done by including the vxlan termination device (ipmr-lo) in
510 * its OIL. The vxlan de-capsulated packets are subject to subsequent overlay
514 * (0.0.0.0, 239.1.1.100) Iif: uplink-1 Oifs: ipmr-lo, uplink-1
515 *****************************************************************************/
516 struct pim_interface
*pim_vxlan_get_term_ifp(struct pim_instance
*pim
)
518 return pim
->vxlan
.term_if
?
519 (struct pim_interface
*)pim
->vxlan
.term_if
->info
: NULL
;
522 static void pim_vxlan_term_mr_oif_add(struct pim_vxlan_sg
*vxlan_sg
)
524 if (vxlan_sg
->flags
& PIM_VXLAN_SGF_OIF_INSTALLED
)
528 zlog_debug("vxlan SG %s term-oif %s add",
529 vxlan_sg
->sg_str
, vxlan_sg
->term_oif
->name
);
531 if (pim_ifchannel_local_membership_add(vxlan_sg
->term_oif
,
533 vxlan_sg
->flags
|= PIM_VXLAN_SGF_OIF_INSTALLED
;
535 zlog_warn("vxlan SG %s term-oif %s add failed",
536 vxlan_sg
->sg_str
, vxlan_sg
->term_oif
->name
);
540 static void pim_vxlan_term_mr_oif_del(struct pim_vxlan_sg
*vxlan_sg
)
542 if (!(vxlan_sg
->flags
& PIM_VXLAN_SGF_OIF_INSTALLED
))
546 zlog_debug("vxlan SG %s oif %s del",
547 vxlan_sg
->sg_str
, vxlan_sg
->term_oif
->name
);
549 vxlan_sg
->flags
&= ~PIM_VXLAN_SGF_OIF_INSTALLED
;
550 pim_ifchannel_local_membership_del(vxlan_sg
->term_oif
, &vxlan_sg
->sg
);
553 static void pim_vxlan_term_mr_up_add(struct pim_vxlan_sg
*vxlan_sg
)
555 struct pim_upstream
*up
;
564 zlog_debug("vxlan SG %s term mroute-up add",
567 PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags
);
568 /* enable MLAG designated-forwarder election on termination mroutes */
569 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags
);
571 up
= pim_upstream_add(vxlan_sg
->pim
, &vxlan_sg
->sg
,
572 NULL
/* iif */, flags
,
573 __PRETTY_FUNCTION__
, NULL
);
577 zlog_warn("vxlan SG %s term mroute-up add failed",
582 static void pim_vxlan_term_mr_up_del(struct pim_vxlan_sg
*vxlan_sg
)
584 struct pim_upstream
*up
= vxlan_sg
->up
;
590 zlog_debug("vxlan SG %s term mroute-up del",
593 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM
) {
594 /* clear out all the vxlan related flags */
595 up
->flags
&= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM
|
596 PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN
);
598 pim_upstream_del(vxlan_sg
->pim
, up
,
599 __PRETTY_FUNCTION__
);
603 static void pim_vxlan_term_mr_add(struct pim_vxlan_sg
*vxlan_sg
)
606 zlog_debug("vxlan SG %s term mroute add", vxlan_sg
->sg_str
);
608 vxlan_sg
->term_oif
= vxlan_sg
->pim
->vxlan
.term_if
;
609 if (!vxlan_sg
->term_oif
)
610 /* defer termination mroute till we have a termination device */
613 pim_vxlan_term_mr_up_add(vxlan_sg
);
614 /* set up local membership for the term-oif */
615 pim_vxlan_term_mr_oif_add(vxlan_sg
);
618 static void pim_vxlan_term_mr_del(struct pim_vxlan_sg
*vxlan_sg
)
621 zlog_debug("vxlan SG %s term mroute del", vxlan_sg
->sg_str
);
623 /* remove local membership associated with the term oif */
624 pim_vxlan_term_mr_oif_del(vxlan_sg
);
625 /* remove references to the upstream entry */
626 pim_vxlan_term_mr_up_del(vxlan_sg
);
629 /************************** vxlan SG cache management ************************/
630 static unsigned int pim_vxlan_sg_hash_key_make(const void *p
)
632 const struct pim_vxlan_sg
*vxlan_sg
= p
;
634 return (jhash_2words(vxlan_sg
->sg
.src
.s_addr
,
635 vxlan_sg
->sg
.grp
.s_addr
, 0));
638 static bool pim_vxlan_sg_hash_eq(const void *p1
, const void *p2
)
640 const struct pim_vxlan_sg
*sg1
= p1
;
641 const struct pim_vxlan_sg
*sg2
= p2
;
643 return ((sg1
->sg
.src
.s_addr
== sg2
->sg
.src
.s_addr
)
644 && (sg1
->sg
.grp
.s_addr
== sg2
->sg
.grp
.s_addr
));
647 static struct pim_vxlan_sg
*pim_vxlan_sg_new(struct pim_instance
*pim
,
648 struct prefix_sg
*sg
)
650 struct pim_vxlan_sg
*vxlan_sg
;
652 vxlan_sg
= XCALLOC(MTYPE_PIM_VXLAN_SG
, sizeof(*vxlan_sg
));
656 pim_str_sg_set(sg
, vxlan_sg
->sg_str
);
659 zlog_debug("vxlan SG %s alloc", vxlan_sg
->sg_str
);
661 vxlan_sg
= hash_get(pim
->vxlan
.sg_hash
, vxlan_sg
, hash_alloc_intern
);
666 struct pim_vxlan_sg
*pim_vxlan_sg_find(struct pim_instance
*pim
,
667 struct prefix_sg
*sg
)
669 struct pim_vxlan_sg lookup
;
672 return hash_lookup(pim
->vxlan
.sg_hash
, &lookup
);
675 struct pim_vxlan_sg
*pim_vxlan_sg_add(struct pim_instance
*pim
,
676 struct prefix_sg
*sg
)
678 struct pim_vxlan_sg
*vxlan_sg
;
680 vxlan_sg
= pim_vxlan_sg_find(pim
, sg
);
684 vxlan_sg
= pim_vxlan_sg_new(pim
, sg
);
686 if (pim_vxlan_is_orig_mroute(vxlan_sg
))
687 pim_vxlan_orig_mr_add(vxlan_sg
);
689 pim_vxlan_term_mr_add(vxlan_sg
);
694 void pim_vxlan_sg_del(struct pim_instance
*pim
, struct prefix_sg
*sg
)
696 struct pim_vxlan_sg
*vxlan_sg
;
698 vxlan_sg
= pim_vxlan_sg_find(pim
, sg
);
702 vxlan_sg
->flags
|= PIM_VXLAN_SGF_DEL_IN_PROG
;
704 pim_vxlan_del_work(vxlan_sg
);
706 if (pim_vxlan_is_orig_mroute(vxlan_sg
))
707 pim_vxlan_orig_mr_del(vxlan_sg
);
709 pim_vxlan_term_mr_del(vxlan_sg
);
711 hash_release(vxlan_sg
->pim
->vxlan
.sg_hash
, vxlan_sg
);
714 zlog_debug("vxlan SG %s free", vxlan_sg
->sg_str
);
716 XFREE(MTYPE_PIM_VXLAN_SG
, vxlan_sg
);
719 /******************************* MLAG handling *******************************/
720 /* The peerlink sub-interface is added as an OIF to the origination-mroute.
721 * This is done to send a copy of the multicast-vxlan encapsulated traffic
722 * to the MLAG peer which may mroute it over the underlay if there are any
723 * interested receivers.
725 static void pim_vxlan_sg_peerlink_update(struct hash_backet
*backet
, void *arg
)
727 struct interface
*new_oif
= (struct interface
*)arg
;
728 struct pim_vxlan_sg
*vxlan_sg
= (struct pim_vxlan_sg
*)backet
->data
;
730 if (!pim_vxlan_is_orig_mroute(vxlan_sg
))
733 if (vxlan_sg
->orig_oif
== new_oif
)
736 pim_vxlan_orig_mr_oif_del(vxlan_sg
);
738 vxlan_sg
->orig_oif
= new_oif
;
739 pim_vxlan_orig_mr_oif_add(vxlan_sg
);
742 /* In the case of anycast VTEPs the VTEP-PIP must be used as the
745 bool pim_vxlan_get_register_src(struct pim_instance
*pim
,
746 struct pim_upstream
*up
, struct in_addr
*src_p
)
748 if (!(vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
))
751 /* if address is not available suppress the pim-register */
752 if (vxlan_mlag
.reg_addr
.s_addr
== INADDR_ANY
)
755 *src_p
= vxlan_mlag
.reg_addr
;
759 void pim_vxlan_mlag_update(bool enable
, bool peer_state
, uint32_t role
,
760 struct interface
*peerlink_rif
,
761 struct in_addr
*reg_addr
)
763 struct pim_instance
*pim
;
764 struct interface
*old_oif
;
765 struct interface
*new_oif
;
766 char addr_buf
[INET_ADDRSTRLEN
];
767 struct pim_interface
*pim_ifp
= NULL
;
769 if (PIM_DEBUG_VXLAN
) {
770 inet_ntop(AF_INET
, reg_addr
,
771 addr_buf
, INET_ADDRSTRLEN
);
772 zlog_debug("vxlan MLAG update %s state %s role %d rif %s addr %s",
773 enable
? "enable" : "disable",
774 peer_state
? "up" : "down",
776 peerlink_rif
? peerlink_rif
->name
: "-",
780 /* XXX: for now vxlan termination is only possible in the default VRF
781 * when that changes this will need to change to iterate all VRFs
783 pim
= pim_get_pim_instance(VRF_DEFAULT
);
785 old_oif
= pim_vxlan_orig_mr_oif_get(pim
);
788 vxlan_mlag
.flags
|= PIM_VXLAN_MLAGF_ENABLED
;
790 vxlan_mlag
.flags
&= ~PIM_VXLAN_MLAGF_ENABLED
;
792 if (vxlan_mlag
.peerlink_rif
!= peerlink_rif
)
793 vxlan_mlag
.peerlink_rif
= peerlink_rif
;
795 vxlan_mlag
.reg_addr
= *reg_addr
;
796 vxlan_mlag
.peer_state
= peer_state
;
797 vxlan_mlag
.role
= role
;
799 /* process changes */
800 if (vxlan_mlag
.peerlink_rif
)
801 pim_ifp
= (struct pim_interface
*)vxlan_mlag
.peerlink_rif
->info
;
802 if ((vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
) &&
803 pim_ifp
&& (pim_ifp
->mroute_vif_index
> 0))
804 pim_vxlan_set_peerlink_rif(pim
, peerlink_rif
);
806 pim_vxlan_set_peerlink_rif(pim
, NULL
);
808 new_oif
= pim_vxlan_orig_mr_oif_get(pim
);
809 if (old_oif
!= new_oif
)
810 hash_iterate(pim
->vxlan
.sg_hash
, pim_vxlan_sg_peerlink_update
,
814 /****************************** misc callbacks *******************************/
815 void pim_vxlan_config_write(struct vty
*vty
, char *spaces
, int *writes
)
817 char addr_buf
[INET_ADDRSTRLEN
];
819 if ((vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
) &&
820 vxlan_mlag
.peerlink_rif
) {
822 inet_ntop(AF_INET
, &vxlan_mlag
.reg_addr
,
823 addr_buf
, sizeof(addr_buf
));
825 "%sip pim mlag %s role %s state %s addr %s\n",
827 vxlan_mlag
.peerlink_rif
->name
,
828 (vxlan_mlag
.role
== PIM_VXLAN_MLAG_ROLE_PRIMARY
) ?
829 "primary":"secondary",
830 vxlan_mlag
.peer_state
? "up" : "down",
836 static void pim_vxlan_set_default_iif(struct pim_instance
*pim
,
837 struct interface
*ifp
)
839 struct interface
*old_iif
;
841 if (pim
->vxlan
.default_iif
== ifp
)
844 old_iif
= pim
->vxlan
.default_iif
;
846 zlog_debug("%s: vxlan default iif changed from %s to %s",
848 old_iif
? old_iif
->name
: "-",
849 ifp
? ifp
->name
: "-");
851 old_iif
= pim_vxlan_orig_mr_iif_get(pim
);
852 pim
->vxlan
.default_iif
= ifp
;
853 ifp
= pim_vxlan_orig_mr_iif_get(pim
);
858 zlog_debug("%s: vxlan orig iif changed from %s to %s",
859 __PRETTY_FUNCTION__
, old_iif
? old_iif
->name
: "-",
860 ifp
? ifp
->name
: "-");
862 /* add/del upstream entries for the existing vxlan SG when the
863 * interface becomes available
865 if (pim
->vxlan
.sg_hash
)
866 hash_iterate(pim
->vxlan
.sg_hash
,
867 pim_vxlan_orig_mr_iif_update
, ifp
);
870 static void pim_vxlan_set_peerlink_rif(struct pim_instance
*pim
,
871 struct interface
*ifp
)
873 struct interface
*old_iif
;
875 if (pim
->vxlan
.peerlink_rif
== ifp
)
878 old_iif
= pim
->vxlan
.peerlink_rif
;
880 zlog_debug("%s: vxlan peerlink_rif changed from %s to %s",
881 __PRETTY_FUNCTION__
, old_iif
? old_iif
->name
: "-",
882 ifp
? ifp
->name
: "-");
884 old_iif
= pim_vxlan_orig_mr_iif_get(pim
);
885 pim
->vxlan
.peerlink_rif
= ifp
;
886 ifp
= pim_vxlan_orig_mr_iif_get(pim
);
891 zlog_debug("%s: vxlan orig iif changed from %s to %s",
892 __PRETTY_FUNCTION__
, old_iif
? old_iif
->name
: "-",
893 ifp
? ifp
->name
: "-");
895 /* add/del upstream entries for the existing vxlan SG when the
896 * interface becomes available
898 if (pim
->vxlan
.sg_hash
)
899 hash_iterate(pim
->vxlan
.sg_hash
,
900 pim_vxlan_orig_mr_iif_update
, ifp
);
903 void pim_vxlan_add_vif(struct interface
*ifp
)
905 struct pim_interface
*pim_ifp
= ifp
->info
;
906 struct pim_instance
*pim
= pim_ifp
->pim
;
908 if (pim
->vrf_id
!= VRF_DEFAULT
)
911 if (if_is_loopback_or_vrf(ifp
))
912 pim_vxlan_set_default_iif(pim
, ifp
);
914 if (vxlan_mlag
.flags
& PIM_VXLAN_MLAGF_ENABLED
&&
915 (ifp
== vxlan_mlag
.peerlink_rif
))
916 pim_vxlan_set_peerlink_rif(pim
, ifp
);
919 void pim_vxlan_del_vif(struct interface
*ifp
)
921 struct pim_interface
*pim_ifp
= ifp
->info
;
922 struct pim_instance
*pim
= pim_ifp
->pim
;
924 if (pim
->vrf_id
!= VRF_DEFAULT
)
927 if (pim
->vxlan
.default_iif
== ifp
)
928 pim_vxlan_set_default_iif(pim
, NULL
);
930 if (pim
->vxlan
.peerlink_rif
== ifp
)
931 pim_vxlan_set_peerlink_rif(pim
, NULL
);
934 static void pim_vxlan_term_mr_oif_update(struct hash_backet
*backet
, void *arg
)
936 struct interface
*ifp
= (struct interface
*)arg
;
937 struct pim_vxlan_sg
*vxlan_sg
= (struct pim_vxlan_sg
*)backet
->data
;
939 if (pim_vxlan_is_orig_mroute(vxlan_sg
))
942 if (vxlan_sg
->term_oif
== ifp
)
946 zlog_debug("vxlan SG %s term oif changed from %s to %s",
948 vxlan_sg
->term_oif
? vxlan_sg
->term_oif
->name
: "-",
949 ifp
? ifp
->name
: "-");
951 pim_vxlan_term_mr_del(vxlan_sg
);
952 vxlan_sg
->term_oif
= ifp
;
953 pim_vxlan_term_mr_add(vxlan_sg
);
956 void pim_vxlan_add_term_dev(struct pim_instance
*pim
,
957 struct interface
*ifp
)
959 struct pim_interface
*pim_ifp
;
961 if (pim
->vxlan
.term_if
== ifp
)
965 zlog_debug("vxlan term oif changed from %s to %s",
966 pim
->vxlan
.term_if
? pim
->vxlan
.term_if
->name
: "-",
969 /* enable pim on the term ifp */
970 pim_ifp
= (struct pim_interface
*)ifp
->info
;
972 PIM_IF_DO_PIM(pim_ifp
->options
);
974 pim_ifp
= pim_if_new(ifp
, false /*igmp*/, true /*pim*/,
975 false /*pimreg*/, true /*vxlan_term*/);
976 /* ensure that pimreg existss before using the newly created
977 * vxlan termination device
979 pim_if_create_pimreg(pim
);
982 pim
->vxlan
.term_if
= ifp
;
984 if (pim
->vxlan
.sg_hash
)
985 hash_iterate(pim_ifp
->pim
->vxlan
.sg_hash
,
986 pim_vxlan_term_mr_oif_update
, ifp
);
989 void pim_vxlan_del_term_dev(struct pim_instance
*pim
)
991 struct interface
*ifp
= pim
->vxlan
.term_if
;
992 struct pim_interface
*pim_ifp
;
995 zlog_debug("vxlan term oif changed from %s to -", ifp
->name
);
997 pim
->vxlan
.term_if
= NULL
;
999 if (pim
->vxlan
.sg_hash
)
1000 hash_iterate(pim
->vxlan
.sg_hash
,
1001 pim_vxlan_term_mr_oif_update
, NULL
);
1003 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1005 PIM_IF_DONT_PIM(pim_ifp
->options
);
1006 if (!PIM_IF_TEST_IGMP(pim_ifp
->options
))
1012 void pim_vxlan_init(struct pim_instance
*pim
)
1016 snprintf(hash_name
, sizeof(hash_name
),
1017 "PIM %s vxlan SG hash", pim
->vrf
->name
);
1018 pim
->vxlan
.sg_hash
= hash_create(pim_vxlan_sg_hash_key_make
,
1019 pim_vxlan_sg_hash_eq
, hash_name
);
1022 void pim_vxlan_exit(struct pim_instance
*pim
)
1024 if (pim
->vxlan
.sg_hash
) {
1025 hash_clean(pim
->vxlan
.sg_hash
, NULL
);
1026 hash_free(pim
->vxlan
.sg_hash
);
1027 pim
->vxlan
.sg_hash
= NULL
;