diff options
-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) |