diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-19 20:54:18 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-19 20:54:18 +0000 |
commit | 9a2afa8acf1879cf27b958867ec93b8685463544 (patch) | |
tree | a93a894585cf78bb551fc46620da5aa9d007910c | |
parent | d5090c4ffd20eb040b8d194bf803318547553814 (diff) |
Rework label mapping algorithms to be more in line with the RFC.
This patch presents a thoroughly review of the label mapping
algorithms. Most of the changes are minor bug fixes in the handling of
received label messages.
Additional improvements:
* Add a few more references to the Appendix A of the RFC5036 ("LDP
Label Distribution Procedures") into the code;
* Add full multipath support;
* Send label withdraws when appropriate;
* Add label withdraw/release wildcard support.
NOTE: As a result of implementing only the "Liberal Label Retention" and
"Downstream Unsolicited" modes, we will never send a label request
("Request Never"). And that means that we can ignore the following
notification messages: "Label Request Aborted", "No Label Resources",
"No Route" and "Label Resources Available". The following algorithms
mentioned in the RFC can also be ignored: "Timeout of Deferred Label
Request", "Detect Local Label Resources Have Become Available" and
"Receive Label Abort Request".
Now, considering that we only support one combination of all modes of
operation, we can say that we have an almost complete implementation of
the protocol.
ok claudio@
-rw-r--r-- | usr.sbin/ldpd/labelmapping.c | 60 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde.c | 165 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde.h | 21 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde_lib.c | 398 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldp.h | 5 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 9 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.c | 11 | ||||
-rw-r--r-- | usr.sbin/ldpd/log.c | 5 |
8 files changed, 408 insertions, 266 deletions
diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c index 1322e481197..df62ce14e44 100644 --- a/usr.sbin/ldpd/labelmapping.c +++ b/usr.sbin/ldpd/labelmapping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: labelmapping.c,v 1.31 2015/02/09 11:53:25 claudio Exp $ */ +/* $OpenBSD: labelmapping.c,v 1.32 2015/07/19 20:54:16 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -41,6 +41,7 @@ void gen_label_tlv(struct ibuf *, u_int32_t); void gen_reqid_tlv(struct ibuf *, u_int32_t); void gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t); +void gen_wcard_fec_tlv(struct ibuf *); int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, u_int16_t, u_int32_t *); @@ -80,10 +81,13 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh) } /* calculate size */ - tlv_size = LDP_MSG_LEN + TLV_HDR_LEN + FEC_ELM_MIN_LEN + - PREFIX_SIZE(me->map.prefixlen); - if (type == MSG_TYPE_LABELMAPPING || - me->map.flags & F_MAP_OPTLABEL) + tlv_size = LDP_MSG_LEN + TLV_HDR_LEN; + if (me->map.flags & F_MAP_WILDCARD) + tlv_size += FEC_ELM_WCARD_LEN; + else + tlv_size += FEC_ELM_PREFIX_MIN_LEN + + PREFIX_SIZE(me->map.prefixlen); + if (me->map.label != NO_LABEL) tlv_size += LABEL_TLV_LEN; if (me->map.flags & F_MAP_REQ_ID) tlv_size += REQID_TLV_LEN; @@ -99,9 +103,11 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh) /* append message and tlvs */ gen_msg_tlv(buf, type, tlv_size); - gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen); - if (type == MSG_TYPE_LABELMAPPING || - me->map.flags & F_MAP_OPTLABEL) + if (me->map.flags & F_MAP_WILDCARD) + gen_wcard_fec_tlv(buf); + else + gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen); + if (me->map.label != NO_LABEL) gen_label_tlv(buf, me->map.label); if (me->map.flags & F_MAP_REQ_ID) gen_reqid_tlv(buf, me->map.requestid); @@ -121,7 +127,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) { struct ldp_msg lm; struct tlv ft; - u_int32_t label, reqid = 0; + u_int32_t label = NO_LABEL, reqid = 0; u_int8_t flags = 0; int feclen, lbllen, tlen; @@ -228,7 +234,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) case TLV_TYPE_LABELREQUEST: switch (type) { case MSG_TYPE_LABELMAPPING: - case MSG_TYPE_LABELABORTREQ: + case MSG_TYPE_LABELREQUEST: if (ntohs(tlv.length) != 4) { session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); @@ -260,7 +266,6 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) memcpy(&labelbuf, buf, sizeof(labelbuf)); label = ntohl(labelbuf); - flags |= F_MAP_OPTLABEL; break; default: /* ignore */ @@ -299,26 +304,35 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) int imsg_type = IMSG_NONE; me->map.flags |= flags; - if (type == MSG_TYPE_LABELMAPPING || - me->map.flags & F_MAP_OPTLABEL) - me->map.label = label; + me->map.label = label; if (me->map.flags & F_MAP_REQ_ID) me->map.requestid = reqid; switch (type) { case MSG_TYPE_LABELMAPPING: + log_debug("label mapping from nbr %s, FEC %s, " + "label %u", inet_ntoa(nbr->id), + log_fec(&me->map), me->map.label); imsg_type = IMSG_LABEL_MAPPING; break; case MSG_TYPE_LABELREQUEST: + log_debug("label request from nbr %s, FEC %s", + inet_ntoa(nbr->id), log_fec(&me->map)); imsg_type = IMSG_LABEL_REQUEST; break; case MSG_TYPE_LABELWITHDRAW: + log_debug("label withdraw from nbr %s, FEC %s", + inet_ntoa(nbr->id), log_fec(&me->map)); imsg_type = IMSG_LABEL_WITHDRAW; break; case MSG_TYPE_LABELRELEASE: + log_debug("label release from nbr %s, FEC %s", + inet_ntoa(nbr->id), log_fec(&me->map)); imsg_type = IMSG_LABEL_RELEASE; break; case MSG_TYPE_LABELABORTREQ: + log_debug("label abort from nbr %s, FEC %s", + inet_ntoa(nbr->id), log_fec(&me->map)); imsg_type = IMSG_LABEL_ABORT; break; default: @@ -436,6 +450,20 @@ gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen) ibuf_add(buf, &prefix, len); } +void +gen_wcard_fec_tlv(struct ibuf *buf) +{ + struct tlv ft; + u_int8_t type; + + ft.type = htons(TLV_TYPE_FEC); + ft.length = htons(sizeof(type)); + ibuf_add(buf, &ft, sizeof(ft)); + + type = FEC_WILDCARD; + ibuf_add(buf, &type, sizeof(type)); +} + int tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, u_int16_t len, u_int8_t *type, u_int32_t *prefix, u_int8_t *prefixlen) @@ -446,7 +474,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, off += sizeof(u_int8_t); if (*type == FEC_WILDCARD) { - if (len == 0) + if (len == FEC_ELM_WCARD_LEN) return (off); else { session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, @@ -460,7 +488,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, return (-1); } - if (len < FEC_ELM_MIN_LEN) { + if (len < FEC_ELM_PREFIX_MIN_LEN) { session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); return (-1); } diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c index 354d6d6ad93..12ff6d9fe08 100644 --- a/usr.sbin/ldpd/lde.c +++ b/usr.sbin/ldpd/lde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.c,v 1.32 2015/07/19 20:50:03 renato Exp $ */ +/* $OpenBSD: lde.c,v 1.33 2015/07/19 20:54:16 renato Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> @@ -231,8 +231,6 @@ lde_dispatch_imsg(int fd, short event, void *bula) } rt_snap(nbr); - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, - imsg.hdr.peerid, 0, NULL, 0); break; case IMSG_LABEL_MAPPING: case IMSG_LABEL_REQUEST: @@ -258,14 +256,20 @@ lde_dispatch_imsg(int fd, short event, void *bula) lde_check_request(&map, nbr); break; case IMSG_LABEL_RELEASE: - lde_check_release(&map, nbr); + if (map.flags & F_MAP_WILDCARD) + lde_check_release_wcard(&map, nbr); + else + lde_check_release(&map, nbr); break; case IMSG_LABEL_WITHDRAW: - lde_check_withdraw(&map, nbr); + if (map.flags & F_MAP_WILDCARD) + lde_check_withdraw_wcard(&map, nbr); + else + lde_check_withdraw(&map, nbr); + break; + case IMSG_LABEL_ABORT: + /* not necessary */ break; - default: - log_warnx("type %d not yet handled. nbr %s", - imsg.hdr.type, inet_ntoa(nbr->id)); } break; case IMSG_ADDRESS_ADD: @@ -467,31 +471,6 @@ lde_send_delete_klabel(struct rt_node *rr, struct rt_lsp *rl) } void -lde_send_labelrequest(struct lde_nbr *ln, struct rt_node *rn) -{ - struct map map; - - /* TODO check if status of peer is OK to send requests (SLRq.2 & 6) - * For now assume no peer will send no-label-resource notifications */ - - /* check if request is already pending */ - if (fec_find(&ln->sent_req, &rn->fec) != NULL) - return; - /* and try to add request to pending list */ - lde_req_add(ln, &rn->fec, 1); - /* msgid does not matter since only one req can be pending */ - - bzero(&map, sizeof(map)); - map.prefix = rn->fec.prefix; - map.prefixlen = rn->fec.prefixlen; - - lde_imsg_compose_ldpe(IMSG_REQUEST_ADD, ln->peerid, 0, - &map, sizeof(map)); - lde_imsg_compose_ldpe(IMSG_REQUEST_ADD_END, ln->peerid, 0, - NULL, 0); -} - -void lde_send_labelmapping(struct lde_nbr *ln, struct rt_node *rn) { struct lde_req *lre; @@ -499,7 +478,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct rt_node *rn) struct map map; /* - * This function skips SL.1 - 3 and SL.9 - 14 because the lable + * This function skips SL.1 - 3 and SL.9 - 14 because the label * allocation is done way earlier (because of the merging nature of * ldpd). */ @@ -509,24 +488,67 @@ lde_send_labelmapping(struct lde_nbr *ln, struct rt_node *rn) map.prefix = rn->fec.prefix; map.prefixlen = rn->fec.prefixlen; - /* is there a pending request for this mapping? */ + /* SL.6: is there a pending request for this mapping? */ lre = (struct lde_req *)fec_find(&ln->recv_req, &rn->fec); if (lre) { /* set label request msg id in the mapping response. */ map.requestid = lre->msgid; map.flags = F_MAP_REQ_ID; + + /* SL.7: delete record of pending request */ lde_req_del(ln, lre, 0); } + /* SL.4: send label mapping */ + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0, + &map, sizeof(map)); + + /* SL.5: record sent label mapping */ me = (struct lde_map *)fec_find(&ln->sent_map, &rn->fec); if (me == NULL) me = lde_map_add(ln, rn, 1); me->label = map.label; +} - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0, - &map, sizeof(map)); - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, - NULL, 0); +void +lde_send_labelwithdraw(struct lde_nbr *ln, struct rt_node *rn) +{ + struct lde_wdraw *lw; + struct map map; + struct fec *f; + + bzero(&map, sizeof(map)); + if (rn) { + map.label = rn->local_label; + map.prefix = rn->fec.prefix; + map.prefixlen = rn->fec.prefixlen; + } else { + map.label = NO_LABEL; + map.flags = F_MAP_WILDCARD; + } + + /* SWd.1: send label withdraw. */ + lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD, ln->peerid, 0, + &map, sizeof(map)); + lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD_END, ln->peerid, 0, NULL, 0); + + /* SWd.2: record label withdraw. */ + if (rn) { + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &rn->fec); + if (lw == NULL) + lw = lde_wdraw_add(ln, rn); + lw->label = map.label; + } else { + RB_FOREACH(f, fec_tree, &rt) { + rn = (struct rt_node *)f; + + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, + &rn->fec); + if (lw == NULL) + lw = lde_wdraw_add(ln, rn); + lw->label = map.label; + } + } } void @@ -535,17 +557,16 @@ lde_send_labelrelease(struct lde_nbr *ln, struct rt_node *rn, u_int32_t label) struct map map; bzero(&map, sizeof(map)); - map.prefix = rn->fec.prefix; - map.prefixlen = rn->fec.prefixlen; - if (label != NO_LABEL) { - map.flags = F_MAP_OPTLABEL; - map.label = label; - } + if (rn) { + map.prefix = rn->fec.prefix; + map.prefixlen = rn->fec.prefixlen; + } else + map.flags = F_MAP_WILDCARD; + map.label = label; lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0, &map, sizeof(map)); - lde_imsg_compose_ldpe(IMSG_RELEASE_ADD_END, ln->peerid, 0, - NULL, 0); + lde_imsg_compose_ldpe(IMSG_RELEASE_ADD_END, ln->peerid, 0, NULL, 0); } void @@ -657,31 +678,6 @@ lde_nbr_clear(void) lde_nbr_del(nbr); } -void -lde_nbr_do_mappings(struct rt_node *rn) -{ - struct lde_nbr *ln; - struct lde_map *me; - struct lde_req *lre; - - /* This handles LMp.17-31 for lde_check_mapping() */ - - RB_FOREACH(ln, nbr_tree, &lde_nbrs) { - /* LMp.18 Did we already send a mapping to this peer? */ - me = (struct lde_map *)fec_find(&ln->sent_map, &rn->fec); - if (me && me->label == rn->local_label) - /* same mapping already sent, skip */ - /* TODO LMp.22-27 Loop detection check */ - continue; - - /* LMp.28 Is this from a pending request? */ - lre = (struct lde_req *)fec_find(&ln->recv_req, &rn->fec); - - lde_send_labelmapping(ln, rn); - /* LMp.30 & 31 are not needed because labels are always added */ - } -} - struct lde_map * lde_map_add(struct lde_nbr *ln, struct rt_node *rn, int sent) { @@ -765,6 +761,31 @@ lde_req_del(struct lde_nbr *ln, struct lde_req *lre, int sent) free(lre); } +struct lde_wdraw * +lde_wdraw_add(struct lde_nbr *ln, struct rt_node *rn) +{ + struct lde_wdraw *lw; + + lw = calloc(1, sizeof(*lw)); + if (lw == NULL) + fatal("lde_wdraw_add"); + + lw->fec = rn->fec; + + if (fec_insert(&ln->sent_wdraw, &lw->fec)) + log_warnx("failed to add %s/%u to sent wdraw", + inet_ntoa(lw->fec.prefix), lw->fec.prefixlen); + + return (lw); +} + +void +lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw) +{ + fec_remove(&ln->sent_wdraw, &lw->fec); + free(lw); +} + int lde_address_add(struct lde_nbr *lr, struct in_addr *addr) { diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h index c7a072ba8d7..4bdbd7fa365 100644 --- a/usr.sbin/ldpd/lde.h +++ b/usr.sbin/ldpd/lde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.h,v 1.25 2015/07/19 18:34:32 renato Exp $ */ +/* $OpenBSD: lde.h,v 1.26 2015/07/19 20:54:16 renato Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -36,11 +36,7 @@ struct fec { RB_PROTOTYPE(fec_tree, fec, entry, fec_compare) extern struct fec_tree rt; -/* - * fec tree of pending label request - * Note: currently only one outstanding request per FEC can be tracked but - * should not be a problem since ldpd does not support multipath for now. - */ +/* request entries */ struct lde_req { struct fec fec; u_int32_t msgid; @@ -54,6 +50,12 @@ struct lde_map { u_int32_t label; }; +/* withdraw entries */ +struct lde_wdraw { + struct fec fec; + u_int32_t label; +}; + /* Addresses belonging to neighbor */ struct lde_nbr_address { TAILQ_ENTRY(lde_nbr_address) entry; @@ -102,15 +104,16 @@ u_int32_t lde_assign_label(void); void lde_send_change_klabel(struct rt_node *, struct rt_lsp *); void lde_send_delete_klabel(struct rt_node *, struct rt_lsp *); void lde_send_labelmapping(struct lde_nbr *, struct rt_node *); -void lde_send_labelrequest(struct lde_nbr *, struct rt_node *); +void lde_send_labelwithdraw(struct lde_nbr *, struct rt_node *); void lde_send_labelrelease(struct lde_nbr *, struct rt_node *, u_int32_t); void lde_send_notification(u_int32_t, u_int32_t, u_int32_t, u_int32_t); -void lde_nbr_do_mappings(struct rt_node *); struct lde_map *lde_map_add(struct lde_nbr *, struct rt_node *, int); void lde_map_del(struct lde_nbr *, struct lde_map *, int); struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int); void lde_req_del(struct lde_nbr *, struct lde_req *, int); +struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct rt_node *); +void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *); struct lde_nbr *lde_find_address(struct in_addr); int lde_address_add(struct lde_nbr *, struct in_addr *); @@ -134,7 +137,9 @@ void lde_kernel_remove(struct kroute *); void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_request(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 *); void lde_label_list_free(struct lde_nbr *); #endif /* _LDE_H_ */ diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c index 2977a6171eb..90dda85c783 100644 --- a/usr.sbin/ldpd/lde_lib.c +++ b/usr.sbin/ldpd/lde_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde_lib.c,v 1.36 2015/07/19 20:50:03 renato Exp $ */ +/* $OpenBSD: lde_lib.c,v 1.37 2015/07/19 20:54:16 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -49,6 +49,9 @@ int lde_nbr_is_nexthop(struct rt_node *, struct lde_nbr *); RB_GENERATE(fec_tree, fec, entry, fec_compare) +extern struct nbr_tree lde_nbrs; +RB_PROTOTYPE(nbr_tree, lde_nbr, entry, lde_nbr_compare) + extern struct ldpd_conf *ldeconf; struct fec_tree rt = RB_INITIALIZER(&rt); @@ -145,6 +148,10 @@ rt_dump(pid_t pid) RB_FOREACH(f, fec_tree, &rt) { rr = (struct rt_node *)f; + if (rr->local_label == NO_LABEL && + LIST_EMPTY(&rr->downstream)) + continue; + rtctl.prefix = rr->fec.prefix; rtctl.prefixlen = rr->fec.prefixlen; rtctl.flags = rr->flags; @@ -173,23 +180,20 @@ void rt_snap(struct lde_nbr *ln) { struct fec *f; - struct rt_node *r; - struct lde_map *me; - struct map map; + struct rt_node *rn; + int count = 0; - bzero(&map, sizeof(map)); RB_FOREACH(f, fec_tree, &rt) { - r = (struct rt_node *)f; - map.prefix = r->fec.prefix; - map.prefixlen = r->fec.prefixlen; - map.label = r->local_label; - - me = lde_map_add(ln, r, 1); - me->label = r->local_label; + rn = (struct rt_node *)f; + if (rn->local_label == NO_LABEL) + continue; - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, ln->peerid, 0, &map, - sizeof(map)); + lde_send_labelmapping(ln, rn); + count++; } + if (count > 0) + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, + ln->peerid, 0, NULL, 0); } void @@ -198,11 +202,8 @@ rt_free(void *arg) struct rt_node *rr = arg; struct rt_lsp *rl; - while ((rl = LIST_FIRST(&rr->lsp))) { - LIST_REMOVE(rl, entry); - free(rl); - } - + while ((rl = LIST_FIRST(&rr->lsp))) + rt_lsp_del(rl); if (!LIST_EMPTY(&rr->downstream)) log_warnx("rt_free: fec %s/%u downstream list not empty", inet_ntoa(rr->fec.prefix), rr->fec.prefixlen); @@ -210,7 +211,7 @@ rt_free(void *arg) log_warnx("rt_free: fec %s/%u upstream list not empty", inet_ntoa(rr->fec.prefix), rr->fec.prefixlen); - free(rl); + free(rr); } void @@ -281,47 +282,74 @@ lde_kernel_insert(struct kroute *kr) { struct rt_node *rn; struct rt_lsp *rl; - struct lde_nbr_address *addr; - struct lde_map *map; + struct lde_map *me; + struct lde_nbr *ln; + char buf[16]; - log_debug("kernel add route %s/%u", inet_ntoa(kr->prefix), - kr->prefixlen); + log_debug("kernel add route %s/%u nexthop %s", + inet_ntoa(kr->prefix), kr->prefixlen, + inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf))); rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, kr->prefixlen); if (rn == NULL) rn = rt_add(kr->prefix, kr->prefixlen); - rl = rt_lsp_find(rn, kr->nexthop); - if (rl == NULL) - rl = rt_lsp_add(rn, kr->nexthop); - - /* There is static assigned label for this route, record it in lib */ - if (kr->local_label != NO_LABEL) { - rn->local_label = kr->local_label; + if (rt_lsp_find(rn, kr->nexthop) != NULL) return; - } - if (rn->local_label == NO_LABEL) { - if (kr->flags & F_CONNECTED) - /* Directly connected route */ - rn->local_label = MPLS_LABEL_IMPLNULL; - else - rn->local_label = lde_assign_label(); - } + if (LIST_EMPTY(&rn->lsp)) { + if (rn->local_label == NO_LABEL) { + if (kr->flags & F_CONNECTED) + rn->local_label = MPLS_LABEL_IMPLNULL; + else + rn->local_label = lde_assign_label(); + } else { + /* Handle local label changes */ + if ((kr->flags & F_CONNECTED) && + rn->local_label != MPLS_LABEL_IMPLNULL) { + /* explicit withdraw of the previous label */ + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, rn); + rn->local_label = MPLS_LABEL_IMPLNULL; + } + + if (!(kr->flags & F_CONNECTED) && + rn->local_label == MPLS_LABEL_IMPLNULL) { + /* explicit withdraw of the previous label */ + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, rn); + rn->local_label = lde_assign_label(); + } + } - LIST_FOREACH(map, &rn->downstream, entry) { - addr = lde_address_find(map->nexthop, &rl->nexthop); - if (addr != NULL) { - rl->remote_label = map->label; - break; + /* FEC.1: perform lsr label distribution procedure */ + RB_FOREACH(ln, nbr_tree, &lde_nbrs) { + lde_send_labelmapping(ln, rn); + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, + ln->peerid, 0, NULL, 0); } } + rl = rt_lsp_add(rn, kr->nexthop); lde_send_change_klabel(rn, rl); - /* Redistribute the current mapping to every nbr */ - lde_nbr_do_mappings(rn); + ln = lde_find_address(rl->nexthop); + if (ln) { + /* FEC.2 */ + me = (struct lde_map *)fec_find(&ln->recv_map, &rn->fec); + if (me) { + struct map map; + + bzero(&map, sizeof(map)); + map.prefix.s_addr = me->fec.prefix.s_addr; + map.prefixlen = me->fec.prefixlen; + map.label = me->label; + + /* FEC.5 */ + lde_check_mapping(&map, ln); + } + } } void @@ -329,9 +357,12 @@ lde_kernel_remove(struct kroute *kr) { struct rt_node *rn; struct rt_lsp *rl; + struct lde_nbr *ln; + char buf[16]; - log_debug("kernel remove route %s/%u", inet_ntoa(kr->prefix), - kr->prefixlen); + log_debug("kernel remove route %s/%u nexthop %s", + inet_ntoa(kr->prefix), kr->prefixlen, + inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf))); rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, kr->prefixlen); @@ -340,13 +371,14 @@ lde_kernel_remove(struct kroute *kr) return; rl = rt_lsp_find(rn, kr->nexthop); - if (rl != NULL) - rt_lsp_del(rl); - - /* XXX handling of total loss of route, withdraw mappings, etc */ + if (rl == NULL) + /* route lost */ + return; - /* Redistribute the current mapping to every nbr */ - lde_nbr_do_mappings(rn); + rt_lsp_del(rl); + if (LIST_EMPTY(&rn->lsp)) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, rn); } void @@ -355,76 +387,76 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) struct rt_node *rn; struct rt_lsp *rl; struct lde_req *lre; - struct lde_nbr_address *addr = NULL; + struct lde_nbr_address *addr; struct lde_map *me; - - log_debug("label mapping from nbr %s, FEC %s, label %u", - inet_ntoa(ln->id), log_fec(map), map->label); + int msgsource = 0; rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, map->prefixlen); - if (rn == NULL) { + if (rn == NULL) rn = rt_add(map->prefix, map->prefixlen); - rn->local_label = lde_assign_label(); - } - /* first check if we have a pending request running */ + /* LMp.1: first check if we have a pending request running */ lre = (struct lde_req *)fec_find(&ln->sent_req, &rn->fec); if (lre) + /* LMp.2: delete record of outstanding label request */ lde_req_del(ln, lre, 1); - /* TODO Loop detection LMp.3 - LMp.8 */ + /* + * LMp.3 - LMp.8: Loop detection LMp.3 - unecessary for frame-mode + * mpls networks + */ - LIST_FOREACH(me, &rn->downstream, entry) { - if (ln != me->nexthop) /* LMp.9 */ - continue; - if (lre) - /* LMp.10 Note 6: req. mappings are always new */ - break; - if (me->label != map->label) { /* LMp.10 */ - /* - * This is, according to the RFC, a try to install a - * multipath LSP which is not supported by the RFC. - * So instead release the old label and install the - * new one. - */ - log_debug("possible multipath FEC %s, " - "label %u, old label %u", - log_fec(map), map->label, me->label); + /* LMp.9 */ + me = (struct lde_map *)fec_find(&ln->recv_map, &rn->fec); + if (me) { + /* LMp.10 */ + if (me->label != map->label && lre == NULL) { + /* LMp.10a */ lde_send_labelrelease(ln, rn, me->label); + + LIST_FOREACH(rl, &rn->lsp, entry) + TAILQ_FOREACH(addr, &ln->addr_list, entry) + if (rl->nexthop.s_addr == + addr->addr.s_addr) { + lde_send_delete_klabel(rn, rl); + rl->remote_label = NO_LABEL; + } } - /* there can only be one mapping */ - break; } - /* LMp.11: get nexthop */ + /* + * LMp.11 - 12: consider multiple nexthops in order to + * support multipath + */ LIST_FOREACH(rl, &rn->lsp, entry) { - addr = lde_address_find(ln, &rl->nexthop); - if (addr) - break; + if (lde_address_find(ln, &rl->nexthop)) { + msgsource = 1; + + /* LMp.15: install FEC in FIB */ + rl->remote_label = map->label; + lde_send_change_klabel(rn, rl); + } } - if (addr == NULL) { - /* in liberal mode just note the mapping */ + if (msgsource == 0) { + /* LMp.13: perform lsr label release procedure */ if (me == NULL) me = lde_map_add(ln, rn, 0); me->label = map->label; - return; } - /* LMp.14 do we actually need this FEC for now this is always true */ - rl->remote_label = map->label; - - /* LMp.15 install FEC in FIB */ - lde_send_change_klabel(rn, rl); - - /* Record the mapping from this peer LMp.16 */ + /* LMp.16: Record the mapping from this peer */ if (me == NULL) me = lde_map_add(ln, rn, 0); me->label = map->label; - /* Redistribute the current mapping to every nbr LMp.17-31 */ - lde_nbr_do_mappings(rn); + + /* + * LMp.17 - LMp.27 are unnecessary since we don't need to implement + * loop detection. LMp.28 - LMp.30 are unnecessary because we are + * merging capable. + */ } void @@ -433,91 +465,112 @@ lde_check_request(struct map *map, struct lde_nbr *ln) struct lde_req *lre; struct rt_node *rn; struct rt_lsp *rl; - struct lde_nbr *lnn; - log_debug("label request from nbr %s, FEC %s", - inet_ntoa(ln->id), log_fec(map)); + /* TODO LRq.1: loop detection */ + /* LRq.2: is there a next hop for fec? */ rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, map->prefixlen); - if (rn == NULL) { + if (rn == NULL || LIST_EMPTY(&rn->lsp)) { lde_send_notification(ln->peerid, S_NO_ROUTE, map->messageid, MSG_TYPE_LABELREQUEST); return; } + /* LRq.3: is MsgSource the next hop? */ LIST_FOREACH(rl, &rn->lsp, entry) { if (lde_address_find(ln, &rl->nexthop)) { lde_send_notification(ln->peerid, S_LOOP_DETECTED, map->messageid, MSG_TYPE_LABELREQUEST); return; } - - if (rl->remote_label != NO_LABEL) - break; } - /* first check if we have a pending request running */ + /* LRq.6: first check if we have a pending request running */ lre = (struct lde_req *)fec_find(&ln->recv_req, &rn->fec); if (lre != NULL) + /* LRq.7: duplicate request */ return; - /* else record label request */ + + /* LRq.8: record label request */ lre = lde_req_add(ln, &rn->fec, 0); if (lre != NULL) lre->msgid = map->messageid; - /* there is a valid mapping available */ - if (rl != NULL) { - /* TODO loop protection handling (LRq.9) */ - lde_send_labelmapping(ln, rn); - return; - } + /* LRq.9: perform LSR label distribution */ + lde_send_labelmapping(ln, rn); + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); - /* no mapping available, try to request */ - /* XXX depending on the request behaviour we could return here */ - LIST_FOREACH(rl, &rn->lsp, entry) { - lnn = lde_find_address(rl->nexthop); - if (lnn == NULL) - continue; - lde_send_labelrequest(lnn, rn); - } + /* + * LRq.10: do nothing (Request Never) since we use liberal + * label retention. + * LRq.11 - 12 are unnecessary since we are merging capable. + */ } void lde_check_release(struct map *map, struct lde_nbr *ln) { - struct rt_node *rn; - struct lde_req *lre; - struct lde_map *me; - - log_debug("label release from nbr %s, FEC %s", - inet_ntoa(ln->id), log_fec(map)); + struct rt_node *rn; + struct lde_wdraw *lw; + struct lde_map *me; rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, map->prefixlen); + /* LRl.1: does FEC match a known FEC? */ if (rn == NULL) return; - /* first check if we have a pending withdraw running */ - lre = (struct lde_req *)fec_find(&ln->sent_wdraw, &rn->fec); - if (lre) { - fec_remove(&ln->sent_wdraw, &lre->fec); - free(lre); + /* LRl.3: first check if we have a pending withdraw running */ + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &rn->fec); + if (lw && (map->label == NO_LABEL || + (lw->label != NO_LABEL && map->label == lw->label))) { + /* LRl.4: delete record of outstanding label withdraw */ + lde_wdraw_del(ln, lw); } - /* check sent map list and remove it if available */ + /* LRl.6: check sent map list and remove it if available */ me = (struct lde_map *)fec_find(&ln->sent_map, &rn->fec); - if (me) + if (me && (map->label == NO_LABEL || map->label == me->label)) lde_map_del(ln, me, 1); - /* remove FEC if not in use anymore */ - /* XXX what about outstanding label requests? */ - if (!LIST_EMPTY(&rn->upstream)) - return; + /* + * LRl.11 - 13 are unnecessary since we remove the label from + * forwarding/switching as soon as the FEC is unreachable. + */ +} + +void +lde_check_release_wcard(struct map *map, struct lde_nbr *ln) +{ + struct fec *f; + struct rt_node *rn; + struct lde_wdraw *lw; + struct lde_map *me; - /* XXX if originated here free all resources */ - /* else decide if a label release should be forwarded. */ - /* Since we do liberal retention we can keep the path mapped. */ + RB_FOREACH(f, fec_tree, &rt) { + rn = (struct rt_node *)f; + + /* LRl.3: first check if we have a pending withdraw running */ + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &rn->fec); + if (lw && (map->label == NO_LABEL || + (lw->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, &rn->fec); + if (me && + (map->label == NO_LABEL || map->label == me->label)) { + lde_map_del(ln, me, 1); + } + + /* + * LRl.11 - 13 are unnecessary since we remove the label from + * forwarding/switching as soon as the FEC is unreachable. + */ + } } void @@ -527,37 +580,58 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) struct rt_lsp *rl; struct lde_map *me; - log_debug("label withdraw from nbr %s, FEC %s", - inet_ntoa(ln->id), log_fec(map)); - rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, map->prefixlen); - - lde_send_labelrelease(ln, rn, map->label); - if (rn == NULL) - /* LSP not available, nothing to do */ - return; + rn = rt_add(map->prefix, map->prefixlen); - /* remove LSP from kernel */ + /* LWd.1: remove label from forwarding/switching use */ LIST_FOREACH(rl, &rn->lsp, entry) { - if (lde_address_find(ln, &rl->nexthop)) - break; - } - if (rl) { - rl->remote_label = NO_LABEL; - lde_send_delete_klabel(rn, rl); + if (lde_address_find(ln, &rl->nexthop)) { + lde_send_delete_klabel(rn, rl); + rl->remote_label = NO_LABEL; + } } - /* check recv map list and remove it if available */ + /* LWd.2: send label release */ + lde_send_labelrelease(ln, rn, map->label); + + /* LWd.3: check previously received label mapping */ me = (struct lde_map *)fec_find(&ln->recv_map, &rn->fec); - if (me) + if (me && (map->label == NO_LABEL || map->label == me->label)) + /* LWd.4: remove record of previously received lbl mapping */ lde_map_del(ln, me, 0); +} - /* if ordered distribution */ - /* walk over upstream list and send withdraws for LSP that depend on - * the removed LSP */ +void +lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) +{ + struct fec *f; + struct rt_node *rn; + struct rt_lsp *rl; + struct lde_map *me; + + /* LWd.2: send label release */ + lde_send_labelrelease(ln, NULL, map->label); - /* if independent distribution and adv on demand */ - /* Generate Event: Recognize New FEC for FEC. */ + RB_FOREACH(f, fec_tree, &rt) { + rn = (struct rt_node *)f; + + /* LWd.1: remove label from forwarding/switching use */ + LIST_FOREACH(rl, &rn->lsp, entry) { + if (lde_address_find(ln, &rl->nexthop)) { + lde_send_delete_klabel(rn, rl); + rl->remote_label = NO_LABEL; + } + } + + /* LWd.3: check previously received label mapping */ + me = (struct lde_map *)fec_find(&ln->recv_map, &rn->fec); + if (me && (map->label == NO_LABEL || map->label == me->label)) + /* + * LWd.4: remove record of previously received + * label mapping + */ + lde_map_del(ln, me, 0); + } } diff --git a/usr.sbin/ldpd/ldp.h b/usr.sbin/ldpd/ldp.h index 3a59fb460e9..e1a4480d8d4 100644 --- a/usr.sbin/ldpd/ldp.h +++ b/usr.sbin/ldpd/ldp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldp.h,v 1.17 2015/03/21 18:34:01 renato Exp $ */ +/* $OpenBSD: ldp.h,v 1.18 2015/07/19 20:54:17 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -195,7 +195,8 @@ struct address_list_tlv { #define ADDR_IPV4 0x1 #define ADDR_IPV6 0x2 -#define FEC_ELM_MIN_LEN 4 +#define FEC_ELM_WCARD_LEN 1 +#define FEC_ELM_PREFIX_MIN_LEN 4 #define FEC_WILDCARD 0x01 #define FEC_PREFIX 0x02 #define FEC_IPV4 0x0001 diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h index 31dd4342122..ed600251b57 100644 --- a/usr.sbin/ldpd/ldpd.h +++ b/usr.sbin/ldpd/ldpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.h,v 1.47 2015/07/19 20:50:03 renato Exp $ */ +/* $OpenBSD: ldpd.h,v 1.48 2015/07/19 20:54:17 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -99,6 +99,8 @@ enum imsg_type { IMSG_MAPPING_ADD_END, IMSG_RELEASE_ADD, IMSG_RELEASE_ADD_END, + IMSG_WITHDRAW_ADD, + IMSG_WITHDRAW_ADD_END, IMSG_ADDRESS_ADD, IMSG_ADDRESS_DEL, IMSG_NOTIFICATION_SEND, @@ -160,15 +162,14 @@ TAILQ_HEAD(mapping_head, mapping_entry); struct map { struct in_addr prefix; + u_int8_t prefixlen; u_int32_t label; u_int32_t messageid; u_int32_t requestid; - u_int8_t prefixlen; u_int8_t flags; }; #define F_MAP_WILDCARD 0x01 /* wildcard FEC */ -#define F_MAP_OPTLABEL 0x02 /* optional label present */ -#define F_MAP_REQ_ID 0x04 /* optional request message id present */ +#define F_MAP_REQ_ID 0x02 /* optional request message id present */ struct notify_msg { u_int32_t messageid; diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c index 353060b41ec..d7b4172c760 100644 --- a/usr.sbin/ldpd/ldpe.c +++ b/usr.sbin/ldpd/ldpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.c,v 1.30 2015/03/21 18:32:01 renato Exp $ */ +/* $OpenBSD: ldpe.c,v 1.31 2015/07/19 20:54:17 renato Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -476,6 +476,7 @@ ldpe_dispatch_lde(int fd, short event, void *bula) case IMSG_MAPPING_ADD: case IMSG_RELEASE_ADD: case IMSG_REQUEST_ADD: + case IMSG_WITHDRAW_ADD: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) fatalx("invalid size of map request"); memcpy(&map, imsg.data, sizeof(map)); @@ -499,11 +500,15 @@ ldpe_dispatch_lde(int fd, short event, void *bula) case IMSG_REQUEST_ADD: nbr_mapping_add(nbr, &nbr->request_list, &map); break; + case IMSG_WITHDRAW_ADD: + nbr_mapping_add(nbr, &nbr->withdraw_list, &map); + break; } break; case IMSG_MAPPING_ADD_END: case IMSG_RELEASE_ADD_END: case IMSG_REQUEST_ADD_END: + case IMSG_WITHDRAW_ADD_END: nbr = nbr_find_peerid(imsg.hdr.peerid); if (nbr == NULL) { log_debug("ldpe_dispatch_lde: cannot find " @@ -526,6 +531,10 @@ ldpe_dispatch_lde(int fd, short event, void *bula) send_labelmessage(nbr, MSG_TYPE_LABELREQUEST, &nbr->request_list); break; + case IMSG_WITHDRAW_ADD_END: + send_labelmessage(nbr, MSG_TYPE_LABELWITHDRAW, + &nbr->withdraw_list); + break; } break; case IMSG_NOTIFICATION_SEND: diff --git a/usr.sbin/ldpd/log.c b/usr.sbin/ldpd/log.c index f0a8dd28a74..8a4e1c538b2 100644 --- a/usr.sbin/ldpd/log.c +++ b/usr.sbin/ldpd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.13 2014/11/03 18:44:36 bluhm Exp $ */ +/* $OpenBSD: log.c,v 1.14 2015/07/19 20:54:17 renato Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -288,6 +288,9 @@ log_fec(struct map *map) static char buf[32]; char pstr[32]; + if (map->flags & F_MAP_WILDCARD) + return ("wildcard"); + if (snprintf(buf, sizeof(buf), "%s/%u", inet_ntop(AF_INET, &map->prefix, pstr, sizeof(pstr)), map->prefixlen) == -1) |