diff --git a/lib/mlag.h b/lib/mlag.h index 2b904d44f4..d461fdc44e 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -26,12 +26,33 @@ extern "C" { #endif +#define MLAG_BUF_LIMIT 2048 + enum mlag_role { MLAG_ROLE_NONE, MLAG_ROLE_PRIMARY, MLAG_ROLE_SECONDARY }; +/* + * This message definition should match mlag.proto + * Beacuse mesasge registartion is based on this + */ +enum mlag_msg_type { + MLAG_MSG_NONE = 0, + MLAG_REGISTER = 1, + MLAG_DEREGISTER = 2, + MLAG_STATUS_UPDATE = 3, + MLAG_MROUTE_ADD = 4, + MLAG_MROUTE_DEL = 5, + MLAG_DUMP = 6, + MLAG_MROUTE_ADD_BULK = 7, + MLAG_MROUTE_DEL_BULK = 8, + MLAG_PIM_CFG_DUMP = 10, + MLAG_VXLAN_UPDATE = 11, + MLAG_PEER_FRR_STATUS = 12, +}; + extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); #ifdef __cplusplus diff --git a/lib/zclient.c b/lib/zclient.c index f809704f86..a51e35fd98 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2536,6 +2536,39 @@ stream_failure: return; } +void zclient_send_mlag_register(struct zclient *client, uint32_t bit_map) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_MLAG_CLIENT_REGISTER, VRF_DEFAULT); + stream_putl(s, bit_map); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); +} + +void zclient_send_mlag_deregister(struct zclient *client) +{ + zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT); +} + +void zclient_send_mlag_data(struct zclient *client, struct stream *client_s) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT); + stream_put(s, client_s->data, client_s->endp); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); +} + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { diff --git a/lib/zclient.h b/lib/zclient.h index 81e454d192..1735495fcc 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -177,6 +177,9 @@ typedef enum { ZEBRA_VXLAN_SG_ADD, ZEBRA_VXLAN_SG_DEL, ZEBRA_VXLAN_SG_REPLAY, + ZEBRA_MLAG_CLIENT_REGISTER, + ZEBRA_MLAG_CLIENT_UNREGISTER, + ZEBRA_MLAG_FORWARD_MSG, } zebra_message_types_t; struct redist_proto { @@ -670,5 +673,11 @@ static inline void zapi_route_set_blackhole(struct zapi_route *api, SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP); }; +extern void zclient_send_mlag_register(struct zclient *client, + uint32_t bit_map); +extern void zclient_send_mlag_deregister(struct zclient *client); + +extern void zclient_send_mlag_data(struct zclient *client, + struct stream *client_s); #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 28b4af9457..2c2b1c9586 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -61,6 +61,7 @@ #include "pim_nht.h" #include "pim_bfd.h" #include "pim_vxlan.h" +#include "pim_mlag.h" #include "bfd.h" #include "pim_bsm.h" @@ -7462,9 +7463,9 @@ DEFPY_HIDDEN (interface_ip_pim_activeactive, pim_ifp = ifp->info; if (no) - pim_ifp->activeactive = false; + pim_if_unconfigure_mlag_dualactive(pim_ifp); else - pim_ifp->activeactive = true; + pim_if_configure_mlag_dualactive(pim_ifp); return CMD_SUCCESS; } @@ -8382,6 +8383,20 @@ DEFUN (no_debug_pim_zebra, return CMD_SUCCESS; } +DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", + DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +{ + PIM_DO_DEBUG_MLAG; + return CMD_SUCCESS; +} + +DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", + NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +{ + PIM_DONT_DEBUG_MLAG; + return CMD_SUCCESS; +} + DEFUN (debug_pim_vxlan, debug_pim_vxlan_cmd, "debug pim vxlan", @@ -10408,6 +10423,8 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(ENABLE_NODE, &debug_pim_zebra_cmd); install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &debug_msdp_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index f5bb316a7a..9f05bc74e5 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -54,6 +54,7 @@ #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" +#define DEBUG_PIM_MLAG_STR "PIM Mlag activity\n" #define DEBUG_PIM_VXLAN_STR "PIM VxLAN events\n" #define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 6848d2dabb..955ad14b01 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -34,6 +34,7 @@ #include "pim_ssmpingd.h" #include "pim_vty.h" #include "pim_bsm.h" +#include "pim_mlag.h" static void pim_instance_terminate(struct pim_instance *pim) { @@ -47,6 +48,8 @@ static void pim_instance_terminate(struct pim_instance *pim) if (pim->static_routes) list_delete(&pim->static_routes); + pim_instance_mlag_terminate(pim); + pim_upstream_terminate(pim); pim_rp_free(pim); @@ -115,6 +118,8 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim_upstream_init(pim); + pim_instance_mlag_init(pim); + pim->last_route_change_time = -1; return pim; } diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 06d41c4b53..dd3ac8fcb0 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -64,6 +64,17 @@ struct pim_router { vrf_id_t vrf_id; enum mlag_role role; + uint32_t pim_mlag_intf_cnt; + /* if true we have registered with MLAG */ + bool mlag_process_register; + /* if true local MLAG process reported that it is connected + * with the peer MLAG process + */ + bool connected_to_mlag; + /* Holds the client data(unencoded) that need to be pushed to MCLAGD*/ + struct stream_fifo *mlag_fifo; + struct stream *mlag_stream; + struct thread *zpthread_mlag_write; }; /* Per VRF PIM DB */ @@ -122,6 +133,9 @@ struct pim_instance { bool ecmp_enable; bool ecmp_rebalance_enable; + /* No. of Dual active I/fs in pim_instance */ + uint32_t inst_mlag_intf_cnt; + /* Bsm related */ struct bsm_scope global_scope; uint64_t bsm_rcvd; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 5a8991c4c0..c57151b900 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -47,6 +47,7 @@ #include "pim_msdp.h" #include "pim_iface.h" #include "pim_bfd.h" +#include "pim_mlag.h" #include "pim_errors.h" extern struct host host; @@ -129,6 +130,7 @@ int main(int argc, char **argv, char **envp) */ pim_zebra_init(); pim_bfd_init(); + pim_mlag_init(); frr_config_fork(); diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c new file mode 100644 index 0000000000..eaec0c716a --- /dev/null +++ b/pimd/pim_mlag.c @@ -0,0 +1,187 @@ +/* PIM Mlag Code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include + +#include "pimd.h" +#include "pim_mlag.h" + +extern struct zclient *zclient; + +static int pim_mlag_register_handler(struct thread *thread) +{ + uint32_t bit_mask = 0; + + if (!zclient) + return -1; + + SET_FLAG(bit_mask, (1 << MLAG_STATUS_UPDATE)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL)); + SET_FLAG(bit_mask, (1 << MLAG_DUMP)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD_BULK)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL_BULK)); + SET_FLAG(bit_mask, (1 << MLAG_PIM_CFG_DUMP)); + SET_FLAG(bit_mask, (1 << MLAG_VXLAN_UPDATE)); + SET_FLAG(bit_mask, (1 << MLAG_PEER_FRR_STATUS)); + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Posting Client Register to MLAG mask:0x%x", + __func__, bit_mask); + + zclient_send_mlag_register(zclient, bit_mask); + return 0; +} + +void pim_mlag_register(void) +{ + if (router->mlag_process_register) + return; + + router->mlag_process_register = true; + + thread_add_event(router->master, pim_mlag_register_handler, NULL, 0, + NULL); +} + +static int pim_mlag_deregister_handler(struct thread *thread) +{ + if (!zclient) + return -1; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Posting Client De-Register to MLAG from PIM", + __func__); + router->connected_to_mlag = false; + zclient_send_mlag_deregister(zclient); + return 0; +} + +void pim_mlag_deregister(void) +{ + /* if somebody still interested in the MLAG channel skip de-reg */ + if (router->pim_mlag_intf_cnt) + return; + + /* not registered; nothing do */ + if (!router->mlag_process_register) + return; + + router->mlag_process_register = false; + + thread_add_event(router->master, pim_mlag_deregister_handler, NULL, 0, + NULL); +} + +void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp) +{ + if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == true) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Configuring active-active on Interface: %s", + __func__, "NULL"); + + pim_ifp->activeactive = true; + if (pim_ifp->pim) + pim_ifp->pim->inst_mlag_intf_cnt++; + + router->pim_mlag_intf_cnt++; + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Total MLAG configured Interfaces on router: %d, Inst:%d", + __func__, router->pim_mlag_intf_cnt, + pim_ifp->pim->inst_mlag_intf_cnt); + + if (router->pim_mlag_intf_cnt == 1) { + /* + * atleast one Interface is configured for MLAG, send register + * to Zebra for receiving MLAG Updates + */ + pim_mlag_register(); + } +} + +void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp) +{ + if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == false) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: UnConfiguring active-active on Interface: %s", + __func__, "NULL"); + + pim_ifp->activeactive = false; + if (pim_ifp->pim) + pim_ifp->pim->inst_mlag_intf_cnt--; + + router->pim_mlag_intf_cnt--; + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Total MLAG configured Interfaces on router: %d, Inst:%d", + __func__, router->pim_mlag_intf_cnt, + pim_ifp->pim->inst_mlag_intf_cnt); + + if (router->pim_mlag_intf_cnt == 0) { + /* + * all the Interfaces are MLAG un-configured, post MLAG + * De-register to Zebra + */ + pim_mlag_deregister(); + } +} + + +void pim_instance_mlag_init(struct pim_instance *pim) +{ + if (!pim) + return; + + pim->inst_mlag_intf_cnt = 0; +} + + +void pim_instance_mlag_terminate(struct pim_instance *pim) +{ + struct interface *ifp; + + if (!pim) + return; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp || pim_ifp->activeactive == false) + continue; + + pim_if_unconfigure_mlag_dualactive(pim_ifp); + } + pim->inst_mlag_intf_cnt = 0; +} + +void pim_mlag_init(void) +{ + router->pim_mlag_intf_cnt = 0; + router->connected_to_mlag = false; + router->mlag_fifo = stream_fifo_new(); + router->zpthread_mlag_write = NULL; + router->mlag_stream = stream_new(MLAG_BUF_LIMIT); +} diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h new file mode 100644 index 0000000000..03fbfccb42 --- /dev/null +++ b/pimd/pim_mlag.h @@ -0,0 +1,42 @@ +/* PIM mlag header. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef __PIM_MLAG_H__ +#define __PIM_MLAG_H__ + +#include "mlag.h" +#include "pim_iface.h" + +extern void pim_mlag_init(void); + +extern void pim_instance_mlag_init(struct pim_instance *pim); + +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); + +#endif diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b0db23f54a..e9cfc7e520 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -50,7 +50,7 @@ #undef PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP -static struct zclient *zclient = NULL; +struct zclient *zclient; /* Router-id update message from zebra. */ diff --git a/pimd/pimd.h b/pimd/pimd.h index 3b83d3b6c7..b7e6d916a8 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -115,6 +115,7 @@ #define PIM_MASK_MTRACE (1 << 25) #define PIM_MASK_VXLAN (1 << 26) #define PIM_MASK_BSM_PROC (1 << 27) +#define PIM_MASK_MLAG (1 << 28) /* Remember 32 bits!!! */ /* PIM error codes */ @@ -171,6 +172,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs & (PIM_MASK_IGMP_TRACE_DETAIL | PIM_MASK_IGMP_TRACE)) #define PIM_DEBUG_ZEBRA (router->debugs & PIM_MASK_ZEBRA) +#define PIM_DEBUG_MLAG (router->debugs & PIM_MASK_MLAG) #define PIM_DEBUG_SSMPINGD (router->debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (router->debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_MROUTE_DETAIL \ @@ -217,6 +219,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DO_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs |= PIM_MASK_IGMP_TRACE_DETAIL) #define PIM_DO_DEBUG_ZEBRA (router->debugs |= PIM_MASK_ZEBRA) +#define PIM_DO_DEBUG_MLAG (router->debugs |= PIM_MASK_MLAG) #define PIM_DO_DEBUG_SSMPINGD (router->debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_MROUTE (router->debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_MROUTE_DETAIL (router->debugs |= PIM_MASK_MROUTE_DETAIL) @@ -248,6 +251,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DONT_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs &= ~PIM_MASK_IGMP_TRACE_DETAIL) #define PIM_DONT_DEBUG_ZEBRA (router->debugs &= ~PIM_MASK_ZEBRA) +#define PIM_DONT_DEBUG_MLAG (router->debugs &= ~PIM_MASK_MLAG) #define PIM_DONT_DEBUG_SSMPINGD (router->debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_MROUTE (router->debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_MROUTE_DETAIL (router->debugs &= ~PIM_MASK_MROUTE_DETAIL) diff --git a/pimd/subdir.am b/pimd/subdir.am index 240b62804f..5407e566a5 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -62,6 +62,7 @@ pimd_libpim_a_SOURCES = \ pimd/pim_zebra.c \ pimd/pim_zlookup.c \ pimd/pim_vxlan.c \ + pimd/pim_mlag.c \ pimd/pimd.c \ # end @@ -114,6 +115,7 @@ noinst_HEADERS += \ pimd/pim_zebra.h \ pimd/pim_zlookup.h \ pimd/pim_vxlan.h \ + pimd/pim_mlag.h \ pimd/pim_vxlan_instance.h \ pimd/pimd.h \ pimd/mtracebis_netlink.h \