]> git.puffer.fish Git - mirror/frr.git/commitdiff
ldpd: send VPLS MAC withdrawals
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 3 Mar 2017 20:50:22 +0000 (17:50 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Fri, 3 Mar 2017 20:50:22 +0000 (17:50 -0300)
RFC 4762 says that MAC address withdrawal messages can be used to
improve convergence time in VPLS networks. This patch makes ldpd send
MAC withdrawals whenever a non-pseudowire interface pertaining to a
VPLS goes down. The processing of received MAC withdrawals will be
implemented later.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/address.c
ldpd/l2vpn.c
ldpd/lde.h
ldpd/ldp.h
ldpd/ldp_zebra.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h

index f4fc21311ae2d3ccb6b31ebed8d1b3ea79ca1462..ad23ca690bf5eacdee4249932063d0ebd719f29e 100644 (file)
 
 static void     send_address(struct nbr *, int, struct if_addr_head *,
                    unsigned int, int);
-static int      gen_address_list_tlv(struct ibuf *, uint16_t, int,
-                   struct if_addr_head *, unsigned int);
+static int      gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
+                   unsigned int);
+static int      gen_mac_list_tlv(struct ibuf *, uint8_t *);
 static void     address_list_add(struct if_addr_head *, struct if_addr *);
 static void     address_list_clr(struct if_addr_head *);
 static void     log_msg_address(int, uint16_t, struct nbr *, int,
                    union ldpd_addr *);
+static void     log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
 
 static void
 send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
@@ -85,8 +87,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
                size -= LDP_HDR_SIZE;
                err |= gen_msg_hdr(buf, msg_type, size);
                size -= LDP_MSG_SIZE;
-               err |= gen_address_list_tlv(buf, size, af, addr_list,
-                   tlv_addr_count);
+               err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
                if (err) {
                        address_list_clr(addr_list);
                        ibuf_free(buf);
@@ -137,6 +138,40 @@ send_address_all(struct nbr *nbr, int af)
        send_address(nbr, af, &addr_list, addr_count, 0);
 }
 
+void
+send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
+{
+       struct ibuf     *buf;
+       uint16_t         size;
+       int              err;
+
+       size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
+           TLV_HDR_SIZE;
+       if (mac)
+               size += ETHER_ADDR_LEN;
+
+       if ((buf = ibuf_open(size)) == NULL)
+               fatal(__func__);
+
+       err = gen_ldp_hdr(buf, size);
+       size -= LDP_HDR_SIZE;
+       err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
+       size -= LDP_MSG_SIZE;
+       err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
+       err |= gen_fec_tlv(buf, fec);
+       err |= gen_mac_list_tlv(buf, mac);
+       if (err) {
+               ibuf_free(buf);
+               return;
+       }
+
+       log_msg_mac_withdrawal(1, nbr, mac);
+
+       evbuf_enqueue(&nbr->tcp->wbuf, buf);
+
+       nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
 int
 recv_address(struct nbr *nbr, char *buf, uint16_t len)
 {
@@ -278,8 +313,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
 }
 
 static int
-gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
-    struct if_addr_head *addr_list, unsigned int tlv_addr_count)
+gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
+    unsigned int tlv_addr_count)
 {
        struct address_list_tlv  alt;
        uint16_t                 addr_size;
@@ -288,7 +323,6 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
 
        memset(&alt, 0, sizeof(alt));
        alt.type = htons(TLV_TYPE_ADDRLIST);
-       alt.length = htons(size - TLV_HDR_SIZE);
 
        switch (af) {
        case AF_INET:
@@ -302,8 +336,12 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
        default:
                fatalx("gen_address_list_tlv: unknown af");
        }
+       alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
 
        err |= ibuf_add(buf, &alt, sizeof(alt));
+       if (addr_list == NULL)
+               return (err);
+
        LIST_FOREACH(if_addr, addr_list, entry) {
                err |= ibuf_add(buf, &if_addr->addr, addr_size);
                if (--tlv_addr_count == 0)
@@ -313,6 +351,23 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
        return (err);
 }
 
+static int
+gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
+{
+       struct tlv       tlv;
+       int              err;
+
+       memset(&tlv, 0, sizeof(tlv));
+       tlv.type = htons(TLV_TYPE_MAC_LIST);
+       if (mac)
+               tlv.length = htons(ETHER_ADDR_LEN);
+       err = ibuf_add(buf, &tlv, sizeof(tlv));
+       if (mac)
+               err |= ibuf_add(buf, mac, ETHER_ADDR_LEN);
+
+       return (err);
+}
+
 static void
 address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
 {
@@ -344,3 +399,13 @@ log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
        debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type),
            inet_ntoa(nbr->id), log_addr(af, addr));
 }
+
+static void
+log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
+{
+       char buf[ETHER_ADDR_STRLEN];
+
+       debug_msg(out, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr->id),
+           (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
+           "wildcard");
+}
index 8e17ccb2585076a46f991827dace8ba9cf8ec173..3f4e21e68556857b4aca49d0040d6840bc78baaa 100644 (file)
@@ -152,6 +152,33 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
        return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
 }
 
+void
+l2vpn_if_update(struct l2vpn_if *lif)
+{
+       struct l2vpn    *l2vpn = lif->l2vpn;
+       struct l2vpn_pw *pw;
+       struct map       fec;
+       struct nbr      *nbr;
+
+       if ((lif->flags & IFF_UP) && (lif->flags & IFF_RUNNING))
+               return;
+
+       RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
+               nbr = nbr_find_ldpid(pw->lsr_id.s_addr);
+               if (nbr == NULL)
+                       continue;
+
+               memset(&fec, 0, sizeof(fec));
+               fec.type = MAP_TYPE_PWID;
+               fec.fec.pwid.type = l2vpn->pw_type;
+               fec.fec.pwid.group_id = 0;
+               fec.flags |= F_MAP_PW_ID;
+               fec.fec.pwid.pwid = pw->pwid;
+
+               send_mac_withdrawal(nbr, &fec, lif->mac);
+       }
+}
+
 static __inline int
 l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b)
 {
index a2b51dad32a31eb1f783c2aa46629337d0e4e627..b5bcb42c8b561d98e44b5c66f36eedb865174688 100644 (file)
@@ -208,6 +208,7 @@ void                 l2vpn_exit(struct l2vpn *);
 struct l2vpn_if        *l2vpn_if_new(struct l2vpn *, struct kif *);
 struct l2vpn_if        *l2vpn_if_find(struct l2vpn *, unsigned int);
 struct l2vpn_if        *l2vpn_if_find_name(struct l2vpn *, const char *);
+void            l2vpn_if_update(struct l2vpn_if *);
 struct l2vpn_pw        *l2vpn_pw_new(struct l2vpn *, struct kif *);
 struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
 struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
index 0a42ab40765873c4b01cdf095f081b79762eeb2a..c2b64d20c67458cb9f413df9157ecfcb1edc62a4 100644 (file)
@@ -93,6 +93,7 @@
 #define TLV_TYPE_FRSESSION     0x0502
 #define TLV_TYPE_LABELREQUEST  0x0600
 /* RFC 4447 */
+#define TLV_TYPE_MAC_LIST      0x8404
 #define TLV_TYPE_PW_STATUS     0x896A
 #define TLV_TYPE_PW_IF_PARAM   0x096B
 #define TLV_TYPE_PW_GROUP_ID   0x096C
index 12954b91af6791ac862adf03e932f1a9d6fb2d7d..c41a0dbd9151516dbfd447946d24c10cbe797b97 100644 (file)
@@ -65,6 +65,8 @@ ifp2kif(struct interface *ifp, struct kif *kif)
        strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
        kif->ifindex = ifp->ifindex;
        kif->flags = ifp->flags;
+       if (ifp->ll_type == ZEBRA_LLT_ETHER)
+               memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN);
 }
 
 static void
index 7d12c66ceeeaccb6ea480885f8a81626c036a34b..0a7e1177bc54f468d1c185672cccaee3ee3e7a31 100644 (file)
@@ -27,6 +27,7 @@
 #include "imsg.h"
 #include "thread.h"
 #include "qobj.h"
+#include "prefix.h"
 #include "filter.h"
 
 #include "ldp.h"
@@ -350,6 +351,7 @@ struct l2vpn_if {
        char                     ifname[IF_NAMESIZE];
        unsigned int             ifindex;
        uint16_t                 flags;
+       uint8_t                  mac[ETHER_ADDR_LEN];
        QOBJ_FIELDS
 };
 RB_HEAD(l2vpn_if_head, l2vpn_if);
@@ -519,6 +521,7 @@ struct kif {
        char                     ifname[IF_NAMESIZE];
        unsigned short           ifindex;
        int                      flags;
+       uint8_t                  mac[ETHER_ADDR_LEN];
        int                      mtu;
 };
 
index bea26a6610eba7174c1518b63b616c572e19d350..93454cf27e377f87c4eb0fa8f5808ea441a907b1 100644 (file)
@@ -251,8 +251,8 @@ ldpe_dispatch_main(struct thread *thread)
        struct iface            *niface;
        struct tnbr             *ntnbr;
        struct nbr_params       *nnbrp;
-       static struct l2vpn     *nl2vpn;
-       struct l2vpn_if         *nlif;
+       static struct l2vpn     *l2vpn, *nl2vpn;
+       struct l2vpn_if         *lif = NULL, *nlif;
        struct l2vpn_pw         *npw;
        struct imsg              imsg;
        int                      fd = THREAD_FD(thread);
@@ -292,11 +292,22 @@ ldpe_dispatch_main(struct thread *thread)
                        kif = imsg.data;
 
                        iface = if_lookup_name(leconf, kif->ifname);
-                       if (!iface)
+                       if (iface) {
+                               if_update_info(iface, kif);
+                               if_update(iface, AF_UNSPEC);
                                break;
+                       }
 
-                       if_update_info(iface, kif);
-                       if_update(iface, AF_UNSPEC);
+                       RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) {
+                               lif = l2vpn_if_find_name(l2vpn, kif->ifname);
+                               if (lif) {
+                                       lif->flags = kif->flags;
+                                       memcpy(lif->mac, kif->mac,
+                                           sizeof(lif->mac));
+                                       l2vpn_if_update(lif);
+                                       break;
+                               }
+                       }
                        break;
                case IMSG_NEWADDR:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE +
index 2bd0568d68a73639492bb96897069de6a2ac2d70..22b75eb008c2723efc24d08d6ea4052efa568768 100644 (file)
@@ -180,6 +180,7 @@ int  gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t);
 /* address.c */
 void    send_address_single(struct nbr *, struct if_addr *, int);
 void    send_address_all(struct nbr *, int);
+void    send_mac_withdrawal(struct nbr *, struct map *, uint8_t *);
 int     recv_address(struct nbr *, char *, uint16_t);
 
 /* labelmapping.c */