#define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION)
#define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr
+#define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true
struct pim_iface_upstream_switch {
struct in_addr address;
#include "pim_upstream.h"
#include "pim_ssm.h"
#include "pim_rp.h"
+#include "pim_mlag.h"
RB_GENERATE(pim_ifchannel_rb, pim_ifchannel, pim_ifp_rb, pim_ifchannel_compare);
pim_ifp = ch->interface->info;
+ if (PIM_I_am_DualActive(pim_ifp)) {
+ if (PIM_DEBUG_MLAG)
+ zlog_debug(
+ "%s: if-chnanel-%s is deleted from a Dual "
+ "active Interface",
+ __func__, ch->sg_str);
+ /* Post Delete only if it is the last Dual-active Interface */
+ if (ch->upstream->dualactive_ifchannel_count == 1) {
+ pim_mlag_up_local_del(pim_ifp->pim, ch->upstream);
+ PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(
+ ch->upstream->flags);
+ }
+ ch->upstream->dualactive_ifchannel_count--;
+ }
+
if (ch->upstream->channel_oil) {
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
else
PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
+ /*
+ * advertise MLAG Data to MLAG peer
+ */
+ if (PIM_I_am_DualActive(pim_ifp)) {
+ up->dualactive_ifchannel_count++;
+ /* Sync once for upstream */
+ if (up->dualactive_ifchannel_count == 1) {
+ PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(up->flags);
+ pim_mlag_up_local_add(pim_ifp->pim, up);
+ }
+ if (PIM_DEBUG_MLAG)
+ zlog_debug(
+ "%s: New Dual active if-chnanel is added to upstream:%s "
+ "count:%d, flags:0x%x",
+ __func__, up->sg_str,
+ up->dualactive_ifchannel_count, up->flags);
+ }
+
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: ifchannel %s is created ", __func__,
ch->sg_str);
#define PIM_MLAG_METADATA_LEN 4
+/*********************ACtual Data processing *****************************/
+/* TBD: There can be duplicate updates to FIB***/
+#define PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil) \
+ do { \
+ if (PIM_DEBUG_MLAG) \
+ zlog_debug( \
+ "%s: add Dual-active Interface to %s " \
+ "to oil:%s", \
+ __func__, ch->interface->name, ch->sg_str); \
+ pim_channel_add_oif(ch_oil, ch->interface, \
+ PIM_OIF_FLAG_PROTO_IGMP, __func__); \
+ } while (0)
+
+#define PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil) \
+ do { \
+ if (PIM_DEBUG_MLAG) \
+ zlog_debug( \
+ "%s: del Dual-active Interface to %s " \
+ "to oil:%s", \
+ __func__, ch->interface->name, ch->sg_str); \
+ pim_channel_del_oif(ch_oil, ch->interface, \
+ PIM_OIF_FLAG_PROTO_IGMP, __func__); \
+ } while (0)
+
+
+static void pim_mlag_calculate_df_for_ifchannels(struct pim_upstream *up,
+ bool is_df)
+{
+ struct listnode *chnode;
+ struct listnode *chnextnode;
+ struct pim_ifchannel *ch;
+ struct pim_interface *pim_ifp = NULL;
+ struct channel_oil *ch_oil = NULL;
+
+ ch_oil = (up) ? up->channel_oil : NULL;
+
+ if (!ch_oil)
+ return;
+
+ if (PIM_DEBUG_MLAG)
+ zlog_debug("%s: Calculating DF for Dual active if-channel%s",
+ __func__, up->sg_str);
+
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
+ pim_ifp = (ch->interface) ? ch->interface->info : NULL;
+ if (!pim_ifp || !PIM_I_am_DualActive(pim_ifp))
+ continue;
+
+ if (is_df)
+ PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil);
+ else
+ PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil);
+ }
+}
+
+static void pim_mlag_inherit_mlag_flags(struct pim_upstream *up, bool is_df)
+{
+ struct listnode *listnode;
+ struct pim_upstream *child;
+
+ for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, child)) {
+ PIM_UPSTREAM_FLAG_SET_MLAG_PEER(child->flags);
+ if (is_df)
+ PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(child->flags);
+ else
+ PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
+ pim_mlag_calculate_df_for_ifchannels(child, is_df);
+ }
+}
+
/******************************* pim upstream sync **************************/
/* Update DF role for the upstream entry and return true on role change */
bool pim_mlag_up_df_role_update(struct pim_instance *pim,
PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
+ /*
+ * This Upstream entry synced to peer Because of Dual-active
+ * Interface configuration
+ */
+ if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
+ pim_mlag_calculate_df_for_ifchannels(up, is_df);
+ pim_mlag_inherit_mlag_flags(up, is_df);
+ }
+
/* If the DF role has changed check if ipmr-lo needs to be
* muted/un-muted. Active-Active devices and vxlan termination
* devices (ipmr-lo) are suppressed on the non-DF.
uint32_t local_cost;
bool rv;
- if (!pim_up_mlag_is_local(up))
+ if (!pim_up_mlag_is_local(up)
+ && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
return false;
/* We are yet to rx a status update from the local MLAG daemon so
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
pim = vrf->info;
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
- if (pim_up_mlag_is_local(up))
+ if (pim_up_mlag_is_local(up)
+ || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
pim_mlag_up_local_add_send(pim, up);
}
}
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
pim = vrf->info;
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
- if (!pim_up_mlag_is_local(up))
+ if (!pim_up_mlag_is_local(up)
+ && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(
+ up->flags))
continue;
/* if role changes re-send to peer */
if (pim_mlag_up_df_role_elect(pim, up) &&
if (PIM_DEBUG_MLAG)
zlog_debug("%s: Received Process-Up from Mlag", __func__);
+ /*
+ * Incase of local MLAG restart, PIM needs to replay all the data
+ * since MLAG is empty.
+ */
+ router->connected_to_mlag = true;
+ router->mlag_flags |= PIM_MLAGF_LOCAL_CONN_UP;
return 0;
}
extern void pim_instance_mlag_terminate(struct pim_instance *pim);
extern void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp);
extern void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp);
-extern void pim_mlag_register(void);
-extern void pim_mlag_deregister(void);
extern int pim_zebra_mlag_process_up(void);
extern int pim_zebra_mlag_process_down(void);
extern int pim_zebra_mlag_handle_msg(struct stream *msg, int len);
extern void pim_zpthread_init(void);
extern void pim_zpthread_terminate(void);
+extern void pim_mlag_register(void);
+extern void pim_mlag_deregister(void);
extern void pim_mlag_up_local_add(struct pim_instance *pim,
- struct pim_upstream *upstream);
+ struct pim_upstream *upstream);
extern void pim_mlag_up_local_del(struct pim_instance *pim,
- struct pim_upstream *upstream);
+ struct pim_upstream *upstream);
extern bool pim_mlag_up_df_role_update(struct pim_instance *pim,
- struct pim_upstream *up, bool is_df, const char *reason);
+ struct pim_upstream *up, bool is_df,
+ const char *reason);
#endif
if (up)
listnode_add(up->sources, child);
+ /*
+ * In case parent is MLAG entry copy the data to child
+ */
+ if (up && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
+ PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child->flags);
+ if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
+ PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
+ else
+ PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
+ child->flags);
+ }
+
return up;
}
/* XXX - duplicate send is possible here if pim_rpf_update
* successfully resolved the nexthop
*/
- if (pim_up_mlag_is_local(up))
+ if (pim_up_mlag_is_local(up)
+ || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
pim_mlag_up_local_add(pim, up);
if (PIM_DEBUG_PIM_TRACE) {
uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
{
- if (!(pim_up_mlag_is_local(up)))
+ if (!(pim_up_mlag_is_local(up))
+ && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
return router->infinite_assert_metric.route_metric;
if ((up->rpf.source_nexthop.interface ==
up->sg_str);
FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
if (!ifp->info)
continue;
if (!ch && !starch)
continue;
+ pim_ifp = ifp->info;
+ if (PIM_I_am_DualActive(pim_ifp)
+ && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
+ && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
+ || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
+ continue;
if (pim_upstream_evaluate_join_desired_interface(up, ch,
starch)) {
int flag = PIM_OIF_FLAG_PROTO_PIM;
struct channel_oil *channel_oil;
struct list *sources;
struct list *ifchannels;
+ /* Counter for Dual active ifchannels*/
+ uint32_t dualactive_ifchannel_count;
enum pim_upstream_state join_state;
enum pim_reg_state reg_state;