summaryrefslogtreecommitdiffstats
path: root/ldpd
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2017-08-08 13:54:32 +0200
committerGitHub <noreply@github.com>2017-08-08 13:54:32 +0200
commitf66e92bc4856352dc4c1c81fa35b1dd570cd83e5 (patch)
treed95a4b505cc238c09ea4d2512f2ad6af92f5cb9c /ldpd
parentMerge pull request #907 from opensourcerouting/vty-close-3.0 (diff)
parentzebra: add support for static pseudowires (diff)
downloadfrr-f66e92bc4856352dc4c1c81fa35b1dd570cd83e5.tar.xz
frr-f66e92bc4856352dc4c1c81fa35b1dd570cd83e5.zip
Merge pull request #783 from opensourcerouting/pw-manager-2
Add Pseudowire management in Zebra
Diffstat (limited to 'ldpd')
-rw-r--r--ldpd/l2vpn.c65
-rw-r--r--ldpd/lde.c60
-rw-r--r--ldpd/lde.h1
-rw-r--r--ldpd/lde_lib.c9
-rw-r--r--ldpd/ldp.h3
-rw-r--r--ldpd/ldp_zebra.c76
-rw-r--r--ldpd/ldpd.c41
-rw-r--r--ldpd/ldpd.h33
8 files changed, 211 insertions, 77 deletions
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index 27948f5a1..afb9528d8 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -234,6 +234,7 @@ void
l2vpn_pw_init(struct l2vpn_pw *pw)
{
struct fec fec;
+ struct zapi_pw zpw;
l2vpn_pw_reset(pw);
@@ -241,16 +242,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
0, (void *)pw);
lde_kernel_update(&fec);
+
+ pw2zpw(pw, &zpw);
+ lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw));
}
void
l2vpn_pw_exit(struct l2vpn_pw *pw)
{
struct fec fec;
+ struct zapi_pw zpw;
l2vpn_pw_fec(pw, &fec);
lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
lde_kernel_update(&fec);
+
+ pw2zpw(pw, &zpw);
+ lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw));
}
static void
@@ -268,7 +276,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw)
{
pw->remote_group = 0;
pw->remote_mtu = 0;
- pw->remote_status = 0;
+ pw->local_status = PW_FORWARDING;
+ pw->remote_status = PW_NOT_FORWARDING;
if (pw->flags & F_PW_CWORD_CONF)
pw->flags |= F_PW_CWORD;
@@ -474,6 +483,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
}
}
+int
+l2vpn_pw_status_update(struct zapi_pw_status *zpw)
+{
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw = NULL;
+ struct lde_nbr *ln;
+ struct fec fec;
+ uint32_t local_status;
+
+ RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
+ pw = l2vpn_pw_find(l2vpn, zpw->ifname);
+ if (pw)
+ break;
+ }
+ if (!pw) {
+ log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname);
+ return (1);
+ }
+
+ if (zpw->status == PW_STATUS_UP)
+ local_status = PW_FORWARDING;
+ else
+ local_status = PW_NOT_FORWARDING;
+
+ /* local status didn't change */
+ if (pw->local_status == local_status)
+ return (0);
+ pw->local_status = local_status;
+
+ /* notify remote peer about the status update */
+ ln = lde_nbr_find_by_lsrid(pw->lsr_id);
+ if (ln == NULL)
+ return (0);
+ l2vpn_pw_fec(pw, &fec);
+ if (pw->flags & F_PW_STATUSTLV)
+ l2vpn_send_pw_status(ln, local_status, &fec);
+ else {
+ struct fec_node *fn;
+ fn = (struct fec_node *)fec_find(&ft, &fec);
+ if (fn) {
+ if (pw->local_status == PW_FORWARDING)
+ lde_send_labelmapping(ln, fn, 1);
+ else
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+ }
+ }
+
+ return (0);
+}
+
void
l2vpn_pw_ctl(pid_t pid)
{
@@ -490,7 +549,9 @@ l2vpn_pw_ctl(pid_t pid)
sizeof(pwctl.ifname));
pwctl.pwid = pw->pwid;
pwctl.lsr_id = pw->lsr_id;
- pwctl.status = pw->flags & F_PW_STATUS_UP;
+ if (pw->local_status == PW_FORWARDING &&
+ pw->remote_status == PW_FORWARDING)
+ pwctl.status = 1;
lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
pid, &pwctl, sizeof(pwctl));
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 7540fc1cb..37d64eaf5 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -491,6 +491,15 @@ lde_dispatch_parent(struct thread *thread)
}
}
break;
+ case IMSG_PW_UPDATE:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_pw_status))
+ fatalx("PW_UPDATE imsg with wrong len");
+
+ if (l2vpn_pw_status_update(imsg.data) != 0)
+ log_warnx("%s: error updating PW status",
+ __func__);
+ break;
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -730,8 +739,8 @@ lde_update_label(struct fec_node *fn)
void
lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
- struct kroute kr;
- struct kpw kpw;
+ struct kroute kr;
+ struct zapi_pw zpw;
struct l2vpn_pw *pw;
switch (fn->fec.type) {
@@ -769,19 +778,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
return;
pw = (struct l2vpn_pw *) fn->data;
- pw->flags |= F_PW_STATUS_UP;
-
- memset(&kpw, 0, sizeof(kpw));
- kpw.ifindex = pw->ifindex;
- kpw.pw_type = fn->fec.u.pwid.type;
- kpw.af = pw->af;
- kpw.nexthop = pw->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));
+ pw2zpw(pw, &zpw);
+ zpw.local_label = fn->local_label;
+ zpw.remote_label = fnh->remote_label;
+ lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw));
break;
}
}
@@ -790,7 +790,7 @@ void
lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
{
struct kroute kr;
- struct kpw kpw;
+ struct zapi_pw zpw;
struct l2vpn_pw *pw;
switch (fn->fec.type) {
@@ -824,21 +824,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
- if (!(pw->flags & F_PW_STATUS_UP))
- return;
- pw->flags &= ~F_PW_STATUS_UP;
-
- memset(&kpw, 0, sizeof(kpw));
- kpw.ifindex = pw->ifindex;
- kpw.pw_type = fn->fec.u.pwid.type;
- kpw.af = pw->af;
- kpw.nexthop = pw->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));
+ pw2zpw(pw, &zpw);
+ zpw.local_label = fn->local_label;
+ zpw.remote_label = fnh->remote_label;
+ lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw));
break;
}
}
@@ -919,8 +908,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
*/
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
if (lw) {
- if (!fec_find(&ln->sent_map_pending, &fn->fec))
+ if (!fec_find(&ln->sent_map_pending, &fn->fec)) {
+ debug_evt("%s: FEC %s: scheduling to send label "
+ "mapping later (waiting for pending label release)",
+ __func__, log_fec(&fn->fec));
lde_map_pending_add(ln, fn);
+ }
return;
}
@@ -966,8 +959,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
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.pw_status = pw->local_status;
}
break;
}
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 1cce48383..43f1d3648 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
struct notify_msg *);
+int l2vpn_pw_status_update(struct zapi_pw_status *);
void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 37a670bc8..c24a57b56 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -396,7 +396,7 @@ lde_kernel_update(struct fec *fec)
lde_gc_start_timer();
} else {
fn->local_label = lde_update_label(fn);
- if (fn->local_label != NO_LABEL && RB_EMPTY(&fn->upstream))
+ if (fn->local_label != NO_LABEL)
/* FEC.1: perform lsr label distribution procedure */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_send_labelmapping(ln, fn, 1);
@@ -531,6 +531,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
pw->remote_mtu = map->fec.pwid.ifmtu;
if (map->flags & F_MAP_PW_STATUS)
pw->remote_status = map->pw_status;
+ else
+ pw->remote_status = PW_FORWARDING;
fnh->remote_label = map->label;
if (l2vpn_pw_ok(pw, fnh))
lde_send_change_klabel(fn, fnh);
@@ -780,6 +782,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL)
continue;
+ pw->remote_status = PW_NOT_FORWARDING;
break;
default:
break;
@@ -808,6 +811,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
+ struct l2vpn_pw *pw;
/* LWd.2: send label release */
lde_send_labelrelease(ln, NULL, map, map->label);
@@ -831,6 +835,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
case FEC_TYPE_PWID:
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
continue;
+ pw = (struct l2vpn_pw *) fn->data;
+ if (pw)
+ pw->remote_status = PW_NOT_FORWARDING;
break;
default:
break;
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index c2b64d20c..cac3da7c5 100644
--- a/ldpd/ldp.h
+++ b/ldpd/ldp.h
@@ -285,9 +285,6 @@ struct address_list_tlv {
#define MAP_TYPE_GENPWID 0x81
#define CONTROL_WORD_FLAG 0x8000
-#define PW_TYPE_ETHERNET_TAGGED 0x0004
-#define PW_TYPE_ETHERNET 0x0005
-#define PW_TYPE_WILDCARD 0x7FFF
#define DEFAULT_PW_TYPE PW_TYPE_ETHERNET
#define PW_TWCARD_RESERVED_BIT 0x8000
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index 3320238a0..f7d715e81 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -54,6 +54,8 @@ static int ldp_interface_address_delete(int, struct zclient *,
zebra_size_t, vrf_id_t);
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
vrf_id_t);
+static int ldp_zebra_read_pw_status_update(int, struct zclient *,
+ zebra_size_t, vrf_id_t);
static void ldp_zebra_connected(struct zclient *);
static struct zclient *zclient;
@@ -94,6 +96,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
}
}
+void
+pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
+{
+ memset(zpw, 0, sizeof(*zpw));
+ strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname));
+ zpw->ifindex = pw->ifindex;
+ zpw->type = pw->l2vpn->pw_type;
+ zpw->af = pw->af;
+ zpw->nexthop.ipv6 = pw->addr.v6;
+ zpw->local_label = NO_LABEL;
+ zpw->remote_label = NO_LABEL;
+ if (pw->flags & F_PW_CWORD)
+ zpw->flags = F_PSEUDOWIRE_CWORD;
+ zpw->data.ldp.lsr_id = pw->lsr_id;
+ zpw->data.ldp.pwid = pw->pwid;
+ strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name,
+ sizeof(zpw->data.ldp.vpn_name));
+}
+
static int
zebra_send_mpls_labels(int cmd, struct kroute *kr)
{
@@ -154,17 +175,40 @@ kr_delete(struct kroute *kr)
}
int
-kmpw_set(struct kpw *kpw)
+kmpw_add(struct zapi_pw *zpw)
{
- /* TODO */
- return (0);
+ debug_zebra_out("pseudowire %s nexthop %s (add)",
+ zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+ return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
}
int
-kmpw_unset(struct kpw *kpw)
+kmpw_del(struct zapi_pw *zpw)
{
- /* TODO */
- return (0);
+ debug_zebra_out("pseudowire %s nexthop %s (del)",
+ zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+ return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw));
+}
+
+int
+kmpw_set(struct zapi_pw *zpw)
+{
+ debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)",
+ zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop),
+ zpw->local_label, zpw->remote_label);
+
+ return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw));
+}
+
+int
+kmpw_unset(struct zapi_pw *zpw)
+{
+ debug_zebra_out("pseudowire %s nexthop %s (unset)",
+ zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+ return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw));
}
void
@@ -466,6 +510,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
return (0);
}
+/*
+ * Receive PW status update from Zebra and send it to LDE process.
+ */
+static int
+ldp_zebra_read_pw_status_update(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct zapi_pw_status zpw;
+
+ zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw);
+
+ debug_zebra_in("pseudowire %s status %s", zpw.ifname,
+ (zpw.status == PW_STATUS_UP) ? "up" : "down");
+
+ main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw));
+
+ return (0);
+}
+
static void
ldp_zebra_connected(struct zclient *zclient)
{
@@ -496,6 +559,7 @@ ldp_zebra_init(struct thread_master *master)
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
+ zclient->pw_status_update = ldp_zebra_read_pw_status_update;
}
void
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index f9e44012e..303baf463 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -591,21 +591,36 @@ main_dispatch_lde(struct thread *thread)
if (kr_delete(imsg.data))
log_warnx("%s: error deleting route", __func__);
break;
- case IMSG_KPWLABEL_CHANGE:
+ case IMSG_KPW_ADD:
+ case IMSG_KPW_DELETE:
+ case IMSG_KPW_SET:
+ case IMSG_KPW_UNSET:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct kpw))
+ sizeof(struct zapi_pw))
fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
- if (kmpw_set(imsg.data))
- log_warnx("%s: error changing pseudowire",
- __func__);
- break;
- case IMSG_KPWLABEL_DELETE:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct kpw))
- fatalx("invalid size of IMSG_KPWLABEL_DELETE");
- if (kmpw_unset(imsg.data))
- log_warnx("%s: error unsetting pseudowire",
- __func__);
+
+ switch (imsg.hdr.type) {
+ case IMSG_KPW_ADD:
+ if (kmpw_add(imsg.data))
+ log_warnx("%s: error adding "
+ "pseudowire", __func__);
+ break;
+ case IMSG_KPW_DELETE:
+ if (kmpw_del(imsg.data))
+ log_warnx("%s: error deleting "
+ "pseudowire", __func__);
+ break;
+ case IMSG_KPW_SET:
+ if (kmpw_set(imsg.data))
+ log_warnx("%s: error setting "
+ "pseudowire", __func__);
+ break;
+ case IMSG_KPW_UNSET:
+ if (kmpw_unset(imsg.data))
+ log_warnx("%s: error unsetting "
+ "pseudowire", __func__);
+ break;
+ }
break;
case IMSG_ACL_CHECK:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 97239ed08..fd7d5c572 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -29,6 +29,8 @@
#include "qobj.h"
#include "prefix.h"
#include "filter.h"
+#include "pw.h"
+#include "zclient.h"
#include "ldp.h"
@@ -43,7 +45,6 @@
#define LDPD_OPT_NOACTION 0x00000004
#define TCP_MD5_KEY_LEN 80
-#define L2VPN_NAME_LEN 32
#define RT_BUF_SIZE 16384
#define MAX_RTSOCK_BUF 128 * 1024
@@ -101,8 +102,10 @@ enum imsg_type {
IMSG_CTL_LOG_VERBOSE,
IMSG_KLABEL_CHANGE,
IMSG_KLABEL_DELETE,
- IMSG_KPWLABEL_CHANGE,
- IMSG_KPWLABEL_DELETE,
+ IMSG_KPW_ADD,
+ IMSG_KPW_DELETE,
+ IMSG_KPW_SET,
+ IMSG_KPW_UNSET,
IMSG_IFSTATUS,
IMSG_NEWADDR,
IMSG_DELADDR,
@@ -148,7 +151,8 @@ enum imsg_type {
IMSG_ACL_CHECK,
IMSG_GET_LABEL_CHUNK,
IMSG_RELEASE_LABEL_CHUNK,
- IMSG_INIT
+ IMSG_INIT,
+ IMSG_PW_UPDATE
};
struct ldpd_init {
@@ -408,6 +412,7 @@ struct l2vpn_pw {
unsigned int ifindex;
uint32_t remote_group;
uint16_t remote_mtu;
+ uint32_t local_status;
uint32_t remote_status;
uint8_t flags;
QOBJ_FIELDS
@@ -419,8 +424,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
#define F_PW_CWORD_CONF 0x04 /* control word configured */
#define F_PW_CWORD 0x08 /* control word negotiated */
-#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */
-#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */
+#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */
struct l2vpn {
RB_ENTRY(l2vpn) entry;
@@ -544,16 +548,6 @@ struct kroute {
uint16_t flags;
};
-struct kpw {
- unsigned short ifindex;
- int pw_type;
- int af;
- union ldpd_addr nexthop;
- uint32_t local_label;
- uint32_t remote_label;
- uint8_t flags;
-};
-
struct kaddr {
char ifname[IF_NAMESIZE];
unsigned short ifindex;
@@ -670,11 +664,14 @@ struct ldpd_conf *parse_config(char *);
int cmdline_symset(char *);
/* kroute.c */
+void pw2zpw(struct l2vpn_pw *, struct zapi_pw *);
void kif_redistribute(const char *);
int kr_change(struct kroute *);
int kr_delete(struct kroute *);
-int kmpw_set(struct kpw *);
-int kmpw_unset(struct kpw *);
+int kmpw_add(struct zapi_pw *);
+int kmpw_del(struct zapi_pw *);
+int kmpw_set(struct zapi_pw *);
+int kmpw_unset(struct zapi_pw *);
/* util.c */
uint8_t mask2prefixlen(in_addr_t);