]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ldpd and Zebra: Expand existing debug commands.
authorlynne <lynne@voltanet.io>
Thu, 7 May 2020 16:31:40 +0000 (12:31 -0400)
committerlynne <lynne@voltanet.io>
Mon, 11 May 2020 20:22:52 +0000 (16:22 -0400)
L2VPN PW are very hard to determine why they do not come up.  The following
fixes expand the existing show commands in ldp and zebra to display a
reason why the PW is in the DOWN state and also display the labeled nexthop
route selected to reach the PW peer.  By adding this information it will
provide the user some guidance on how to debug the PW issue.  Also fixed an
assert if labels were changed for a PW that is between directly connected
peers.

Signed-off-by: Lynne Morrison <lynne@voltanet.io>
ldpd/l2vpn.c
ldpd/lde.c
ldpd/ldp_vty_exec.c
ldpd/ldpd.h
ldpd/logmsg.c
zebra/zebra_pw.c

index b234e3ebe34f1ba3f78c8de03fd957fca911a031..4a944fa01968095f774778eaa3145ec1f664e5c0 100644 (file)
@@ -303,6 +303,7 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
        if (fnh->remote_label == NO_LABEL) {
                log_warnx("%s: pseudowire %s: no remote label", __func__,
                          pw->ifname);
+               pw->reason = F_PW_NO_REMOTE_LABEL;
                return (0);
        }
 
@@ -310,6 +311,7 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
        if (pw->l2vpn->mtu != pw->remote_mtu) {
                log_warnx("%s: pseudowire %s: MTU mismatch detected", __func__,
                          pw->ifname);
+               pw->reason = F_PW_MTU_MISMATCH;
                return (0);
        }
 
@@ -318,9 +320,11 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
            pw->remote_status != PW_FORWARDING) {
                log_warnx("%s: pseudowire %s: remote end is down", __func__,
                          pw->ifname);
+               pw->reason = F_PW_REMOTE_NOT_FWD;
                return (0);
        }
 
+       pw->reason = F_PW_NO_ERR;
        return (1);
 }
 
@@ -517,10 +521,13 @@ l2vpn_pw_status_update(struct zapi_pw_status *zpw)
                return (1);
        }
 
-       if (zpw->status == PW_STATUS_UP)
+       if (zpw->status == PW_STATUS_UP) {
                local_status = PW_FORWARDING;
-       else
+               pw->reason = F_PW_NO_ERR;
+       } else {
                local_status = PW_NOT_FORWARDING;
+               pw->reason = F_PW_LOCAL_NOT_FWD;
+       }
 
        /* local status didn't change */
        if (pw->local_status == local_status)
@@ -604,6 +611,7 @@ l2vpn_binding_ctl(pid_t pid)
                        pwctl.local_ifmtu = pw->l2vpn->mtu;
                        pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ?
                            1 : 0;
+                       pwctl.reason = pw->reason;
                } else
                        pwctl.local_label = NO_LABEL;
 
index 7d1df158a536a59027ba19b9f3f6696664cd1edb..32202789603dfdd56bdddffc4dd1c55c5de7dda9 100644 (file)
@@ -751,7 +751,6 @@ lde_update_label(struct fec_node *fn)
                                return (MPLS_LABEL_IMPLICIT_NULL);
                        return MPLS_LABEL_IPV6_EXPLICIT_NULL;
                default:
-                       fatalx("lde_update_label: unexpected fec type");
                        break;
                }
        }
@@ -1421,8 +1420,10 @@ lde_nbr_del(struct lde_nbr *ln)
                                if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
                                        continue;
                                pw = (struct l2vpn_pw *) fn->data;
-                               if (pw)
+                               if (pw) {
+                                       pw->reason = F_PW_NO_REMOTE_LABEL;
                                        l2vpn_pw_reset(pw);
+                               }
                                break;
                        default:
                                break;
index d317da7b205398365b39efbaca4d849517335a47..d74017c7e27ff551a5f166fdf7613b81d983fe9e 100644 (file)
@@ -1256,6 +1256,8 @@ show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg,
                            "GroupID: %u\n", "", pw->local_cword,
                            pw_type_name(pw->type),pw->local_gid);
                        vty_out (vty, "%-8sMTU: %u\n", "",pw->local_ifmtu);
+                       vty_out (vty, "%-8sLast failure: %s\n", "",
+                           pw_error_code(pw->reason));
                } else
                        vty_out (vty,"    Local Label: unassigned\n");
 
@@ -1309,6 +1311,8 @@ show_l2vpn_binding_msg_json(struct imsg *imsg, struct show_params *params,
                            pw->local_gid);
                        json_object_int_add(json_pw, "localIfMtu",
                            pw->local_ifmtu);
+                       json_object_string_add(json_pw, "lastFailureReason",
+                           pw_error_code(pw->reason));
                } else
                        json_object_string_add(json_pw, "localLabel",
                            "unassigned");
index 606fb372bbd2b758b04764456f3585a6b1baf25a..c1bcc56c448b1c06c5fc806a8ec88fd104497316 100644 (file)
@@ -422,6 +422,7 @@ struct l2vpn_pw {
        uint32_t                 local_status;
        uint32_t                 remote_status;
        uint8_t                  flags;
+       uint8_t                  reason;
        QOBJ_FIELDS
 };
 RB_HEAD(l2vpn_pw_head, l2vpn_pw);
@@ -433,6 +434,12 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
 #define F_PW_CWORD             0x08    /* control word negotiated */
 #define F_PW_STATIC_NBR_ADDR   0x10    /* static neighbor address configured */
 
+#define F_PW_NO_ERR             0x00   /* no error reported */
+#define F_PW_LOCAL_NOT_FWD      0x01   /* locally can't forward over PW */
+#define F_PW_REMOTE_NOT_FWD     0x02   /* remote end of PW reported fwd error*/
+#define F_PW_NO_REMOTE_LABEL    0x03   /* have not recvd label from peer */
+#define F_PW_MTU_MISMATCH       0x04   /* mtu mismatch between peers */
+
 struct l2vpn {
        RB_ENTRY(l2vpn)          entry;
        char                     name[L2VPN_NAME_LEN];
@@ -662,6 +669,7 @@ struct ctl_pw {
        uint16_t                 remote_ifmtu;
        uint8_t                  remote_cword;
        uint32_t                 status;
+       uint8_t                  reason;
 };
 
 extern struct ldpd_conf                *ldpd_conf, *vty_conf;
@@ -808,6 +816,7 @@ const char  *if_type_name(enum iface_type);
 const char     *msg_name(uint16_t);
 const char     *status_code_name(uint32_t);
 const char     *pw_type_name(uint16_t);
+const char     *pw_error_code(uint8_t);
 
 /* quagga */
 extern struct thread_master    *master;
index 2c9fbf0dae5fc03d68ea9f0615396b6696d8b0a2..6427d0e13b106073267b3a7fc688b281831fb02b 100644 (file)
@@ -485,3 +485,25 @@ pw_type_name(uint16_t pw_type)
                return (buf);
        }
 }
+
+const char *
+pw_error_code(uint8_t status)
+{
+       static char buf[16];
+
+       switch (status) {
+       case F_PW_NO_ERR:
+               return ("No Error");
+       case F_PW_LOCAL_NOT_FWD:
+               return ("local not forwarding");
+       case F_PW_REMOTE_NOT_FWD:
+               return ("remote not forwarding");
+       case F_PW_NO_REMOTE_LABEL:
+               return ("no remote label");
+       case F_PW_MTU_MISMATCH:
+               return ("mtu mismatch between peers");
+       default:
+               snprintf(buf, sizeof(buf), "[%0x]", status);
+               return (buf);
+       }
+}
index c26b7a6157aaaa9e3b4ed984500d05445f35e1b6..273843baa2bcd3f9a91273c5bf0fcee1e8e30937 100644 (file)
@@ -24,6 +24,8 @@
 #include "thread.h"
 #include "command.h"
 #include "vrf.h"
+#include "lib/json.h"
+#include "printfrr.h"
 
 #include "zebra/debug.h"
 #include "zebra/rib.h"
@@ -506,6 +508,155 @@ DEFUN (show_pseudowires,
        return CMD_SUCCESS;
 }
 
+static void vty_show_mpls_pseudowire_detail(struct vty *vty)
+{
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+       struct route_entry *re;
+       struct nexthop *nexthop;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
+               char buf_nbr[INET6_ADDRSTRLEN];
+               char buf_nh[100];
+
+               vty_out(vty, "Interface: %s\n", pw->ifname);
+               inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+               vty_out(vty, "  Neighbor: %s\n",
+                       (pw->af != AF_UNSPEC) ? buf_nbr : "-");
+               if (pw->local_label != MPLS_NO_LABEL)
+                       vty_out(vty, "  Local Label: %u\n", pw->local_label);
+               else
+                       vty_out(vty, "  Local Label: %s\n", "-");
+               if (pw->remote_label != MPLS_NO_LABEL)
+                       vty_out(vty, "  Remote Label: %u\n", pw->remote_label);
+               else
+                       vty_out(vty, "  Remote Label: %s\n", "-");
+               vty_out(vty, "  Protocol: %s\n",
+                       zebra_route_string(pw->protocol));
+               if (pw->protocol == ZEBRA_ROUTE_LDP)
+                       vty_out(vty, "  VC-ID: %u\n", pw->data.ldp.pwid);
+               vty_out(vty, "  Status: %s \n",
+                       (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP)
+                               ? "Up"
+                               : "Down");
+               re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
+                              &pw->nexthop, NULL);
+               if (re) {
+                       for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+                               snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
+                                          nexthop);
+                               vty_out(vty, "  Next Hop: %s\n", buf_nh);
+                               if (nexthop->nh_label)
+                                       vty_out(vty, "  Next Hop label: %u\n",
+                                               nexthop->nh_label->label[0]);
+                               else
+                                       vty_out(vty, "  Next Hop label: %s\n",
+                                               "-");
+                       }
+               }
+       }
+}
+
+static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
+{
+       struct route_entry *re;
+       struct nexthop *nexthop;
+       char buf_nbr[INET6_ADDRSTRLEN];
+       char buf_nh[100];
+       json_object *json_pw = NULL;
+       json_object *json_nexthop = NULL;
+       json_object *json_nexthops = NULL;
+
+       json_nexthops = json_object_new_array();
+       json_pw = json_object_new_object();
+
+       json_object_string_add(json_pw, "interface", pw->ifname);
+       if (pw->af == AF_UNSPEC)
+               json_object_string_add(json_pw, "neighbor", "-");
+       else {
+               inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+               json_object_string_add(json_pw, "neighbor", buf_nbr);
+       }
+       if (pw->local_label != MPLS_NO_LABEL)
+               json_object_int_add(json_pw, "localLabel", pw->local_label);
+       else
+               json_object_string_add(json_pw, "localLabel", "-");
+       if (pw->remote_label != MPLS_NO_LABEL)
+               json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
+       else
+               json_object_string_add(json_pw, "remoteLabel", "-");
+       json_object_string_add(json_pw, "protocol",
+                              zebra_route_string(pw->protocol));
+       if (pw->protocol == ZEBRA_ROUTE_LDP)
+               json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
+       json_object_string_add(
+               json_pw, "Status",
+               (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) ? "Up"
+                                                                    : "Down");
+       re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
+                      &pw->nexthop, NULL);
+       if (re) {
+               for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+                       json_nexthop = json_object_new_object();
+                       snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
+                       json_object_string_add(json_nexthop, "nexthop", buf_nh);
+                       if (nexthop->nh_label)
+                               json_object_int_add(
+                                       json_nexthop, "nhLabel",
+                                       nexthop->nh_label->label[0]);
+                       else
+                               json_object_string_add(json_nexthop, "nhLabel",
+                                                      "-");
+
+                       json_object_array_add(json_nexthops, json_nexthop);
+               }
+               json_object_object_add(json_pw, "nexthops", json_nexthops);
+       }
+       json_object_array_add(json_pws, json_pw);
+}
+
+static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
+{
+       json_object *json = NULL;
+       json_object *json_pws = NULL;
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       json = json_object_new_object();
+       json_pws = json_object_new_array();
+       RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
+               vty_show_mpls_pseudowire(pw, json_pws);
+       }
+       json_object_object_add(json, "pw", json_pws);
+       vty_out(vty, "%s\n",
+               json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
+       json_object_free(json);
+}
+
+DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
+      "show mpls pseudowires detail [json]$json",
+      SHOW_STR MPLS_STR
+      "Pseudowires\n"
+      "Detailed output\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+
+       if (uj)
+               vty_show_mpls_pseudowire_detail_json(vty);
+       else
+               vty_show_mpls_pseudowire_detail(vty);
+
+       return CMD_SUCCESS;
+}
+
 /* Pseudowire configuration write function. */
 static int zebra_pw_config(struct vty *vty)
 {
@@ -568,4 +719,5 @@ void zebra_pw_vty_init(void)
        install_element(PW_NODE, &pseudowire_control_word_cmd);
 
        install_element(VIEW_NODE, &show_pseudowires_cmd);
+       install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
 }