#include <zebra.h>
#include "ldpd.h"
+#include "ldpe.h"
#include "lde.h"
#include "log.h"
RB_INIT(lde_map_head, &fn->downstream);
LIST_INIT(&fn->nexthops);
+ if (fec->type == FEC_TYPE_PWID)
+ fn->pw_remote_status = PW_FORWARDING;
+
if (fec_insert(&ft, &fn->fec))
log_warnx("failed to add %s to ft tree",
log_fec(&fn->fec));
{
struct fec_node *fn;
struct fec_nh *fnh;
+ struct iface *iface;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
fn->data = data;
fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
- if (fnh == NULL)
+ if (fnh == NULL) {
fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
route_instance);
+ /*
+ * Ordered Control: if not a connected route and not a route
+ * learned over an interface not running LDP and not a PW
+ * then mark to wait until we receive labelmap msg before
+ * installing in kernel and sending to peer
+ */
+ iface = if_lookup(ldeconf, ifindex);
+ if ((ldeconf->flags & F_LDPD_ORDERED_CONTROL) &&
+ !connected && iface != NULL && fec->type != FEC_TYPE_PWID)
+ fnh->flags |= F_FEC_NH_DEFER;
+ }
+
fnh->flags |= F_FEC_NH_NEW;
if (connected)
fnh->flags |= F_FEC_NH_CONNECTED;
struct fec_nh *fnh, *safe;
struct lde_nbr *ln;
struct lde_map *me;
+ struct iface *iface;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
return;
LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) {
- if (fnh->flags & F_FEC_NH_NEW)
+ if (fnh->flags & F_FEC_NH_NEW) {
fnh->flags &= ~F_FEC_NH_NEW;
- else {
+ /*
+ * if LDP configured on interface or a static route
+ * clear flag else treat fec as a connected route
+ */
+ iface = if_lookup(ldeconf,fnh->ifindex);
+ if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC)
+ fnh->flags &=~F_FEC_NH_NO_LDP;
+ else
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ } else {
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
}
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
if (me)
/* FEC.5 */
- lde_check_mapping(&me->map, ln);
+ lde_check_mapping(&me->map, ln, 0);
}
}
}
void
-lde_check_mapping(struct map *map, struct lde_nbr *ln)
+lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
{
struct fec fec;
struct fec_node *fn;
struct lde_req *lre;
struct lde_map *me;
struct l2vpn_pw *pw;
+ bool send_map = false;
lde_map2fec(map, ln->id, &fec);
lde_req_del(ln, lre, 1);
/* RFC 4447 control word and status tlv negotiation */
- if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map))
+ if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map)) {
+ if (rcvd_label_mapping && map->flags & F_MAP_PW_STATUS)
+ fn->pw_remote_status = map->pw_status;
+
return;
+ }
/*
* LMp.3 - LMp.8: loop detection - unnecessary for frame-mode
if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
+ /*
+ * Ordered Control: labelmap msg received from
+ * NH so clear flag and send labelmap msg to
+ * peer
+ */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ send_map = true;
+ fnh->flags &= ~F_FEC_NH_DEFER;
+ }
fnh->remote_label = map->label;
lde_send_change_klabel(fn, fnh);
break;
pw->remote_group = map->fec.pwid.group_id;
if (map->flags & F_MAP_PW_IFMTU)
pw->remote_mtu = map->fec.pwid.ifmtu;
- if (map->flags & F_MAP_PW_STATUS)
+ if (rcvd_label_mapping && map->flags & F_MAP_PW_STATUS) {
pw->remote_status = map->pw_status;
+ fn->pw_remote_status = map->pw_status;
+ }
else
pw->remote_status = PW_FORWARDING;
fnh->remote_label = map->label;
* loop detection. LMp.28 - LMp.30 are unnecessary because we are
* merging capable.
*/
+
+ /*
+ * Ordered Control: just received a labelmap for this fec from NH so
+ * need to send labelmap to all peers
+ * LMp.20 - LMp21 Execute procedure to send Label Mapping
+ */
+ if (send_map && fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
}
void
struct fec_nh *fnh;
struct lde_map *me;
struct l2vpn_pw *pw;
+ struct lde_nbr *lnbr;
/* wildcard label withdraw */
if (map->type == MAP_TYPE_WILDCARD ||
if (me && (map->label == NO_LABEL || map->label == me->map.label))
/* LWd.4: remove record of previously received lbl mapping */
lde_map_del(ln, me, 0);
+
+ /* Ordered Control: additional withdraw steps */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ /* LWd.8: for each neighbor other that src of withdraw msg */
+ RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+ if (ln->peerid == lnbr->peerid)
+ continue;
+
+ /* LWd.9: check if previously sent a label mapping */
+ me = (struct lde_map *)fec_find(&lnbr->sent_map,
+ &fn->fec);
+ /*
+ * LWd.10: does label sent to peer "map" to withdraw
+ * label
+ */
+ if (me)
+ /* LWd.11: send label withdraw */
+ lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+ }
+ }
}
void
struct fec_nh *fnh;
struct lde_map *me;
struct l2vpn_pw *pw;
+ struct lde_nbr *lnbr;
/* LWd.2: send label release */
lde_send_labelrelease(ln, NULL, map, map->label);
* label mapping
*/
lde_map_del(ln, me, 0);
+
+ /* Ordered Control: additional withdraw steps */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ /* LWd.8: for each neighbor other that src of withdraw msg */
+ RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+ if (ln->peerid == lnbr->peerid)
+ continue;
+
+ /* LWd.9: check if previously sent a label mapping */
+ me = (struct lde_map *)fec_find(&lnbr->sent_map,
+ &fn->fec);
+ /*
+ * LWd.10: does label sent to peer "map" to withdraw
+ * label
+ */
+ if (me)
+ /* LWd.11: send label withdraw */
+ lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+ }
+ }
}
}