diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-06-30 22:15:03 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-06-30 22:15:03 +0000 |
commit | 34931cd02c9f2f36b1c40b7669d8c87152fea6be (patch) | |
tree | 6b2302a9030ce6632bbe048678a4c6e2c9008a60 /usr.sbin/ldpd | |
parent | 43d133ff81055647efc440fd43eb7896003b5d2d (diff) |
Make it possible to store multiple LSP to a FEC. This is another step to
handle multipath routes in MPLS.
Looks good to michele@
Diffstat (limited to 'usr.sbin/ldpd')
-rw-r--r-- | usr.sbin/ldpd/lde.c | 64 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde.h | 18 | ||||
-rw-r--r-- | usr.sbin/ldpd/lde_lib.c | 350 |
3 files changed, 247 insertions, 185 deletions
diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c index 0a87fafa813..58935519ca8 100644 --- a/usr.sbin/ldpd/lde.c +++ b/usr.sbin/ldpd/lde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.c,v 1.19 2010/06/30 05:21:38 claudio Exp $ */ +/* $OpenBSD: lde.c,v 1.20 2010/06/30 22:15:02 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> @@ -431,29 +431,34 @@ lde_assign_label(void) } void -lde_send_change_klabel(struct rt_node *r) +lde_send_change_klabel(struct rt_node *rr, struct rt_lsp *rl) { struct kroute kr; bzero(&kr, sizeof(kr)); - kr.prefix.s_addr = r->fec.prefix.s_addr; - kr.prefixlen = r->fec.prefixlen; - kr.nexthop.s_addr = r->nexthop.s_addr; - kr.local_label = r->local_label; - kr.remote_label = r->remote_label; + kr.prefix.s_addr = rr->fec.prefix.s_addr; + kr.prefixlen = rr->fec.prefixlen; + kr.local_label = rr->local_label; + + kr.nexthop.s_addr = rl->nexthop.s_addr; + kr.remote_label = rl->remote_label; imsg_compose_event(iev_main, IMSG_KLABEL_CHANGE, 0, 0, -1, &kr, sizeof(kr)); } void -lde_send_delete_klabel(struct rt_node *r) +lde_send_delete_klabel(struct rt_node *rr, struct rt_lsp *rl) { struct kroute kr; bzero(&kr, sizeof(kr)); - kr.prefix.s_addr = r->fec.prefix.s_addr; - kr.prefixlen = r->fec.prefixlen; + kr.prefix.s_addr = rr->fec.prefix.s_addr; + kr.prefixlen = rr->fec.prefixlen; + kr.local_label = rr->local_label; + + kr.nexthop.s_addr = rl->nexthop.s_addr; + kr.remote_label = rl->remote_label; imsg_compose_event(iev_main, IMSG_KLABEL_DELETE, 0, 0, -1, &kr, sizeof(kr)); @@ -585,10 +590,11 @@ lde_nbr_clear(void) void lde_nbr_do_mappings(struct rt_node *rn) { + struct map map; struct lde_nbr *ln; struct lde_map *lm; struct lde_req *lr; - struct map map; + struct rt_lsp *rl; map.label = rn->local_label; map.prefix = rn->fec.prefix; @@ -610,9 +616,12 @@ lde_nbr_do_mappings(struct rt_node *rn) if (ldeconf->mode & MODE_DIST_ORDERED) { /* ordered mode needs the downstream path to be * ready before we can send the mapping upstream */ - if (rn->nexthop.s_addr != INADDR_ANY && - rn->remote_label == NO_LABEL) - /* not local FEC but no remote-label, skip */ + LIST_FOREACH(rl, &rn->lsp, entry) { + /* no remote-label, skip */ + if (rl->remote_label == NO_LABEL) + continue; + } + if (rl == NULL) continue; } @@ -642,6 +651,33 @@ lde_nbr_do_mappings(struct rt_node *rn) } } +struct lde_map * +lde_map_add(struct lde_nbr *ln, struct rt_node *rn, int sent) +{ + struct lde_map *me; + + me = calloc(1, sizeof(*me)); + if (me == NULL) + fatal("lde_map_add"); + + me->fec = rn->fec; + me->nexthop = ln; + + if (sent) { + LIST_INSERT_HEAD(&rn->upstream, me, entry); + if (fec_insert(&ln->sent_map, &me->fec)) + log_warnx("failed to add %s/%u to sent map", + inet_ntoa(me->fec.prefix), me->fec.prefixlen); + } else { + LIST_INSERT_HEAD(&rn->downstream, me, entry); + if (fec_insert(&ln->recv_map, &me->fec)) + log_warnx("failed to add %s/%u to recv map", + inet_ntoa(me->fec.prefix), me->fec.prefixlen); + } + + return (me); +} + void lde_map_free(void *ptr) { diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h index 16a09be974c..8bc08c29895 100644 --- a/usr.sbin/ldpd/lde.h +++ b/usr.sbin/ldpd/lde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.h,v 1.14 2010/06/30 05:21:38 claudio Exp $ */ +/* $OpenBSD: lde.h,v 1.15 2010/06/30 22:15:02 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -77,26 +77,31 @@ struct lde_nbr { u_int16_t lspace; }; +struct rt_lsp { + LIST_ENTRY(rt_lsp) entry; + + struct in_addr nexthop; + u_int32_t remote_label; +}; + struct rt_node { struct fec fec; - struct in_addr nexthop; + LIST_HEAD(, rt_lsp) lsp; /* label switching pathes */ LIST_HEAD(, lde_map) downstream; /* recv mappings */ LIST_HEAD(, lde_map) upstream; /* sent mappings */ u_int32_t local_label; - u_int32_t remote_label; u_int16_t lspace; u_int8_t flags; - u_int8_t present; /* Is it present in fib? */ }; /* lde.c */ pid_t lde(struct ldpd_conf *, int [2], int [2], int [2]); int lde_imsg_compose_ldpe(int, u_int32_t, pid_t, void *, u_int16_t); u_int32_t lde_assign_label(void); -void lde_send_change_klabel(struct rt_node *); -void lde_send_delete_klabel(struct rt_node *); +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(u_int32_t, struct map *); void lde_send_labelrequest(u_int32_t, struct map *); void lde_send_labelrelease(u_int32_t, struct map *); @@ -105,6 +110,7 @@ void lde_send_notification(u_int32_t, u_int32_t, u_int32_t, void lde_nbr_del(struct lde_nbr *); void lde_nbr_do_mappings(struct rt_node *); +struct lde_map *lde_map_add(struct lde_nbr *, struct rt_node *, int); struct lde_nbr *lde_find_address(struct in_addr); diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c index 3b4051a39fe..cc4be767118 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.23 2010/06/30 05:21:38 claudio Exp $ */ +/* $OpenBSD: lde_lib.c,v 1.24 2010/06/30 22:15:02 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -40,6 +40,12 @@ static int fec_compare(struct fec *, struct fec *); +void rt_free(void *); +struct rt_node *rt_add(struct in_addr, u_int8_t); +struct rt_lsp *rt_lsp_find(struct rt_node *, struct in_addr); +struct rt_lsp *rt_lsp_add(struct rt_node *, struct in_addr); +void rt_lsp_del(struct rt_lsp *); + RB_PROTOTYPE(fec_tree, fec, entry, fec_compare) RB_GENERATE(fec_tree, fec, entry, fec_compare) @@ -118,34 +124,48 @@ fec_clear(struct fec_tree *fh, void (*free_cb)(void *)) } +/* routing table functions */ void rt_dump(pid_t pid) { struct fec *f; - struct rt_node *r; + struct rt_node *rr; + struct rt_lsp *rl; + struct lde_map *me; static struct ctl_rt rtctl; RB_FOREACH(f, fec_tree, &rt) { - r = (struct rt_node *)f; - rtctl.prefix.s_addr = r->fec.prefix.s_addr; - rtctl.prefixlen = r->fec.prefixlen; - rtctl.nexthop.s_addr = r->nexthop.s_addr; - rtctl.flags = r->flags; - rtctl.local_label = r->local_label; - rtctl.remote_label = r->remote_label; - - if (!r->present) - rtctl.in_use = 0; - else + rr = (struct rt_node *)f; + rtctl.prefix = rr->fec.prefix; + rtctl.prefixlen = rr->fec.prefixlen; + rtctl.flags = rr->flags; + rtctl.local_label = rr->local_label; + + LIST_FOREACH(rl, &rr->lsp, entry) { + rtctl.nexthop = rl->nexthop; + rtctl.remote_label = rl->remote_label; rtctl.in_use = 1; - if (rtctl.nexthop.s_addr == htonl(INADDR_LOOPBACK)) - rtctl.connected = 1; - else - rtctl.connected = 0; + if (rtctl.nexthop.s_addr == htonl(INADDR_ANY)) + rtctl.connected = 1; + else + rtctl.connected = 0; - lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, &rtctl, - sizeof(rtctl)); + lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, + &rtctl, sizeof(rtctl)); + } + if (LIST_EMPTY(&rr->lsp)) { + LIST_FOREACH(me, &rr->downstream, entry) { + rtctl.in_use = 0; + rtctl.connected = 0; + /* we don't know the nexthop use id instead */ + rtctl.nexthop = me->nexthop->id; + rtctl.remote_label = me->label; + + lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, + &rtctl, sizeof(rtctl)); + } + } } } @@ -169,15 +189,94 @@ rt_snap(u_int32_t peerid) } void +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); + } + + if (!LIST_EMPTY(&rr->downstream)) + log_warnx("rt_free: fec %s/%u downstream list not empty", + inet_ntoa(rr->fec.prefix), rr->fec.prefixlen); + if (!LIST_EMPTY(&rr->upstream)) + log_warnx("rt_free: fec %s/%u upstream list not empty", + inet_ntoa(rr->fec.prefix), rr->fec.prefixlen); + + free(rl); +} + +void rt_clear(void) { - fec_clear(&rt, free); + fec_clear(&rt, rt_free); +} + +struct rt_node * +rt_add(struct in_addr prefix, u_int8_t prefixlen) +{ + struct rt_node *rn; + + rn = calloc(1, sizeof(*rn)); + if (rn == NULL) + fatal("rt_add"); + + rn->fec.prefix.s_addr = prefix.s_addr; + rn->fec.prefixlen = prefixlen; + rn->local_label = NO_LABEL; + LIST_INIT(&rn->upstream); + LIST_INIT(&rn->downstream); + LIST_INIT(&rn->lsp); + + if (fec_insert(&rt, &rn->fec)) + log_warnx("failed to add %s/%u to rt tree", + inet_ntoa(rn->fec.prefix), rn->fec.prefixlen); + + return (rn); +} + +struct rt_lsp * +rt_lsp_find(struct rt_node *rn, struct in_addr nexthop) +{ + struct rt_lsp *rl; + + LIST_FOREACH(rl, &rn->lsp, entry) + if (rl->nexthop.s_addr == nexthop.s_addr) + return (rl); + return (NULL); +} + +struct rt_lsp * +rt_lsp_add(struct rt_node *rn, struct in_addr nexthop) +{ + struct rt_lsp *rl; + + rl = calloc(1, sizeof(*rl)); + if (rl == NULL) + fatal("rt_lsp_add"); + + rl->nexthop.s_addr = nexthop.s_addr; + rl->remote_label = NO_LABEL; + LIST_INSERT_HEAD(&rn->lsp, rl, entry); + + return (rl); +} + +void +rt_lsp_del(struct rt_lsp *rl) +{ + LIST_REMOVE(rl, entry); + free(rl); } void lde_kernel_insert(struct kroute *kr) { struct rt_node *rn; + struct rt_lsp *rl; struct lde_nbr_address *addr; struct lde_map *map; @@ -186,56 +285,12 @@ lde_kernel_insert(struct kroute *kr) rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, kr->prefixlen); - if (rn == NULL) { - rn = calloc(1, sizeof(*rn)); - if (rn == NULL) - fatal("lde_insert"); - - rn->fec.prefix.s_addr = kr->prefix.s_addr; - rn->fec.prefixlen = kr->prefixlen; - rn->remote_label = NO_LABEL; - rn->local_label = NO_LABEL; - LIST_INIT(&rn->upstream); - LIST_INIT(&rn->downstream); - - if (fec_insert(&rt, &rn->fec)) - log_warnx("failed to add %s/%u to rt tree", - inet_ntoa(rn->fec.prefix), rn->fec.prefixlen); - } - - if (rn->present) { - if (kr->nexthop.s_addr == rn->nexthop.s_addr) - return; - - /* The nexthop has changed, change also the label associated - with prefix */ - rn->remote_label = NO_LABEL; - rn->nexthop.s_addr = kr->nexthop.s_addr; - - if ((ldeconf->mode & MODE_RET_LIBERAL) == 0) { - /* XXX: we support just liberal retention for now */ - log_warnx("lde_kernel_insert: missing mode"); - return; - } - - LIST_FOREACH(map, &rn->downstream, entry) { - addr = lde_address_find(map->nexthop, &rn->nexthop); - if (addr != NULL) { - rn->remote_label = map->label; - break; - } - } - - log_debug("lde_kernel_insert: prefix %s%u, " - "changing label to %u", inet_ntoa(rn->fec.prefix), - rn->fec.prefixlen, map ? map->label : 0); - - lde_send_change_klabel(rn); - return; - } + if (rn == NULL) + rn = rt_add(kr->prefix, kr->prefixlen); - rn->present = 1; - rn->nexthop.s_addr = kr->nexthop.s_addr; + 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) { @@ -243,24 +298,23 @@ lde_kernel_insert(struct kroute *kr) return; } + if (rn->local_label == NO_LABEL) { + if (kr->nexthop.s_addr == INADDR_ANY) + /* Directly connected route */ + rn->local_label = MPLS_LABEL_IMPLNULL; + else + rn->local_label = lde_assign_label(); + } + LIST_FOREACH(map, &rn->downstream, entry) { - addr = lde_address_find(map->nexthop, &rn->nexthop); + addr = lde_address_find(map->nexthop, &rl->nexthop); if (addr != NULL) { - rn->remote_label = map->label; + rl->remote_label = map->label; break; } } - if (rn->local_label == NO_LABEL) { - /* Directly connected route */ - if (kr->nexthop.s_addr == INADDR_ANY) { - rn->local_label = MPLS_LABEL_IMPLNULL; - rn->nexthop.s_addr = htonl(INADDR_LOOPBACK); - } else - rn->local_label = lde_assign_label(); - } - - lde_send_change_klabel(rn); + lde_send_change_klabel(rn, rl); /* Redistribute the current mapping to every nbr */ lde_nbr_do_mappings(rn); @@ -270,8 +324,7 @@ void lde_kernel_remove(struct kroute *kr) { struct rt_node *rn; - struct lde_map *map; - struct lde_nbr *ln; + struct rt_lsp *rl; log_debug("kernel remove route %s/%u", inet_ntoa(kr->prefix), kr->prefixlen); @@ -279,36 +332,27 @@ lde_kernel_remove(struct kroute *kr) rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, kr->prefixlen); if (rn == NULL) + /* route lost */ return; - if (ldeconf->mode & MODE_RET_LIBERAL) { - ln = lde_find_address(rn->nexthop); - if (ln) { - map = calloc(1, sizeof(*map)); - if (map == NULL) - fatal("lde_kernel_remove"); - - map->label = rn->remote_label; - map->fec = rn->fec; - map->nexthop = ln; - LIST_INSERT_HEAD(&rn->downstream, map, entry); - if (fec_insert(&ln->recv_map, &map->fec)) - log_warnx("failed to add %s/%u to recv map (1)", - inet_ntoa(map->fec.prefix), - map->fec.prefixlen); - } - } + rl = rt_lsp_find(rn, kr->nexthop); + if (rl == NULL) + /* nexthop lost */ - rn->remote_label = NO_LABEL; - rn->nexthop.s_addr = INADDR_ANY; - rn->present = 0; + rt_lsp_del(rl); + + /* XXX handling of total loss of route, withdraw mappings, etc */ + + /* Redistribute the current mapping to every nbr */ + lde_nbr_do_mappings(rn); } void lde_check_mapping(struct map *map, struct lde_nbr *ln) { struct rt_node *rn; - struct lde_nbr_address *addr; + struct rt_lsp *rl; + struct lde_nbr_address *addr = NULL; struct lde_map *me; log_debug("label mapping from nbr %s, FEC %s/%u, label %u", @@ -322,22 +366,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) if (ldeconf->mode & MODE_RET_CONSERVATIVE) return; - rn = calloc(1, sizeof(*rn)); - if (rn == NULL) - fatal("lde_check_mapping"); - - rn->fec.prefix = map->prefix; - rn->fec.prefixlen = map->prefixlen; + rn = rt_add(map->prefix, map->prefixlen); rn->local_label = lde_assign_label(); - rn->remote_label = NO_LABEL; - rn->present = 0; - - LIST_INIT(&rn->upstream); - LIST_INIT(&rn->downstream); - - if (fec_insert(&rt, &rn->fec)) - log_warnx("failed to add %s/%u to rt tree", - inet_ntoa(rn->fec.prefix), rn->fec.prefixlen); } LIST_FOREACH(me, &rn->downstream, entry) { @@ -355,54 +385,34 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) } } - addr = lde_address_find(ln, &rn->nexthop); - if (addr == NULL || !rn->present) { + LIST_FOREACH(rl, &rn->lsp, entry) { + addr = lde_address_find(ln, &rl->nexthop); + if (addr) + break; + } + + if (addr == NULL) { /* route not yet available */ if (ldeconf->mode & MODE_RET_CONSERVATIVE) { lde_send_labelrelease(ln->peerid, map); return; } /* in liberal mode just note the mapping */ - if (me == NULL) { - me = calloc(1, sizeof(*me)); - if (me == NULL) - fatal("lde_check_mapping"); - me->fec = rn->fec; - me->nexthop = ln; - - LIST_INSERT_HEAD(&rn->downstream, me, entry); - if (fec_insert(&ln->recv_map, &me->fec)) - log_warnx("failed to add %s/%u to recv map (2)", - inet_ntoa(me->fec.prefix), - me->fec.prefixlen); - } + if (me == NULL) + me = lde_map_add(ln, rn, 0); me->label = map->label; return; } - rn->remote_label = map->label; - - /* If we are ingress for this LSP install the label */ - if (rn->nexthop.s_addr == INADDR_ANY) - lde_send_change_klabel(rn); + rl->remote_label = map->label; /* Record the mapping from this peer */ - if (me == NULL) { - me = calloc(1, sizeof(*me)); - if (me == NULL) - fatal("lde_check_mapping"); - - me->fec = rn->fec; - me->nexthop = ln; - LIST_INSERT_HEAD(&rn->downstream, me, entry); - if (fec_insert(&ln->recv_map, &me->fec)) - log_warnx("failed to add %s/%u to recv map (3)", - inet_ntoa(me->fec.prefix), me->fec.prefixlen); - } + if (me == NULL) + me = lde_map_add(ln, rn, 0); me->label = map->label; - lde_send_change_klabel(rn); + lde_send_change_klabel(rn, rl); /* Redistribute the current mapping to every nbr */ lde_nbr_do_mappings(rn); @@ -413,6 +423,7 @@ 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; struct map localmap; @@ -421,35 +432,44 @@ lde_check_request(struct map *map, struct lde_nbr *ln) rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, map->prefixlen); - if (rn == NULL || rn->remote_label == NO_LABEL) { + if (rn == NULL) { lde_send_notification(ln->peerid, S_NO_ROUTE, map->messageid, MSG_TYPE_LABELREQUEST); return; } - if (lde_address_find(ln, &rn->nexthop)) { - lde_send_notification(ln->peerid, S_LOOP_DETECTED, - map->messageid, MSG_TYPE_LABELREQUEST); - return; - } - + /* first check if we have a pending request running */ lre = (struct lde_req *)fec_find(&ln->recv_req, &rn->fec); if (lre != NULL) return; - if (rn->nexthop.s_addr == INADDR_ANY || - rn->remote_label != NO_LABEL) { + 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; + } + + /* there is a valid mapping available */ + if (rl != NULL) { bzero(&localmap, sizeof(localmap)); localmap.prefix = map->prefix; localmap.prefixlen = map->prefixlen; localmap.label = rn->local_label; lde_send_labelmapping(ln->peerid, &localmap); - } else { - lnn = lde_find_address(rn->nexthop); + return; + } + + /* no mapping available, try to request */ + LIST_FOREACH(rl, &rn->lsp, entry) { + lnn = lde_find_address(rl->nexthop); if (lnn == NULL) - /* XXX this feels wrong.... */ - return; + continue; lde_send_labelrequest(lnn->peerid, map); |