]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_cmd.c
pimd: Create pimreg interface when we start any interface config
[mirror_frr.git] / pimd / pim_cmd.c
index e002bfee50c2e26bb8e22acabad169e2e3a7a831..19a42964ebaaed1cf9f8d3dde302a1f41de02f5f 100644 (file)
@@ -60,6 +60,7 @@
 #include "pim_ssm.h"
 #include "pim_nht.h"
 #include "pim_bfd.h"
+#include "pim_vxlan.h"
 #include "bfd.h"
 
 #ifndef VTYSH_EXTRACT_PL
@@ -1206,6 +1207,8 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
                        print_header = 1;
                        for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
                                                  up)) {
+                               if (!up->rpf.source_nexthop.interface)
+                                       continue;
 
                                if (strcmp(ifp->name,
                                           up->rpf.source_nexthop
@@ -1696,7 +1699,8 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
        }
 }
 
-static void pim_show_join(struct pim_instance *pim, struct vty *vty, bool uj)
+static void pim_show_join(struct pim_instance *pim, struct vty *vty,
+                         struct prefix_sg *sg, bool uj)
 {
        struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
@@ -1718,6 +1722,12 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, bool uj)
                        continue;
 
                RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       if (sg->grp.s_addr != 0
+                           && sg->grp.s_addr != ch->sg.grp.s_addr)
+                               continue;
+                       if (sg->src.s_addr != 0
+                           && sg->src.s_addr != ch->sg.src.s_addr)
+                       continue;
                        pim_show_join_helper(vty, pim_ifp, ch, json, now, uj);
                } /* scan interface channels */
        }
@@ -1956,7 +1966,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                json = json_object_new_object();
        } else {
                vty_out(vty,
-                       "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G)");
+                       "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN");
                vty_out(vty,
                        "\nInstalled Source           Group            IIF               OIL\n");
        }
@@ -2085,7 +2095,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                        } else {
                                if (first_oif) {
                                        first_oif = 0;
-                                       vty_out(vty, "%s(%c%c%c%c)", out_ifname,
+                                       vty_out(vty, "%s(%c%c%c%c%c)", out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
                                                        ? 'I'
@@ -2094,6 +2104,10 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                 & PIM_OIF_FLAG_PROTO_PIM)
                                                        ? 'J'
                                                        : ' ',
+                                               (c_oil->oif_flags[oif_vif_index]
+                                                & PIM_OIF_FLAG_PROTO_VXLAN)
+                                                       ? 'V'
+                                                       : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_SOURCE)
                                                        ? 'S'
@@ -2103,7 +2117,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                        ? '*'
                                                        : ' ');
                                } else
-                                       vty_out(vty, ", %s(%c%c%c%c)",
+                                       vty_out(vty, ", %s(%c%c%c%c%c)",
                                                out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
@@ -2113,6 +2127,10 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                 & PIM_OIF_FLAG_PROTO_PIM)
                                                        ? 'J'
                                                        : ' ',
+                                               (c_oil->oif_flags[oif_vif_index]
+                                                & PIM_OIF_FLAG_PROTO_VXLAN)
+                                                       ? 'V'
+                                                       : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_SOURCE)
                                                        ? 'S'
@@ -2295,6 +2313,41 @@ static void json_object_pim_upstream_add(json_object *json,
        /* XXX: need to print ths flag in the plain text display as well */
        if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
                json_object_boolean_true_add(json, "sourceMsdp");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+               json_object_boolean_true_add(json, "sendSGRptPrune");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+               json_object_boolean_true_add(json, "lastHopRouter");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+               json_object_boolean_true_add(json, "disableKATExpiry");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+               json_object_boolean_true_add(json, "staticIncomingInterface");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+               json_object_boolean_true_add(json,
+                                            "allowIncomingInterfaceinOil");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+               json_object_boolean_true_add(json, "noPimRegistrationData");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+               json_object_boolean_true_add(json, "forcePimRegistration");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+               json_object_boolean_true_add(json, "sourceVxlanOrigination");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+               json_object_boolean_true_add(json, "sourceVxlanTermination");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+               json_object_boolean_true_add(json, "mlagVxlan");
+
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
+               json_object_boolean_true_add(json,
+                                            "mlagNonDesignatedForwarder");
 }
 
 static const char *
@@ -2335,7 +2388,7 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
 }
 
 static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
-                             bool uj)
+                             struct prefix_sg *sg, bool uj)
 {
        struct listnode *upnode;
        struct pim_upstream *up;
@@ -2362,6 +2415,11 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                char msdp_reg_timer[10];
                char state_str[PIM_REG_STATE_STR_LEN];
 
+               if (sg->grp.s_addr != 0 && sg->grp.s_addr != up->sg.grp.s_addr)
+                       continue;
+               if (sg->src.s_addr != 0 && sg->src.s_addr != up->sg.src.s_addr)
+                       continue;
+
                pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
                pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
                pim_time_uptime(uptime, sizeof(uptime),
@@ -3777,24 +3835,45 @@ DEFUN (show_ip_pim_interface_vrf_all,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_pim_join,
+DEFPY (show_ip_pim_join,
        show_ip_pim_join_cmd,
-       "show ip pim [vrf NAME] join [json]",
+       "show ip pim [vrf NAME] join [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
        SHOW_STR
        IP_STR
        PIM_STR
        VRF_CMD_HELP_STR
        "PIM interface join information\n"
+       "The Source or Group\n"
+       "The Group\n"
        JSON_STR)
 {
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
-       bool uj = use_json(argc, argv);
+       struct prefix_sg sg = {0};
+       struct vrf *v;
+       bool uj = !!json;
+       struct pim_instance *pim;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
+               return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
+
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
                return CMD_WARNING;
+       }
 
-       pim_show_join(vrf->info, vty, uj);
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+
+       pim_show_join(pim, vty, &sg, uj);
 
        return CMD_SUCCESS;
 }
@@ -3809,6 +3888,7 @@ DEFUN (show_ip_pim_join_vrf_all,
        "PIM interface join information\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        struct vrf *vrf;
        bool first = true;
@@ -3823,7 +3903,7 @@ DEFUN (show_ip_pim_join_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               pim_show_join(vrf->info, vty, uj);
+               pim_show_join(vrf->info, vty, &sg, uj);
        }
        if (uj)
                vty_out(vty, "}\n");
@@ -4022,24 +4102,44 @@ DEFUN (show_ip_pim_state_vrf_all,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_pim_upstream,
+DEFPY (show_ip_pim_upstream,
        show_ip_pim_upstream_cmd,
-       "show ip pim [vrf NAME] upstream [json]",
+       "show ip pim [vrf NAME] upstream [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
        SHOW_STR
        IP_STR
        PIM_STR
        VRF_CMD_HELP_STR
        "PIM upstream information\n"
+       "The Source or Group\n"
+       "The Group\n"
        JSON_STR)
 {
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
-       bool uj = use_json(argc, argv);
+       struct prefix_sg sg = {0};
+       struct vrf *v;
+       bool uj = !!json;
+       struct pim_instance *pim;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
+               return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
+
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
                return CMD_WARNING;
+       }
 
-       pim_show_upstream(vrf->info, vty, uj);
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+       pim_show_upstream(pim, vty, &sg, uj);
 
        return CMD_SUCCESS;
 }
@@ -4054,6 +4154,7 @@ DEFUN (show_ip_pim_upstream_vrf_all,
        "PIM upstream information\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        struct vrf *vrf;
        bool first = true;
@@ -4068,7 +4169,7 @@ DEFUN (show_ip_pim_upstream_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               pim_show_upstream(vrf->info, vty, uj);
+               pim_show_upstream(vrf->info, vty, &sg, uj);
        }
 
        return CMD_SUCCESS;
@@ -4257,7 +4358,6 @@ DEFUN (show_ip_pim_nexthop_lookup,
        "Source/RP address\n"
        "Multicast Group address\n")
 {
-       struct pim_nexthop_cache *pnc = NULL;
        struct prefix nht_p;
        int result = 0;
        struct in_addr src_addr, grp_addr;
@@ -4269,7 +4369,6 @@ DEFUN (show_ip_pim_nexthop_lookup,
        char grp_str[PREFIX_STRLEN];
        int idx = 2;
        struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
-       struct pim_rpf rpf;
 
        if (!vrf)
                return CMD_WARNING;
@@ -4315,18 +4414,7 @@ DEFUN (show_ip_pim_nexthop_lookup,
        grp.u.prefix4 = grp_addr;
        memset(&nexthop, 0, sizeof(nexthop));
 
-       memset(&rpf, 0, sizeof(struct pim_rpf));
-       rpf.rpf_addr.family = AF_INET;
-       rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
-       rpf.rpf_addr.u.prefix4 = vif_source;
-
-       pnc = pim_nexthop_cache_find(vrf->info, &rpf);
-       if (pnc)
-               result = pim_ecmp_nexthop_search(vrf->info, pnc, &nexthop,
-                                                &nht_p, &grp, 0);
-       else
-               result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p,
-                                                &grp, 0);
+       result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p, &grp, 0);
 
        if (!result) {
                vty_out(vty,
@@ -4506,8 +4594,8 @@ DEFUN (show_ip_multicast_vrf_all,
        return CMD_SUCCESS;
 }
 
-static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
-                       bool uj)
+static void show_mroute(struct pim_instance *pim, struct vty *vty,
+                       struct prefix_sg *sg, bool fill, bool uj)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
@@ -4544,6 +4632,13 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                if (!c_oil->installed && !uj)
                        continue;
 
+               if (sg->grp.s_addr != 0 &&
+                   sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
+                       continue;
+               if (sg->src.s_addr != 0 &&
+                   sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr)
+                       continue;
+
                pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
                               sizeof(grp_str));
                pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
@@ -4629,6 +4724,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                                        json_object_boolean_true_add(
                                                json_ifp_out, "protocolIgmp");
 
+                               if (c_oil->oif_flags[oif_vif_index]
+                                   & PIM_OIF_FLAG_PROTO_VXLAN)
+                                       json_object_boolean_true_add(
+                                               json_ifp_out, "protocolVxlan");
+
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE)
                                        json_object_boolean_true_add(
@@ -4671,6 +4771,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                                        strcpy(proto, "IGMP");
                                }
 
+                               if (c_oil->oif_flags[oif_vif_index]
+                                   & PIM_OIF_FLAG_PROTO_VXLAN) {
+                                       strcpy(proto, "VxLAN");
+                               }
+
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE) {
                                        strcpy(proto, "SRC");
@@ -4831,28 +4936,43 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
        }
 }
 
-DEFUN (show_ip_mroute,
+DEFPY (show_ip_mroute,
        show_ip_mroute_cmd,
-       "show ip mroute [vrf NAME] [fill] [json]",
+       "show ip mroute [vrf NAME] [A.B.C.D$s_or_g [A.B.C.D$g]] [fill$fill] [json$json]",
        SHOW_STR
        IP_STR
        MROUTE_STR
        VRF_CMD_HELP_STR
+       "The Source or Group\n"
+       "The Group\n"
        "Fill in Assumed data\n"
        JSON_STR)
 {
-       bool uj = use_json(argc, argv);
-       bool fill = false;
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+       struct prefix_sg sg = {0};
+       struct pim_instance *pim;
+       struct vrf *v;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
                return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
 
-       if (argv_find(argv, argc, "fill", &idx))
-               fill = true;
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
+               return CMD_WARNING;
+       }
 
-       show_mroute(vrf->info, vty, fill, uj);
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+       show_mroute(pim, vty, &sg, !!fill, !!json);
        return CMD_SUCCESS;
 }
 
@@ -4866,6 +4986,7 @@ DEFUN (show_ip_mroute_vrf_all,
        "Fill in Assumed data\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        int idx = 4;
        struct vrf *vrf;
@@ -4885,7 +5006,7 @@ DEFUN (show_ip_mroute_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               show_mroute(vrf->info, vty, fill, uj);
+               show_mroute(vrf->info, vty, &sg, fill, uj);
        }
        if (uj)
                vty_out(vty, "}\n");
@@ -5783,7 +5904,8 @@ static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp)
        pim_ifp = ifp->info;
 
        if (!pim_ifp) {
-               pim_ifp = pim_if_new(ifp, true, false, false);
+               pim_ifp = pim_if_new(ifp, true, false, false,
+                       false /*vxlan_term*/);
                if (!pim_ifp) {
                        vty_out(vty, "Could not enable IGMP on interface %s\n",
                                ifp->name);
@@ -6394,7 +6516,8 @@ static int pim_cmd_interface_add(struct interface *ifp)
        struct pim_interface *pim_ifp = ifp->info;
 
        if (!pim_ifp) {
-               pim_ifp = pim_if_new(ifp, false, true, false);
+               pim_ifp = pim_if_new(ifp, false, true, false,
+                       false /*vxlan_term*/);
                if (!pim_ifp) {
                        return 0;
                }
@@ -6404,6 +6527,8 @@ static int pim_cmd_interface_add(struct interface *ifp)
 
        pim_if_addr_add_all(ifp);
        pim_if_membership_refresh(ifp);
+
+       pim_if_create_pimreg(pim_ifp->pim);
        return 1;
 }
 
@@ -7068,21 +7193,23 @@ DEFUN (no_debug_mroute_detail,
        return CMD_SUCCESS;
 }
 
-DEFUN (debug_static,
-       debug_static_cmd,
-       "debug static",
+DEFUN (debug_pim_static,
+       debug_pim_static_cmd,
+       "debug pim static",
        DEBUG_STR
+       DEBUG_PIM_STR
        DEBUG_STATIC_STR)
 {
        PIM_DO_DEBUG_STATIC;
        return CMD_SUCCESS;
 }
 
-DEFUN (no_debug_static,
-       no_debug_static_cmd,
-       "no debug static",
+DEFUN (no_debug_pim_static,
+       no_debug_pim_static_cmd,
+       "no debug pim static",
        NO_STR
        DEBUG_STR
+       DEBUG_PIM_STR
        DEBUG_STATIC_STR)
 {
        PIM_DONT_DEBUG_STATIC;
@@ -7391,6 +7518,29 @@ DEFUN (no_debug_pim_zebra,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_pim_vxlan,
+       debug_pim_vxlan_cmd,
+       "debug pim vxlan",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_VXLAN_STR)
+{
+       PIM_DO_DEBUG_VXLAN;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_vxlan,
+       no_debug_pim_vxlan_cmd,
+       "no debug pim vxlan",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_VXLAN_STR)
+{
+       PIM_DONT_DEBUG_VXLAN;
+       return CMD_SUCCESS;
+}
+
 DEFUN (debug_msdp,
        debug_msdp_cmd,
        "debug msdp",
@@ -7414,14 +7564,6 @@ DEFUN (no_debug_msdp,
        return CMD_SUCCESS;
 }
 
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp,
-              undebug_msdp_cmd,
-              "undebug msdp",
-              UNDEBUG_STR DEBUG_MSDP_STR)
-
 DEFUN (debug_msdp_events,
        debug_msdp_events_cmd,
        "debug msdp events",
@@ -7445,16 +7587,6 @@ DEFUN (no_debug_msdp_events,
        return CMD_SUCCESS;
 }
 
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp_events,
-              undebug_msdp_events_cmd,
-              "undebug msdp events",
-              UNDEBUG_STR
-              DEBUG_MSDP_STR
-              DEBUG_MSDP_EVENTS_STR)
-
 DEFUN (debug_msdp_packets,
        debug_msdp_packets_cmd,
        "debug msdp packets",
@@ -7478,16 +7610,6 @@ DEFUN (no_debug_msdp_packets,
        return CMD_SUCCESS;
 }
 
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp_packets,
-              undebug_msdp_packets_cmd,
-              "undebug msdp packets",
-              UNDEBUG_STR
-              DEBUG_MSDP_STR
-              DEBUG_MSDP_PACKETS_STR)
-
 DEFUN (debug_mtrace,
        debug_mtrace_cmd,
        "debug mtrace",
@@ -8720,6 +8842,369 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all,
        return CMD_SUCCESS;
 }
 
+struct pim_sg_cache_walk_data {
+       struct vty *vty;
+       json_object *json;
+       json_object *json_group;
+       struct in_addr addr;
+       bool addr_match;
+};
+
+static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
+                        struct pim_sg_cache_walk_data *cwd)
+{
+       struct vty *vty = cwd->vty;
+       json_object *json = cwd->json;
+       char src_str[INET_ADDRSTRLEN];
+       char grp_str[INET_ADDRSTRLEN];
+       json_object *json_row;
+       bool installed = (vxlan_sg->up) ? true : false;
+       const char *iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+       const char *oif_name;
+
+       if (pim_vxlan_is_orig_mroute(vxlan_sg))
+               oif_name = vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+       else
+               oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+       if (cwd->addr_match && (vxlan_sg->sg.src.s_addr != cwd->addr.s_addr) &&
+                       (vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) {
+               return;
+       }
+       pim_inet4_dump("<src?>", vxlan_sg->sg.src, src_str, sizeof(src_str));
+       pim_inet4_dump("<grp?>", vxlan_sg->sg.grp, grp_str, sizeof(grp_str));
+       if (json) {
+               json_object_object_get_ex(json, grp_str, &cwd->json_group);
+
+               if (!cwd->json_group) {
+                       cwd->json_group = json_object_new_object();
+                       json_object_object_add(json, grp_str,
+                                       cwd->json_group);
+               }
+
+               json_row = json_object_new_object();
+               json_object_string_add(json_row, "source", src_str);
+               json_object_string_add(json_row, "group", grp_str);
+               json_object_string_add(json_row, "input", iif_name);
+               json_object_string_add(json_row, "output", oif_name);
+               if (installed)
+                       json_object_boolean_true_add(json_row, "installed");
+               else
+                       json_object_boolean_false_add(json_row, "installed");
+               json_object_object_add(cwd->json_group, src_str, json_row);
+       } else {
+               vty_out(vty, "%-15s %-15s %-15s %-15s %-5s\n",
+                               src_str, grp_str, iif_name, oif_name,
+                               installed?"I":"");
+       }
+}
+
+static void pim_show_vxlan_sg_hash_entry(struct hash_backet *backet, void *arg)
+{
+       pim_show_vxlan_sg_entry((struct pim_vxlan_sg *)backet->data,
+                (struct pim_sg_cache_walk_data *)arg);
+}
+
+static void pim_show_vxlan_sg(struct pim_instance *pim,
+               struct vty *vty, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Output          Flags\n");
+       }
+
+       memset(&cwd, 0, sizeof(cwd));
+       cwd.vty = vty;
+       cwd.json = json;
+       hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
+               struct vty *vty, char *addr_str, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+       int result = 0;
+
+       memset(&cwd, 0, sizeof(cwd));
+       result = inet_pton(AF_INET, addr_str, &cwd.addr);
+       if (result <= 0) {
+               vty_out(vty, "Bad address %s: errno=%d: %s\n", addr_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Output          Flags\n");
+       }
+
+       cwd.vty = vty;
+       cwd.json = json;
+       cwd.addr_match = true;
+       hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+static void pim_show_vxlan_sg_one(struct pim_instance *pim,
+               struct vty *vty, char *src_str, char *grp_str, bool uj)
+{
+       json_object *json = NULL;
+       struct prefix_sg sg;
+       int result = 0;
+       struct pim_vxlan_sg *vxlan_sg;
+       const char *iif_name;
+       bool installed;
+       const char *oif_name;
+
+       result = inet_pton(AF_INET, src_str, &sg.src);
+       if (result <= 0) {
+               vty_out(vty, "Bad src address %s: errno=%d: %s\n", src_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+       result = inet_pton(AF_INET, grp_str, &sg.grp);
+       if (result <= 0) {
+               vty_out(vty, "Bad grp address %s: errno=%d: %s\n", grp_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+
+       sg.family = AF_INET;
+       sg.prefixlen = IPV4_MAX_BITLEN;
+       if (uj)
+               json = json_object_new_object();
+
+       vxlan_sg = pim_vxlan_sg_find(pim, &sg);
+       if (vxlan_sg) {
+               installed = (vxlan_sg->up) ? true : false;
+               iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+
+               if (pim_vxlan_is_orig_mroute(vxlan_sg))
+                       oif_name =
+                               vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+               else
+                       oif_name =
+                               vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+               if (uj) {
+                       json_object_string_add(json, "source", src_str);
+                       json_object_string_add(json, "group", grp_str);
+                       json_object_string_add(json, "input", iif_name);
+                       json_object_string_add(json, "output", oif_name);
+                       if (installed)
+                               json_object_boolean_true_add(json, "installed");
+                       else
+                               json_object_boolean_false_add(json,
+                                       "installed");
+               } else {
+                       vty_out(vty, "SG : %s\n", vxlan_sg->sg_str);
+                       vty_out(vty, "  Input     : %s\n", iif_name);
+                       vty_out(vty, "  Output    : %s\n", oif_name);
+                       vty_out(vty, "  installed : %s\n",
+                               installed?"yes":"no");
+               }
+       }
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+DEFUN (show_ip_pim_vxlan_sg,
+       show_ip_pim_vxlan_sg_cmd,
+       "show ip pim [vrf NAME] vxlan-groups [A.B.C.D [A.B.C.D]] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "VxLAN BUM groups\n"
+       "source or group ip\n"
+       "group ip\n"
+       JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf;
+       int idx = 2;
+
+       vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ?
+               argv[idx++]->arg:NULL;
+       char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx) ?
+               argv[idx]->arg:NULL;
+
+       if (src_ip && grp_ip)
+               pim_show_vxlan_sg_one(vrf->info, vty, src_ip, grp_ip, uj);
+       else if (src_ip)
+               pim_show_vxlan_sg_match_addr(vrf->info, vty, src_ip, uj);
+       else
+               pim_show_vxlan_sg(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+static void pim_show_vxlan_sg_work(struct pim_instance *pim,
+               struct vty *vty, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+       struct listnode *node;
+       struct pim_vxlan_sg *vxlan_sg;
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Flags\n");
+       }
+
+       memset(&cwd, 0, sizeof(cwd));
+       cwd.vty = vty;
+       cwd.json = json;
+       for (ALL_LIST_ELEMENTS_RO(pim_vxlan_p->work_list, node, vxlan_sg))
+               pim_show_vxlan_sg_entry(vxlan_sg, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work,
+              show_ip_pim_vxlan_sg_work_cmd,
+              "show ip pim [vrf NAME] vxlan-work [json]",
+              SHOW_STR
+              IP_STR
+              PIM_STR
+              VRF_CMD_HELP_STR
+              "VxLAN work list\n"
+              JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf;
+       int idx = 2;
+
+       vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_vxlan_sg_work(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_ip_pim_mlag,
+       no_ip_pim_mlag_cmd,
+       "no ip pim mlag",
+       NO_STR
+       IP_STR
+       PIM_STR
+       "MLAG\n")
+{
+       struct in_addr addr;
+
+       addr.s_addr = 0;
+       pim_vxlan_mlag_update(true/*mlag_enable*/,
+               false/*peer_state*/, PIM_VXLAN_MLAG_ROLE_SECONDARY,
+               NULL/*peerlink*/, &addr);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (ip_pim_mlag,
+       ip_pim_mlag_cmd,
+       "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
+       IP_STR
+       PIM_STR
+       "MLAG\n"
+       "peerlink sub interface\n"
+       "MLAG role\n"
+       "MLAG role primary\n"
+       "MLAG role secondary\n"
+       "peer session state\n"
+       "peer session state up\n"
+       "peer session state down\n"
+       "configure PIP\n"
+       "unique ip address\n")
+{
+       struct interface *ifp;
+       const char *peerlink;
+       uint32_t role;
+       int idx;
+       bool peer_state;
+       int result;
+       struct in_addr reg_addr;
+
+       idx = 3;
+       peerlink = argv[idx]->arg;
+       ifp = if_lookup_by_name(peerlink, VRF_DEFAULT);
+       if (!ifp) {
+               vty_out(vty, "No such interface name %s\n", peerlink);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       if (!strcmp(argv[idx]->arg, "primary")) {
+               role = PIM_VXLAN_MLAG_ROLE_PRIMARY;
+       } else if (!strcmp(argv[idx]->arg, "secondary")) {
+               role = PIM_VXLAN_MLAG_ROLE_SECONDARY;
+       } else {
+               vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       if (!strcmp(argv[idx]->arg, "up")) {
+               peer_state = true;
+       } else if (strcmp(argv[idx]->arg, "down")) {
+               peer_state = false;
+       } else {
+               vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       result = inet_pton(AF_INET, argv[idx]->arg, &reg_addr);
+       if (result <= 0) {
+               vty_out(vty, "%% Bad reg address %s: errno=%d: %s\n",
+                       argv[idx]->arg,
+                       errno, safe_strerror(errno));
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       pim_vxlan_mlag_update(true, peer_state, role, ifp, &reg_addr);
+
+       return CMD_SUCCESS;
+}
+
 void pim_cmd_init(void)
 {
        install_node(&interface_node,
@@ -8793,6 +9278,8 @@ void pim_cmd_init(void)
        install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
        install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd);
+       install_element(CONFIG_NODE, &ip_pim_mlag_cmd);
+       install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd);
 
        install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -8895,8 +9382,8 @@ void pim_cmd_init(void)
        install_element(ENABLE_NODE, &debug_mroute_detail_cmd);
        install_element(ENABLE_NODE, &no_debug_mroute_cmd);
        install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd);
-       install_element(ENABLE_NODE, &debug_static_cmd);
-       install_element(ENABLE_NODE, &no_debug_static_cmd);
+       install_element(ENABLE_NODE, &debug_pim_static_cmd);
+       install_element(ENABLE_NODE, &no_debug_pim_static_cmd);
        install_element(ENABLE_NODE, &debug_pim_cmd);
        install_element(ENABLE_NODE, &no_debug_pim_cmd);
        install_element(ENABLE_NODE, &debug_pim_nht_cmd);
@@ -8919,15 +9406,14 @@ 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_vxlan_cmd);
+       install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd);
        install_element(ENABLE_NODE, &debug_msdp_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_cmd);
-       install_element(ENABLE_NODE, &undebug_msdp_cmd);
        install_element(ENABLE_NODE, &debug_msdp_events_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_events_cmd);
-       install_element(ENABLE_NODE, &undebug_msdp_events_cmd);
        install_element(ENABLE_NODE, &debug_msdp_packets_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
-       install_element(ENABLE_NODE, &undebug_msdp_packets_cmd);
        install_element(ENABLE_NODE, &debug_mtrace_cmd);
        install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
 
@@ -8943,8 +9429,8 @@ void pim_cmd_init(void)
        install_element(CONFIG_NODE, &debug_mroute_detail_cmd);
        install_element(CONFIG_NODE, &no_debug_mroute_cmd);
        install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd);
-       install_element(CONFIG_NODE, &debug_static_cmd);
-       install_element(CONFIG_NODE, &no_debug_static_cmd);
+       install_element(CONFIG_NODE, &debug_pim_static_cmd);
+       install_element(CONFIG_NODE, &no_debug_pim_static_cmd);
        install_element(CONFIG_NODE, &debug_pim_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_cmd);
        install_element(CONFIG_NODE, &debug_pim_nht_cmd);
@@ -8963,15 +9449,14 @@ void pim_cmd_init(void)
        install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
        install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd);
+       install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
+       install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
        install_element(CONFIG_NODE, &debug_msdp_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_cmd);
-       install_element(CONFIG_NODE, &undebug_msdp_cmd);
        install_element(CONFIG_NODE, &debug_msdp_events_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_events_cmd);
-       install_element(CONFIG_NODE, &undebug_msdp_events_cmd);
        install_element(CONFIG_NODE, &debug_msdp_packets_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
-       install_element(CONFIG_NODE, &undebug_msdp_packets_cmd);
        install_element(CONFIG_NODE, &debug_mtrace_cmd);
        install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
 
@@ -8993,6 +9478,8 @@ void pim_cmd_init(void)
        install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
        install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd);
        install_element(INTERFACE_NODE, &interface_pim_use_source_cmd);
        install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd);
        /* Install BFD command */