summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2017-03-03 17:50:22 -0300
committerRenato Westphal <renato@opensourcerouting.org>2017-03-03 17:50:22 -0300
commit26519d8c02d9b88631fc8322c35c638bcbc8c2e2 (patch)
tree5674f800b6930f97ab025f841307aeec2f9ea77c
parentfd1cf443e92a7dc5b9ed7efe11223af7f22f2437 (diff)
ldpd: send VPLS MAC withdrawals
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>
-rw-r--r--ldpd/address.c79
-rw-r--r--ldpd/l2vpn.c27
-rw-r--r--ldpd/lde.h1
-rw-r--r--ldpd/ldp.h1
-rw-r--r--ldpd/ldp_zebra.c2
-rw-r--r--ldpd/ldpd.h3
-rw-r--r--ldpd/ldpe.c21
-rw-r--r--ldpd/ldpe.h1
8 files changed, 123 insertions, 12 deletions
diff --git a/ldpd/address.c b/ldpd/address.c
index f4fc21311a..ad23ca690b 100644
--- a/ldpd/address.c
+++ b/ldpd/address.c
@@ -26,12 +26,14 @@
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");
+}
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index 8e17ccb258..3f4e21e685 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -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)
{
diff --git a/ldpd/lde.h b/ldpd/lde.h
index a2b51dad32..b5bcb42c8b 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -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 *);
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index 0a42ab4076..c2b64d20c6 100644
--- a/ldpd/ldp.h
+++ b/ldpd/ldp.h
@@ -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
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index 12954b91af..c41a0dbd91 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -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
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 7d12c66cee..0a7e1177bc 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -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;
};
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index bea26a6610..93454cf27e 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -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 +
diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h
index 2bd0568d68..22b75eb008 100644
--- a/ldpd/ldpe.h
+++ b/ldpd/ldpe.h
@@ -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 */