summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/ldpd/address.c6
-rw-r--r--usr.sbin/ldpd/adjacency.c8
-rw-r--r--usr.sbin/ldpd/control.c4
-rw-r--r--usr.sbin/ldpd/hello.c4
-rw-r--r--usr.sbin/ldpd/kroute.c115
-rw-r--r--usr.sbin/ldpd/l2vpn.c498
-rw-r--r--usr.sbin/ldpd/labelmapping.c338
-rw-r--r--usr.sbin/ldpd/lde.c303
-rw-r--r--usr.sbin/ldpd/lde.h56
-rw-r--r--usr.sbin/ldpd/lde_lib.c211
-rw-r--r--usr.sbin/ldpd/ldp.h64
-rw-r--r--usr.sbin/ldpd/ldpd.c190
-rw-r--r--usr.sbin/ldpd/ldpd.conf.589
-rw-r--r--usr.sbin/ldpd/ldpd.h111
-rw-r--r--usr.sbin/ldpd/ldpe.c37
-rw-r--r--usr.sbin/ldpd/ldpe.h13
-rw-r--r--usr.sbin/ldpd/log.c91
-rw-r--r--usr.sbin/ldpd/log.h7
-rw-r--r--usr.sbin/ldpd/notification.c160
19 files changed, 2028 insertions, 277 deletions
diff --git a/usr.sbin/ldpd/address.c b/usr.sbin/ldpd/address.c
index 4f998e0e55d..50bcd1756a6 100644
--- a/usr.sbin/ldpd/address.c
+++ b/usr.sbin/ldpd/address.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: address.c,v 1.16 2015/07/21 04:39:28 renato Exp $ */
+/* $OpenBSD: address.c,v 1.17 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -111,7 +111,7 @@ recv_address(struct nbr *nbr, char *buf, u_int16_t len)
}
/* For now we only support IPv4 */
- if (alt.family != htons(ADDR_IPV4)) {
+ if (alt.family != htons(AF_IPV4)) {
send_notification_nbr(nbr, S_UNSUP_ADDR, addr.msgid, addr.type);
return (-1);
}
@@ -148,7 +148,7 @@ gen_address_list_tlv(struct ibuf *buf, struct if_addr *if_addr,
alt.type = TLV_TYPE_ADDRLIST;
alt.length = htons(size);
/* XXX: just ipv4 for now */
- alt.family = htons(ADDR_IPV4);
+ alt.family = htons(AF_IPV4);
ibuf_add(buf, &alt, sizeof(alt));
diff --git a/usr.sbin/ldpd/adjacency.c b/usr.sbin/ldpd/adjacency.c
index bce3151323e..da6b429897f 100644
--- a/usr.sbin/ldpd/adjacency.c
+++ b/usr.sbin/ldpd/adjacency.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: adjacency.c,v 1.6 2015/07/21 04:43:28 renato Exp $ */
+/* $OpenBSD: adjacency.c,v 1.7 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -148,7 +148,8 @@ adj_itimer(int fd, short event, void *arg)
LIST_REMOVE(adj, iface_entry);
break;
case HELLO_TARGETED:
- if (!(adj->source.target->flags & F_TNBR_CONFIGURED)) {
+ if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
+ adj->source.target->pw_count == 0) {
/* remove dynamic targeted neighbor */
LIST_REMOVE(adj->source.target, entry);
tnbr_del(adj->source.target);
@@ -210,7 +211,8 @@ tnbr_del(struct tnbr *tnbr)
struct tnbr *
tnbr_check(struct tnbr *tnbr)
{
- if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC))) {
+ if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
+ tnbr->pw_count == 0) {
LIST_REMOVE(tnbr, entry);
tnbr_del(tnbr);
return (NULL);
diff --git a/usr.sbin/ldpd/control.c b/usr.sbin/ldpd/control.c
index 34ca615f0f2..d6c0e4a7025 100644
--- a/usr.sbin/ldpd/control.c
+++ b/usr.sbin/ldpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.15 2015/02/09 11:54:24 claudio Exp $ */
+/* $OpenBSD: control.c,v 1.16 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -251,6 +251,8 @@ control_dispatch_imsg(int fd, short event, void *bula)
ldpe_adj_ctl(c);
break;
case IMSG_CTL_SHOW_LIB:
+ case IMSG_CTL_SHOW_L2VPN_PW:
+ case IMSG_CTL_SHOW_L2VPN_BINDING:
c->iev.ibuf.pid = imsg.hdr.pid;
ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c
index 891042b0fde..1ef5b19fde3 100644
--- a/usr.sbin/ldpd/hello.c
+++ b/usr.sbin/ldpd/hello.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hello.c,v 1.27 2015/07/21 04:43:28 renato Exp $ */
+/* $OpenBSD: hello.c,v 1.28 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -66,7 +66,7 @@ send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr)
dst.sin_addr.s_addr = tnbr->addr.s_addr;
holdtime = tnbr->hello_holdtime;
flags = TARGETED_HELLO;
- if (tnbr->flags & F_TNBR_CONFIGURED)
+ if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
flags |= REQUEST_TARG_HELLO;
fd = tnbr->discovery_fd;
break;
diff --git a/usr.sbin/ldpd/kroute.c b/usr.sbin/ldpd/kroute.c
index d29500611dc..2f94690fb97 100644
--- a/usr.sbin/ldpd/kroute.c
+++ b/usr.sbin/ldpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.45 2015/07/21 04:43:28 renato Exp $ */
+/* $OpenBSD: kroute.c,v 1.46 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/tree.h>
#include <sys/uio.h>
@@ -47,6 +48,7 @@ struct {
pid_t pid;
int fib_sync;
int fd;
+ int ioctl_fd;
struct event ev;
} kr_state;
@@ -79,6 +81,7 @@ struct kif_node {
RB_ENTRY(kif_node) entry;
TAILQ_HEAD(, kif_addr) addrs;
struct kif k;
+ struct kpw *kpw;
};
void kr_redist_remove(struct kroute *);
@@ -208,6 +211,12 @@ kr_init(int fs)
kr_dispatch_msg, NULL);
event_add(&kr_state.ev, NULL);
+ if ((kr_state.ioctl_fd = socket(AF_INET,
+ SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
+ log_warn("kr_init: ioctl socket");
+ return (-1);
+ }
+
return (0);
}
@@ -294,6 +303,7 @@ kr_fib_couple(void)
struct kroute_prefix *kp;
struct kroute_priority *kprio;
struct kroute_node *kn;
+ struct kif_node *kif;
if (kr_state.fib_sync == 1) /* already coupled */
return;
@@ -319,6 +329,10 @@ kr_fib_couple(void)
}
}
+ RB_FOREACH(kif, kif_tree, &kit)
+ if (kif->kpw)
+ kmpw_install(kif->k.ifname, kif->kpw);
+
log_info("kernel routing table coupled");
}
@@ -329,6 +343,7 @@ kr_fib_decouple(void)
struct kroute_priority *kprio;
struct kroute_node *kn;
u_int32_t rl;
+ struct kif_node *kif;
if (kr_state.fib_sync == 0) /* already decoupled */
return;
@@ -356,6 +371,10 @@ kr_fib_decouple(void)
}
}
+ RB_FOREACH(kif, kif_tree, &kit)
+ if (kif->kpw)
+ kmpw_uninstall(kif->k.ifname, kif->kpw);
+
kr_state.fib_sync = 0;
log_info("kernel routing table decoupled");
}
@@ -1427,3 +1446,97 @@ rtmsg_process(char *buf, size_t len)
return (offset);
}
+
+void
+kmpw_set(struct kpw *kpw)
+{
+ struct kif_node *kif;
+
+ kif = kif_find(kpw->ifindex);
+ if (kif == NULL) {
+ log_warn("kmpw_set: failed to find mpw by index (%u)",
+ kpw->ifindex);
+ return;
+ }
+
+ if (kif->kpw == NULL)
+ kif->kpw = malloc(sizeof(*kif->kpw));
+ memcpy(kif->kpw, kpw, sizeof(*kif->kpw));
+
+ kmpw_install(kif->k.ifname, kpw);
+}
+
+void
+kmpw_unset(struct kpw *kpw)
+{
+ struct kif_node *kif;
+
+ kif = kif_find(kpw->ifindex);
+ if (kif == NULL) {
+ log_warn("kmpw_unset: failed to find mpw by index (%u)",
+ kpw->ifindex);
+ return;
+ }
+
+ if (kif->kpw == NULL) {
+ log_warn("kmpw_unset: %s is not set", kif->k.ifname);
+ return;
+ }
+
+ free(kif->kpw);
+ kif->kpw = NULL;
+ kmpw_uninstall(kif->k.ifname, kpw);
+}
+
+void
+kmpw_install(const char *ifname, struct kpw *kpw)
+{
+ struct sockaddr_in *sin;
+ struct ifreq ifr;
+ struct ifmpwreq imr;
+
+ memset(&imr, 0, sizeof(imr));
+ switch (kpw->pw_type) {
+ case PW_TYPE_ETHERNET:
+ imr.imr_type = IMR_TYPE_ETHERNET;
+ break;
+ case PW_TYPE_ETHERNET_TAGGED:
+ imr.imr_type = IMR_TYPE_ETHERNET_TAGGED;
+ break;
+
+ default:
+ log_warn("kmpw_install: unhandled pseudowire type (%#X)",
+ kpw->pw_type);
+ }
+
+ if (kpw->flags & F_PW_CONTROLWORD)
+ imr.imr_flags |= IMR_FLAG_CONTROLWORD;
+
+ sin = (struct sockaddr_in *) &imr.imr_nexthop;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = kpw->nexthop.s_addr;
+ sin->sin_len = sizeof(struct sockaddr_in);
+
+ imr.imr_lshim.shim_label = kpw->local_label;
+ imr.imr_rshim.shim_label = kpw->remote_label;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t) &imr;
+ if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr))
+ log_warn("ioctl SETMPWCFG");
+}
+
+void
+kmpw_uninstall(const char *ifname, struct kpw *kpw)
+{
+ struct ifreq ifr;
+ struct ifmpwreq imr;
+
+ memset(&imr, 0, sizeof(imr));
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t) &imr;
+ if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr))
+ log_warn("ioctl SETMPWCFG");
+}
diff --git a/usr.sbin/ldpd/l2vpn.c b/usr.sbin/ldpd/l2vpn.c
new file mode 100644
index 00000000000..b93523c7779
--- /dev/null
+++ b/usr.sbin/ldpd/l2vpn.c
@@ -0,0 +1,498 @@
+/* $OpenBSD: l2vpn.c,v 1.1 2015/07/21 04:52:29 renato Exp $ */
+
+/*
+ * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+ * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ldpd.h"
+#include "lde.h"
+#include "ldpe.h"
+#include "control.h"
+#include "log.h"
+
+RB_PROTOTYPE(fec_tree, fec, entry, fec_compare)
+extern struct fec_tree ft;
+
+extern struct ldpd_conf *ldeconf;
+extern struct ldpd_conf *leconf;
+
+struct l2vpn *
+l2vpn_new(const char *name)
+{
+ struct l2vpn *l2vpn;
+
+ if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL)
+ err(1, "l2vpn_new: calloc");
+
+ strlcpy(l2vpn->name, name, sizeof(l2vpn->name));
+
+ /* set default values */
+ l2vpn->mtu = DEFAULT_L2VPN_MTU;
+ l2vpn->pw_type = PW_TYPE_ETHERNET;
+
+ return (l2vpn);
+}
+
+struct l2vpn *
+l2vpn_find(struct ldpd_conf *xconf, char *name)
+{
+ struct l2vpn *l2vpn;
+
+ LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry)
+ if (strcmp(l2vpn->name, name) == 0)
+ return (l2vpn);
+
+ return (NULL);
+}
+
+void
+l2vpn_del(struct l2vpn *l2vpn)
+{
+ struct l2vpn_if *lif;
+ struct l2vpn_pw *pw;
+
+ while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
+ LIST_REMOVE(lif, entry);
+ l2vpn_if_del(lif);
+ }
+ while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
+ LIST_REMOVE(pw, entry);
+ l2vpn_pw_del(pw);
+ }
+
+ free(l2vpn);
+}
+
+void
+l2vpn_init(struct l2vpn *l2vpn)
+{
+ struct l2vpn_pw *pw;
+
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry)
+ l2vpn_pw_init(pw);
+}
+
+struct l2vpn_if *
+l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
+{
+ struct l2vpn_if *lif;
+
+ if ((lif = calloc(1, sizeof(*lif))) == NULL)
+ err(1, "l2vpn_if_new: calloc");
+
+ lif->l2vpn = l2vpn;
+ strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
+ lif->ifindex = kif->ifindex;
+ lif->flags = kif->flags;
+ lif->link_state = kif->link_state;
+
+ return (lif);
+}
+
+struct l2vpn_if *
+l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
+{
+ struct l2vpn_if *lif;
+
+ LIST_FOREACH(lif, &l2vpn->if_list, entry)
+ if (lif->ifindex == ifindex)
+ return (lif);
+
+ return (NULL);
+}
+
+void
+l2vpn_if_del(struct l2vpn_if *lif)
+{
+ free(lif);
+}
+
+struct l2vpn_pw *
+l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
+{
+ struct l2vpn_pw *pw;
+
+ if ((pw = calloc(1, sizeof(*pw))) == NULL)
+ err(1, "l2vpn_pw_new: calloc");
+
+ pw->l2vpn = l2vpn;
+ strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
+ pw->ifindex = kif->ifindex;
+
+ return (pw);
+}
+
+struct l2vpn_pw *
+l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
+{
+ struct l2vpn_pw *pw;
+
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry)
+ if (pw->ifindex == ifindex)
+ return (pw);
+
+ return (NULL);
+}
+
+void
+l2vpn_pw_del(struct l2vpn_pw *pw)
+{
+ struct fec fec;
+
+ if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
+ return;
+
+ l2vpn_pw_fec(pw, &fec);
+ lde_kernel_remove(&fec, pw->addr);
+ free(pw);
+}
+
+void
+l2vpn_pw_init(struct l2vpn_pw *pw)
+{
+ struct fec fec;
+
+ if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
+ return;
+
+ l2vpn_pw_fec(pw, &fec);
+ lde_kernel_insert(&fec, pw->addr, 0, (void *)pw);
+}
+
+void
+l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec)
+{
+ bzero(fec, sizeof(*fec));
+ fec->type = FEC_TYPE_PWID;
+ fec->u.pwid.type = pw->l2vpn->pw_type;
+ fec->u.pwid.pwid = pw->pwid;
+ fec->u.pwid.nexthop.s_addr = pw->addr.s_addr;
+}
+
+void
+l2vpn_pw_reset(struct l2vpn_pw *pw)
+{
+ pw->remote_group = 0;
+ pw->remote_mtu = 0;
+ if (!(pw->flags & F_PW_CONTROLWORD_CONF))
+ pw->flags &= ~F_PW_CONTROLWORD;
+ if (!(pw->flags & F_PW_STATUSTLV_CONF))
+ pw->flags &= ~F_PW_STATUSTLV;
+}
+
+int
+l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
+{
+ struct fec fec;
+ struct fec_node *fn;
+
+ /* check for a remote label */
+ if (fnh->remote_label == NO_LABEL)
+ return (0);
+
+ /* MTUs must match */
+ if (pw->l2vpn->mtu != pw->remote_mtu)
+ return (0);
+
+ /* check pw status if applicable */
+ if ((pw->flags & F_PW_STATUSTLV) &&
+ pw->remote_status != PW_FORWARDING)
+ return (0);
+
+ /* check for a working lsp to the nexthop */
+ bzero(&fec, sizeof(fec));
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix.s_addr = pw->addr.s_addr;
+ fec.u.ipv4.prefixlen = 32;
+ fn = (struct fec_node *)fec_find(&ft, &fec);
+ if (fn == NULL)
+ return (0);
+ LIST_FOREACH(fnh, &fn->nexthops, entry)
+ if (fnh->remote_label == NO_LABEL)
+ return (0);
+
+ return (1);
+}
+
+int
+l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
+{
+ struct fec_nh *fnh;
+ struct l2vpn_pw *pw;
+
+ /* NOTE: thanks martini & friends for all this mess */
+
+ fnh = fec_nh_find(fn, ln->id);
+ if (fnh == NULL)
+ /*
+ * pseudowire not configured, return and record
+ * the mapping later
+ */
+ return (0);
+ pw = (struct l2vpn_pw *) fnh->data;
+
+ l2vpn_pw_reset(pw);
+
+ /* RFC4447 - Section 6.2: control word negotiation */
+ if (fec_find(&ln->sent_map, &fn->fec)) {
+ if ((map->flags & F_MAP_PW_CWORD) &&
+ !(pw->flags & F_PW_CONTROLWORD_CONF)) {
+ /* ignore the received label mapping */
+ return (1);
+ } else if (!(map->flags & F_MAP_PW_CWORD) &&
+ (pw->flags & F_PW_CONTROLWORD_CONF)) {
+ /* TODO append a "Wrong C-bit" status code */
+ lde_send_labelwithdraw(ln, fn);
+
+ pw->flags &= ~F_PW_CONTROLWORD;
+ lde_send_labelmapping(ln, fn, 1);
+ }
+ } else if (map->flags & F_MAP_PW_CWORD) {
+ if (pw->flags & F_PW_CONTROLWORD_CONF)
+ pw->flags |= F_PW_CONTROLWORD;
+ else
+ /* act as if no label mapping had been received */
+ return (1);
+ } else
+ pw->flags &= ~F_PW_CONTROLWORD;
+
+ /* RFC4447 - Section 5.4.3: pseudowire status negotiation */
+ if (fec_find(&ln->recv_map, &fn->fec) == NULL &&
+ !(map->flags & F_MAP_PW_STATUS))
+ pw->flags &= ~F_PW_STATUSTLV;
+
+ return (0);
+}
+
+void
+l2vpn_send_pw_status(u_int32_t peerid, u_int32_t status, struct fec *fec)
+{
+ struct notify_msg nm;
+
+ bzero(&nm, sizeof(nm));
+ nm.status = S_PW_STATUS;
+
+ nm.pw_status = status;
+ nm.flags |= F_NOTIF_PW_STATUS;
+
+ lde_fec2map(fec, &nm.fec);
+ nm.flags |= F_NOTIF_FEC;
+
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
+ &nm, sizeof(nm));
+}
+
+void
+l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
+{
+ struct fec fec;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ struct l2vpn_pw *pw;
+
+ /* TODO group wildcard */
+ if (!(nm->fec.flags & F_MAP_PW_ID))
+ return;
+
+ lde_map2fec(&nm->fec, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
+ if (fn == NULL)
+ /* unknown fec */
+ return;
+
+ fnh = fec_nh_find(fn, ln->id);
+ if (fnh == NULL)
+ return;
+ pw = (struct l2vpn_pw *) fnh->data;
+
+ /* remote status didn't change */
+ if (pw->remote_status == nm->pw_status)
+ return;
+
+ pw->remote_status = nm->pw_status;
+
+ if (l2vpn_pw_ok(pw, fnh))
+ lde_send_change_klabel(fn, fnh);
+ else
+ lde_send_delete_klabel(fn, fnh);
+}
+
+void
+l2vpn_sync_pws(struct in_addr addr)
+{
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ struct fec fec;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+
+ LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
+ if (pw->addr.s_addr == addr.s_addr) {
+ l2vpn_pw_fec(pw, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
+ if (fn == NULL)
+ continue;
+ fnh = fec_nh_find(fn, pw->addr);
+ if (fnh == NULL)
+ continue;
+
+ if (l2vpn_pw_ok(pw, fnh))
+ lde_send_change_klabel(fn, fnh);
+ else
+ lde_send_delete_klabel(fn, fnh);
+ }
+ }
+ }
+}
+
+void
+l2vpn_pw_ctl(pid_t pid)
+{
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ static struct ctl_pw pwctl;
+
+ LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
+ bzero(&pwctl, sizeof(pwctl));
+ strlcpy(pwctl.ifname, pw->ifname,
+ sizeof(pwctl.ifname));
+ pwctl.pwid = pw->pwid;
+ pwctl.nexthop.s_addr = pw->addr.s_addr;
+ pwctl.status = pw->flags & F_PW_STATUS_UP;
+
+ lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
+ pid, &pwctl, sizeof(pwctl));
+ }
+}
+
+void
+l2vpn_binding_ctl(pid_t pid)
+{
+ struct fec *f;
+ struct fec_node *fn;
+ struct lde_map *me;
+ struct fec_nh *fnh;
+ struct l2vpn_pw *pw;
+ static struct ctl_pw pwctl;
+
+ RB_FOREACH(f, fec_tree, &ft) {
+ if (f->type != FEC_TYPE_PWID)
+ continue;
+
+ fn = (struct fec_node *)f;
+ if (fn->local_label == NO_LABEL &&
+ LIST_EMPTY(&fn->downstream))
+ continue;
+
+ fnh = fec_nh_find(fn, f->u.pwid.nexthop);
+ if (fnh != NULL)
+ pw = (struct l2vpn_pw *) fnh->data;
+ else
+ pw = NULL;
+
+ bzero(&pwctl, sizeof(pwctl));
+ pwctl.type = f->u.pwid.type;
+ pwctl.pwid = f->u.pwid.pwid;
+ pwctl.nexthop = f->u.pwid.nexthop;
+
+ if (pw) {
+ pwctl.local_label = fn->local_label;
+ pwctl.local_gid = 0;
+ pwctl.local_ifmtu = pw->l2vpn->mtu;
+ } else
+ pwctl.local_label = NO_LABEL;
+
+ LIST_FOREACH(me, &fn->downstream, entry)
+ if (f->u.pwid.nexthop.s_addr == me->nexthop->id.s_addr)
+ break;
+
+ if (me) {
+ pwctl.remote_label = me->map.label;
+ pwctl.remote_gid = me->map.fec.pwid.group_id;
+ if (me->map.flags & F_MAP_PW_IFMTU)
+ pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
+
+ lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
+ 0, pid, &pwctl, sizeof(pwctl));
+ } else if (pw) {
+ pwctl.remote_label = NO_LABEL;
+
+ lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
+ 0, pid, &pwctl, sizeof(pwctl));
+ }
+ }
+}
+
+/* ldpe */
+
+void
+ldpe_l2vpn_init(struct l2vpn *l2vpn)
+{
+ struct l2vpn_pw *pw;
+
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry)
+ ldpe_l2vpn_pw_init(pw);
+}
+
+void
+ldpe_l2vpn_exit(struct l2vpn *l2vpn)
+{
+ struct l2vpn_pw *pw;
+
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry)
+ ldpe_l2vpn_pw_exit(pw);
+}
+
+void
+ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
+{
+ struct tnbr *tnbr;
+
+ if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
+ return;
+
+ tnbr = tnbr_find(leconf, pw->addr);
+ if (tnbr->discovery_fd == 0)
+ tnbr_init(leconf, tnbr);
+}
+
+void
+ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
+{
+ struct tnbr *tnbr;
+
+ if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY)
+ return;
+
+ tnbr = tnbr_find(leconf, pw->addr);
+ if (tnbr) {
+ tnbr->pw_count--;
+ tnbr_check(tnbr);
+ }
+}
diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c
index df62ce14e44..2652092c594 100644
--- a/usr.sbin/ldpd/labelmapping.c
+++ b/usr.sbin/ldpd/labelmapping.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: labelmapping.c,v 1.32 2015/07/19 20:54:16 renato Exp $ */
+/* $OpenBSD: labelmapping.c,v 1.33 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -40,13 +40,9 @@
void gen_label_tlv(struct ibuf *, u_int32_t);
void gen_reqid_tlv(struct ibuf *, u_int32_t);
-void gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t);
-void gen_wcard_fec_tlv(struct ibuf *);
int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, u_int16_t,
u_int32_t *);
-int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, u_int16_t,
- u_int8_t *, u_int32_t *, u_int8_t *);
static void
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, u_int16_t size)
@@ -82,11 +78,27 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh)
/* calculate size */
tlv_size = LDP_MSG_LEN + TLV_HDR_LEN;
- if (me->map.flags & F_MAP_WILDCARD)
+
+ switch (me->map.type) {
+ case FEC_WILDCARD:
tlv_size += FEC_ELM_WCARD_LEN;
- else
+ break;
+ case FEC_PREFIX:
tlv_size += FEC_ELM_PREFIX_MIN_LEN +
- PREFIX_SIZE(me->map.prefixlen);
+ PREFIX_SIZE(me->map.fec.ipv4.prefixlen);
+ break;
+ case FEC_PWID:
+ tlv_size += FEC_PWID_ELM_MIN_LEN;
+
+ if (me->map.flags & F_MAP_PW_ID)
+ tlv_size += sizeof(u_int32_t);
+ if (me->map.flags & F_MAP_PW_IFMTU)
+ tlv_size += FEC_SUBTLV_IFMTU_LEN;
+ if (me->map.flags & F_MAP_PW_STATUS)
+ tlv_size += PW_STATUS_TLV_LEN;
+ break;
+ }
+
if (me->map.label != NO_LABEL)
tlv_size += LABEL_TLV_LEN;
if (me->map.flags & F_MAP_REQ_ID)
@@ -103,14 +115,13 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh)
/* append message and tlvs */
gen_msg_tlv(buf, type, tlv_size);
- if (me->map.flags & F_MAP_WILDCARD)
- gen_wcard_fec_tlv(buf);
- else
- gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
+ gen_fec_tlv(buf, &me->map);
if (me->map.label != NO_LABEL)
gen_label_tlv(buf, me->map.label);
if (me->map.flags & F_MAP_REQ_ID)
gen_reqid_tlv(buf, me->map.requestid);
+ if (me->map.flags & F_MAP_PW_STATUS)
+ gen_pw_status_tlv(buf, me->map.pw_status);
TAILQ_REMOVE(mh, me, entry);
free(me);
@@ -128,10 +139,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
struct ldp_msg lm;
struct tlv ft;
u_int32_t label = NO_LABEL, reqid = 0;
+ u_int32_t pw_status = 0;
u_int8_t flags = 0;
-
int feclen, lbllen, tlen;
- u_int8_t addr_type;
struct mapping_entry *me;
struct mapping_head mh;
@@ -168,23 +178,29 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
TAILQ_INSERT_HEAD(&mh, me, entry);
if ((tlen = tlv_decode_fec_elm(nbr, &lm, buf, feclen,
- &addr_type, &me->map.prefix.s_addr, &me->map.prefixlen)) == -1)
+ &me->map)) == -1)
goto err;
+ if (me->map.type == FEC_PWID &&
+ type == MSG_TYPE_LABELMAPPING &&
+ !(me->map.flags & F_MAP_PW_ID)) {
+ send_notification_nbr(nbr, S_MISS_MSG, lm.msgid,
+ lm.type);
+ return (-1);
+ }
/*
* The Wildcard FEC Element can be used only in the
* Label Withdraw and Label Release messages.
*/
- if (addr_type == FEC_WILDCARD) {
+ if (me->map.type == FEC_WILDCARD) {
switch (type) {
- case MSG_TYPE_LABELWITHDRAW:
- case MSG_TYPE_LABELRELEASE:
- me->map.flags |= F_MAP_WILDCARD;
- break;
- default:
+ case MSG_TYPE_LABELMAPPING:
+ case MSG_TYPE_LABELREQUEST:
+ case MSG_TYPE_LABELABORTREQ:
session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid,
lm.type);
goto err;
+ default:
break;
}
}
@@ -218,7 +234,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
- u_int32_t reqbuf, labelbuf;
+ u_int32_t reqbuf, labelbuf, statusbuf;
if (len < sizeof(tlv)) {
session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid,
@@ -227,10 +243,15 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
}
bcopy(buf, &tlv, sizeof(tlv));
+ if (ntohs(tlv.length) > len - TLV_HDR_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid,
+ lm.type);
+ goto err;
+ }
buf += TLV_HDR_LEN;
len -= TLV_HDR_LEN;
- switch (ntohs(tlv.type)) {
+ switch (ntohs(tlv.type) & ~UNKNOWN_FLAG) {
case TLV_TYPE_LABELREQUEST:
switch (type) {
case MSG_TYPE_LABELMAPPING:
@@ -287,6 +308,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
break;
}
break;
+ case TLV_TYPE_PW_STATUS:
+ switch (type) {
+ case MSG_TYPE_LABELMAPPING:
+ if (ntohs(tlv.length) != 4) {
+ session_shutdown(nbr, S_BAD_TLV_LEN,
+ lm.msgid, lm.type);
+ goto err;
+ }
+
+ flags |= F_MAP_PW_STATUS;
+ memcpy(&statusbuf, buf, sizeof(statusbuf));
+ pw_status = ntohl(statusbuf);
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ break;
default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) {
send_notification_nbr(nbr, S_UNKNOWN_TLV,
@@ -307,32 +346,34 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type)
me->map.label = label;
if (me->map.flags & F_MAP_REQ_ID)
me->map.requestid = reqid;
+ if (me->map.flags & F_MAP_PW_STATUS)
+ me->map.pw_status = pw_status;
switch (type) {
case MSG_TYPE_LABELMAPPING:
log_debug("label mapping from nbr %s, FEC %s, "
"label %u", inet_ntoa(nbr->id),
- log_fec(&me->map), me->map.label);
+ log_map(&me->map), me->map.label);
imsg_type = IMSG_LABEL_MAPPING;
break;
case MSG_TYPE_LABELREQUEST:
log_debug("label request from nbr %s, FEC %s",
- inet_ntoa(nbr->id), log_fec(&me->map));
+ inet_ntoa(nbr->id), log_map(&me->map));
imsg_type = IMSG_LABEL_REQUEST;
break;
case MSG_TYPE_LABELWITHDRAW:
log_debug("label withdraw from nbr %s, FEC %s",
- inet_ntoa(nbr->id), log_fec(&me->map));
+ inet_ntoa(nbr->id), log_map(&me->map));
imsg_type = IMSG_LABEL_WITHDRAW;
break;
case MSG_TYPE_LABELRELEASE:
log_debug("label release from nbr %s, FEC %s",
- inet_ntoa(nbr->id), log_fec(&me->map));
+ inet_ntoa(nbr->id), log_map(&me->map));
imsg_type = IMSG_LABEL_RELEASE;
break;
case MSG_TYPE_LABELABORTREQ:
log_debug("label abort from nbr %s, FEC %s",
- inet_ntoa(nbr->id), log_fec(&me->map));
+ inet_ntoa(nbr->id), log_map(&me->map));
imsg_type = IMSG_LABEL_ABORT;
break;
default:
@@ -426,54 +467,99 @@ gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid)
}
void
-gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen)
+gen_pw_status_tlv(struct ibuf *buf, u_int32_t status)
{
- struct tlv ft;
- u_int8_t type;
- u_int16_t family;
- u_int8_t len;
+ struct pw_status_tlv st;
- len = PREFIX_SIZE(prefixlen);
- ft.type = htons(TLV_TYPE_FEC);
- ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) +
- len);
+ st.type = htons(TLV_TYPE_PW_STATUS);
+ st.length = htons(sizeof(status));
+ st.value = htonl(status);
- ibuf_add(buf, &ft, sizeof(ft));
-
- type = FEC_PREFIX;
- family = htons(FEC_IPV4);
-
- ibuf_add(buf, &type, sizeof(type));
- ibuf_add(buf, &family, sizeof(family));
- ibuf_add(buf, &prefixlen, sizeof(prefixlen));
- if (len)
- ibuf_add(buf, &prefix, len);
+ ibuf_add(buf, &st, sizeof(st));
}
void
-gen_wcard_fec_tlv(struct ibuf *buf)
+gen_fec_tlv(struct ibuf *buf, struct map *map)
{
struct tlv ft;
- u_int8_t type;
+ u_int16_t family, len, pw_type, ifmtu;
+ u_int8_t pw_len = 0;
+ u_int32_t group_id, pwid;
ft.type = htons(TLV_TYPE_FEC);
- ft.length = htons(sizeof(type));
- ibuf_add(buf, &ft, sizeof(ft));
- type = FEC_WILDCARD;
- ibuf_add(buf, &type, sizeof(type));
+ switch (map->type) {
+ case FEC_WILDCARD:
+ ft.length = htons(sizeof(u_int8_t));
+ ibuf_add(buf, &ft, sizeof(ft));
+ ibuf_add(buf, &map->type, sizeof(map->type));
+ break;
+ case FEC_PREFIX:
+ len = PREFIX_SIZE(map->fec.ipv4.prefixlen);
+ ft.length = htons(sizeof(map->type) + sizeof(family) +
+ sizeof(map->fec.ipv4.prefixlen) + len);
+ ibuf_add(buf, &ft, sizeof(ft));
+
+ ibuf_add(buf, &map->type, sizeof(map->type));
+ family = htons(AF_IPV4);
+ ibuf_add(buf, &family, sizeof(family));
+ ibuf_add(buf, &map->fec.ipv4.prefixlen,
+ sizeof(map->fec.ipv4.prefixlen));
+ if (len)
+ ibuf_add(buf, &map->fec.ipv4.prefix, len);
+ break;
+ case FEC_PWID:
+ if (map->flags & F_MAP_PW_ID)
+ pw_len += sizeof(u_int32_t);
+ if (map->flags & F_MAP_PW_IFMTU)
+ pw_len += FEC_SUBTLV_IFMTU_LEN;
+
+ len = FEC_PWID_ELM_MIN_LEN + pw_len;
+
+ ft.length = htons(len);
+ ibuf_add(buf, &ft, sizeof(ft));
+
+ ibuf_add(buf, &map->type, sizeof(u_int8_t));
+ pw_type = map->fec.pwid.type;
+ if (map->flags & F_MAP_PW_CWORD)
+ pw_type |= CONTROL_WORD_FLAG;
+ pw_type = htons(pw_type);
+ ibuf_add(buf, &pw_type, sizeof(u_int16_t));
+ ibuf_add(buf, &pw_len, sizeof(u_int8_t));
+ group_id = htonl(map->fec.pwid.group_id);
+ ibuf_add(buf, &group_id, sizeof(u_int32_t));
+ if (map->flags & F_MAP_PW_ID) {
+ pwid = htonl(map->fec.pwid.pwid);
+ ibuf_add(buf, &pwid, sizeof(u_int32_t));
+ }
+ if (map->flags & F_MAP_PW_IFMTU) {
+ struct subtlv stlv;
+
+ stlv.type = SUBTLV_IFMTU;
+ stlv.length = FEC_SUBTLV_IFMTU_LEN;
+ ibuf_add(buf, &stlv, sizeof(u_int16_t));
+
+ ifmtu = htons(map->fec.pwid.ifmtu);
+ ibuf_add(buf, &ifmtu, sizeof(u_int16_t));
+ }
+ break;
+ default:
+ break;
+ }
}
int
tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf,
- u_int16_t len, u_int8_t *type, u_int32_t *prefix, u_int8_t *prefixlen)
+ u_int16_t len, struct map *map)
{
u_int16_t family, off = 0;
+ u_int8_t pw_len;
- *type = *buf;
+ map->type = *buf;
off += sizeof(u_int8_t);
- if (*type == FEC_WILDCARD) {
+ switch (map->type) {
+ case FEC_WILDCARD:
if (len == FEC_ELM_WCARD_LEN)
return (off);
else {
@@ -481,36 +567,128 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf,
lm->type);
return (-1);
}
- }
+ break;
+ case FEC_PREFIX:
+ if (len < FEC_ELM_PREFIX_MIN_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
+ lm->type);
+ return (-1);
+ }
- if (*type != FEC_PREFIX) {
- send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type);
- return (-1);
- }
+ /* Address Family */
+ bcopy(buf + off, &family, sizeof(family));
+ off += sizeof(family);
- if (len < FEC_ELM_PREFIX_MIN_LEN) {
- session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
- return (-1);
- }
+ if (family != htons(AF_IPV4)) {
+ send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid,
+ lm->type);
+ return (-1);
+ }
- bcopy(buf + off, &family, sizeof(family));
- off += sizeof(family);
+ /* PreLen */
+ map->fec.ipv4.prefixlen = buf[off];
+ off += sizeof(u_int8_t);
- if (family != htons(FEC_IPV4)) {
- send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, lm->type);
- return (-1);
- }
+ if (len < off + PREFIX_SIZE(map->fec.ipv4.prefixlen)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
+ lm->type);
+ return (-1);
+ }
- *prefixlen = buf[off];
- off += sizeof(u_int8_t);
+ /* Prefix */
+ map->fec.ipv4.prefix.s_addr = 0;
+ bcopy(buf + off, &map->fec.ipv4.prefix,
+ PREFIX_SIZE(map->fec.ipv4.prefixlen));
- if (len < off + PREFIX_SIZE(*prefixlen)) {
- session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type);
- return (-1);
- }
+ return (off + PREFIX_SIZE(map->fec.ipv4.prefixlen));
+ break;
+ case FEC_PWID:
+ if (len < FEC_PWID_ELM_MIN_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
+ lm->type);
+ return (-1);
+ }
+
+ /* PW type */
+ bcopy(buf + off, &map->fec.pwid.type, sizeof(u_int16_t));
+ map->fec.pwid.type = ntohs(map->fec.pwid.type);
+ if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
+ map->flags |= F_MAP_PW_CWORD;
+ map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
+ }
+ off += sizeof(u_int16_t);
+
+ /* PW info Length */
+ pw_len = buf[off];
+ off += sizeof(u_int8_t);
+
+ if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
+ lm->type);
+ return (-1);
+ }
- *prefix = 0;
- bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen));
+ /* Group ID */
+ bcopy(buf + off, &map->fec.pwid.group_id, sizeof(u_int32_t));
+ map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
+ off += sizeof(u_int32_t);
- return (off + PREFIX_SIZE(*prefixlen));
+ /* PW ID */
+ if (pw_len == 0)
+ return (off);
+
+ if (pw_len < sizeof(u_int32_t)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid,
+ lm->type);
+ return (-1);
+ }
+
+ bcopy(buf + off, &map->fec.pwid.pwid, sizeof(u_int32_t));
+ map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
+ map->flags |= F_MAP_PW_ID;
+ off += sizeof(u_int32_t);
+ pw_len -= sizeof(u_int32_t);
+
+ /* Optional Interface Parameter Sub-TLVs */
+ while (pw_len > 0) {
+ struct subtlv stlv;
+
+ if (pw_len < sizeof(stlv)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN,
+ lm->msgid, lm->type);
+ return (-1);
+ }
+
+ bcopy(buf + off, &stlv, sizeof(stlv));
+ off += SUBTLV_HDR_LEN;
+ pw_len -= SUBTLV_HDR_LEN;
+
+ switch (stlv.type) {
+ case SUBTLV_IFMTU:
+ if (stlv.length != FEC_SUBTLV_IFMTU_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN,
+ lm->msgid, lm->type);
+ return (-1);
+ }
+ bcopy(buf + off, &map->fec.pwid.ifmtu,
+ sizeof(u_int16_t));
+ map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
+ map->flags |= F_MAP_PW_IFMTU;
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ off += stlv.length - SUBTLV_HDR_LEN;
+ pw_len -= stlv.length - SUBTLV_HDR_LEN;
+ }
+
+ return (off);
+ break;
+ default:
+ send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type);
+ break;
+ }
+
+ return (-1);
}
diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c
index 82ff83c444d..5d3f698b856 100644
--- a/usr.sbin/ldpd/lde.c
+++ b/usr.sbin/ldpd/lde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde.c,v 1.37 2015/07/21 04:48:42 renato Exp $ */
+/* $OpenBSD: lde.c,v 1.38 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
@@ -83,6 +83,7 @@ lde(struct ldpd_conf *xconf, int pipe_parent2lde[2], int pipe_ldpe2lde[2],
struct timeval now;
struct passwd *pw;
pid_t pid;
+ struct l2vpn *l2vpn;
switch (pid = fork()) {
case -1:
@@ -150,6 +151,10 @@ lde(struct ldpd_conf *xconf, int pipe_parent2lde[2], int pipe_ldpe2lde[2],
gettimeofday(&now, NULL);
ldeconf->uptime = now.tv_sec;
+ /* initialize l2vpns */
+ LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
+ l2vpn_init(l2vpn);
+
event_dispatch();
lde_shutdown();
@@ -200,6 +205,7 @@ lde_dispatch_imsg(int fd, short event, void *bula)
struct lde_nbr *nbr;
struct map map;
struct in_addr addr;
+ struct notify_msg nm;
ssize_t n;
int shut = 0, verbose;
@@ -257,13 +263,13 @@ lde_dispatch_imsg(int fd, short event, void *bula)
lde_check_request(&map, nbr);
break;
case IMSG_LABEL_RELEASE:
- if (map.flags & F_MAP_WILDCARD)
+ if (map.type == FEC_WILDCARD)
lde_check_release_wcard(&map, nbr);
else
lde_check_release(&map, nbr);
break;
case IMSG_LABEL_WITHDRAW:
- if (map.flags & F_MAP_WILDCARD)
+ if (map.type == FEC_WILDCARD)
lde_check_withdraw_wcard(&map, nbr);
else
lde_check_withdraw(&map, nbr);
@@ -311,6 +317,26 @@ lde_dispatch_imsg(int fd, short event, void *bula)
}
break;
+ case IMSG_NOTIFICATION:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
+ fatalx("invalid size of OE request");
+ memcpy(&nm, imsg.data, sizeof(nm));
+
+ nbr = lde_nbr_find(imsg.hdr.peerid);
+ if (nbr == NULL) {
+ log_debug("lde_dispatch_imsg: cannot find "
+ "lde neighbor");
+ return;
+ }
+
+ switch (nm.status) {
+ case S_PW_STATUS:
+ l2vpn_recv_pw_status(nbr, &nm);
+ break;
+ default:
+ break;
+ }
+ break;
case IMSG_NEIGHBOR_UP:
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr))
fatalx("invalid size of OE request");
@@ -330,6 +356,18 @@ lde_dispatch_imsg(int fd, short event, void *bula)
lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
imsg.hdr.pid, NULL, 0);
break;
+ case IMSG_CTL_SHOW_L2VPN_PW:
+ l2vpn_pw_ctl(imsg.hdr.pid);
+
+ lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
+ imsg.hdr.pid, NULL, 0);
+ break;
+ case IMSG_CTL_SHOW_L2VPN_BINDING:
+ l2vpn_binding_ctl(imsg.hdr.pid);
+
+ lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
+ imsg.hdr.pid, NULL, 0);
+ break;
case IMSG_CTL_LOG_VERBOSE:
/* already checked by ldpe */
memcpy(&verbose, imsg.data, sizeof(verbose));
@@ -358,12 +396,16 @@ lde_dispatch_parent(int fd, short event, void *bula)
struct iface *niface;
struct tnbr *ntnbr;
struct nbr_params *nnbrp;
+ static struct l2vpn *nl2vpn;
+ struct l2vpn_if *nlif;
+ struct l2vpn_pw *npw;
struct imsg imsg;
struct kroute kr;
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
ssize_t n;
int shut = 0;
+ struct fec fec;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1)
@@ -393,7 +435,11 @@ lde_dispatch_parent(int fd, short event, void *bula)
}
memcpy(&kr, imsg.data, sizeof(kr));
- lde_kernel_insert(&kr);
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix.s_addr = kr.prefix.s_addr;
+ fec.u.ipv4.prefixlen = kr.prefixlen;
+ lde_kernel_insert(&fec, kr.nexthop,
+ kr.flags & F_CONNECTED, NULL);
break;
case IMSG_NETWORK_DEL:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
@@ -403,7 +449,10 @@ lde_dispatch_parent(int fd, short event, void *bula)
}
memcpy(&kr, imsg.data, sizeof(kr));
- lde_kernel_remove(&kr);
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix.s_addr = kr.prefix.s_addr;
+ fec.u.ipv4.prefixlen = kr.prefixlen;
+ lde_kernel_remove(&fec, kr.nexthop);
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
@@ -415,6 +464,7 @@ lde_dispatch_parent(int fd, short event, void *bula)
LIST_INIT(&nconf->addr_list);
LIST_INIT(&nconf->tnbr_list);
LIST_INIT(&nconf->nbrp_list);
+ LIST_INIT(&nconf->l2vpn_list);
break;
case IMSG_RECONF_IFACE:
if ((niface = malloc(sizeof(struct iface))) == NULL)
@@ -440,6 +490,32 @@ lde_dispatch_parent(int fd, short event, void *bula)
LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry);
break;
+ case IMSG_RECONF_L2VPN:
+ if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL)
+ fatal(NULL);
+ memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
+
+ LIST_INIT(&nl2vpn->if_list);
+ LIST_INIT(&nl2vpn->pw_list);
+
+ LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
+ break;
+ case IMSG_RECONF_L2VPN_IF:
+ if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
+ fatal(NULL);
+ memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
+
+ nlif->l2vpn = nl2vpn;
+ LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
+ break;
+ case IMSG_RECONF_L2VPN_PW:
+ if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
+ fatal(NULL);
+ memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
+
+ npw->l2vpn = nl2vpn;
+ LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
+ break;
case IMSG_RECONF_END:
merge_config(ldeconf, nconf);
nconf = NULL;
@@ -474,40 +550,140 @@ void
lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
struct kroute kr;
-
- bzero(&kr, sizeof(kr));
- kr.prefix.s_addr = fn->fec.prefix.s_addr;
- kr.prefixlen = fn->fec.prefixlen;
- kr.local_label = fn->local_label;
-
- kr.nexthop.s_addr = fnh->nexthop.s_addr;
- kr.remote_label = fnh->remote_label;
-
- lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr));
+ struct kpw kpw;
+ struct l2vpn_pw *pw;
+
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ bzero(&kr, sizeof(kr));
+ kr.prefix.s_addr = fn->fec.u.ipv4.prefix.s_addr;
+ kr.prefixlen = fn->fec.u.ipv4.prefixlen;
+ kr.local_label = fn->local_label;
+ kr.nexthop.s_addr = fnh->nexthop.s_addr;
+ kr.remote_label = fnh->remote_label;
+
+ lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
+ sizeof(kr));
+
+ if (fnh->remote_label != NO_LABEL &&
+ fn->fec.u.ipv4.prefixlen == 32)
+ l2vpn_sync_pws(fn->fec.u.ipv4.prefix);
+ break;
+ case FEC_TYPE_PWID:
+ if (fn->local_label == NO_LABEL ||
+ fnh->remote_label == NO_LABEL)
+ return;
+
+ pw = (struct l2vpn_pw *) fnh->data;
+ if (pw->flags & F_PW_STATUS_UP)
+ return;
+ pw->flags |= F_PW_STATUS_UP;
+
+ bzero(&kpw, sizeof(kpw));
+ kpw.ifindex = pw->ifindex;
+ kpw.pw_type = fn->fec.u.pwid.type;
+ kpw.nexthop.s_addr = fnh->nexthop.s_addr;
+ kpw.local_label = fn->local_label;
+ kpw.remote_label = fnh->remote_label;
+ kpw.flags = pw->flags;
+
+ lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
+ sizeof(kpw));
+ break;
+ }
}
void
lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
struct kroute kr;
+ struct kpw kpw;
+ struct l2vpn_pw *pw;
+
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ bzero(&kr, sizeof(kr));
+ kr.prefix.s_addr = fn->fec.u.ipv4.prefix.s_addr;
+ kr.prefixlen = fn->fec.u.ipv4.prefixlen;
+ kr.local_label = fn->local_label;
+ kr.nexthop.s_addr = fnh->nexthop.s_addr;
+ kr.remote_label = fnh->remote_label;
+
+ lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
+ sizeof(kr));
+
+ if (fn->fec.u.ipv4.prefixlen == 32)
+ l2vpn_sync_pws(fn->fec.u.ipv4.prefix);
+ break;
+ case FEC_TYPE_PWID:
+ pw = (struct l2vpn_pw *) fnh->data;
+ if (!(pw->flags & F_PW_STATUS_UP))
+ return;
+ pw->flags &= ~F_PW_STATUS_UP;
+
+ bzero(&kpw, sizeof(kpw));
+ kpw.ifindex = pw->ifindex;
+ kpw.pw_type = fn->fec.u.pwid.type;
+ kpw.nexthop.s_addr = fnh->nexthop.s_addr;
+ kpw.local_label = fn->local_label;
+ kpw.remote_label = fnh->remote_label;
+ kpw.flags = pw->flags;
+
+ lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
+ sizeof(kpw));
+ break;
+ }
+}
+
+void
+lde_fec2map(struct fec *fec, struct map *map)
+{
+ bzero(map, sizeof(*map));
- bzero(&kr, sizeof(kr));
- kr.prefix.s_addr = fn->fec.prefix.s_addr;
- kr.prefixlen = fn->fec.prefixlen;
- kr.local_label = fn->local_label;
+ switch (fec->type) {
+ case FEC_TYPE_IPV4:
+ map->type = FEC_PREFIX;
+ map->fec.ipv4.prefix = fec->u.ipv4.prefix;
+ map->fec.ipv4.prefixlen = fec->u.ipv4.prefixlen;
+ break;
+ case FEC_TYPE_PWID:
+ map->type = FEC_PWID;
+ map->fec.pwid.type = fec->u.pwid.type;
+ map->fec.pwid.group_id = 0;
+ map->flags |= F_MAP_PW_ID;
+ map->fec.pwid.pwid = fec->u.pwid.pwid;
+ break;
+ }
+}
- kr.nexthop.s_addr = fnh->nexthop.s_addr;
- kr.remote_label = fnh->remote_label;
+void
+lde_map2fec(struct map *map, struct in_addr nbrid, struct fec *fec)
+{
+ bzero(fec, sizeof(*fec));
- lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr));
+ switch (map->type) {
+ case FEC_PREFIX:
+ fec->type = FEC_TYPE_IPV4;
+ fec->u.ipv4.prefix.s_addr = map->fec.ipv4.prefix.s_addr;
+ fec->u.ipv4.prefixlen = map->fec.ipv4.prefixlen;
+ break;
+ case FEC_PWID:
+ fec->type = FEC_TYPE_PWID;
+ fec->u.pwid.type = map->fec.pwid.type;
+ fec->u.pwid.pwid = map->fec.pwid.pwid;
+ fec->u.pwid.nexthop.s_addr = nbrid.s_addr;
+ break;
+ }
}
void
-lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn)
+lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
{
struct lde_req *lre;
struct lde_map *me;
struct map map;
+ struct fec_nh *fnh;
+ struct l2vpn_pw *pw;
/*
* This function skips SL.1 - 3 and SL.9 - 14 because the label
@@ -516,9 +692,26 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn)
*/
bzero(&map, sizeof(map));
+ lde_fec2map(&fn->fec, &map);
+
+ if (fn->fec.type == FEC_TYPE_PWID) {
+ fnh = fec_nh_find(fn, ln->id);
+ if (fnh == NULL)
+ /* not the other end of the pseudowire */
+ return;
+
+ pw = (struct l2vpn_pw *) fnh->data;
+ map.flags |= F_MAP_PW_IFMTU;
+ map.fec.pwid.ifmtu = pw->l2vpn->mtu;
+ if (pw->flags & F_PW_CONTROLWORD)
+ map.flags |= F_MAP_PW_CWORD;
+ if (pw->flags & F_PW_STATUSTLV) {
+ map.flags |= F_MAP_PW_STATUS;
+ /* VPLS are always up */
+ map.pw_status = PW_FORWARDING;
+ }
+ }
map.label = fn->local_label;
- map.prefix = fn->fec.prefix;
- map.prefixlen = fn->fec.prefixlen;
/* SL.6: is there a pending request for this mapping? */
lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
@@ -534,6 +727,9 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn)
/* SL.4: send label mapping */
lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0,
&map, sizeof(map));
+ if (single)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
+ NULL, 0);
/* SL.5: record sent label mapping */
me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
@@ -548,15 +744,29 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn)
struct lde_wdraw *lw;
struct map map;
struct fec *f;
+ struct fec_nh *fnh = NULL;
+ struct l2vpn_pw *pw;
+
+ if (fn->fec.type == FEC_TYPE_PWID) {
+ fnh = fec_nh_find(fn, ln->id);
+ if (fnh == NULL)
+ /* not the other end of the pseudowire */
+ return;
+ }
bzero(&map, sizeof(map));
if (fn) {
+ lde_fec2map(&fn->fec, &map);
map.label = fn->local_label;
- map.prefix = fn->fec.prefix;
- map.prefixlen = fn->fec.prefixlen;
+
+ if (fn->fec.type == FEC_TYPE_PWID) {
+ pw = (struct l2vpn_pw *) fnh->data;
+ if (pw->flags & F_PW_CONTROLWORD)
+ map.flags |= F_MAP_PW_CWORD;
+ }
} else {
+ map.type = FEC_WILDCARD;
map.label = NO_LABEL;
- map.flags = F_MAP_WILDCARD;
}
/* SWd.1: send label withdraw. */
@@ -586,14 +796,28 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn)
void
lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, u_int32_t label)
{
- struct map map;
+ struct map map;
+ struct fec_nh *fnh = NULL;
+ struct l2vpn_pw *pw;
+
+ if (fn->fec.type == FEC_TYPE_PWID) {
+ fnh = fec_nh_find(fn, ln->id);
+ if (fnh == NULL)
+ /* not the other end of the pseudowire */
+ return;
+ }
bzero(&map, sizeof(map));
if (fn) {
- map.prefix = fn->fec.prefix;
- map.prefixlen = fn->fec.prefixlen;
+ lde_fec2map(&fn->fec, &map);
+
+ if (fn->fec.type == FEC_TYPE_PWID) {
+ pw = (struct l2vpn_pw *) fnh->data;
+ if (pw->flags & F_PW_CONTROLWORD)
+ map.flags |= F_MAP_PW_CWORD;
+ }
} else
- map.flags = F_MAP_WILDCARD;
+ map.type = FEC_WILDCARD;
map.label = label;
lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
@@ -725,14 +949,14 @@ lde_map_add(struct lde_nbr *ln, struct fec_node *fn, int sent)
if (sent) {
LIST_INSERT_HEAD(&fn->upstream, me, entry);
if (fec_insert(&ln->sent_map, &me->fec))
- log_warnx("failed to add %s/%u to sent map",
- inet_ntoa(me->fec.prefix), me->fec.prefixlen);
+ log_warnx("failed to add %s to sent map",
+ log_fec(&me->fec));
/* XXX on failure more cleanup is needed */
} else {
LIST_INSERT_HEAD(&fn->downstream, me, entry);
if (fec_insert(&ln->recv_map, &me->fec))
- log_warnx("failed to add %s/%u to recv map",
- inet_ntoa(me->fec.prefix), me->fec.prefixlen);
+ log_warnx("failed to add %s to recv map",
+ log_fec(&me->fec));
}
return (me);
@@ -772,8 +996,7 @@ lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent)
if (fec_insert(t, &lre->fec)) {
log_warnx("failed to add %s/%u to %s req",
- inet_ntoa(lre->fec.prefix), lre->fec.prefixlen,
- sent ? "sent" : "recv");
+ log_fec(&lre->fec), sent ? "sent" : "recv");
free(lre);
return (NULL);
}
@@ -805,8 +1028,8 @@ lde_wdraw_add(struct lde_nbr *ln, struct fec_node *fn)
lw->fec = fn->fec;
if (fec_insert(&ln->sent_wdraw, &lw->fec))
- log_warnx("failed to add %s/%u to sent wdraw",
- inet_ntoa(lw->fec.prefix), lw->fec.prefixlen);
+ log_warnx("failed to add %s to sent wdraw",
+ log_fec(&lw->fec));
return (lw);
}
diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h
index d1165c09c39..72edfa2418f 100644
--- a/usr.sbin/ldpd/lde.h
+++ b/usr.sbin/ldpd/lde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde.h,v 1.28 2015/07/21 04:48:42 renato Exp $ */
+/* $OpenBSD: lde.h,v 1.29 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -28,10 +28,25 @@
RB_HEAD(fec_tree, fec);
+enum fec_type {
+ FEC_TYPE_IPV4,
+ FEC_TYPE_PWID
+};
+
struct fec {
RB_ENTRY(fec) entry;
- struct in_addr prefix;
- u_int8_t prefixlen;
+ enum fec_type type;
+ union {
+ struct {
+ struct in_addr prefix;
+ u_int8_t prefixlen;
+ } ipv4;
+ struct {
+ u_int16_t type;
+ u_int32_t pwid;
+ struct in_addr nexthop;
+ } pwid;
+ } u;
};
RB_PROTOTYPE(fec_tree, fec, entry, fec_compare)
extern struct fec_tree ft;
@@ -82,6 +97,7 @@ struct fec_nh {
struct in_addr nexthop;
u_int32_t remote_label;
+ void *data; /* fec specific data */
};
struct fec_node {
@@ -92,7 +108,6 @@ struct fec_node {
LIST_HEAD(, lde_map) upstream; /* sent mappings */
u_int32_t local_label;
- u_int8_t flags;
};
/* lde.c */
@@ -100,10 +115,12 @@ pid_t lde(struct ldpd_conf *, int [2], int [2], int [2]);
int lde_imsg_compose_parent(int, pid_t, void *, u_int16_t);
int lde_imsg_compose_ldpe(int, u_int32_t, pid_t, void *, u_int16_t);
u_int32_t lde_assign_label(void);
+void lde_fec2map(struct fec *, struct map *);
+void lde_map2fec(struct map *, struct in_addr, struct fec *);
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
void lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
-void lde_send_labelmapping(struct lde_nbr *, struct fec_node *);
+void lde_send_labelmapping(struct lde_nbr *, struct fec_node *, int);
void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *);
void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, u_int32_t);
void lde_send_notification(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
@@ -124,7 +141,6 @@ int lde_address_del(struct lde_nbr *, struct in_addr *);
void fec_init(struct fec_tree *);
int fec_insert(struct fec_tree *, struct fec *);
int fec_remove(struct fec_tree *, struct fec *);
-struct fec *fec_find_prefix(struct fec_tree *, in_addr_t, u_int8_t);
struct fec *fec_find(struct fec_tree *, struct fec *);
void fec_clear(struct fec_tree *, void (*)(void *));
@@ -132,8 +148,9 @@ void rt_dump(pid_t);
void fec_snap(struct lde_nbr *);
void fec_tree_clear(void);
-void lde_kernel_insert(struct kroute *);
-void lde_kernel_remove(struct kroute *);
+struct fec_nh *fec_nh_find(struct fec_node *, struct in_addr);
+void lde_kernel_insert(struct fec *, struct in_addr, int, void *);
+void lde_kernel_remove(struct fec *, struct in_addr);
void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(struct map *, struct lde_nbr *);
void lde_check_release(struct map *, struct lde_nbr *);
@@ -142,4 +159,27 @@ void lde_check_withdraw(struct map *, struct lde_nbr *);
void lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
void lde_label_list_free(struct lde_nbr *);
+/* l2vpn.c */
+struct l2vpn *l2vpn_new(const char *);
+struct l2vpn *l2vpn_find(struct ldpd_conf *, char *);
+void l2vpn_del(struct l2vpn *);
+void l2vpn_init(struct l2vpn *);
+struct l2vpn_if *l2vpn_if_new(struct l2vpn *, struct kif *);
+struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int);
+void l2vpn_if_del(struct l2vpn_if *l);
+struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *);
+struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
+void l2vpn_pw_del(struct l2vpn_pw *);
+void l2vpn_pw_init(struct l2vpn_pw *);
+void l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
+void l2vpn_pw_reset(struct l2vpn_pw *);
+int l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *);
+int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
+ struct map *);
+void l2vpn_send_pw_status(u_int32_t, u_int32_t, struct fec *);
+void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
+void l2vpn_sync_pws(struct in_addr);
+void l2vpn_pw_ctl(pid_t);
+void l2vpn_binding_ctl(pid_t);
+
#endif /* _LDE_H_ */
diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c
index b21c1d92477..d95da676cf7 100644
--- a/usr.sbin/ldpd/lde_lib.c
+++ b/usr.sbin/ldpd/lde_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde_lib.c,v 1.39 2015/07/21 04:48:42 renato Exp $ */
+/* $OpenBSD: lde_lib.c,v 1.40 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -41,8 +41,7 @@
static int fec_compare(struct fec *, struct fec *);
void fec_free(void *);
-struct fec_node *fec_add(struct in_addr, u_int8_t);
-struct fec_nh *fec_nh_find(struct fec_node *, struct in_addr);
+struct fec_node *fec_add(struct fec *fec);
struct fec_nh *fec_nh_add(struct fec_node *, struct in_addr);
void fec_nh_del(struct fec_nh *);
int lde_nbr_is_nexthop(struct fec_node *, struct lde_nbr *);
@@ -66,27 +65,45 @@ fec_init(struct fec_tree *fh)
static int
fec_compare(struct fec *a, struct fec *b)
{
- if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr))
+ if (a->type < b->type)
return (-1);
- if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr))
+ if (a->type > b->type)
return (1);
- if (a->prefixlen < b->prefixlen)
- return (-1);
- if (a->prefixlen > b->prefixlen)
- return (1);
-
- return (0);
-}
-struct fec *
-fec_find_prefix(struct fec_tree *fh, in_addr_t prefix, u_int8_t prefixlen)
-{
- struct fec s;
-
- s.prefix.s_addr = prefix;
- s.prefixlen = prefixlen;
+ switch (a->type) {
+ case FEC_TYPE_IPV4:
+ if (ntohl(a->u.ipv4.prefix.s_addr) <
+ ntohl(b->u.ipv4.prefix.s_addr))
+ return (-1);
+ if (ntohl(a->u.ipv4.prefix.s_addr) >
+ ntohl(b->u.ipv4.prefix.s_addr))
+ return (1);
+ if (a->u.ipv4.prefixlen < b->u.ipv4.prefixlen)
+ return (-1);
+ if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen)
+ return (1);
+ return (0);
+ break;
+ case FEC_TYPE_PWID:
+ if (a->u.pwid.type < b->u.pwid.type)
+ return (-1);
+ if (a->u.pwid.type > b->u.pwid.type)
+ return (1);
+ if (a->u.pwid.pwid < b->u.pwid.pwid)
+ return (-1);
+ if (a->u.pwid.pwid > b->u.pwid.pwid)
+ return (1);
+ if (ntohl(a->u.pwid.nexthop.s_addr) <
+ ntohl(b->u.pwid.nexthop.s_addr))
+ return (-1);
+ if (ntohl(a->u.pwid.nexthop.s_addr) >
+ ntohl(b->u.pwid.nexthop.s_addr))
+ return (1);
+ return (0);
+ break;
+ }
- return (fec_find(fh, &s));
+ return (-1);
}
struct fec *
@@ -107,8 +124,7 @@ int
fec_remove(struct fec_tree *fh, struct fec *f)
{
if (RB_REMOVE(fec_tree, fh, f) == NULL) {
- log_warnx("fec_remove failed for %s/%u",
- inet_ntoa(f->prefix), f->prefixlen);
+ log_warnx("fec_remove failed for %s", log_fec(f));
return (-1);
}
return (0);
@@ -148,13 +164,15 @@ rt_dump(pid_t pid)
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+
if (fn->local_label == NO_LABEL &&
LIST_EMPTY(&fn->downstream))
continue;
- rtctl.prefix = fn->fec.prefix;
- rtctl.prefixlen = fn->fec.prefixlen;
- rtctl.flags = fn->flags;
+ rtctl.prefix = fn->fec.u.ipv4.prefix;
+ rtctl.prefixlen = fn->fec.u.ipv4.prefixlen;
rtctl.local_label = fn->local_label;
LIST_FOREACH(me, &fn->downstream, entry) {
@@ -188,7 +206,7 @@ fec_snap(struct lde_nbr *ln)
if (fn->local_label == NO_LABEL)
continue;
- lde_send_labelmapping(ln, fn);
+ lde_send_labelmapping(ln, fn, 0);
count++;
}
if (count > 0)
@@ -205,11 +223,11 @@ fec_free(void *arg)
while ((fnh = LIST_FIRST(&fn->nexthops)))
fec_nh_del(fnh);
if (!LIST_EMPTY(&fn->downstream))
- log_warnx("fec_free: fec %s/%u downstream list not empty",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("fec_free: fec %s downstream list not empty",
+ log_fec(&fn->fec));
if (!LIST_EMPTY(&fn->upstream))
- log_warnx("fec_free: fec %s/%u upstream list not empty",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("fec_free: fec %s upstream list not empty",
+ log_fec(&fn->fec));
free(fn);
}
@@ -221,7 +239,7 @@ fec_tree_clear(void)
}
struct fec_node *
-fec_add(struct in_addr prefix, u_int8_t prefixlen)
+fec_add(struct fec *fec)
{
struct fec_node *fn;
@@ -229,16 +247,15 @@ fec_add(struct in_addr prefix, u_int8_t prefixlen)
if (fn == NULL)
fatal("fec_add");
- fn->fec.prefix.s_addr = prefix.s_addr;
- fn->fec.prefixlen = prefixlen;
+ memcpy(&fn->fec, fec, sizeof(fn->fec));
fn->local_label = NO_LABEL;
LIST_INIT(&fn->upstream);
LIST_INIT(&fn->downstream);
LIST_INIT(&fn->nexthops);
if (fec_insert(&ft, &fn->fec))
- log_warnx("failed to add %s/%u to ft tree",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("failed to add %s to ft tree",
+ log_fec(&fn->fec));
return (fn);
}
@@ -278,35 +295,33 @@ fec_nh_del(struct fec_nh *fnh)
}
void
-lde_kernel_insert(struct kroute *kr)
+lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
+ void *data)
{
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
struct lde_nbr *ln;
- char buf[16];
- log_debug("kernel add route %s/%u nexthop %s",
- inet_ntoa(kr->prefix), kr->prefixlen,
- inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf)));
+ log_debug("lde add fec %s nexthop %s",
+ log_fec(fec), inet_ntoa(nexthop));
- fn = (struct fec_node *)fec_find_prefix(&ft, kr->prefix.s_addr,
- kr->prefixlen);
+ fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
- fn = fec_add(kr->prefix, kr->prefixlen);
+ fn = fec_add(fec);
- if (fec_nh_find(fn, kr->nexthop) != NULL)
+ if (fec_nh_find(fn, nexthop) != NULL)
return;
if (LIST_EMPTY(&fn->nexthops)) {
if (fn->local_label == NO_LABEL) {
- if (kr->flags & F_CONNECTED)
+ if (connected)
fn->local_label = MPLS_LABEL_IMPLNULL;
else
fn->local_label = lde_assign_label();
} else {
/* Handle local label changes */
- if ((kr->flags & F_CONNECTED) &&
+ if (connected &&
fn->local_label != MPLS_LABEL_IMPLNULL) {
/* explicit withdraw of the previous label */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -314,7 +329,7 @@ lde_kernel_insert(struct kroute *kr)
fn->local_label = MPLS_LABEL_IMPLNULL;
}
- if (!(kr->flags & F_CONNECTED) &&
+ if (!connected &&
fn->local_label == MPLS_LABEL_IMPLNULL) {
/* explicit withdraw of the previous label */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -324,16 +339,13 @@ lde_kernel_insert(struct kroute *kr)
}
/* FEC.1: perform lsr label distribution procedure */
- RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
- lde_send_labelmapping(ln, fn);
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END,
- ln->peerid, 0, NULL, 0);
- }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
}
- fnh = fec_nh_add(fn, kr->nexthop);
+ fnh = fec_nh_add(fn, nexthop);
+ fnh->data = data;
lde_send_change_klabel(fn, fnh);
-
ln = lde_find_address(fnh->nexthop);
if (ln) {
/* FEC.2 */
@@ -345,28 +357,26 @@ lde_kernel_insert(struct kroute *kr)
}
void
-lde_kernel_remove(struct kroute *kr)
+lde_kernel_remove(struct fec *fec, struct in_addr nexthop)
{
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_nbr *ln;
- char buf[16];
- log_debug("kernel remove route %s/%u nexthop %s",
- inet_ntoa(kr->prefix), kr->prefixlen,
- inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf)));
+ log_debug("lde remove fec %s nexthop %s",
+ log_fec(fec), inet_ntoa(nexthop));
- fn = (struct fec_node *)fec_find_prefix(&ft, kr->prefix.s_addr,
- kr->prefixlen);
+ fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
/* route lost */
return;
- fnh = fec_nh_find(fn, kr->nexthop);
+ fnh = fec_nh_find(fn, nexthop);
if (fnh == NULL)
/* route lost */
return;
+ lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
if (LIST_EMPTY(&fn->nexthops))
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -376,17 +386,19 @@ lde_kernel_remove(struct kroute *kr)
void
lde_check_mapping(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_req *lre;
struct lde_nbr_address *addr;
struct lde_map *me;
+ struct l2vpn_pw *pw;
int msgsource = 0;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
- fn = fec_add(map->prefix, map->prefixlen);
+ fn = fec_add(&fec);
/* LMp.1: first check if we have a pending request running */
lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec);
@@ -394,6 +406,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
/* LMp.2: delete record of outstanding label request */
lde_req_del(ln, lre, 1);
+ /* RFC 4447 control word and status tlv negotiation */
+ if (map->type == FEC_PWID && l2vpn_pw_negotiate(ln, fn, map))
+ return;
+
/*
* LMp.3 - LMp.8: Loop detection LMp.3 - unecessary for frame-mode
* mpls networks
@@ -422,27 +438,38 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
* support multipath
*/
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (lde_address_find(ln, &fnh->nexthop)) {
- msgsource = 1;
+ if (lde_address_find(ln, &fnh->nexthop) == NULL)
+ continue;
- /* LMp.15: install FEC in FIB */
- fnh->remote_label = map->label;
+ msgsource = 1;
+
+ /* LMp.15: install FEC in FIB */
+ fnh->remote_label = map->label;
+ switch (map->type) {
+ case FEC_PREFIX:
lde_send_change_klabel(fn, fnh);
+ break;
+ case FEC_PWID:
+ pw = (struct l2vpn_pw *) fnh->data;
+ pw->remote_group = map->fec.pwid.group_id;
+ if (map->flags & F_MAP_PW_IFMTU)
+ pw->remote_mtu = map->fec.pwid.ifmtu;
+ if (map->flags & F_MAP_PW_STATUS)
+ pw->remote_status = map->pw_status;
+ if (l2vpn_pw_ok(pw, fnh))
+ lde_send_change_klabel(fn, fnh);
+ break;
}
}
- if (msgsource == 0) {
- /* LMp.13: perform lsr label release procedure */
- if (me == NULL)
- me = lde_map_add(ln, fn, 0);
- memcpy(&me->map, map, sizeof(*map));
- return;
- }
-
- /* LMp.16: Record the mapping from this peer */
+ /* LMp.13 & LMp.16: Record the mapping from this peer */
if (me == NULL)
me = lde_map_add(ln, fn, 0);
memcpy(&me->map, map, sizeof(*map));
+ if (msgsource == 0)
+ /* LMp.13: just return since we use liberal lbl retention */
+ return;
+
/*
* LMp.17 - LMp.27 are unnecessary since we don't need to implement
* loop detection. LMp.28 - LMp.30 are unnecessary because we are
@@ -453,6 +480,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
void
lde_check_request(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct lde_req *lre;
struct fec_node *fn;
struct fec_nh *fnh;
@@ -460,8 +488,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
/* TODO LRq.1: loop detection */
/* LRq.2: is there a next hop for fec? */
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
lde_send_notification(ln->peerid, S_NO_ROUTE, map->messageid,
MSG_TYPE_LABELREQUEST);
@@ -489,8 +517,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
lre->msgid = map->messageid;
/* LRq.9: perform LSR label distribution */
- lde_send_labelmapping(ln, fn);
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
+ lde_send_labelmapping(ln, fn, 1);
/*
* LRq.10: do nothing (Request Never) since we use liberal
@@ -502,12 +529,17 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
void
lde_check_release(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct lde_wdraw *lw;
struct lde_map *me;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ /* TODO group wildcard */
+ if (!(map->flags & F_MAP_PW_ID))
+ return;
+
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
/* LRl.1: does FEC match a known FEC? */
if (fn == NULL)
return;
@@ -567,14 +599,19 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
void
lde_check_withdraw(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ /* TODO group wildcard */
+ if (!(map->flags & F_MAP_PW_ID))
+ return;
+
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
- fn = fec_add(map->prefix, map->prefixlen);
+ fn = fec_add(&fec);
/* LWd.1: remove label from forwarding/switching use */
LIST_FOREACH(fnh, &fn->nexthops, entry) {
diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h
index e1a4480d8d4..a0830380124 100644
--- a/usr.sbin/ldpd/ldp.h
+++ b/usr.sbin/ldpd/ldp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldp.h,v 1.18 2015/07/19 20:54:17 renato Exp $ */
+/* $OpenBSD: ldp.h,v 1.19 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -49,6 +49,13 @@
#define INIT_DELAY_TMR 15
#define MAX_DELAY_TMR 120
+#define MIN_PWID_ID 1
+#define MAX_PWID_ID 0xffffffff
+
+#define DEFAULT_L2VPN_MTU 1500
+#define MIN_L2VPN_MTU 512
+#define MAX_L2VPN_MTU 0xffff
+
/* LDP message types */
#define MSG_TYPE_NOTIFICATION 0x0001
#define MSG_TYPE_HELLO 0x0100
@@ -82,6 +89,10 @@
#define TLV_TYPE_ATMSESSIONPAR 0x0501
#define TLV_TYPE_FRSESSION 0x0502
#define TLV_TYPE_LABELREQUEST 0x0600
+/* RFC 4447 */
+#define TLV_TYPE_PW_STATUS 0x096A
+#define TLV_TYPE_PW_IF_PARAM 0x096B
+#define TLV_TYPE_PW_GROUP_ID 0x096C
/* LDP header */
struct ldp_hdr {
@@ -158,6 +169,15 @@ struct hello_prms_opt4_tlv {
#define S_UNSUP_ADDR 0x00000017
#define S_KEEPALIVE_BAD 0x80000018
#define S_INTERN_ERR 0x80000019
+/* RFC 4447 */
+#define S_ILLEGAL_CBIT 0x00000024
+#define S_WRONG_CBIT 0x00000025
+#define S_INCPT_BITRATE 0x00000026
+#define S_CEP_MISCONF 0x00000027
+#define S_PW_STATUS 0x00000028
+#define S_UNASSIGN_TAI 0x00000029
+#define S_MISCONF_ERR 0x0000002A
+#define S_WITHDRAW_MTHD 0x0000002B
struct sess_prms_tlv {
u_int16_t type;
@@ -185,6 +205,9 @@ struct status_tlv {
#define STATUS_TLV_LEN 10
#define STATUS_FATAL 0x80000000
+#define AF_IPV4 0x1
+#define AF_IPV6 0x2
+
struct address_list_tlv {
u_int16_t type;
u_int16_t length;
@@ -192,14 +215,30 @@ struct address_list_tlv {
/* address entries */
} __packed;
-#define ADDR_IPV4 0x1
-#define ADDR_IPV6 0x2
-
#define FEC_ELM_WCARD_LEN 1
#define FEC_ELM_PREFIX_MIN_LEN 4
+#define FEC_PWID_ELM_MIN_LEN 8
#define FEC_WILDCARD 0x01
#define FEC_PREFIX 0x02
-#define FEC_IPV4 0x0001
+#define FEC_PWID 0x80
+#define FEC_GENPWID 0x81
+
+#define CONTROL_WORD_FLAG 0x8000
+#define PW_TYPE_ETHERNET_TAGGED 0x0004
+#define PW_TYPE_ETHERNET 0x0005
+
+/* RFC 4447 Sub-TLV record */
+struct subtlv {
+ u_int8_t type;
+ u_int8_t length;
+};
+#define SUBTLV_HDR_LEN 2
+
+#define SUBTLV_IFMTU 0x01
+#define SUBTLV_VLANID 0x06
+
+#define FEC_SUBTLV_IFMTU_LEN 4
+#define FEC_SUBTLV_VLANID_LEN 4
struct label_tlv {
u_int16_t type;
@@ -217,6 +256,21 @@ struct reqid_tlv {
#define REQID_TLV_LEN 8
+struct pw_status_tlv {
+ u_int16_t type;
+ u_int16_t length;
+ u_int32_t value;
+};
+
+#define PW_STATUS_TLV_LEN 8
+
+#define PW_FORWARDING 0
+#define PW_NOT_FORWARDING (1 << 0)
+#define PW_LOCAL_RX_FAULT (1 << 1)
+#define PW_LOCAL_TX_FAULT (1 << 2)
+#define PW_PSN_RX_FAULT (1 << 3)
+#define PW_PSN_TX_FAULT (1 << 4)
+
#define NO_LABEL UINT_MAX
#endif /* !_LDP_H_ */
diff --git a/usr.sbin/ldpd/ldpd.c b/usr.sbin/ldpd/ldpd.c
index f0c72fd9f29..0f6dccce512 100644
--- a/usr.sbin/ldpd/ldpd.c
+++ b/usr.sbin/ldpd/ldpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.c,v 1.24 2015/07/21 04:45:21 renato Exp $ */
+/* $OpenBSD: ldpd.c,v 1.25 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -56,6 +56,7 @@ void main_dispatch_lde(int, short, void *);
int ldp_reload(void);
int ldp_sendboth(enum imsg_type, void *, u_int16_t);
+void merge_l2vpns(struct ldpd_conf *, struct l2vpn *, struct l2vpn *);
int pipe_parent2ldpe[2];
int pipe_parent2lde[2];
@@ -399,6 +400,7 @@ main_dispatch_lde(int fd, short event, void *bula)
struct imsg imsg;
ssize_t n;
int shut = 0;
+ struct kpw *kpw;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1)
@@ -437,6 +439,22 @@ main_dispatch_lde(int fd, short event, void *bula)
log_warn("main_dispatch_lde: error deleting "
"route");
break;
+ case IMSG_KPWLABEL_CHANGE:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct kpw))
+ fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
+
+ kpw = imsg.data;
+ kmpw_set(kpw);
+ break;
+ case IMSG_KPWLABEL_DELETE:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct kpw))
+ fatalx("invalid size of IMSG_KPWLABEL_DELETE");
+
+ kpw = imsg.data;
+ kmpw_unset(kpw);
+ break;
default:
log_debug("main_dispatch_lde: error handling imsg %d",
imsg.hdr.type);
@@ -528,6 +546,9 @@ ldp_reload(void)
struct iface *iface;
struct tnbr *tnbr;
struct nbr_params *nbrp;
+ struct l2vpn *l2vpn;
+ struct l2vpn_if *lif;
+ struct l2vpn_pw *pw;
struct ldpd_conf *xconf;
if ((xconf = parse_config(conffile, ldpd_conf->opts)) == NULL)
@@ -554,6 +575,23 @@ ldp_reload(void)
return (-1);
}
+ LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
+ if (ldp_sendboth(IMSG_RECONF_L2VPN, l2vpn,
+ sizeof(*l2vpn)) == -1)
+ return (-1);
+
+ LIST_FOREACH(lif, &l2vpn->if_list, entry) {
+ if (ldp_sendboth(IMSG_RECONF_L2VPN_IF, lif,
+ sizeof(*lif)) == -1)
+ return (-1);
+ }
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
+ if (ldp_sendboth(IMSG_RECONF_L2VPN_PW, pw,
+ sizeof(*pw)) == -1)
+ return (-1);
+ }
+ }
+
if (ldp_sendboth(IMSG_RECONF_END, NULL, 0) == -1)
return (-1);
@@ -578,6 +616,7 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
struct iface *iface, *itmp, *xi;
struct tnbr *tnbr, *ttmp, *xt;
struct nbr_params *nbrp, *ntmp, *xn;
+ struct l2vpn *l2vpn, *ltmp, *xl;
struct nbr *nbr;
/* change of rtr_id needs a restart */
@@ -706,10 +745,158 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
}
+ /* merge l2vpns */
+ LIST_FOREACH_SAFE(l2vpn, &conf->l2vpn_list, entry, ltmp) {
+ /* find deleted l2vpns */
+ if ((xl = l2vpn_find(xconf, l2vpn->name)) == NULL) {
+ LIST_REMOVE(l2vpn, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_del(l2vpn);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_exit(l2vpn);
+ free(l2vpn);
+ break;
+ case PROC_MAIN:
+ free(l2vpn);
+ break;
+ }
+ }
+ }
+ LIST_FOREACH_SAFE(xl, &xconf->l2vpn_list, entry, ltmp) {
+ /* find new l2vpns */
+ if ((l2vpn = l2vpn_find(conf, xl->name)) == NULL) {
+ LIST_REMOVE(xl, entry);
+ LIST_INSERT_HEAD(&conf->l2vpn_list, xl, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_init(xl);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_init(xl);
+ break;
+ case PROC_MAIN:
+ break;
+ }
+ continue;
+ }
+
+ /* update existing l2vpns */
+ merge_l2vpns(conf, l2vpn, xl);
+ }
+
free(xconf);
}
void
+merge_l2vpns(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
+{
+ struct l2vpn_if *lif, *ftmp, *xf;
+ struct l2vpn_pw *pw, *ptmp, *xp;
+
+ /* merge intefaces */
+ LIST_FOREACH_SAFE(lif, &l2vpn->if_list, entry, ftmp) {
+ /* find deleted interfaces */
+ if ((xf = l2vpn_if_find(xl, lif->ifindex)) == NULL) {
+ LIST_REMOVE(lif, entry);
+ free(lif);
+ }
+ }
+ LIST_FOREACH_SAFE(xf, &xl->if_list, entry, ftmp) {
+ /* find new interfaces */
+ if ((lif = l2vpn_if_find(l2vpn, xf->ifindex)) == NULL) {
+ LIST_REMOVE(xf, entry);
+ LIST_INSERT_HEAD(&l2vpn->if_list, xf, entry);
+ lif->l2vpn = l2vpn;
+ continue;
+ }
+
+ /* update existing interfaces */
+ lif->l2vpn = l2vpn;
+ }
+
+ /* merge pseudowires */
+ LIST_FOREACH_SAFE(pw, &l2vpn->pw_list, entry, ptmp) {
+ /* find deleted pseudowires */
+ if ((xp = l2vpn_pw_find(xl, pw->ifindex)) == NULL) {
+ LIST_REMOVE(pw, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_pw_del(pw);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_pw_exit(pw);
+ free(pw);
+ break;
+ case PROC_MAIN:
+ free(pw);
+ break;
+ }
+ }
+ }
+ LIST_FOREACH_SAFE(xp, &xl->pw_list, entry, ptmp) {
+ /* find new pseudowires */
+ if ((pw = l2vpn_pw_find(l2vpn, xp->ifindex)) == NULL) {
+ LIST_REMOVE(xp, entry);
+ LIST_INSERT_HEAD(&l2vpn->pw_list, xp, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_pw_init(xp);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_pw_init(xp);
+ break;
+ case PROC_MAIN:
+ break;
+ }
+ continue;
+ }
+
+ /* changes that require a full reset of the pseudowire */
+ if (l2vpn->pw_type != xl->pw_type ||
+ l2vpn->mtu != xl->mtu ||
+ pw->addr.s_addr != xp->addr.s_addr ||
+ pw->pwid != xp->pwid ||
+ ((pw->flags &
+ (F_PW_STATUSTLV_CONF|F_PW_CONTROLWORD_CONF)) !=
+ (xp->flags &
+ (F_PW_STATUSTLV_CONF|F_PW_CONTROLWORD_CONF)))) {
+ LIST_REMOVE(pw, entry);
+ LIST_REMOVE(xp, entry);
+ LIST_INSERT_HEAD(&l2vpn->pw_list, xp, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_pw_del(pw);
+ l2vpn_pw_init(xp);
+ break;
+ case PROC_LDP_ENGINE:
+ if (pw->addr.s_addr != xp->addr.s_addr) {
+ ldpe_l2vpn_pw_exit(pw);
+ ldpe_l2vpn_pw_init(xp);
+ }
+ free(pw);
+ break;
+ case PROC_MAIN:
+ free(pw);
+ break;
+ }
+ }
+
+ /* update existing pseudowires */
+ pw->l2vpn = xp->l2vpn;
+ }
+
+ l2vpn->mtu = xl->mtu;
+ l2vpn->br_ifindex = xl->br_ifindex;
+}
+
+void
config_clear(struct ldpd_conf *conf)
{
struct ldpd_conf *xconf;
@@ -720,6 +907,7 @@ config_clear(struct ldpd_conf *conf)
LIST_INIT(&xconf->iface_list);
LIST_INIT(&xconf->tnbr_list);
LIST_INIT(&xconf->nbrp_list);
+ LIST_INIT(&xconf->l2vpn_list);
merge_config(conf, xconf);
free(conf);
diff --git a/usr.sbin/ldpd/ldpd.conf.5 b/usr.sbin/ldpd/ldpd.conf.5
index 34c37717a9f..02a0f7ef096 100644
--- a/usr.sbin/ldpd/ldpd.conf.5
+++ b/usr.sbin/ldpd/ldpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ldpd.conf.5,v 1.17 2015/07/19 22:36:30 jmc Exp $
+.\" $OpenBSD: ldpd.conf.5,v 1.18 2015/07/21 04:52:29 renato Exp $
.\"
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -18,7 +18,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 19 2015 $
+.Dd $Mdocdate: July 21 2015 $
.Dt LDPD.CONF 5
.Os
.Sh NAME
@@ -31,7 +31,7 @@ daemon implements the Label Distribution Protocol as described in RFC 5036.
.Sh SECTIONS
The
.Nm
-config file is divided into five main sections.
+config file is divided into six main sections.
.Bl -tag -width xxxx
.It Sy Macros
User-defined variables may be defined and used later, simplifying the
@@ -45,6 +45,8 @@ Interface-specific parameters.
Targeted neighbor specific parameters.
.It Sy Neighbors Configuration
Neighbor-specific parameters.
+.It Sy Layer 2 VPNs Configuration
+Layer 2 VPNs parameters as per RFC 4447.
.El
.Sh MACROS
Much like
@@ -159,6 +161,87 @@ Neighbor-specific parameters are listed below.
.It Ic password Ar secret
Enable TCP MD5 signatures per RFC 5036.
.El
+.Sh LAYER 2 VPNS
+.Xr ldpd 8
+implements the signaling of pseudowires which can be used to
+implement either the VPWS solution (also known as PWE3) or the VPLS
+solution. Currently only the VPLS solution is supported.
+.Bd -literal -offset indent
+l2vpn name type vpls {
+ bridge bridge0
+ interface em1
+ pseudowire mpw1 {
+ pw-id 100
+ neighbor 192.168.1.10
+ }
+ pseudowire mpw2 {
+ pw-id 200
+ neighbor 10.0.1.5
+ }
+}
+.Ed
+.Pp
+Layer 2 VPN specific parameters are listed below.
+.Bl -tag -width Ds
+.It Xo
+.Ic type
+.Pq Ic ethernet Ns | Ns Ic ethernet-tagged
+.Xc
+Specify the type of the configured pseudowires. The type must be the
+same at both endpoints. The default is
+.Ic ethernet .
+.Pp
+.It Ic mtu Ar number
+Set the MTU advertised in the pseudowires. Local and remote MTUs must
+match for a pseudowire to be set up. The default value is 1500.
+.Pp
+.It Ic bridge Ar interface
+Set the bridge interface the VPLS is associated with. This parameter
+is optional and is only used to remove MAC addresses received from MAC
+address withdrawal messages. Only one bridge interface can be set.
+.Pp
+.It Ic interface Ar interface
+Configure a non pseudowire interface pertaining to the VPLS. This
+parameter is optional and is only used to send MAC address withdrawal
+messages when the specified interface is shutdown. Multiple interfaces
+can be configured.
+.Sh PSEUDOWIRES
+Each
+.Xr mpw 4
+pseudowire interface can have several parameters configured individually,
+otherwise they are inherited. A pseudowire interface is specified by
+its name.
+.Bd -literal -offset indent
+pseudowire mpw5 {
+ pw-id 5000
+ neighbor 172.16.1.50
+}
+.Ed
+.Pp
+Pseudowire-specific parameters are listed below.
+.Bl -tag -width Ds
+.Pp
+.It Ic neighbor Ar address
+Specify the endpoint of the pseudowire on the remote PE router. A targeted
+neighbor will automatically be created for this address.
+.Pp
+.It Ic pw-id Ar number
+Set the PW ID used to identify the pseudowire. The PW ID must be the
+same at both endpoints. Valid range is 1\-4294967295.
+.It Xo
+.Ic status-tlv
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+Specify whether the use of the Status TLV is preferred or not
+preferred. The default is
+.Ic yes .
+.It Xo
+.Ic control-word
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+Specify whether the use of the control word is preferred or not
+preferred. The default is
+.Ic yes .
.Sh FILES
.Bl -tag -width "/etc/ldpd.conf" -compact
.It Pa /etc/ldpd.conf
diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h
index 87fd28128bb..8b0b5ef2324 100644
--- a/usr.sbin/ldpd/ldpd.h
+++ b/usr.sbin/ldpd/ldpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.h,v 1.53 2015/07/21 04:45:21 renato Exp $ */
+/* $OpenBSD: ldpd.h,v 1.54 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -38,6 +38,7 @@
#define LDPD_USER "_ldpd"
#define TCP_MD5_KEY_LEN 80
+#define L2VPN_NAME_LEN 32
#define NBR_IDSELF 1
#define NBR_CNTSTART (NBR_IDSELF + 1)
@@ -77,6 +78,8 @@ enum imsg_type {
IMSG_CTL_SHOW_DISCOVERY,
IMSG_CTL_SHOW_NBR,
IMSG_CTL_SHOW_LIB,
+ IMSG_CTL_SHOW_L2VPN_PW,
+ IMSG_CTL_SHOW_L2VPN_BINDING,
IMSG_CTL_FIB_COUPLE,
IMSG_CTL_FIB_DECOUPLE,
IMSG_CTL_KROUTE,
@@ -86,6 +89,8 @@ enum imsg_type {
IMSG_CTL_LOG_VERBOSE,
IMSG_KLABEL_CHANGE,
IMSG_KLABEL_DELETE,
+ IMSG_KPWLABEL_CHANGE,
+ IMSG_KPWLABEL_DELETE,
IMSG_IFSTATUS,
IMSG_NEWADDR,
IMSG_DELADDR,
@@ -105,6 +110,7 @@ enum imsg_type {
IMSG_WITHDRAW_ADD_END,
IMSG_ADDRESS_ADD,
IMSG_ADDRESS_DEL,
+ IMSG_NOTIFICATION,
IMSG_NOTIFICATION_SEND,
IMSG_NEIGHBOR_UP,
IMSG_NEIGHBOR_DOWN,
@@ -114,6 +120,9 @@ enum imsg_type {
IMSG_RECONF_IFACE,
IMSG_RECONF_TNBR,
IMSG_RECONF_NBRP,
+ IMSG_RECONF_L2VPN,
+ IMSG_RECONF_L2VPN_IF,
+ IMSG_RECONF_L2VPN_PW,
IMSG_RECONF_END
};
@@ -164,21 +173,41 @@ enum nbr_action {
TAILQ_HEAD(mapping_head, mapping_entry);
struct map {
- struct in_addr prefix;
- u_int8_t prefixlen;
- u_int32_t label;
+ u_int8_t type;
u_int32_t messageid;
+ union map_fec {
+ struct {
+ struct in_addr prefix;
+ u_int8_t prefixlen;
+ } ipv4;
+ struct {
+ u_int16_t type;
+ u_int32_t pwid;
+ u_int32_t group_id;
+ u_int16_t ifmtu;
+ } pwid;
+ } fec;
+ u_int32_t label;
u_int32_t requestid;
+ u_int32_t pw_status;
u_int8_t flags;
};
-#define F_MAP_WILDCARD 0x01 /* wildcard FEC */
-#define F_MAP_REQ_ID 0x02 /* optional request message id present */
+#define F_MAP_REQ_ID 0x01 /* optional request message id present */
+#define F_MAP_PW_CWORD 0x02 /* pseudowire control word */
+#define F_MAP_PW_ID 0x04 /* pseudowire connection id */
+#define F_MAP_PW_IFMTU 0x08 /* pseudowire interface parameter */
+#define F_MAP_PW_STATUS 0x10 /* pseudowire status */
struct notify_msg {
u_int32_t messageid;
u_int32_t status;
u_int32_t type;
+ u_int32_t pw_status;
+ struct map fec;
+ u_int8_t flags;
};
+#define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */
+#define F_NOTIF_FEC 0x02 /* fec tlv present */
struct if_addr {
LIST_ENTRY(if_addr) entry;
@@ -218,6 +247,7 @@ struct tnbr {
u_int16_t hello_holdtime;
u_int16_t hello_interval;
+ u_int16_t pw_count;
u_int8_t flags;
};
#define F_TNBR_CONFIGURED 0x01
@@ -239,6 +269,47 @@ struct nbr_params {
} auth;
};
+struct l2vpn_if {
+ LIST_ENTRY(l2vpn_if) entry;
+ struct l2vpn *l2vpn;
+ char ifname[IF_NAMESIZE];
+ unsigned int ifindex;
+ u_int16_t flags;
+ u_int8_t link_state;
+};
+
+struct l2vpn_pw {
+ LIST_ENTRY(l2vpn_pw) entry;
+ struct l2vpn *l2vpn;
+ struct in_addr addr;
+ u_int32_t pwid;
+ char ifname[IF_NAMESIZE];
+ unsigned int ifindex;
+ u_int32_t remote_group;
+ u_int16_t remote_mtu;
+ u_int32_t remote_status;
+ u_int8_t flags;
+};
+#define F_PW_STATUSTLV_CONF 0x01 /* status tlv configured */
+#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
+#define F_PW_CONTROLWORD_CONF 0x04 /* control word configured */
+#define F_PW_CONTROLWORD 0x08 /* control word negotiated */
+#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */
+
+struct l2vpn {
+ LIST_ENTRY(l2vpn) entry;
+ char name[L2VPN_NAME_LEN];
+ int type;
+ int pw_type;
+ int mtu;
+ char br_ifname[IF_NAMESIZE];
+ unsigned int br_ifindex;
+ LIST_HEAD(, l2vpn_if) if_list;
+ LIST_HEAD(, l2vpn_pw) pw_list;
+};
+#define L2VPN_TYPE_VPWS 1
+#define L2VPN_TYPE_VPLS 2
+
/* ldp_conf */
enum {
PROC_MAIN,
@@ -257,6 +328,7 @@ struct ldpd_conf {
struct if_addr_head addr_list;
LIST_HEAD(, tnbr) tnbr_list;
LIST_HEAD(, nbr_params) nbrp_list;
+ LIST_HEAD(, l2vpn) l2vpn_list;
u_int32_t opts;
#define LDPD_OPT_VERBOSE 0x00000001
@@ -284,6 +356,15 @@ struct kroute {
u_int8_t priority;
};
+struct kpw {
+ u_short ifindex;
+ int pw_type;
+ struct in_addr nexthop;
+ u_int32_t local_label;
+ u_int32_t remote_label;
+ u_int8_t flags;
+};
+
struct kaddr {
u_short ifindex;
struct in_addr addr;
@@ -341,6 +422,20 @@ struct ctl_rt {
u_int8_t in_use;
};
+struct ctl_pw {
+ u_int16_t type;
+ char ifname[IF_NAMESIZE];
+ u_int32_t pwid;
+ struct in_addr nexthop;
+ u_int32_t local_label;
+ u_int32_t local_gid;
+ u_int16_t local_ifmtu;
+ u_int32_t remote_label;
+ u_int32_t remote_gid;
+ u_int16_t remote_ifmtu;
+ u_int32_t status;
+};
+
/* parse.y */
struct ldpd_conf *parse_config(char *, int);
int cmdline_symset(char *);
@@ -360,6 +455,10 @@ void kr_ifinfo(char *, pid_t);
struct kif *kif_findname(char *);
u_int8_t mask2prefixlen(in_addr_t);
in_addr_t prefixlen2mask(u_int8_t);
+void kmpw_set(struct kpw *);
+void kmpw_unset(struct kpw *);
+void kmpw_install(const char *, struct kpw *);
+void kmpw_uninstall(const char *, struct kpw *);
/* log.h */
const char *nbr_state_name(int);
diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c
index 2a1a81ae2f3..5e82620eae0 100644
--- a/usr.sbin/ldpd/ldpe.c
+++ b/usr.sbin/ldpd/ldpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.c,v 1.35 2015/07/21 04:45:21 renato Exp $ */
+/* $OpenBSD: ldpe.c,v 1.36 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -333,6 +333,9 @@ ldpe_dispatch_main(int fd, short event, void *bula)
struct iface *niface;
struct tnbr *ntnbr;
struct nbr_params *nnbrp;
+ static struct l2vpn *nl2vpn;
+ struct l2vpn_if *nlif;
+ struct l2vpn_pw *npw;
struct imsg imsg;
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
@@ -441,6 +444,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)
LIST_INIT(&nconf->addr_list);
LIST_INIT(&nconf->tnbr_list);
LIST_INIT(&nconf->nbrp_list);
+ LIST_INIT(&nconf->l2vpn_list);
break;
case IMSG_RECONF_IFACE:
if ((niface = malloc(sizeof(struct iface))) == NULL)
@@ -466,6 +470,32 @@ ldpe_dispatch_main(int fd, short event, void *bula)
LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry);
break;
+ case IMSG_RECONF_L2VPN:
+ if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL)
+ fatal(NULL);
+ memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
+
+ LIST_INIT(&nl2vpn->if_list);
+ LIST_INIT(&nl2vpn->pw_list);
+
+ LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
+ break;
+ case IMSG_RECONF_L2VPN_IF:
+ if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
+ fatal(NULL);
+ memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
+
+ nlif->l2vpn = nl2vpn;
+ LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
+ break;
+ case IMSG_RECONF_L2VPN_PW:
+ if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
+ fatal(NULL);
+ memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
+
+ npw->l2vpn = nl2vpn;
+ LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
+ break;
case IMSG_RECONF_END:
merge_config(leconf, nconf);
nconf = NULL;
@@ -602,11 +632,12 @@ ldpe_dispatch_lde(int fd, short event, void *bula)
if (nbr->state != NBR_STA_OPER)
return;
- send_notification_nbr(nbr, nm.status,
- htonl(nm.messageid), htonl(nm.type));
+ send_notification_full(nbr->tcp, &nm);
break;
case IMSG_CTL_END:
case IMSG_CTL_SHOW_LIB:
+ case IMSG_CTL_SHOW_L2VPN_PW:
+ case IMSG_CTL_SHOW_L2VPN_BINDING:
control_imsg_relay(&imsg);
break;
default:
diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h
index d69b973f11b..3aceadf3d91 100644
--- a/usr.sbin/ldpd/ldpe.h
+++ b/usr.sbin/ldpd/ldpe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.h,v 1.39 2015/07/21 04:43:28 renato Exp $ */
+/* $OpenBSD: ldpe.h,v 1.40 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -127,6 +127,7 @@ int recv_keepalive(struct nbr *, char *, u_int16_t);
void send_notification_nbr(struct nbr *, u_int32_t, u_int32_t, u_int32_t);
void send_notification(u_int32_t, struct tcp_conn *, u_int32_t,
u_int32_t);
+void send_notification_full(struct tcp_conn *, struct notify_msg *);
int recv_notification(struct nbr *, char *, u_int16_t);
/* address.c */
@@ -138,6 +139,10 @@ void send_address_withdraw(struct nbr *, struct if_addr *);
#define PREFIX_SIZE(x) (((x) + 7) / 8)
void send_labelmessage(struct nbr *, u_int16_t, struct mapping_head *);
int recv_labelmessage(struct nbr *, char *, u_int16_t, u_int16_t);
+void gen_fec_tlv(struct ibuf *, struct map *);
+void gen_pw_status_tlv(struct ibuf *, u_int32_t);
+int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
+ u_int16_t, struct map *);
/* ldpe.c */
pid_t ldpe(struct ldpd_conf *, int[2], int[2], int[2]);
@@ -248,4 +253,10 @@ int pfkey_establish(struct nbr *, struct nbr_params *);
int pfkey_remove(struct nbr *);
int pfkey_init(struct ldpd_sysdep *);
+/* l2vpn.c */
+void ldpe_l2vpn_init(struct l2vpn *);
+void ldpe_l2vpn_exit(struct l2vpn *);
+void ldpe_l2vpn_pw_init(struct l2vpn_pw *);
+void ldpe_l2vpn_pw_exit(struct l2vpn_pw *);
+
#endif /* _LDPE_H_ */
diff --git a/usr.sbin/ldpd/log.c b/usr.sbin/ldpd/log.c
index 8a4e1c538b2..cf28c293012 100644
--- a/usr.sbin/ldpd/log.c
+++ b/usr.sbin/ldpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.14 2015/07/19 20:54:17 renato Exp $ */
+/* $OpenBSD: log.c,v 1.15 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -30,6 +30,7 @@
#include <unistd.h>
#include "ldpd.h"
+#include "lde.h"
#include "log.h"
static const char * const procnames[] = {
@@ -276,6 +277,22 @@ notification_name(u_int32_t status)
return ("Bad KeepAlive Time");
case S_INTERN_ERR:
return ("Internal Error");
+ case S_ILLEGAL_CBIT:
+ return ("Illegal C-Bit");
+ case S_WRONG_CBIT:
+ return ("Wrong C-Bit");
+ case S_INCPT_BITRATE:
+ return ("Incompatible bit-rate");
+ case S_CEP_MISCONF:
+ return ("CEP-TDM mis-configuration");
+ case S_PW_STATUS:
+ return ("PW Status");
+ case S_UNASSIGN_TAI:
+ return ("Unassigned/Unrecognized TAI");
+ case S_MISCONF_ERR:
+ return ("Generic Misconfiguration Error");
+ case S_WITHDRAW_MTHD:
+ return ("Label Withdraw PW Status Method");
default:
snprintf(buf, sizeof(buf), "[%08x]", status);
return (buf);
@@ -283,18 +300,74 @@ notification_name(u_int32_t status)
}
const char *
-log_fec(struct map *map)
+pw_type_name(u_int16_t pw_type)
{
- static char buf[32];
- char pstr[32];
+ static char buf[64];
+
+ switch (pw_type) {
+ case PW_TYPE_ETHERNET_TAGGED:
+ return ("Eth Tagged");
+ case PW_TYPE_ETHERNET:
+ return ("Ethernet");
+ default:
+ snprintf(buf, sizeof(buf), "[%0x]", pw_type);
+ return (buf);
+ }
+}
+
+const char *
+log_map(struct map *map)
+{
+ static char buf[64];
+ char pstr[64];
+
+ switch (map->type) {
+ case FEC_WILDCARD:
+ if (snprintf(buf, sizeof(buf), "wildcard"))
+ return ("???");
+ break;
+ case FEC_PREFIX:
+ if (snprintf(buf, sizeof(buf), "%s/%u",
+ inet_ntop(AF_INET, &map->fec.ipv4.prefix, pstr,
+ sizeof(pstr)), map->fec.ipv4.prefixlen) == -1)
+ return ("???");
+ break;
+ case FEC_PWID:
+ if (snprintf(buf, sizeof(buf), "pwid %u (%s)",
+ map->fec.pwid.pwid,
+ pw_type_name(map->fec.pwid.type)) == -1)
+ return ("???");
+ break;
+ default:
+ return ("???");
+ }
+
+ return (buf);
+}
- if (map->flags & F_MAP_WILDCARD)
- return ("wildcard");
+const char *
+log_fec(struct fec *fec)
+{
+ static char buf[64];
+ char pstr[32];
- if (snprintf(buf, sizeof(buf), "%s/%u",
- inet_ntop(AF_INET, &map->prefix, pstr, sizeof(pstr)),
- map->prefixlen) == -1)
+ switch (fec->type) {
+ case FEC_TYPE_IPV4:
+ if (snprintf(buf, sizeof(buf), "%s/%u",
+ inet_ntop(AF_INET, &fec->u.ipv4.prefix, pstr,
+ sizeof(pstr)), fec->u.ipv4.prefixlen) == -1)
+ return ("???");
+ break;
+ case FEC_TYPE_PWID:
+ if (snprintf(buf, sizeof(buf),
+ "pwid %u (%s) - %s",
+ fec->u.pwid.pwid, pw_type_name(fec->u.pwid.type),
+ inet_ntoa(fec->u.pwid.nexthop)) == -1)
+ return ("???");
+ break;
+ default:
return ("???");
+ }
return (buf);
}
diff --git a/usr.sbin/ldpd/log.h b/usr.sbin/ldpd/log.h
index ba10c360c8c..452fb986bc3 100644
--- a/usr.sbin/ldpd/log.h
+++ b/usr.sbin/ldpd/log.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.h,v 1.5 2014/11/03 18:44:36 bluhm Exp $ */
+/* $OpenBSD: log.h,v 1.6 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -31,7 +31,10 @@ void log_info(const char *, ...);
void log_debug(const char *, ...);
void fatal(const char *) __dead;
void fatalx(const char *) __dead;
-const char *log_fec(struct map *);
+const char *pw_type_name(u_int16_t);
+const char *log_map(struct map *);
+struct fec;
+const char *log_fec(struct fec *);
void log_rtmsg(u_char);
#endif /* _LOG_H_ */
diff --git a/usr.sbin/ldpd/notification.c b/usr.sbin/ldpd/notification.c
index e1dfacdc609..70045451cff 100644
--- a/usr.sbin/ldpd/notification.c
+++ b/usr.sbin/ldpd/notification.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: notification.c,v 1.17 2014/10/25 03:23:49 lteo Exp $ */
+/* $OpenBSD: notification.c,v 1.18 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -39,26 +39,32 @@
int gen_status_tlv(struct ibuf *, u_int32_t, u_int32_t, u_int32_t);
void
-send_notification_nbr(struct nbr *nbr, u_int32_t status, u_int32_t msgid,
- u_int32_t type)
-{
- log_debug("send_notification_nbr: nbr ID %s, status %s",
- inet_ntoa(nbr->id), notification_name(status));
- send_notification(status, nbr->tcp, msgid, type);
- nbr_fsm(nbr, NBR_EVT_PDU_SENT);
-}
-
-void
-send_notification(u_int32_t status, struct tcp_conn *tcp, u_int32_t msgid,
- u_int32_t type)
+send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
{
struct ibuf *buf;
u_int16_t size;
+ if (tcp->nbr)
+ log_debug("send_notification_full: nbr ID %s, status %s",
+ inet_ntoa(tcp->nbr->id), notification_name(nm->status));
+
if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
fatal("send_notification");
+ /* calculate size */
size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + STATUS_SIZE;
+ if (nm->flags & F_NOTIF_PW_STATUS)
+ size += PW_STATUS_TLV_LEN;
+ if (nm->flags & F_NOTIF_FEC) {
+ size += TLV_HDR_LEN;
+ switch (nm->fec.type) {
+ case FEC_PWID:
+ size += FEC_PWID_ELM_MIN_LEN;
+ if (nm->fec.flags & F_MAP_PW_ID)
+ size += sizeof(u_int32_t);
+ break;
+ }
+ }
gen_ldp_hdr(buf, size);
@@ -66,20 +72,46 @@ send_notification(u_int32_t status, struct tcp_conn *tcp, u_int32_t msgid,
gen_msg_tlv(buf, MSG_TYPE_NOTIFICATION, size);
- size -= sizeof(struct ldp_msg);
-
- gen_status_tlv(buf, status, msgid, type);
+ gen_status_tlv(buf, nm->status, nm->messageid, nm->type);
+ /* optional tlvs */
+ if (nm->flags & F_NOTIF_PW_STATUS)
+ gen_pw_status_tlv(buf, nm->pw_status);
+ if (nm->flags & F_NOTIF_FEC)
+ gen_fec_tlv(buf, &nm->fec);
evbuf_enqueue(&tcp->wbuf, buf);
}
+/* send a notification without optional tlvs */
+void
+send_notification(u_int32_t status, struct tcp_conn *tcp, u_int32_t msgid,
+ u_int32_t type)
+{
+ struct notify_msg nm;
+
+ bzero(&nm, sizeof(nm));
+ nm.status = status;
+ nm.messageid = msgid;
+ nm.type = type;
+
+ send_notification_full(tcp, &nm);
+}
+
+void
+send_notification_nbr(struct nbr *nbr, u_int32_t status, u_int32_t msgid,
+ u_int32_t type)
+{
+ send_notification(status, nbr->tcp, msgid, type);
+ nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
int
recv_notification(struct nbr *nbr, char *buf, u_int16_t len)
{
struct ldp_msg not;
struct status_tlv st;
-
- log_debug("recv_notification: neighbor ID %s", inet_ntoa(nbr->id));
+ struct notify_msg nm;
+ int tlen;
bcopy(buf, &not, sizeof(not));
@@ -97,8 +129,89 @@ recv_notification(struct nbr *nbr, char *buf, u_int16_t len)
session_shutdown(nbr, S_BAD_TLV_LEN, not.msgid, not.type);
return (-1);
}
+ buf += STATUS_SIZE;
+ len -= STATUS_SIZE;
+
+ bzero(&nm, sizeof(nm));
+ nm.status = ntohl(st.status_code);
+
+ /* Optional Parameters */
+ while (len > 0) {
+ struct tlv tlv;
+
+ if (len < sizeof(tlv)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, not.msgid,
+ not.type);
+ return (-1);
+ }
+
+ bcopy(buf, &tlv, sizeof(tlv));
+ if (ntohs(tlv.length) > len - TLV_HDR_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, not.msgid,
+ not.type);
+ return (-1);
+ }
+ buf += TLV_HDR_LEN;
+ len -= TLV_HDR_LEN;
+
+ switch (ntohs(tlv.type) & ~UNKNOWN_FLAG) {
+ case TLV_TYPE_EXTSTATUS:
+ case TLV_TYPE_RETURNEDPDU:
+ case TLV_TYPE_RETURNEDMSG:
+ /* TODO is there any use for this? */
+ break;
+ case TLV_TYPE_PW_STATUS:
+ if (ntohs(tlv.length) != 4) {
+ session_shutdown(nbr, S_BAD_TLV_LEN,
+ not.msgid, not.type);
+ return (-1);
+ }
+
+ nm.pw_status = ntohl(*(u_int32_t *)buf);
+ nm.flags |= F_NOTIF_PW_STATUS;
+ break;
+ case TLV_TYPE_FEC:
+ if ((tlen = tlv_decode_fec_elm(nbr, &not, buf,
+ ntohs(tlv.length), &nm.fec)) == -1)
+ return (-1);
+ /* allow only one fec element */
+ if (tlen != ntohs(tlv.length)) {
+ session_shutdown(nbr, S_BAD_TLV_VAL,
+ not.msgid, not.type);
+ return (-1);
+ }
+ nm.flags |= F_NOTIF_FEC;
+ break;
+ default:
+ if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) {
+ send_notification_nbr(nbr, S_UNKNOWN_TLV,
+ not.msgid, not.type);
+ }
+ /* ignore unknown tlv */
+ break;
+ }
+ buf += ntohs(tlv.length);
+ len -= ntohs(tlv.length);
+ }
- /* TODO optional parameters: ext status, returned PDU and msg */
+ if (nm.status == S_PW_STATUS) {
+ if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {
+ send_notification_nbr(nbr, S_MISS_MSG,
+ not.msgid, not.type);
+ return (-1);
+ }
+
+ switch (nm.fec.type) {
+ case FEC_PWID:
+ case FEC_GENPWID:
+ break;
+ default:
+ send_notification_nbr(nbr, S_BAD_TLV_VAL,
+ not.msgid, not.type);
+ return (-1);
+ break;
+ }
+ }
if (st.status_code & htonl(STATUS_FATAL))
log_warnx("received notification from neighbor %s: %s",
@@ -120,7 +233,10 @@ recv_notification(struct nbr *nbr, char *buf, u_int16_t len)
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
return (-1);
}
- /* XXX in some cases we should inform the RDE about non-fatal ones */
+
+ if (nm.status == S_PW_STATUS)
+ ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
+ &nm, sizeof(nm));
return (ntohs(not.length));
}
@@ -137,8 +253,8 @@ gen_status_tlv(struct ibuf *buf, u_int32_t status, u_int32_t msgid,
st.length = htons(STATUS_TLV_LEN);
st.status_code = htonl(status);
- st.msg_id = msgid;
- st.msg_type = type;
+ st.msg_id = htonl(msgid);
+ st.msg_type = htonl(type);
return (ibuf_add(buf, &st, STATUS_SIZE));
}