ldpd and Zebra: Expand existing debug commands.

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>
This commit is contained in:
lynne 2020-05-07 12:31:40 -04:00
parent a9b763e381
commit 6bbdd9e979
6 changed files with 200 additions and 4 deletions

View 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;

View 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;

View 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");

View 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;

View 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);
}
}

View 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);
}