mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-16 09:24:38 +00:00
Merge pull request #249 from opensourcerouting/ldpd-rfcs
ldpd: implement new RFCs and other assorted enhancements
This commit is contained in:
commit
e4e41e3277
175
ldpd/address.c
175
ldpd/address.c
@ -26,10 +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,
|
||||
@ -83,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);
|
||||
@ -92,9 +95,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
|
||||
}
|
||||
|
||||
while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
|
||||
debug_msg_send("%s: lsr-id %s address %s",
|
||||
msg_name(msg_type), inet_ntoa(nbr->id),
|
||||
log_addr(af, &if_addr->addr));
|
||||
log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
|
||||
|
||||
LIST_REMOVE(if_addr, entry);
|
||||
free(if_addr);
|
||||
@ -137,16 +138,63 @@ 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)
|
||||
{
|
||||
struct ldp_msg msg;
|
||||
uint16_t msg_type;
|
||||
struct address_list_tlv alt;
|
||||
enum imsg_type type;
|
||||
struct address_list_tlv alt;
|
||||
uint16_t alt_len;
|
||||
uint16_t alt_family;
|
||||
struct lde_addr lde_addr;
|
||||
|
||||
memcpy(&msg, buf, sizeof(msg));
|
||||
msg_type = ntohs(msg.type);
|
||||
switch (msg_type) {
|
||||
case MSG_TYPE_ADDR:
|
||||
type = IMSG_ADDRESS_ADD;
|
||||
break;
|
||||
case MSG_TYPE_ADDRWITHDRAW:
|
||||
type = IMSG_ADDRESS_DEL;
|
||||
break;
|
||||
default:
|
||||
fatalx("recv_address: unexpected msg type");
|
||||
}
|
||||
buf += LDP_MSG_SIZE;
|
||||
len -= LDP_MSG_SIZE;
|
||||
|
||||
@ -155,17 +203,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
|
||||
session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&alt, buf, sizeof(alt));
|
||||
if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
|
||||
alt_len = ntohs(alt.length);
|
||||
alt_family = ntohs(alt.family);
|
||||
if (alt_len > len - TLV_HDR_SIZE) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
|
||||
session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type);
|
||||
send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
switch (ntohs(alt.family)) {
|
||||
switch (alt_family) {
|
||||
case AF_IPV4:
|
||||
if (!nbr->v4_enabled)
|
||||
/* just ignore the message */
|
||||
@ -177,22 +226,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
|
||||
return (0);
|
||||
break;
|
||||
default:
|
||||
send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type);
|
||||
send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
alt_len -= sizeof(alt.family);
|
||||
buf += sizeof(alt);
|
||||
len -= sizeof(alt);
|
||||
|
||||
msg_type = ntohs(msg.type);
|
||||
if (msg_type == MSG_TYPE_ADDR)
|
||||
type = IMSG_ADDRESS_ADD;
|
||||
else
|
||||
type = IMSG_ADDRESS_DEL;
|
||||
|
||||
while (len > 0) {
|
||||
switch (ntohs(alt.family)) {
|
||||
/* Process all received addresses */
|
||||
while (alt_len > 0) {
|
||||
switch (alt_family) {
|
||||
case AF_IPV4:
|
||||
if (len < sizeof(struct in_addr)) {
|
||||
if (alt_len < sizeof(struct in_addr)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
@ -204,9 +249,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
|
||||
|
||||
buf += sizeof(struct in_addr);
|
||||
len -= sizeof(struct in_addr);
|
||||
alt_len -= sizeof(struct in_addr);
|
||||
break;
|
||||
case AF_IPV6:
|
||||
if (len < sizeof(struct in6_addr)) {
|
||||
if (alt_len < sizeof(struct in6_addr)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
@ -218,24 +264,57 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
|
||||
|
||||
buf += sizeof(struct in6_addr);
|
||||
len -= sizeof(struct in6_addr);
|
||||
alt_len -= sizeof(struct in6_addr);
|
||||
break;
|
||||
default:
|
||||
fatalx("recv_address: unknown af");
|
||||
}
|
||||
|
||||
debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type),
|
||||
inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
|
||||
log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
|
||||
|
||||
ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
|
||||
sizeof(lde_addr));
|
||||
}
|
||||
|
||||
/* Optional Parameters */
|
||||
while (len > 0) {
|
||||
struct tlv tlv;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
|
||||
if (len < sizeof(tlv)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&tlv, buf, TLV_HDR_SIZE);
|
||||
tlv_type = ntohs(tlv.type);
|
||||
tlv_len = ntohs(tlv.length);
|
||||
if (tlv_len + TLV_HDR_SIZE > len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
buf += TLV_HDR_SIZE;
|
||||
len -= TLV_HDR_SIZE;
|
||||
|
||||
switch (tlv_type) {
|
||||
default:
|
||||
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
|
||||
send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type, tlv_type, tlv_len, buf);
|
||||
/* ignore unknown tlv */
|
||||
break;
|
||||
}
|
||||
buf += tlv_len;
|
||||
len -= tlv_len;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -243,8 +322,7 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
|
||||
int err = 0;
|
||||
|
||||
memset(&alt, 0, sizeof(alt));
|
||||
alt.type = TLV_TYPE_ADDRLIST;
|
||||
alt.length = htons(size - TLV_HDR_SIZE);
|
||||
alt.type = htons(TLV_TYPE_ADDRLIST);
|
||||
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
@ -258,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)
|
||||
@ -269,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)
|
||||
{
|
||||
@ -292,3 +391,21 @@ address_list_clr(struct if_addr_head *addr_list)
|
||||
free(if_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
|
||||
union ldpd_addr *addr)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
@ -148,9 +148,10 @@ control_connbyfd(int fd)
|
||||
{
|
||||
struct ctl_conn *c;
|
||||
|
||||
for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
|
||||
c = TAILQ_NEXT(c, entry))
|
||||
; /* nothing */
|
||||
TAILQ_FOREACH(c, &ctl_conns, entry) {
|
||||
if (c->iev.ibuf.fd == fd)
|
||||
break;
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
@ -160,9 +161,10 @@ control_connbypid(pid_t pid)
|
||||
{
|
||||
struct ctl_conn *c;
|
||||
|
||||
for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
|
||||
c = TAILQ_NEXT(c, entry))
|
||||
; /* nothing */
|
||||
TAILQ_FOREACH(c, &ctl_conns, entry) {
|
||||
if (c->iev.ibuf.pid == pid)
|
||||
break;
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
283
ldpd/init.c
283
ldpd/init.c
@ -24,6 +24,9 @@
|
||||
#include "ldp_debug.h"
|
||||
|
||||
static int gen_init_prms_tlv(struct ibuf *, struct nbr *);
|
||||
static int gen_cap_dynamic_tlv(struct ibuf *);
|
||||
static int gen_cap_twcard_tlv(struct ibuf *, int);
|
||||
static int gen_cap_unotif_tlv(struct ibuf *, int);
|
||||
|
||||
void
|
||||
send_init(struct nbr *nbr)
|
||||
@ -34,15 +37,18 @@ send_init(struct nbr *nbr)
|
||||
|
||||
debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));
|
||||
|
||||
size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
|
||||
size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
|
||||
CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
|
||||
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_INIT, size);
|
||||
size -= LDP_MSG_SIZE;
|
||||
err |= gen_init_prms_tlv(buf, nbr);
|
||||
err |= gen_cap_dynamic_tlv(buf);
|
||||
err |= gen_cap_twcard_tlv(buf, 1);
|
||||
err |= gen_cap_unotif_tlv(buf, 1);
|
||||
if (err) {
|
||||
ibuf_free(buf);
|
||||
return;
|
||||
@ -57,6 +63,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
|
||||
struct ldp_msg msg;
|
||||
struct sess_prms_tlv sess;
|
||||
uint16_t max_pdu_len;
|
||||
int caps_rcvd = 0;
|
||||
|
||||
debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id));
|
||||
|
||||
@ -93,6 +100,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
|
||||
/* Optional Parameters */
|
||||
while (len > 0) {
|
||||
struct tlv tlv;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
|
||||
if (len < sizeof(tlv)) {
|
||||
@ -101,6 +109,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
|
||||
}
|
||||
|
||||
memcpy(&tlv, buf, TLV_HDR_SIZE);
|
||||
tlv_type = ntohs(tlv.type);
|
||||
tlv_len = ntohs(tlv.length);
|
||||
if (tlv_len + TLV_HDR_SIZE > len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
@ -109,17 +118,81 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
|
||||
buf += TLV_HDR_SIZE;
|
||||
len -= TLV_HDR_SIZE;
|
||||
|
||||
switch (ntohs(tlv.type)) {
|
||||
/*
|
||||
* RFC 5561 - Section 6:
|
||||
* "The S-bit of a Capability Parameter in an Initialization
|
||||
* message MUST be 1 and SHOULD be ignored on receipt".
|
||||
*/
|
||||
switch (tlv_type) {
|
||||
case TLV_TYPE_ATMSESSIONPAR:
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
|
||||
return (-1);
|
||||
case TLV_TYPE_FRSESSION:
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
|
||||
return (-1);
|
||||
case TLV_TYPE_DYNAMIC_CAP:
|
||||
if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
|
||||
|
||||
nbr->flags |= F_NBR_CAP_DYNAMIC;
|
||||
|
||||
log_debug("%s: lsr-id %s announced the Dynamic "
|
||||
"Capability Announcement capability", __func__,
|
||||
inet_ntoa(nbr->id));
|
||||
break;
|
||||
case TLV_TYPE_TWCARD_CAP:
|
||||
if (tlv_len != CAP_TLV_TWCARD_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
|
||||
|
||||
nbr->flags |= F_NBR_CAP_TWCARD;
|
||||
|
||||
log_debug("%s: lsr-id %s announced the Typed Wildcard "
|
||||
"FEC capability", __func__, inet_ntoa(nbr->id));
|
||||
break;
|
||||
case TLV_TYPE_UNOTIF_CAP:
|
||||
if (tlv_len != CAP_TLV_UNOTIF_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
|
||||
|
||||
nbr->flags |= F_NBR_CAP_UNOTIF;
|
||||
|
||||
log_debug("%s: lsr-id %s announced the Unrecognized "
|
||||
"Notification capability", __func__,
|
||||
inet_ntoa(nbr->id));
|
||||
break;
|
||||
default:
|
||||
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
|
||||
send_notification_nbr(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type);
|
||||
send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
|
||||
msg.id, msg.type, tlv_type, tlv_len, buf);
|
||||
/* ignore unknown tlv */
|
||||
break;
|
||||
}
|
||||
@ -145,6 +218,164 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
send_capability(struct nbr *nbr, uint16_t capability, int enable)
|
||||
{
|
||||
struct ibuf *buf;
|
||||
uint16_t size;
|
||||
int err = 0;
|
||||
|
||||
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
|
||||
|
||||
size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
|
||||
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_CAPABILITY, size);
|
||||
|
||||
switch (capability) {
|
||||
case TLV_TYPE_TWCARD_CAP:
|
||||
err |= gen_cap_twcard_tlv(buf, enable);
|
||||
break;
|
||||
case TLV_TYPE_UNOTIF_CAP:
|
||||
err |= gen_cap_unotif_tlv(buf, enable);
|
||||
break;
|
||||
case TLV_TYPE_DYNAMIC_CAP:
|
||||
/*
|
||||
* RFC 5561 - Section 9:
|
||||
* "An LDP speaker MUST NOT include the Dynamic Capability
|
||||
* Announcement Parameter in Capability messages sent to
|
||||
* its peers".
|
||||
*/
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
fatalx("send_capability: unsupported capability");
|
||||
}
|
||||
|
||||
if (err) {
|
||||
ibuf_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
evbuf_enqueue(&nbr->tcp->wbuf, buf);
|
||||
nbr_fsm(nbr, NBR_EVT_PDU_SENT);
|
||||
}
|
||||
|
||||
int
|
||||
recv_capability(struct nbr *nbr, char *buf, uint16_t len)
|
||||
{
|
||||
struct ldp_msg msg;
|
||||
int enable = 0;
|
||||
int caps_rcvd = 0;
|
||||
|
||||
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
|
||||
|
||||
memcpy(&msg, buf, sizeof(msg));
|
||||
buf += LDP_MSG_SIZE;
|
||||
len -= LDP_MSG_SIZE;
|
||||
|
||||
/* Optional Parameters */
|
||||
while (len > 0) {
|
||||
struct tlv tlv;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
uint8_t reserved;
|
||||
|
||||
if (len < sizeof(tlv)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&tlv, buf, TLV_HDR_SIZE);
|
||||
tlv_type = ntohs(tlv.type);
|
||||
tlv_len = ntohs(tlv.length);
|
||||
if (tlv_len + TLV_HDR_SIZE > len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
buf += TLV_HDR_SIZE;
|
||||
len -= TLV_HDR_SIZE;
|
||||
|
||||
switch (tlv_type) {
|
||||
case TLV_TYPE_TWCARD_CAP:
|
||||
if (tlv_len != CAP_TLV_TWCARD_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
|
||||
|
||||
memcpy(&reserved, buf, sizeof(reserved));
|
||||
enable = reserved & STATE_BIT;
|
||||
if (enable)
|
||||
nbr->flags |= F_NBR_CAP_TWCARD;
|
||||
else
|
||||
nbr->flags &= ~F_NBR_CAP_TWCARD;
|
||||
|
||||
log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
|
||||
"capability", __func__, inet_ntoa(nbr->id),
|
||||
(enable) ? "announced" : "withdrew");
|
||||
break;
|
||||
case TLV_TYPE_UNOTIF_CAP:
|
||||
if (tlv_len != CAP_TLV_UNOTIF_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
}
|
||||
caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
|
||||
|
||||
memcpy(&reserved, buf, sizeof(reserved));
|
||||
enable = reserved & STATE_BIT;
|
||||
if (enable)
|
||||
nbr->flags |= F_NBR_CAP_UNOTIF;
|
||||
else
|
||||
nbr->flags &= ~F_NBR_CAP_UNOTIF;
|
||||
|
||||
log_debug("%s: lsr-id %s %s the Unrecognized "
|
||||
"Notification capability", __func__,
|
||||
inet_ntoa(nbr->id), (enable) ? "announced" :
|
||||
"withdrew");
|
||||
break;
|
||||
case TLV_TYPE_DYNAMIC_CAP:
|
||||
/*
|
||||
* RFC 5561 - Section 9:
|
||||
* "An LDP speaker that receives a Capability message
|
||||
* from a peer that includes the Dynamic Capability
|
||||
* Announcement Parameter SHOULD silently ignore the
|
||||
* parameter and process any other Capability Parameters
|
||||
* in the message".
|
||||
*/
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
|
||||
send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
|
||||
msg.id, msg.type, tlv_type, tlv_len, buf);
|
||||
/* ignore unknown tlv */
|
||||
break;
|
||||
}
|
||||
buf += tlv_len;
|
||||
len -= tlv_len;
|
||||
}
|
||||
|
||||
nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
|
||||
{
|
||||
@ -163,3 +394,45 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
|
||||
|
||||
return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
|
||||
}
|
||||
|
||||
static int
|
||||
gen_cap_dynamic_tlv(struct ibuf *buf)
|
||||
{
|
||||
struct capability_tlv cap;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
|
||||
cap.length = htons(CAP_TLV_DYNAMIC_LEN);
|
||||
/* the S-bit is always 1 for the Dynamic Capability Announcement */
|
||||
cap.reserved = STATE_BIT;
|
||||
|
||||
return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
|
||||
}
|
||||
|
||||
static int
|
||||
gen_cap_twcard_tlv(struct ibuf *buf, int enable)
|
||||
{
|
||||
struct capability_tlv cap;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.type = htons(TLV_TYPE_TWCARD_CAP);
|
||||
cap.length = htons(CAP_TLV_TWCARD_LEN);
|
||||
if (enable)
|
||||
cap.reserved = STATE_BIT;
|
||||
|
||||
return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
|
||||
}
|
||||
|
||||
static int
|
||||
gen_cap_unotif_tlv(struct ibuf *buf, int enable)
|
||||
{
|
||||
struct capability_tlv cap;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.type = htons(TLV_TYPE_UNOTIF_CAP);
|
||||
cap.length = htons(CAP_TLV_UNOTIF_LEN);
|
||||
if (enable)
|
||||
cap.reserved = STATE_BIT;
|
||||
|
||||
return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
|
||||
}
|
||||
|
111
ldpd/l2vpn.c
111
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)
|
||||
{
|
||||
@ -330,7 +357,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
|
||||
st.status_code = S_WRONG_CBIT;
|
||||
st.msg_id = map->msg_id;
|
||||
st.msg_type = htons(MSG_TYPE_LABELMAPPING);
|
||||
lde_send_labelwithdraw(ln, fn, NO_LABEL, &st);
|
||||
lde_send_labelwithdraw(ln, fn, NULL, &st);
|
||||
|
||||
pw->flags &= ~F_PW_CWORD;
|
||||
lde_send_labelmapping(ln, fn, 1);
|
||||
@ -353,7 +380,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
|
||||
}
|
||||
|
||||
void
|
||||
l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
|
||||
l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
|
||||
@ -364,8 +391,27 @@ l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
|
||||
lde_fec2map(fec, &nm.fec);
|
||||
nm.flags |= F_NOTIF_FEC;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
|
||||
&nm, sizeof(nm));
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
|
||||
sizeof(nm));
|
||||
}
|
||||
|
||||
void
|
||||
l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
|
||||
uint16_t pw_type, uint32_t group_id)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
|
||||
memset(&nm, 0, sizeof(nm));
|
||||
nm.status_code = S_PW_STATUS;
|
||||
nm.pw_status = status;
|
||||
nm.flags |= F_NOTIF_PW_STATUS;
|
||||
nm.fec.type = MAP_TYPE_PWID;
|
||||
nm.fec.fec.pwid.type = pw_type;
|
||||
nm.fec.fec.pwid.group_id = group_id;
|
||||
nm.flags |= F_NOTIF_FEC;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
|
||||
sizeof(nm));
|
||||
}
|
||||
|
||||
void
|
||||
@ -376,9 +422,11 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
|
||||
struct fec_nh *fnh;
|
||||
struct l2vpn_pw *pw;
|
||||
|
||||
/* TODO group wildcard */
|
||||
if (!(nm->fec.flags & F_MAP_PW_ID))
|
||||
if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
|
||||
!(nm->fec.flags & F_MAP_PW_ID)) {
|
||||
l2vpn_recv_pw_status_wcard(ln, nm);
|
||||
return;
|
||||
}
|
||||
|
||||
lde_map2fec(&nm->fec, ln->id, &fec);
|
||||
fn = (struct fec_node *)fec_find(&ft, &fec);
|
||||
@ -397,7 +445,6 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
|
||||
/* remote status didn't change */
|
||||
if (pw->remote_status == nm->pw_status)
|
||||
return;
|
||||
|
||||
pw->remote_status = nm->pw_status;
|
||||
|
||||
if (l2vpn_pw_ok(pw, fnh))
|
||||
@ -406,6 +453,56 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
|
||||
lde_send_delete_klabel(fn, fnh);
|
||||
}
|
||||
|
||||
/* RFC4447 PWid group wildcard */
|
||||
void
|
||||
l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
|
||||
{
|
||||
struct fec *f;
|
||||
struct fec_node *fn;
|
||||
struct fec_nh *fnh;
|
||||
struct l2vpn_pw *pw;
|
||||
struct map *wcard = &nm->fec;
|
||||
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
if (fn->fec.type != FEC_TYPE_PWID)
|
||||
continue;
|
||||
|
||||
pw = (struct l2vpn_pw *) fn->data;
|
||||
if (pw == NULL)
|
||||
continue;
|
||||
|
||||
switch (wcard->type) {
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
|
||||
wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
|
||||
continue;
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
|
||||
continue;
|
||||
if (wcard->fec.pwid.group_id != pw->remote_group)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
|
||||
0, 0);
|
||||
if (fnh == NULL)
|
||||
continue;
|
||||
|
||||
/* remote status didn't change */
|
||||
if (pw->remote_status == nm->pw_status)
|
||||
continue;
|
||||
pw->remote_status = nm->pw_status;
|
||||
|
||||
if (l2vpn_pw_ok(pw, fnh))
|
||||
lde_send_change_klabel(fn, fnh);
|
||||
else
|
||||
lde_send_delete_klabel(fn, fnh);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
l2vpn_sync_pws(int af, union ldpd_addr *addr)
|
||||
{
|
||||
|
@ -28,9 +28,8 @@
|
||||
|
||||
static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
|
||||
static int gen_label_tlv(struct ibuf *, uint32_t);
|
||||
static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
|
||||
uint16_t, uint32_t *);
|
||||
static int gen_reqid_tlv(struct ibuf *, uint32_t);
|
||||
static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
|
||||
|
||||
static void
|
||||
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
|
||||
@ -71,25 +70,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
|
||||
}
|
||||
|
||||
/* calculate size */
|
||||
msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE;
|
||||
switch (me->map.type) {
|
||||
case MAP_TYPE_WILDCARD:
|
||||
msg_size += FEC_ELM_WCARD_LEN;
|
||||
break;
|
||||
case MAP_TYPE_PREFIX:
|
||||
msg_size += FEC_ELM_PREFIX_MIN_LEN +
|
||||
PREFIX_SIZE(me->map.fec.prefix.prefixlen);
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
msg_size += FEC_PWID_ELM_MIN_LEN;
|
||||
if (me->map.flags & F_MAP_PW_ID)
|
||||
msg_size += PW_STATUS_TLV_LEN;
|
||||
if (me->map.flags & F_MAP_PW_IFMTU)
|
||||
msg_size += FEC_SUBTLV_IFMTU_SIZE;
|
||||
if (me->map.flags & F_MAP_PW_STATUS)
|
||||
msg_size += PW_STATUS_TLV_SIZE;
|
||||
break;
|
||||
}
|
||||
msg_size = LDP_MSG_SIZE;
|
||||
msg_size += len_fec_tlv(&me->map);
|
||||
if (me->map.label != NO_LABEL)
|
||||
msg_size += LABEL_TLV_SIZE;
|
||||
if (me->map.flags & F_MAP_REQ_ID)
|
||||
@ -124,9 +106,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
|
||||
return;
|
||||
}
|
||||
|
||||
debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type),
|
||||
inet_ntoa(nbr->id), log_map(&me->map),
|
||||
log_label(me->map.label));
|
||||
log_msg_mapping(1, type, nbr, &me->map);
|
||||
|
||||
TAILQ_REMOVE(mh, me, entry);
|
||||
free(me);
|
||||
@ -146,7 +126,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
uint32_t label = NO_LABEL, reqid = 0;
|
||||
uint32_t pw_status = 0;
|
||||
uint8_t flags = 0;
|
||||
int feclen, lbllen, tlen;
|
||||
int feclen, tlen;
|
||||
uint16_t current_tlv = 1;
|
||||
struct mapping_entry *me;
|
||||
struct mapping_head mh;
|
||||
struct map map;
|
||||
@ -163,7 +144,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
|
||||
memcpy(&ft, buf, sizeof(ft));
|
||||
if (ntohs(ft.type) != TLV_TYPE_FEC) {
|
||||
send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type);
|
||||
send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
feclen = ntohs(ft.length);
|
||||
@ -187,9 +168,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
!(map.flags & F_MAP_PW_ID) &&
|
||||
type != MSG_TYPE_LABELWITHDRAW &&
|
||||
type != MSG_TYPE_LABELRELEASE) {
|
||||
send_notification_nbr(nbr, S_MISS_MSG, msg.id,
|
||||
send_notification(nbr->tcp, S_MISS_MSG, msg.id,
|
||||
msg.type);
|
||||
return (-1);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -209,6 +190,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 5561 - Section 4:
|
||||
* "An LDP implementation that supports the Typed Wildcard
|
||||
* FEC Element MUST support its use in Label Request, Label
|
||||
* Withdraw, and Label Release messages".
|
||||
*/
|
||||
if (map.type == MAP_TYPE_TYPED_WCARD) {
|
||||
switch (type) {
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
case MSG_TYPE_LABELABORTREQ:
|
||||
session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
|
||||
msg.type);
|
||||
goto err;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LDP supports the use of multiple FEC Elements per
|
||||
* FEC for the Label Mapping message only.
|
||||
@ -226,19 +225,10 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
feclen -= tlen;
|
||||
} while (feclen > 0);
|
||||
|
||||
/* Mandatory Label TLV */
|
||||
if (type == MSG_TYPE_LABELMAPPING) {
|
||||
lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
|
||||
if (lbllen == -1)
|
||||
goto err;
|
||||
|
||||
buf += lbllen;
|
||||
len -= lbllen;
|
||||
}
|
||||
|
||||
/* Optional Parameters */
|
||||
while (len > 0) {
|
||||
struct tlv tlv;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
uint32_t reqbuf, labelbuf, statusbuf;
|
||||
|
||||
@ -248,6 +238,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
}
|
||||
|
||||
memcpy(&tlv, buf, TLV_HDR_SIZE);
|
||||
tlv_type = ntohs(tlv.type);
|
||||
tlv_len = ntohs(tlv.length);
|
||||
if (tlv_len + TLV_HDR_SIZE > len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
@ -256,7 +247,18 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
buf += TLV_HDR_SIZE;
|
||||
len -= TLV_HDR_SIZE;
|
||||
|
||||
switch (ntohs(tlv.type)) {
|
||||
/*
|
||||
* For Label Mapping messages the Label TLV is mandatory and
|
||||
* should appear right after the FEC TLV.
|
||||
*/
|
||||
if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING &&
|
||||
!(tlv_type & TLV_TYPE_GENERICLABEL)) {
|
||||
send_notification(nbr->tcp, S_MISS_MSG, msg.id,
|
||||
msg.type);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (tlv_type) {
|
||||
case TLV_TYPE_LABELREQUEST:
|
||||
switch (type) {
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
@ -282,6 +284,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
break;
|
||||
case TLV_TYPE_GENERICLABEL:
|
||||
switch (type) {
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
case MSG_TYPE_LABELWITHDRAW:
|
||||
case MSG_TYPE_LABELRELEASE:
|
||||
if (tlv_len != LABEL_TLV_LEN) {
|
||||
@ -292,6 +295,16 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
|
||||
memcpy(&labelbuf, buf, sizeof(labelbuf));
|
||||
label = ntohl(labelbuf);
|
||||
/* do not accept invalid labels */
|
||||
if (label > MPLS_LABEL_MAX ||
|
||||
(label <= MPLS_LABEL_RESERVED_MAX &&
|
||||
label != MPLS_LABEL_IPV4NULL &&
|
||||
label != MPLS_LABEL_IPV6NULL &&
|
||||
label != MPLS_LABEL_IMPLNULL)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL,
|
||||
msg.id, msg.type);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
@ -301,6 +314,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
case TLV_TYPE_ATMLABEL:
|
||||
case TLV_TYPE_FRLABEL:
|
||||
switch (type) {
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
case MSG_TYPE_LABELWITHDRAW:
|
||||
case MSG_TYPE_LABELRELEASE:
|
||||
/* unsupported */
|
||||
@ -341,13 +355,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
break;
|
||||
default:
|
||||
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
|
||||
send_notification_nbr(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type);
|
||||
send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type, tlv_type, tlv_len, buf);
|
||||
/* ignore unknown tlv */
|
||||
break;
|
||||
}
|
||||
buf += tlv_len;
|
||||
len -= tlv_len;
|
||||
current_tlv++;
|
||||
}
|
||||
|
||||
/* notify lde about the received message. */
|
||||
@ -396,9 +411,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
if (me->map.flags & F_MAP_REQ_ID)
|
||||
me->map.requestid = reqid;
|
||||
|
||||
debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type),
|
||||
inet_ntoa(nbr->id), log_map(&me->map),
|
||||
log_label(me->map.label));
|
||||
log_msg_mapping(0, type, nbr, &me->map);
|
||||
|
||||
switch (type) {
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
@ -423,14 +436,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
|
||||
ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
|
||||
sizeof(struct map));
|
||||
|
||||
next:
|
||||
next:
|
||||
TAILQ_REMOVE(&mh, me, entry);
|
||||
free(me);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
err:
|
||||
err:
|
||||
mapping_list_clr(&mh);
|
||||
|
||||
return (-1);
|
||||
@ -449,53 +462,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label)
|
||||
return (ibuf_add(buf, <, sizeof(lt)));
|
||||
}
|
||||
|
||||
static int
|
||||
tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
|
||||
uint16_t len, uint32_t *label)
|
||||
{
|
||||
struct label_tlv lt;
|
||||
|
||||
if (len < sizeof(lt)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
|
||||
return (-1);
|
||||
}
|
||||
memcpy(<, buf, sizeof(lt));
|
||||
|
||||
if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
|
||||
send_notification_nbr(nbr, S_MISS_MSG, msg->id, msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (htons(lt.type)) {
|
||||
case TLV_TYPE_GENERICLABEL:
|
||||
if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*label = ntohl(lt.label);
|
||||
if (*label > MPLS_LABEL_MAX ||
|
||||
(*label <= MPLS_LABEL_RESERVED_MAX &&
|
||||
*label != MPLS_LABEL_IPV4NULL &&
|
||||
*label != MPLS_LABEL_IPV6NULL &&
|
||||
*label != MPLS_LABEL_IMPLNULL)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case TLV_TYPE_ATMLABEL:
|
||||
case TLV_TYPE_FRLABEL:
|
||||
default:
|
||||
/* unsupported */
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (sizeof(lt));
|
||||
}
|
||||
|
||||
static int
|
||||
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
|
||||
{
|
||||
@ -520,12 +486,52 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
|
||||
return (ibuf_add(buf, &st, sizeof(st)));
|
||||
}
|
||||
|
||||
uint16_t
|
||||
len_fec_tlv(struct map *map)
|
||||
{
|
||||
uint16_t len = TLV_HDR_SIZE;
|
||||
|
||||
switch (map->type) {
|
||||
case MAP_TYPE_WILDCARD:
|
||||
len += FEC_ELM_WCARD_LEN;
|
||||
break;
|
||||
case MAP_TYPE_PREFIX:
|
||||
len += FEC_ELM_PREFIX_MIN_LEN +
|
||||
PREFIX_SIZE(map->fec.prefix.prefixlen);
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
len += FEC_PWID_ELM_MIN_LEN;
|
||||
if (map->flags & F_MAP_PW_ID)
|
||||
len += PW_STATUS_TLV_LEN;
|
||||
if (map->flags & F_MAP_PW_IFMTU)
|
||||
len += FEC_SUBTLV_IFMTU_SIZE;
|
||||
if (map->flags & F_MAP_PW_STATUS)
|
||||
len += PW_STATUS_TLV_SIZE;
|
||||
break;
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
len += FEC_ELM_TWCARD_MIN_LEN;
|
||||
switch (map->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
case MAP_TYPE_PWID:
|
||||
len += sizeof(uint16_t);
|
||||
break;
|
||||
default:
|
||||
fatalx("len_fec_tlv: unexpected fec type");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatalx("len_fec_tlv: unexpected fec type");
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int
|
||||
gen_fec_tlv(struct ibuf *buf, struct map *map)
|
||||
{
|
||||
struct tlv ft;
|
||||
uint16_t family, len, pw_type, ifmtu;
|
||||
uint8_t pw_len = 0;
|
||||
uint8_t pw_len = 0, twcard_len;
|
||||
uint32_t group_id, pwid;
|
||||
int err = 0;
|
||||
|
||||
@ -562,7 +568,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
if (map->flags & F_MAP_PW_ID)
|
||||
pw_len += PW_STATUS_TLV_LEN;
|
||||
pw_len += FEC_PWID_SIZE;
|
||||
if (map->flags & F_MAP_PW_IFMTU)
|
||||
pw_len += FEC_SUBTLV_IFMTU_SIZE;
|
||||
|
||||
@ -595,6 +601,50 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
|
||||
err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
|
||||
}
|
||||
break;
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
len = FEC_ELM_TWCARD_MIN_LEN;
|
||||
switch (map->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
case MAP_TYPE_PWID:
|
||||
len += sizeof(uint16_t);
|
||||
break;
|
||||
default:
|
||||
fatalx("gen_fec_tlv: unexpected fec type");
|
||||
}
|
||||
ft.length = htons(len);
|
||||
err |= ibuf_add(buf, &ft, sizeof(ft));
|
||||
err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
|
||||
err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
|
||||
|
||||
switch (map->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
twcard_len = sizeof(uint16_t);
|
||||
err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
|
||||
|
||||
switch (map->fec.twcard.u.prefix_af) {
|
||||
case AF_INET:
|
||||
family = htons(AF_IPV4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
family = htons(AF_IPV6);
|
||||
break;
|
||||
default:
|
||||
fatalx("gen_fec_tlv: unknown af");
|
||||
break;
|
||||
}
|
||||
|
||||
err |= ibuf_add(buf, &family, sizeof(uint16_t));
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
twcard_len = sizeof(uint16_t);
|
||||
err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
|
||||
pw_type = htons(map->fec.twcard.u.pw_type);
|
||||
err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
|
||||
break;
|
||||
default:
|
||||
fatalx("gen_fec_tlv: unexpected fec type");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -607,7 +657,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
|
||||
uint16_t len, struct map *map)
|
||||
{
|
||||
uint16_t off = 0;
|
||||
uint8_t pw_len;
|
||||
uint8_t pw_len, twcard_len;
|
||||
|
||||
map->type = *buf;
|
||||
off += sizeof(uint8_t);
|
||||
@ -642,7 +692,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
|
||||
map->fec.prefix.af = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id,
|
||||
send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
@ -751,11 +801,84 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
|
||||
pw_len -= stlv.length;
|
||||
}
|
||||
|
||||
return (off);
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
if (len < FEC_ELM_TWCARD_MIN_LEN) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
|
||||
off += sizeof(uint8_t);
|
||||
memcpy(&twcard_len, buf + off, sizeof(uint8_t));
|
||||
off += sizeof(uint8_t);
|
||||
if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (map->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
if (twcard_len != sizeof(uint16_t)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&map->fec.twcard.u.prefix_af, buf + off,
|
||||
sizeof(uint16_t));
|
||||
map->fec.twcard.u.prefix_af =
|
||||
ntohs(map->fec.twcard.u.prefix_af);
|
||||
off += sizeof(uint16_t);
|
||||
|
||||
switch (map->fec.twcard.u.prefix_af) {
|
||||
case AF_IPV4:
|
||||
map->fec.twcard.u.prefix_af = AF_INET;
|
||||
break;
|
||||
case AF_IPV6:
|
||||
map->fec.twcard.u.prefix_af = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
if (twcard_len != sizeof(uint16_t)) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(&map->fec.twcard.u.pw_type, buf + off,
|
||||
sizeof(uint16_t));
|
||||
map->fec.twcard.u.pw_type =
|
||||
ntohs(map->fec.twcard.u.pw_type);
|
||||
/* ignore the reserved bit as per RFC 6667 */
|
||||
map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
|
||||
off += sizeof(uint16_t);
|
||||
break;
|
||||
default:
|
||||
send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
|
||||
msg->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (off);
|
||||
default:
|
||||
send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type);
|
||||
send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
|
||||
{
|
||||
debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
|
||||
inet_ntoa(nbr->id), log_map(map), log_label(map->label));
|
||||
}
|
||||
|
207
ldpd/lde.c
207
ldpd/lde.c
@ -37,7 +37,7 @@
|
||||
static void lde_shutdown(void);
|
||||
static int lde_dispatch_imsg(struct thread *);
|
||||
static int lde_dispatch_parent(struct thread *);
|
||||
static __inline int lde_nbr_compare(struct lde_nbr *,
|
||||
static __inline int lde_nbr_compare(struct lde_nbr *,
|
||||
struct lde_nbr *);
|
||||
static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
|
||||
static void lde_nbr_del(struct lde_nbr *);
|
||||
@ -205,9 +205,9 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
struct imsgbuf *ibuf = &iev->ibuf;
|
||||
struct imsg imsg;
|
||||
struct lde_nbr *ln;
|
||||
struct map map;
|
||||
struct lde_addr lde_addr;
|
||||
struct notify_msg nm;
|
||||
struct map *map;
|
||||
struct lde_addr *lde_addr;
|
||||
struct notify_msg *nm;
|
||||
ssize_t n;
|
||||
int shut = 0;
|
||||
|
||||
@ -240,9 +240,10 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
case IMSG_LABEL_RELEASE:
|
||||
case IMSG_LABEL_WITHDRAW:
|
||||
case IMSG_LABEL_ABORT:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct map))
|
||||
fatalx("lde_dispatch_imsg: wrong imsg len");
|
||||
memcpy(&map, imsg.data, sizeof(map));
|
||||
map = imsg.data;
|
||||
|
||||
ln = lde_nbr_find(imsg.hdr.peerid);
|
||||
if (ln == NULL) {
|
||||
@ -253,22 +254,16 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
case IMSG_LABEL_MAPPING:
|
||||
lde_check_mapping(&map, ln);
|
||||
lde_check_mapping(map, ln);
|
||||
break;
|
||||
case IMSG_LABEL_REQUEST:
|
||||
lde_check_request(&map, ln);
|
||||
lde_check_request(map, ln);
|
||||
break;
|
||||
case IMSG_LABEL_RELEASE:
|
||||
if (map.type == MAP_TYPE_WILDCARD)
|
||||
lde_check_release_wcard(&map, ln);
|
||||
else
|
||||
lde_check_release(&map, ln);
|
||||
lde_check_release(map, ln);
|
||||
break;
|
||||
case IMSG_LABEL_WITHDRAW:
|
||||
if (map.type == MAP_TYPE_WILDCARD)
|
||||
lde_check_withdraw_wcard(&map, ln);
|
||||
else
|
||||
lde_check_withdraw(&map, ln);
|
||||
lde_check_withdraw(map, ln);
|
||||
break;
|
||||
case IMSG_LABEL_ABORT:
|
||||
/* not necessary */
|
||||
@ -276,9 +271,10 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
}
|
||||
break;
|
||||
case IMSG_ADDRESS_ADD:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct lde_addr))
|
||||
fatalx("lde_dispatch_imsg: wrong imsg len");
|
||||
memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
|
||||
lde_addr = imsg.data;
|
||||
|
||||
ln = lde_nbr_find(imsg.hdr.peerid);
|
||||
if (ln == NULL) {
|
||||
@ -286,16 +282,17 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
if (lde_address_add(ln, &lde_addr) < 0) {
|
||||
if (lde_address_add(ln, lde_addr) < 0) {
|
||||
log_debug("%s: cannot add address %s, it "
|
||||
"already exists", __func__,
|
||||
log_addr(lde_addr.af, &lde_addr.addr));
|
||||
log_addr(lde_addr->af, &lde_addr->addr));
|
||||
}
|
||||
break;
|
||||
case IMSG_ADDRESS_DEL:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct lde_addr))
|
||||
fatalx("lde_dispatch_imsg: wrong imsg len");
|
||||
memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
|
||||
lde_addr = imsg.data;
|
||||
|
||||
ln = lde_nbr_find(imsg.hdr.peerid);
|
||||
if (ln == NULL) {
|
||||
@ -303,16 +300,17 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
if (lde_address_del(ln, &lde_addr) < 0) {
|
||||
if (lde_address_del(ln, lde_addr) < 0) {
|
||||
log_debug("%s: cannot delete address %s, it "
|
||||
"does not exist", __func__,
|
||||
log_addr(lde_addr.af, &lde_addr.addr));
|
||||
log_addr(lde_addr->af, &lde_addr->addr));
|
||||
}
|
||||
break;
|
||||
case IMSG_NOTIFICATION:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct notify_msg))
|
||||
fatalx("lde_dispatch_imsg: wrong imsg len");
|
||||
memcpy(&nm, imsg.data, sizeof(nm));
|
||||
nm = imsg.data;
|
||||
|
||||
ln = lde_nbr_find(imsg.hdr.peerid);
|
||||
if (ln == NULL) {
|
||||
@ -321,10 +319,17 @@ lde_dispatch_imsg(struct thread *thread)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (nm.status_code) {
|
||||
switch (nm->status_code) {
|
||||
case S_PW_STATUS:
|
||||
l2vpn_recv_pw_status(ln, &nm);
|
||||
l2vpn_recv_pw_status(ln, nm);
|
||||
break;
|
||||
case S_ENDOFLIB:
|
||||
/*
|
||||
* Do nothing for now. Should be useful in
|
||||
* the future when we implement LDP-IGP
|
||||
* Synchronization (RFC 5443) and Graceful
|
||||
* Restart (RFC 3478).
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -391,7 +396,7 @@ lde_dispatch_parent(struct thread *thread)
|
||||
struct l2vpn_if *nlif;
|
||||
struct l2vpn_pw *npw;
|
||||
struct imsg imsg;
|
||||
struct kroute kr;
|
||||
struct kroute *kr;
|
||||
int fd = THREAD_FD(thread);
|
||||
struct imsgev *iev = THREAD_ARG(thread);
|
||||
struct imsgbuf *ibuf = &iev->ibuf;
|
||||
@ -415,22 +420,23 @@ lde_dispatch_parent(struct thread *thread)
|
||||
switch (imsg.hdr.type) {
|
||||
case IMSG_NETWORK_ADD:
|
||||
case IMSG_NETWORK_UPDATE:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct kroute)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
memcpy(&kr, imsg.data, sizeof(kr));
|
||||
kr = imsg.data;
|
||||
|
||||
switch (kr.af) {
|
||||
switch (kr->af) {
|
||||
case AF_INET:
|
||||
fec.type = FEC_TYPE_IPV4;
|
||||
fec.u.ipv4.prefix = kr.prefix.v4;
|
||||
fec.u.ipv4.prefixlen = kr.prefixlen;
|
||||
fec.u.ipv4.prefix = kr->prefix.v4;
|
||||
fec.u.ipv4.prefixlen = kr->prefixlen;
|
||||
break;
|
||||
case AF_INET6:
|
||||
fec.type = FEC_TYPE_IPV6;
|
||||
fec.u.ipv6.prefix = kr.prefix.v6;
|
||||
fec.u.ipv6.prefixlen = kr.prefixlen;
|
||||
fec.u.ipv6.prefix = kr->prefix.v6;
|
||||
fec.u.ipv6.prefixlen = kr->prefixlen;
|
||||
break;
|
||||
default:
|
||||
fatalx("lde_dispatch_parent: unknown af");
|
||||
@ -438,9 +444,9 @@ lde_dispatch_parent(struct thread *thread)
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
case IMSG_NETWORK_ADD:
|
||||
lde_kernel_insert(&fec, kr.af, &kr.nexthop,
|
||||
kr.ifindex, kr.priority,
|
||||
kr.flags & F_CONNECTED, NULL);
|
||||
lde_kernel_insert(&fec, kr->af, &kr->nexthop,
|
||||
kr->ifindex, kr->priority,
|
||||
kr->flags & F_CONNECTED, NULL);
|
||||
break;
|
||||
case IMSG_NETWORK_UPDATE:
|
||||
lde_kernel_update(&fec);
|
||||
@ -929,8 +935,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
|
||||
struct status_tlv *st)
|
||||
lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
|
||||
struct map *wcard, struct status_tlv *st)
|
||||
{
|
||||
struct lde_wdraw *lw;
|
||||
struct map map;
|
||||
@ -959,11 +965,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
|
||||
break;
|
||||
}
|
||||
map.label = fn->local_label;
|
||||
} else {
|
||||
memset(&map, 0, sizeof(map));
|
||||
map.type = MAP_TYPE_WILDCARD;
|
||||
map.label = label;
|
||||
}
|
||||
} else
|
||||
memcpy(&map, wcard, sizeof(map));
|
||||
|
||||
if (st) {
|
||||
map.st.status_code = st->status_code;
|
||||
@ -984,8 +987,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
|
||||
lw = lde_wdraw_add(ln, fn);
|
||||
lw->label = map.label;
|
||||
} else {
|
||||
struct lde_map *me;
|
||||
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
|
||||
if (lde_wildcard_apply(wcard, &fn->fec, me) == 0)
|
||||
continue;
|
||||
|
||||
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
|
||||
&fn->fec);
|
||||
@ -997,16 +1005,62 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label)
|
||||
lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label)
|
||||
{
|
||||
struct lde_nbr *ln;
|
||||
struct map wcard;
|
||||
|
||||
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
|
||||
lde_send_labelwithdraw(ln, fn, label, NULL);
|
||||
memset(&wcard, 0, sizeof(wcard));
|
||||
wcard.type = MAP_TYPE_WILDCARD;
|
||||
wcard.label = label;
|
||||
lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
|
||||
lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af,
|
||||
uint32_t label)
|
||||
{
|
||||
struct map wcard;
|
||||
|
||||
memset(&wcard, 0, sizeof(wcard));
|
||||
wcard.type = MAP_TYPE_TYPED_WCARD;
|
||||
wcard.fec.twcard.type = MAP_TYPE_PREFIX;
|
||||
wcard.fec.twcard.u.prefix_af = af;
|
||||
wcard.label = label;
|
||||
lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *ln, uint16_t pw_type,
|
||||
uint32_t label)
|
||||
{
|
||||
struct map wcard;
|
||||
|
||||
memset(&wcard, 0, sizeof(wcard));
|
||||
wcard.type = MAP_TYPE_TYPED_WCARD;
|
||||
wcard.fec.twcard.type = MAP_TYPE_PWID;
|
||||
wcard.fec.twcard.u.pw_type = pw_type;
|
||||
wcard.label = label;
|
||||
lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type,
|
||||
uint32_t group_id)
|
||||
{
|
||||
struct map wcard;
|
||||
|
||||
memset(&wcard, 0, sizeof(wcard));
|
||||
wcard.type = MAP_TYPE_PWID;
|
||||
wcard.fec.pwid.type = pw_type;
|
||||
wcard.fec.pwid.group_id = group_id;
|
||||
/* we can not append a Label TLV when using PWid group wildcards. */
|
||||
wcard.label = NO_LABEL;
|
||||
lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn,
|
||||
struct map *wcard, uint32_t label)
|
||||
{
|
||||
struct map map;
|
||||
struct l2vpn_pw *pw;
|
||||
@ -1032,10 +1086,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
|
||||
map.flags |= F_MAP_PW_CWORD;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
memset(&map, 0, sizeof(map));
|
||||
map.type = MAP_TYPE_WILDCARD;
|
||||
}
|
||||
} else
|
||||
memcpy(&map, wcard, sizeof(map));
|
||||
map.label = label;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
|
||||
@ -1044,7 +1096,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
|
||||
lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id,
|
||||
uint16_t msg_type)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
@ -1055,7 +1107,39 @@ lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
|
||||
nm.msg_id = msg_id;
|
||||
nm.msg_type = msg_type;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
|
||||
&nm, sizeof(nm));
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_notification_eol_prefix(struct lde_nbr *ln, int af)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
|
||||
memset(&nm, 0, sizeof(nm));
|
||||
nm.status_code = S_ENDOFLIB;
|
||||
nm.fec.type = MAP_TYPE_TYPED_WCARD;
|
||||
nm.fec.fec.twcard.type = MAP_TYPE_PREFIX;
|
||||
nm.fec.fec.twcard.u.prefix_af = af;
|
||||
nm.flags |= F_NOTIF_FEC;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
|
||||
&nm, sizeof(nm));
|
||||
}
|
||||
|
||||
void
|
||||
lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
|
||||
memset(&nm, 0, sizeof(nm));
|
||||
nm.status_code = S_ENDOFLIB;
|
||||
nm.fec.type = MAP_TYPE_TYPED_WCARD;
|
||||
nm.fec.fec.twcard.type = MAP_TYPE_PWID;
|
||||
nm.fec.fec.twcard.u.pw_type = pw_type;
|
||||
nm.flags |= F_NOTIF_FEC;
|
||||
|
||||
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
|
||||
&nm, sizeof(nm));
|
||||
}
|
||||
|
||||
@ -1076,6 +1160,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
|
||||
ln->id = new->id;
|
||||
ln->v4_enabled = new->v4_enabled;
|
||||
ln->v6_enabled = new->v6_enabled;
|
||||
ln->flags = new->flags;
|
||||
ln->peerid = peerid;
|
||||
fec_init(&ln->recv_map);
|
||||
fec_init(&ln->sent_map);
|
||||
@ -1352,13 +1437,11 @@ lde_change_egress_label(int af)
|
||||
|
||||
/* explicitly withdraw all null labels */
|
||||
RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
|
||||
lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL);
|
||||
lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
|
||||
if (ln->v4_enabled)
|
||||
lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL,
|
||||
NULL);
|
||||
lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL);
|
||||
if (ln->v6_enabled)
|
||||
lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL,
|
||||
NULL);
|
||||
lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL);
|
||||
}
|
||||
|
||||
/* update label of connected routes */
|
||||
|
28
ldpd/lde.h
28
ldpd/lde.h
@ -90,6 +90,7 @@ struct lde_nbr {
|
||||
struct in_addr id;
|
||||
int v4_enabled; /* announce/process v4 msgs */
|
||||
int v6_enabled; /* announce/process v6 msgs */
|
||||
int flags; /* capabilities */
|
||||
struct fec_tree recv_req;
|
||||
struct fec_tree sent_req;
|
||||
struct fec_tree recv_map;
|
||||
@ -143,11 +144,20 @@ void lde_map2fec(struct map *, struct in_addr, struct fec *);
|
||||
void lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
|
||||
int);
|
||||
void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *,
|
||||
uint32_t, struct status_tlv *);
|
||||
void lde_send_labelwithdraw_all(struct fec_node *, uint32_t);
|
||||
void lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
|
||||
struct map *, struct status_tlv *);
|
||||
void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t);
|
||||
void lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *,
|
||||
uint16_t, uint32_t);
|
||||
void lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *, uint16_t,
|
||||
uint32_t);
|
||||
void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t);
|
||||
void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t,
|
||||
uint32_t);
|
||||
void lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
|
||||
struct map *, uint32_t);
|
||||
void lde_send_notification(struct lde_nbr *, uint32_t, uint32_t,
|
||||
uint16_t);
|
||||
void lde_send_notification_eol_prefix(struct lde_nbr *, int);
|
||||
void lde_send_notification_eol_pwid(struct lde_nbr *, uint16_t);
|
||||
struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr);
|
||||
struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
|
||||
struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
|
||||
@ -178,10 +188,13 @@ void lde_kernel_remove(struct fec *, int, union ldpd_addr *,
|
||||
void lde_kernel_update(struct fec *);
|
||||
void lde_check_mapping(struct map *, struct lde_nbr *);
|
||||
void lde_check_request(struct map *, struct lde_nbr *);
|
||||
void lde_check_request_wcard(struct map *, struct lde_nbr *);
|
||||
void lde_check_release(struct map *, struct lde_nbr *);
|
||||
void lde_check_release_wcard(struct map *, struct lde_nbr *);
|
||||
void lde_check_withdraw(struct map *, struct lde_nbr *);
|
||||
void lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
|
||||
int lde_wildcard_apply(struct map *, struct fec *,
|
||||
struct lde_map *);
|
||||
int lde_gc_timer(struct thread *);
|
||||
void lde_gc_start_timer(void);
|
||||
void lde_gc_stop_timer(void);
|
||||
@ -195,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 *);
|
||||
@ -204,8 +218,12 @@ void l2vpn_pw_reset(struct l2vpn_pw *);
|
||||
int l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *);
|
||||
int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
|
||||
struct map *);
|
||||
void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *);
|
||||
void l2vpn_send_pw_status(struct lde_nbr *, uint32_t, struct fec *);
|
||||
void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
|
||||
uint16_t, 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 *);
|
||||
void l2vpn_sync_pws(int, union ldpd_addr *);
|
||||
void l2vpn_pw_ctl(pid_t);
|
||||
void l2vpn_binding_ctl(pid_t);
|
||||
|
138
ldpd/lde_lib.c
138
ldpd/lde_lib.c
@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec)
|
||||
}
|
||||
|
||||
if (LIST_EMPTY(&fn->nexthops)) {
|
||||
lde_send_labelwithdraw_all(fn, NO_LABEL);
|
||||
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
|
||||
lde_send_labelwithdraw(ln, fn, NULL, NULL);
|
||||
fn->local_label = NO_LABEL;
|
||||
fn->data = NULL;
|
||||
} else {
|
||||
@ -478,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
|
||||
/* LMp.10 */
|
||||
if (me->map.label != map->label && lre == NULL) {
|
||||
/* LMp.10a */
|
||||
lde_send_labelrelease(ln, fn, me->map.label);
|
||||
lde_send_labelrelease(ln, fn, NULL, me->map.label);
|
||||
|
||||
/*
|
||||
* Can not use lde_nbr_find_by_addr() because there's
|
||||
@ -554,6 +555,12 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
|
||||
struct fec_node *fn;
|
||||
struct fec_nh *fnh;
|
||||
|
||||
/* wildcard label request */
|
||||
if (map->type == MAP_TYPE_TYPED_WCARD) {
|
||||
lde_check_request_wcard(map, ln);
|
||||
return;
|
||||
}
|
||||
|
||||
/* LRq.1: skip loop detection (not necessary) */
|
||||
|
||||
/* LRq.2: is there a next hop for fec? */
|
||||
@ -561,7 +568,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
|
||||
fn = (struct fec_node *)fec_find(&ft, &fec);
|
||||
if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
|
||||
/* LRq.5: send No Route notification */
|
||||
lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id,
|
||||
lde_send_notification(ln, S_NO_ROUTE, map->msg_id,
|
||||
htons(MSG_TYPE_LABELREQUEST));
|
||||
return;
|
||||
}
|
||||
@ -575,8 +582,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
|
||||
continue;
|
||||
|
||||
/* LRq.4: send Loop Detected notification */
|
||||
lde_send_notification(ln->peerid, S_LOOP_DETECTED,
|
||||
map->msg_id, htons(MSG_TYPE_LABELREQUEST));
|
||||
lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id,
|
||||
htons(MSG_TYPE_LABELREQUEST));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@ -604,6 +611,40 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
lde_check_request_wcard(struct map *map, struct lde_nbr *ln)
|
||||
{
|
||||
struct fec *f;
|
||||
struct fec_node *fn;
|
||||
struct lde_req *lre;
|
||||
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
|
||||
/* only a typed wildcard is possible here */
|
||||
if (lde_wildcard_apply(map, &fn->fec, NULL) == 0)
|
||||
continue;
|
||||
|
||||
/* LRq.2: is there a next hop for fec? */
|
||||
if (LIST_EMPTY(&fn->nexthops))
|
||||
continue;
|
||||
|
||||
/* LRq.6: first check if we have a pending request running */
|
||||
lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
|
||||
if (lre != NULL)
|
||||
/* LRq.7: duplicate request */
|
||||
continue;
|
||||
|
||||
/* LRq.8: record label request */
|
||||
lre = lde_req_add(ln, &fn->fec, 0);
|
||||
if (lre != NULL)
|
||||
lre->msg_id = ntohl(map->msg_id);
|
||||
|
||||
/* LRq.9: perform LSR label distribution */
|
||||
lde_send_labelmapping(ln, fn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lde_check_release(struct map *map, struct lde_nbr *ln)
|
||||
{
|
||||
@ -612,9 +653,13 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
|
||||
struct lde_wdraw *lw;
|
||||
struct lde_map *me;
|
||||
|
||||
/* TODO group wildcard */
|
||||
if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
|
||||
/* wildcard label release */
|
||||
if (map->type == MAP_TYPE_WILDCARD ||
|
||||
map->type == MAP_TYPE_TYPED_WCARD ||
|
||||
(map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
|
||||
lde_check_release_wcard(map, ln);
|
||||
return;
|
||||
}
|
||||
|
||||
lde_map2fec(map, ln->id, &fec);
|
||||
fn = (struct fec_node *)fec_find(&ft, &fec);
|
||||
@ -624,8 +669,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
|
||||
|
||||
/* LRl.3: first check if we have a pending withdraw running */
|
||||
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
|
||||
if (lw && (map->label == NO_LABEL ||
|
||||
(lw->label != NO_LABEL && map->label == lw->label))) {
|
||||
if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
|
||||
/* LRl.4: delete record of outstanding label withdraw */
|
||||
lde_wdraw_del(ln, lw);
|
||||
}
|
||||
@ -651,17 +695,20 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
|
||||
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
|
||||
|
||||
/* LRl.1: does FEC match a known FEC? */
|
||||
if (lde_wildcard_apply(map, &fn->fec, me) == 0)
|
||||
continue;
|
||||
|
||||
/* LRl.3: first check if we have a pending withdraw running */
|
||||
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
|
||||
if (lw && (map->label == NO_LABEL ||
|
||||
(lw->label != NO_LABEL && map->label == lw->label))) {
|
||||
if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
|
||||
/* LRl.4: delete record of outstanding lbl withdraw */
|
||||
lde_wdraw_del(ln, lw);
|
||||
}
|
||||
|
||||
/* LRl.6: check sent map list and remove it if available */
|
||||
me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
|
||||
if (me &&
|
||||
(map->label == NO_LABEL || map->label == me->map.label))
|
||||
lde_map_del(ln, me, 1);
|
||||
@ -682,9 +729,13 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
|
||||
struct lde_map *me;
|
||||
struct l2vpn_pw *pw;
|
||||
|
||||
/* TODO group wildcard */
|
||||
if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
|
||||
/* wildcard label withdraw */
|
||||
if (map->type == MAP_TYPE_WILDCARD ||
|
||||
map->type == MAP_TYPE_TYPED_WCARD ||
|
||||
(map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
|
||||
lde_check_withdraw_wcard(map, ln);
|
||||
return;
|
||||
}
|
||||
|
||||
lde_map2fec(map, ln->id, &fec);
|
||||
fn = (struct fec_node *)fec_find(&ft, &fec);
|
||||
@ -707,12 +758,15 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (map->label != NO_LABEL && map->label != fnh->remote_label)
|
||||
continue;
|
||||
|
||||
lde_send_delete_klabel(fn, fnh);
|
||||
fnh->remote_label = NO_LABEL;
|
||||
}
|
||||
|
||||
/* LWd.2: send label release */
|
||||
lde_send_labelrelease(ln, fn, map->label);
|
||||
lde_send_labelrelease(ln, fn, NULL, map->label);
|
||||
|
||||
/* LWd.3: check previously received label mapping */
|
||||
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
|
||||
@ -730,10 +784,14 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
||||
struct lde_map *me;
|
||||
|
||||
/* LWd.2: send label release */
|
||||
lde_send_labelrelease(ln, NULL, map->label);
|
||||
lde_send_labelrelease(ln, NULL, map, map->label);
|
||||
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
|
||||
|
||||
if (lde_wildcard_apply(map, &fn->fec, me) == 0)
|
||||
continue;
|
||||
|
||||
/* LWd.1: remove label from forwarding/switching use */
|
||||
LIST_FOREACH(fnh, &fn->nexthops, entry) {
|
||||
@ -751,12 +809,15 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (map->label != NO_LABEL && map->label !=
|
||||
fnh->remote_label)
|
||||
continue;
|
||||
|
||||
lde_send_delete_klabel(fn, fnh);
|
||||
fnh->remote_label = NO_LABEL;
|
||||
}
|
||||
|
||||
/* LWd.3: check previously received label mapping */
|
||||
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
|
||||
if (me && (map->label == NO_LABEL ||
|
||||
map->label == me->map.label))
|
||||
/*
|
||||
@ -767,6 +828,49 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me)
|
||||
{
|
||||
switch (wcard->type) {
|
||||
case MAP_TYPE_WILDCARD:
|
||||
/* full wildcard */
|
||||
return (1);
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
switch (wcard->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
if (wcard->fec.twcard.u.prefix_af == AF_INET &&
|
||||
fec->type != FEC_TYPE_IPV4)
|
||||
return (0);
|
||||
if (wcard->fec.twcard.u.prefix_af == AF_INET6 &&
|
||||
fec->type != FEC_TYPE_IPV6)
|
||||
return (0);
|
||||
return (1);
|
||||
case MAP_TYPE_PWID:
|
||||
if (fec->type != FEC_TYPE_PWID)
|
||||
return (0);
|
||||
if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
|
||||
wcard->fec.twcard.u.pw_type != fec->u.pwid.type)
|
||||
return (0);
|
||||
return (1);
|
||||
default:
|
||||
fatalx("lde_wildcard_apply: unexpected fec type");
|
||||
}
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
/* RFC4447 pw-id group wildcard */
|
||||
if (fec->type != FEC_TYPE_PWID)
|
||||
return (0);
|
||||
if (fec->u.pwid.type != wcard->fec.pwid.type)
|
||||
return (0);
|
||||
if (me == NULL || (me->map.fec.pwid.group_id !=
|
||||
wcard->fec.pwid.group_id))
|
||||
return (0);
|
||||
return (1);
|
||||
default:
|
||||
fatalx("lde_wildcard_apply: unexpected fec type");
|
||||
}
|
||||
}
|
||||
|
||||
/* gabage collector timer: timer to remove dead entries from the LIB */
|
||||
|
||||
/* ARGSUSED */
|
||||
|
41
ldpd/ldp.h
41
ldpd/ldp.h
@ -63,6 +63,7 @@
|
||||
#define MSG_TYPE_HELLO 0x0100
|
||||
#define MSG_TYPE_INIT 0x0200
|
||||
#define MSG_TYPE_KEEPALIVE 0x0201
|
||||
#define MSG_TYPE_CAPABILITY 0x0202 /* RFC 5561 */
|
||||
#define MSG_TYPE_ADDR 0x0300
|
||||
#define MSG_TYPE_ADDRWITHDRAW 0x0301
|
||||
#define MSG_TYPE_LABELMAPPING 0x0400
|
||||
@ -92,9 +93,17 @@
|
||||
#define TLV_TYPE_FRSESSION 0x0502
|
||||
#define TLV_TYPE_LABELREQUEST 0x0600
|
||||
/* RFC 4447 */
|
||||
#define TLV_TYPE_PW_STATUS 0x096A
|
||||
#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
|
||||
/* RFC 5561 */
|
||||
#define TLV_TYPE_RETURNED_TLVS 0x8304
|
||||
#define TLV_TYPE_DYNAMIC_CAP 0x8506
|
||||
/* RFC 5918 */
|
||||
#define TLV_TYPE_TWCARD_CAP 0x850B
|
||||
/* RFC 5919 */
|
||||
#define TLV_TYPE_UNOTIF_CAP 0x8603
|
||||
/* RFC 7552 */
|
||||
#define TLV_TYPE_DUALSTACK 0x8701
|
||||
|
||||
@ -196,6 +205,10 @@ struct hello_prms_opt16_tlv {
|
||||
#define S_UNASSIGN_TAI 0x00000029
|
||||
#define S_MISCONF_ERR 0x0000002A
|
||||
#define S_WITHDRAW_MTHD 0x0000002B
|
||||
/* RFC 5561 */
|
||||
#define S_UNSSUPORTDCAP 0x0000002E
|
||||
/* RFC 5919 */
|
||||
#define S_ENDOFLIB 0x0000002F
|
||||
/* RFC 7552 */
|
||||
#define S_TRANS_MISMTCH 0x80000032
|
||||
#define S_DS_NONCMPLNCE 0x80000033
|
||||
@ -227,6 +240,26 @@ struct status_tlv {
|
||||
#define STATUS_TLV_LEN 10
|
||||
#define STATUS_FATAL 0x80000000
|
||||
|
||||
struct capability_tlv {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
uint8_t reserved;
|
||||
};
|
||||
#define STATE_BIT 0x80
|
||||
|
||||
#define F_CAP_TLV_RCVD_DYNAMIC 0x01
|
||||
#define F_CAP_TLV_RCVD_TWCARD 0x02
|
||||
#define F_CAP_TLV_RCVD_UNOTIF 0x04
|
||||
|
||||
#define CAP_TLV_DYNAMIC_SIZE 5
|
||||
#define CAP_TLV_DYNAMIC_LEN 1
|
||||
|
||||
#define CAP_TLV_TWCARD_SIZE 5
|
||||
#define CAP_TLV_TWCARD_LEN 1
|
||||
|
||||
#define CAP_TLV_UNOTIF_SIZE 5
|
||||
#define CAP_TLV_UNOTIF_LEN 1
|
||||
|
||||
#define AF_IPV4 0x1
|
||||
#define AF_IPV6 0x2
|
||||
|
||||
@ -242,17 +275,23 @@ struct address_list_tlv {
|
||||
#define FEC_ELM_WCARD_LEN 1
|
||||
#define FEC_ELM_PREFIX_MIN_LEN 4
|
||||
#define FEC_PWID_ELM_MIN_LEN 8
|
||||
#define FEC_PWID_SIZE 4
|
||||
#define FEC_ELM_TWCARD_MIN_LEN 3
|
||||
|
||||
#define MAP_TYPE_WILDCARD 0x01
|
||||
#define MAP_TYPE_PREFIX 0x02
|
||||
#define MAP_TYPE_TYPED_WCARD 0x05
|
||||
#define MAP_TYPE_PWID 0x80
|
||||
#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
|
||||
|
||||
/* RFC 4447 Sub-TLV record */
|
||||
struct subtlv {
|
||||
uint8_t type;
|
||||
|
@ -104,6 +104,14 @@ do { \
|
||||
log_debug("msg[out]: " emsg, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define debug_msg(out, emsg, ...) \
|
||||
do { \
|
||||
if (out) \
|
||||
debug_msg_send(emsg, __VA_ARGS__); \
|
||||
else \
|
||||
debug_msg_recv(emsg, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define debug_kalive_recv(emsg, ...) \
|
||||
do { \
|
||||
if (LDP_DEBUG(msg, MSG_RECV_ALL)) \
|
||||
|
@ -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
|
||||
|
16
ldpd/ldpd.h
16
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"
|
||||
@ -220,6 +221,13 @@ struct map {
|
||||
uint32_t group_id;
|
||||
uint16_t ifmtu;
|
||||
} pwid;
|
||||
struct {
|
||||
uint8_t type;
|
||||
union {
|
||||
uint16_t prefix_af;
|
||||
uint16_t pw_type;
|
||||
} u;
|
||||
} twcard;
|
||||
} fec;
|
||||
struct {
|
||||
uint32_t status_code;
|
||||
@ -244,10 +252,16 @@ struct notify_msg {
|
||||
uint16_t msg_type; /* network byte order */
|
||||
uint32_t pw_status;
|
||||
struct map fec;
|
||||
struct {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
char *data;
|
||||
} rtlvs;
|
||||
uint8_t flags;
|
||||
};
|
||||
#define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */
|
||||
#define F_NOTIF_FEC 0x02 /* fec tlv present */
|
||||
#define F_NOTIF_RETURNED_TLVS 0x04 /* returned tlvs present */
|
||||
|
||||
struct if_addr {
|
||||
LIST_ENTRY(if_addr) entry;
|
||||
@ -337,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);
|
||||
@ -506,6 +521,7 @@ struct kif {
|
||||
char ifname[IF_NAMESIZE];
|
||||
unsigned short ifindex;
|
||||
int flags;
|
||||
uint8_t mac[ETHER_ADDR_LEN];
|
||||
int mtu;
|
||||
};
|
||||
|
||||
|
50
ldpd/ldpe.c
50
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 +
|
||||
@ -529,10 +540,10 @@ ldpe_dispatch_lde(struct thread *thread)
|
||||
struct imsgev *iev = THREAD_ARG(thread);
|
||||
struct imsgbuf *ibuf = &iev->ibuf;
|
||||
struct imsg imsg;
|
||||
struct map map;
|
||||
struct notify_msg nm;
|
||||
struct map *map;
|
||||
struct notify_msg *nm;
|
||||
struct nbr *nbr;
|
||||
int n, shut = 0;
|
||||
struct nbr *nbr = NULL;
|
||||
|
||||
iev->ev_read = NULL;
|
||||
|
||||
@ -552,9 +563,10 @@ ldpe_dispatch_lde(struct thread *thread)
|
||||
case IMSG_RELEASE_ADD:
|
||||
case IMSG_REQUEST_ADD:
|
||||
case IMSG_WITHDRAW_ADD:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct map))
|
||||
fatalx("invalid size of map request");
|
||||
memcpy(&map, imsg.data, sizeof(map));
|
||||
map = imsg.data;
|
||||
|
||||
nbr = nbr_find_peerid(imsg.hdr.peerid);
|
||||
if (nbr == NULL) {
|
||||
@ -567,16 +579,16 @@ ldpe_dispatch_lde(struct thread *thread)
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
case IMSG_MAPPING_ADD:
|
||||
mapping_list_add(&nbr->mapping_list, &map);
|
||||
mapping_list_add(&nbr->mapping_list, map);
|
||||
break;
|
||||
case IMSG_RELEASE_ADD:
|
||||
mapping_list_add(&nbr->release_list, &map);
|
||||
mapping_list_add(&nbr->release_list, map);
|
||||
break;
|
||||
case IMSG_REQUEST_ADD:
|
||||
mapping_list_add(&nbr->request_list, &map);
|
||||
mapping_list_add(&nbr->request_list, map);
|
||||
break;
|
||||
case IMSG_WITHDRAW_ADD:
|
||||
mapping_list_add(&nbr->withdraw_list, &map);
|
||||
mapping_list_add(&nbr->withdraw_list, map);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -613,9 +625,10 @@ ldpe_dispatch_lde(struct thread *thread)
|
||||
}
|
||||
break;
|
||||
case IMSG_NOTIFICATION_SEND:
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
|
||||
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
|
||||
sizeof(struct notify_msg))
|
||||
fatalx("invalid size of OE request");
|
||||
memcpy(&nm, imsg.data, sizeof(nm));
|
||||
nm = imsg.data;
|
||||
|
||||
nbr = nbr_find_peerid(imsg.hdr.peerid);
|
||||
if (nbr == NULL) {
|
||||
@ -626,7 +639,7 @@ ldpe_dispatch_lde(struct thread *thread)
|
||||
if (nbr->state != NBR_STA_OPER)
|
||||
break;
|
||||
|
||||
send_notification_full(nbr->tcp, &nm);
|
||||
send_notification_full(nbr->tcp, nm);
|
||||
break;
|
||||
case IMSG_CTL_END:
|
||||
case IMSG_CTL_SHOW_LIB:
|
||||
@ -791,8 +804,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
|
||||
continue;
|
||||
|
||||
ictl = if_to_ctl(ia);
|
||||
imsg_compose_event(&c->iev,
|
||||
IMSG_CTL_SHOW_INTERFACE,
|
||||
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE,
|
||||
0, 0, -1, ictl, sizeof(struct ctl_iface));
|
||||
}
|
||||
}
|
||||
|
13
ldpd/ldpe.h
13
ldpd/ldpe.h
@ -111,6 +111,9 @@ struct nbr {
|
||||
int flags;
|
||||
};
|
||||
#define F_NBR_GTSM_NEGOTIATED 0x01
|
||||
#define F_NBR_CAP_DYNAMIC 0x02
|
||||
#define F_NBR_CAP_TWCARD 0x04
|
||||
#define F_NBR_CAP_UNOTIF 0x08
|
||||
|
||||
RB_HEAD(nbr_id_head, nbr);
|
||||
RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare)
|
||||
@ -159,6 +162,8 @@ void recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *,
|
||||
/* init.c */
|
||||
void send_init(struct nbr *);
|
||||
int recv_init(struct nbr *, char *, uint16_t);
|
||||
void send_capability(struct nbr *, uint16_t, int);
|
||||
int recv_capability(struct nbr *, char *, uint16_t);
|
||||
|
||||
/* keepalive.c */
|
||||
void send_keepalive(struct nbr *);
|
||||
@ -166,15 +171,16 @@ int recv_keepalive(struct nbr *, char *, uint16_t);
|
||||
|
||||
/* notification.c */
|
||||
void send_notification_full(struct tcp_conn *, struct notify_msg *);
|
||||
void send_notification(uint32_t, struct tcp_conn *, uint32_t,
|
||||
uint16_t);
|
||||
void send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t);
|
||||
void send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t);
|
||||
void send_notification_rtlvs(struct nbr *, uint32_t, uint32_t, uint16_t,
|
||||
uint16_t, uint16_t, char *);
|
||||
int recv_notification(struct nbr *, char *, uint16_t);
|
||||
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 */
|
||||
@ -182,6 +188,7 @@ int recv_address(struct nbr *, char *, uint16_t);
|
||||
void send_labelmessage(struct nbr *, uint16_t, struct mapping_head *);
|
||||
int recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t);
|
||||
int gen_pw_status_tlv(struct ibuf *, uint32_t);
|
||||
uint16_t len_fec_tlv(struct map *);
|
||||
int gen_fec_tlv(struct ibuf *, struct map *);
|
||||
int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
|
||||
uint16_t, struct map *);
|
||||
|
37
ldpd/log.c
37
ldpd/log.c
@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src)
|
||||
const char *
|
||||
log_map(const struct map *map)
|
||||
{
|
||||
static char buf[64];
|
||||
static char buf[128];
|
||||
|
||||
switch (map->type) {
|
||||
case MAP_TYPE_WILDCARD:
|
||||
@ -327,11 +327,34 @@ log_map(const struct map *map)
|
||||
return ("???");
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
if (snprintf(buf, sizeof(buf), "pwid %u (%s)",
|
||||
map->fec.pwid.pwid,
|
||||
if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
|
||||
map->fec.pwid.pwid, map->fec.pwid.group_id,
|
||||
pw_type_name(map->fec.pwid.type)) == -1)
|
||||
return ("???");
|
||||
break;
|
||||
case MAP_TYPE_TYPED_WCARD:
|
||||
if (snprintf(buf, sizeof(buf), "typed wildcard") < 0)
|
||||
return ("???");
|
||||
switch (map->fec.twcard.type) {
|
||||
case MAP_TYPE_PREFIX:
|
||||
if (snprintf(buf + strlen(buf), sizeof(buf) -
|
||||
strlen(buf), " (prefix, address-family %s)",
|
||||
af_name(map->fec.twcard.u.prefix_af)) < 0)
|
||||
return ("???");
|
||||
break;
|
||||
case MAP_TYPE_PWID:
|
||||
if (snprintf(buf + strlen(buf), sizeof(buf) -
|
||||
strlen(buf), " (pwid, type %s)",
|
||||
pw_type_name(map->fec.twcard.u.pw_type)) < 0)
|
||||
return ("???");
|
||||
break;
|
||||
default:
|
||||
if (snprintf(buf + strlen(buf), sizeof(buf) -
|
||||
strlen(buf), " (unknown type)") < 0)
|
||||
return ("???");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ("???");
|
||||
}
|
||||
@ -464,6 +487,8 @@ msg_name(uint16_t msg)
|
||||
return ("initialization");
|
||||
case MSG_TYPE_KEEPALIVE:
|
||||
return ("keepalive");
|
||||
case MSG_TYPE_CAPABILITY:
|
||||
return ("capability");
|
||||
case MSG_TYPE_ADDR:
|
||||
return ("address");
|
||||
case MSG_TYPE_ADDRWITHDRAW:
|
||||
@ -557,6 +582,10 @@ status_code_name(uint32_t status)
|
||||
return ("Generic Misconfiguration Error");
|
||||
case S_WITHDRAW_MTHD:
|
||||
return ("Label Withdraw PW Status Method");
|
||||
case S_UNSSUPORTDCAP:
|
||||
return ("Unsupported Capability");
|
||||
case S_ENDOFLIB:
|
||||
return ("End-of-LIB");
|
||||
case S_TRANS_MISMTCH:
|
||||
return ("Transport Connection Mismatch");
|
||||
case S_DS_NONCMPLNCE:
|
||||
@ -577,6 +606,8 @@ pw_type_name(uint16_t pw_type)
|
||||
return ("Eth Tagged");
|
||||
case PW_TYPE_ETHERNET:
|
||||
return ("Ethernet");
|
||||
case PW_TYPE_WILDCARD:
|
||||
return ("Wildcard");
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "[%0x]", pw_type);
|
||||
return (buf);
|
||||
|
@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr)
|
||||
lde_nbr.id = nbr->id;
|
||||
lde_nbr.v4_enabled = nbr->v4_enabled;
|
||||
lde_nbr.v6_enabled = nbr->v6_enabled;
|
||||
lde_nbr.flags = nbr->flags;
|
||||
return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
|
||||
&lde_nbr, sizeof(lde_nbr)));
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include "ldpe.h"
|
||||
#include "ldp_debug.h"
|
||||
|
||||
static int gen_returned_tlvs(struct ibuf *, uint16_t, uint16_t, char *);
|
||||
static void log_msg_notification(int, struct nbr *, struct notify_msg *);
|
||||
|
||||
void
|
||||
send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
|
||||
{
|
||||
@ -35,16 +38,10 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
|
||||
size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE;
|
||||
if (nm->flags & F_NOTIF_PW_STATUS)
|
||||
size += PW_STATUS_TLV_SIZE;
|
||||
if (nm->flags & F_NOTIF_FEC) {
|
||||
size += TLV_HDR_SIZE;
|
||||
switch (nm->fec.type) {
|
||||
case MAP_TYPE_PWID:
|
||||
size += FEC_PWID_ELM_MIN_LEN;
|
||||
if (nm->fec.flags & F_MAP_PW_ID)
|
||||
size += sizeof(uint32_t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nm->flags & F_NOTIF_FEC)
|
||||
size += len_fec_tlv(&nm->fec);
|
||||
if (nm->flags & F_NOTIF_RETURNED_TLVS)
|
||||
size += TLV_HDR_SIZE * 2 + nm->rtlvs.length;
|
||||
|
||||
if ((buf = ibuf_open(size)) == NULL)
|
||||
fatal(__func__);
|
||||
@ -58,22 +55,25 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
|
||||
err |= gen_pw_status_tlv(buf, nm->pw_status);
|
||||
if (nm->flags & F_NOTIF_FEC)
|
||||
err |= gen_fec_tlv(buf, &nm->fec);
|
||||
if (nm->flags & F_NOTIF_RETURNED_TLVS)
|
||||
err |= gen_returned_tlvs(buf, nm->rtlvs.type, nm->rtlvs.length,
|
||||
nm->rtlvs.data);
|
||||
if (err) {
|
||||
ibuf_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcp->nbr)
|
||||
debug_msg_send("notification: lsr-id %s status %s%s",
|
||||
inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code),
|
||||
(nm->status_code & STATUS_FATAL) ? " (fatal)" : "");
|
||||
if (tcp->nbr) {
|
||||
log_msg_notification(1, tcp->nbr, nm);
|
||||
nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT);
|
||||
}
|
||||
|
||||
evbuf_enqueue(&tcp->wbuf, buf);
|
||||
}
|
||||
|
||||
/* send a notification without optional tlvs */
|
||||
void
|
||||
send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
|
||||
send_notification(struct tcp_conn *tcp, uint32_t status_code, uint32_t msg_id,
|
||||
uint16_t msg_type)
|
||||
{
|
||||
struct notify_msg nm;
|
||||
@ -87,11 +87,24 @@ send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
|
||||
}
|
||||
|
||||
void
|
||||
send_notification_nbr(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
|
||||
uint16_t msg_type)
|
||||
send_notification_rtlvs(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
|
||||
uint16_t msg_type, uint16_t tlv_type, uint16_t tlv_len, char *tlv_data)
|
||||
{
|
||||
send_notification(status_code, nbr->tcp, msg_id, msg_type);
|
||||
nbr_fsm(nbr, NBR_EVT_PDU_SENT);
|
||||
struct notify_msg nm;
|
||||
|
||||
memset(&nm, 0, sizeof(nm));
|
||||
nm.status_code = status_code;
|
||||
nm.msg_id = msg_id;
|
||||
nm.msg_type = msg_type;
|
||||
/* do not append the given TLV if it's too big (shouldn't happen) */
|
||||
if (tlv_len < 1024) {
|
||||
nm.rtlvs.type = tlv_type;
|
||||
nm.rtlvs.length = tlv_len;
|
||||
nm.rtlvs.data = tlv_data;
|
||||
nm.flags |= F_NOTIF_RETURNED_TLVS;
|
||||
}
|
||||
|
||||
send_notification_full(nbr->tcp, &nm);
|
||||
}
|
||||
|
||||
int
|
||||
@ -126,6 +139,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
/* Optional Parameters */
|
||||
while (len > 0) {
|
||||
struct tlv tlv;
|
||||
uint16_t tlv_type;
|
||||
uint16_t tlv_len;
|
||||
|
||||
if (len < sizeof(tlv)) {
|
||||
@ -134,6 +148,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
}
|
||||
|
||||
memcpy(&tlv, buf, TLV_HDR_SIZE);
|
||||
tlv_type = ntohs(tlv.type);
|
||||
tlv_len = ntohs(tlv.length);
|
||||
if (tlv_len + TLV_HDR_SIZE > len) {
|
||||
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
|
||||
@ -142,7 +157,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
buf += TLV_HDR_SIZE;
|
||||
len -= TLV_HDR_SIZE;
|
||||
|
||||
switch (ntohs(tlv.type)) {
|
||||
switch (tlv_type) {
|
||||
case TLV_TYPE_EXTSTATUS:
|
||||
case TLV_TYPE_RETURNEDPDU:
|
||||
case TLV_TYPE_RETURNEDMSG:
|
||||
@ -172,8 +187,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
break;
|
||||
default:
|
||||
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
|
||||
send_notification_nbr(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type);
|
||||
send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
|
||||
msg.id, msg.type, tlv_type, tlv_len, buf);
|
||||
/* ignore unknown tlv */
|
||||
break;
|
||||
}
|
||||
@ -181,9 +196,11 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
len -= tlv_len;
|
||||
}
|
||||
|
||||
if (nm.status_code == S_PW_STATUS) {
|
||||
/* sanity checks */
|
||||
switch (nm.status_code) {
|
||||
case S_PW_STATUS:
|
||||
if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {
|
||||
send_notification_nbr(nbr, S_MISS_MSG,
|
||||
send_notification(nbr->tcp, S_MISS_MSG,
|
||||
msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
@ -192,15 +209,28 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
case MAP_TYPE_PWID:
|
||||
break;
|
||||
default:
|
||||
send_notification_nbr(nbr, S_BAD_TLV_VAL,
|
||||
send_notification(nbr->tcp, S_BAD_TLV_VAL,
|
||||
msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case S_ENDOFLIB:
|
||||
if (!(nm.flags & F_NOTIF_FEC)) {
|
||||
send_notification(nbr->tcp, S_MISS_MSG,
|
||||
msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
if (nm.fec.type != MAP_TYPE_TYPED_WCARD) {
|
||||
send_notification(nbr->tcp, S_BAD_TLV_VAL,
|
||||
msg.id, msg.type);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id),
|
||||
status_code_name(ntohl(st.status_code)),
|
||||
(st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");
|
||||
log_msg_notification(0, nbr, &nm);
|
||||
|
||||
if (st.status_code & htonl(STATUS_FATAL)) {
|
||||
if (nbr->state == NBR_STA_OPENSENT)
|
||||
@ -210,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (nm.status_code == S_PW_STATUS)
|
||||
/* lde needs to know about a few notification messages */
|
||||
switch (nm.status_code) {
|
||||
case S_PW_STATUS:
|
||||
case S_ENDOFLIB:
|
||||
ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
|
||||
&nm, sizeof(nm));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -236,3 +273,42 @@ gen_status_tlv(struct ibuf *buf, uint32_t status_code, uint32_t msg_id,
|
||||
|
||||
return (ibuf_add(buf, &st, STATUS_SIZE));
|
||||
}
|
||||
|
||||
static int
|
||||
gen_returned_tlvs(struct ibuf *buf, uint16_t type, uint16_t length,
|
||||
char *tlv_data)
|
||||
{
|
||||
struct tlv rtlvs;
|
||||
struct tlv tlv;
|
||||
int err;
|
||||
|
||||
rtlvs.type = htons(TLV_TYPE_RETURNED_TLVS);
|
||||
rtlvs.length = htons(length + TLV_HDR_SIZE);
|
||||
tlv.type = htons(type);
|
||||
tlv.length = htons(length);
|
||||
|
||||
err = ibuf_add(buf, &rtlvs, sizeof(rtlvs));
|
||||
err |= ibuf_add(buf, &tlv, sizeof(tlv));
|
||||
err |= ibuf_add(buf, tlv_data, length);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
void
|
||||
log_msg_notification(int out, struct nbr *nbr, struct notify_msg *nm)
|
||||
{
|
||||
if (nm->status_code & STATUS_FATAL) {
|
||||
debug_msg(out, "notification: lsr-id %s, status %s "
|
||||
"(fatal error)", inet_ntoa(nbr->id),
|
||||
status_code_name(nm->status_code));
|
||||
return;
|
||||
}
|
||||
|
||||
debug_msg(out, "notification: lsr-id %s, status %s",
|
||||
inet_ntoa(nbr->id), status_code_name(nm->status_code));
|
||||
if (nm->flags & F_NOTIF_FEC)
|
||||
debug_msg(out, "notification: fec %s", log_map(&nm->fec));
|
||||
if (nm->flags & F_NOTIF_PW_STATUS)
|
||||
debug_msg(out, "notification: pw-status %s",
|
||||
(nm->pw_status) ? "not forwarding" : "forwarding");
|
||||
}
|
||||
|
@ -519,13 +519,7 @@ session_read(struct thread *thread)
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case MSG_TYPE_ADDR:
|
||||
case MSG_TYPE_ADDRWITHDRAW:
|
||||
case MSG_TYPE_LABELMAPPING:
|
||||
case MSG_TYPE_LABELREQUEST:
|
||||
case MSG_TYPE_LABELWITHDRAW:
|
||||
case MSG_TYPE_LABELRELEASE:
|
||||
case MSG_TYPE_LABELABORTREQ:
|
||||
default:
|
||||
if (nbr->state != NBR_STA_OPER) {
|
||||
session_shutdown(nbr, S_SHUTDOWN,
|
||||
msg->id, msg->type);
|
||||
@ -533,8 +527,6 @@ session_read(struct thread *thread)
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* switch LDP packet type */
|
||||
@ -548,6 +540,9 @@ session_read(struct thread *thread)
|
||||
case MSG_TYPE_KEEPALIVE:
|
||||
ret = recv_keepalive(nbr, pdu, msg_size);
|
||||
break;
|
||||
case MSG_TYPE_CAPABILITY:
|
||||
ret = recv_capability(nbr, pdu, msg_size);
|
||||
break;
|
||||
case MSG_TYPE_ADDR:
|
||||
case MSG_TYPE_ADDRWITHDRAW:
|
||||
ret = recv_address(nbr, pdu, msg_size);
|
||||
@ -564,7 +559,7 @@ session_read(struct thread *thread)
|
||||
log_debug("%s: unknown LDP message from nbr %s",
|
||||
__func__, inet_ntoa(nbr->id));
|
||||
if (!(ntohs(msg->type) & UNKNOWN_FLAG))
|
||||
send_notification_nbr(nbr,
|
||||
send_notification(nbr->tcp,
|
||||
S_UNKNOWN_MSG, msg->id, msg->type);
|
||||
/* ignore the message */
|
||||
ret = 0;
|
||||
@ -632,7 +627,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
|
||||
case NBR_STA_OPER:
|
||||
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
|
||||
|
||||
send_notification_nbr(nbr, status, msg_id, msg_type);
|
||||
send_notification(nbr->tcp, status, msg_id, msg_type);
|
||||
|
||||
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
|
||||
break;
|
||||
@ -788,7 +783,7 @@ pending_conn_timeout(struct thread *thread)
|
||||
* notification message reliably.
|
||||
*/
|
||||
tcp = tcp_new(pconn->fd, NULL);
|
||||
send_notification(S_NO_HELLO, tcp, 0, 0);
|
||||
send_notification(tcp, S_NO_HELLO, 0, 0);
|
||||
msgbuf_write(&tcp->wbuf.wbuf);
|
||||
|
||||
pending_conn_del(pconn);
|
||||
|
@ -131,7 +131,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
|
||||
sa.sadb_sa_exttype = SADB_EXT_SA;
|
||||
sa.sadb_sa_len = sizeof(sa) / 8;
|
||||
sa.sadb_sa_replay = 0;
|
||||
sa.sadb_sa_spi = spi;
|
||||
sa.sadb_sa_spi = htonl(spi);
|
||||
sa.sadb_sa_state = SADB_SASTATE_MATURE;
|
||||
break;
|
||||
}
|
||||
@ -280,7 +280,7 @@ pfkey_read(int sd, struct sadb_msg *h)
|
||||
}
|
||||
|
||||
static int
|
||||
pfkey_reply(int sd, uint32_t *spip)
|
||||
pfkey_reply(int sd, uint32_t *spi)
|
||||
{
|
||||
struct sadb_msg hdr, *msg;
|
||||
struct sadb_ext *ext;
|
||||
@ -317,7 +317,7 @@ pfkey_reply(int sd, uint32_t *spip)
|
||||
}
|
||||
|
||||
if (hdr.sadb_msg_type == SADB_GETSPI) {
|
||||
if (spip == NULL) {
|
||||
if (spi == NULL) {
|
||||
explicit_bzero(data, len);
|
||||
free(data);
|
||||
return (0);
|
||||
@ -331,7 +331,7 @@ pfkey_reply(int sd, uint32_t *spip)
|
||||
ext->sadb_ext_len * PFKEY2_CHUNK)) {
|
||||
if (ext->sadb_ext_type == SADB_EXT_SA) {
|
||||
sa = (struct sadb_sa *) ext;
|
||||
*spip = sa->sadb_sa_spi;
|
||||
*spi = ntohl(sa->sadb_sa_spi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user