]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ldpd: integrate with the pseudowire manager in zebra
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 30 Jun 2017 15:19:39 +0000 (12:19 -0300)
committerDavid Lamparter <equinox@opensourcerouting.org>
Wed, 9 Aug 2017 10:35:16 +0000 (12:35 +0200)
If we receive a notification from zebra indicating that the installation
of a pseudowire has failed (e.g. no reachability), send a PW Status
notification to the remote peer (or a Label Withdraw if the remote peer
doesn't support the PW Status TLV).

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/l2vpn.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
lib/pw.h

index f15461d3d2b0176d0f4f1bc6ff603a71b82d85bd..9bad503b9c815f47a4294cdcff48d97394ae69ac 100644 (file)
@@ -235,6 +235,7 @@ void
 l2vpn_pw_init(struct l2vpn_pw *pw)
 {
        struct fec       fec;
+       struct zapi_pw   zpw;
 
        l2vpn_pw_reset(pw);
 
@@ -242,16 +243,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
@@ -269,7 +277,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;
@@ -475,6 +484,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)
 {
@@ -491,7 +550,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));
index 77643ff48bbad3ca037925dcd020cfe35faa7309..5e98efa4779c28d6d5ee8bffb6025051aeb84086 100644 (file)
@@ -472,6 +472,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 +
@@ -712,8 +721,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) {
@@ -751,19 +760,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;
        }
 }
@@ -772,7 +772,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) {
@@ -806,21 +806,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;
        }
 }
@@ -948,8 +937,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;
        }
index 1cce483832d19283e81a1466f5d2530259faedf1..43f1d36481767029d997a91d2c221f6b96a821b8 100644 (file)
@@ -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);
 
index edf686537fdd5cb37832d501e4cef7f7a19838fe..bafd33f26602913d710ad83fc5006840fc0344ee 100644 (file)
@@ -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);
@@ -774,6 +776,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;
@@ -802,6 +805,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);
@@ -825,6 +829,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;
index efc6bd52790631004d0b1e70bf7e48e500143eca..ecc7db8f2ebb30ec6dffb87bd2f92e380f89e276 100644 (file)
@@ -52,6 +52,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;
@@ -92,6 +94,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)
 {
@@ -152,17 +173,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
@@ -464,6 +508,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)
 {
@@ -494,6 +557,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
index abcad79d67cad6a6ca4cf5106e8e5bcb3cde3eb5..2d7afd5df8afe051485b5abcd638d913836516e7 100644 (file)
@@ -578,21 +578,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 +
index c09f62e6396a08647b51b9f6cc23557b14ddf7aa..31d0bc69b159b7c586a4ef8f6b3cfeafadb00546 100644 (file)
@@ -31,6 +31,7 @@
 #include "filter.h"
 #include "vty.h"
 #include "pw.h"
+#include "zclient.h"
 
 #include "ldp.h"
 
@@ -45,7 +46,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
@@ -103,8 +103,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 +150,8 @@ enum imsg_type {
        IMSG_DEBUG_UPDATE,
        IMSG_LOG,
        IMSG_ACL_CHECK,
-       IMSG_INIT
+       IMSG_INIT,
+       IMSG_PW_UPDATE
 };
 
 struct ldpd_init {
@@ -408,6 +411,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 +423,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;
@@ -543,16 +546,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;
@@ -669,11 +662,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);
index b34f681acbdeb0663edefef8b4be0833d0fda94d..2cfaa47e5d6ef3b38ceb7c7cd21469b7ea925dfb 100644 (file)
--- a/lib/pw.h
+++ b/lib/pw.h
@@ -20,6 +20,9 @@
 #ifndef _FRR_PW_H
 #define _FRR_PW_H
 
+/* L2VPN name length. */
+#define L2VPN_NAME_LEN         32
+
 /* Pseudowire type - LDP and BGP use the same values. */
 #define PW_TYPE_ETHERNET_TAGGED        0x0004  /* RFC 4446 */
 #define PW_TYPE_ETHERNET       0x0005  /* RFC 4446 */
@@ -37,7 +40,9 @@
  */
 union pw_protocol_fields {
        struct {
-               /* TODO */
+               struct in_addr lsr_id;
+               uint32_t pwid;
+               char vpn_name[L2VPN_NAME_LEN];
        } ldp;
        struct {
                /* TODO */