summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldpd/l2vpn.c12
-rw-r--r--ldpd/lde.c5
-rw-r--r--ldpd/ldp_vty_exec.c4
-rw-r--r--ldpd/ldpd.h9
-rw-r--r--ldpd/logmsg.c22
-rw-r--r--zebra/zebra_pw.c152
6 files changed, 200 insertions, 4 deletions
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index b234e3ebe3..4a944fa019 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -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;
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 7d1df158a5..3220278960 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -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;
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
index d317da7b20..d74017c7e2 100644
--- a/ldpd/ldp_vty_exec.c
+++ b/ldpd/ldp_vty_exec.c
@@ -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");
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 606fb372bb..c1bcc56c44 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -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;
diff --git a/ldpd/logmsg.c b/ldpd/logmsg.c
index 2c9fbf0dae..6427d0e13b 100644
--- a/ldpd/logmsg.c
+++ b/ldpd/logmsg.c
@@ -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);
+ }
+}
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index c26b7a6157..273843baa2 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -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);
}