summaryrefslogtreecommitdiffstats
path: root/ldpd/labelmapping.c
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2017-03-03 21:50:22 +0100
committerRenato Westphal <renato@opensourcerouting.org>2017-03-03 21:50:22 +0100
commitd4afb81972d9666d730445fa81090d711fc0d54f (patch)
tree50eb9c287f7cb1ff7b2b0c87f03c58b29c3cb8a8 /ldpd/labelmapping.c
parentldpd: implement RFC 5561 (LDP Capabilities) (diff)
downloadfrr-d4afb81972d9666d730445fa81090d711fc0d54f.tar.xz
frr-d4afb81972d9666d730445fa81090d711fc0d54f.zip
ldpd: implement RFC 5918 (Typed Wildcard FEC)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'ldpd/labelmapping.c')
-rw-r--r--ldpd/labelmapping.c120
1 files changed, 118 insertions, 2 deletions
diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c
index e35f01b13..4559ae628 100644
--- a/ldpd/labelmapping.c
+++ b/ldpd/labelmapping.c
@@ -90,6 +90,16 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
if (me->map.flags & F_MAP_PW_STATUS)
msg_size += PW_STATUS_TLV_SIZE;
break;
+ case MAP_TYPE_TYPED_WCARD:
+ msg_size += FEC_ELM_TWCARD_MIN_LEN;
+ switch (me->map.fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ msg_size += sizeof(uint16_t);
+ break;
+ default:
+ fatalx("send_labelmessage: unexpected fec type");
+ }
+ break;
}
if (me->map.label != NO_LABEL)
msg_size += LABEL_TLV_SIZE;
@@ -209,6 +219,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.
*/
@@ -524,7 +552,7 @@ 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;
@@ -594,6 +622,43 @@ 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:
+ 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;
+ default:
+ fatalx("gen_fec_tlv: unexpected fec type");
+ }
+ break;
default:
break;
}
@@ -606,7 +671,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);
@@ -751,6 +816,57 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
}
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;
+ default:
+ send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ return (off);
default:
send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
break;