]> git.puffer.fish Git - mirror/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)
committerRenato Westphal <renato@opensourcerouting.org>
Tue, 25 Jul 2017 03:53:23 +0000 (00:53 -0300)
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 27948f5a1aa50debfd6659a4396e2d15f666c37c..afb9528d8099d756e30488b92a11bf41ffad6dc8 100644 (file)
@@ -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));
index 7540fc1cb419207fcf056ca4e432f76845304e23..a47351875bf6b944671c0e76aceefb1de0ea128b 100644 (file)
@@ -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;
        }
 }
@@ -966,8 +955,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 37a670bc8ca58be4988cba4cfa7172df69b4bb5b..2149945943b36ae28c71db58a7dec6a62741ef1f 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);
@@ -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;
index 3320238a05c6df1add4b166b524ddb9ea462e408..f7d715e81c67bf9318ab40447e6373c3dd9591e2 100644 (file)
@@ -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
index f9e44012efd8e88636cc9abc2cefed88ae870329..303baf463b43150bbaf26bb0f578edfef6e9a306 100644 (file)
@@ -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 +
index 21f5e16f88e3fbbaed092e323f084e8f807872d4..fd7d5c5729f6d279337386a3a8cdcef701ac6cb8 100644 (file)
@@ -30,6 +30,7 @@
 #include "prefix.h"
 #include "filter.h"
 #include "pw.h"
+#include "zclient.h"
 
 #include "ldp.h"
 
@@ -44,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
@@ -102,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,
@@ -149,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 {
@@ -409,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
@@ -420,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;
@@ -545,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;
@@ -671,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);
index 2fba996eaedd03e3149c3f6169175911536c00f1..63d8e52dddbab59538bff67e4b301ba990e94fec 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 */
@@ -38,7 +41,9 @@
 union pw_protocol_fields
 {
   struct {
-      /* TODO */
+      struct in_addr lsr_id;
+      uint32_t pwid;
+      char vpn_name[L2VPN_NAME_LEN];
   } ldp;
   struct {
       /* TODO */