if (adj->source.type == HELLO_TARGETED) {
if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
- adj->source.target->pw_count == 0) {
+ adj->source.target->pw_count == 0 &&
+ adj->source.target->rlfa_count == 0) {
/* remove dynamic targeted neighbor */
tnbr_del(leconf, adj->source.target);
return (0);
tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
{
if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
- tnbr->pw_count == 0) {
+ tnbr->pw_count == 0 && tnbr->rlfa_count == 0) {
tnbr_del(xconf, tnbr);
return (NULL);
}
af = tnbr->af;
holdtime = tnbr_get_hello_holdtime(tnbr);
flags = F_HELLO_TARGETED;
- if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
+ if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count
+ || tnbr->rlfa_count)
flags |= F_HELLO_REQ_TARG;
fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
#include "log.h"
#include "lde.h"
#include "ldp_debug.h"
+#include "rlfa.h"
#include <lib/log.h>
#include "memory.h"
int shut = 0;
struct fec fec;
struct ldp_access *laccess;
+ struct ldp_rlfa_node *rnode, *rntmp;
+ struct ldp_rlfa_client *rclient;
+ struct zapi_rlfa_request *rlfa_req;
+ struct zapi_rlfa_igp *rlfa_igp;
iev->ev_read = NULL;
lde_check_filter_af(AF_INET6, &ldeconf->ipv6,
laccess->name);
break;
+ case IMSG_RLFA_REG:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_rlfa_request)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ rlfa_req = imsg.data;
+ rnode = rlfa_node_find(&rlfa_req->destination,
+ rlfa_req->pq_address);
+ if (!rnode)
+ rnode = rlfa_node_new(&rlfa_req->destination,
+ rlfa_req->pq_address);
+ rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+ if (rclient)
+ /* RLFA already registered - do nothing */
+ break;
+ rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+ lde_rlfa_check(rclient);
+ break;
+ case IMSG_RLFA_UNREG_ALL:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_rlfa_igp)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ rlfa_igp = imsg.data;
+
+ RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+ &rlfa_node_tree, rntmp) {
+ rclient = rlfa_client_find(rnode, rlfa_igp);
+ if (!rclient)
+ continue;
+
+ rlfa_client_del(rclient);
+ }
+ break;
default:
log_debug("%s: unexpected imsg %d", __func__,
imsg.hdr.type);
}
}
+void
+lde_fec2prefix(const struct fec *fec, struct prefix *prefix)
+{
+ memset(prefix, 0, sizeof(*prefix));
+ switch (fec->type) {
+ case FEC_TYPE_IPV4:
+ prefix->family = AF_INET;
+ prefix->u.prefix4 = fec->u.ipv4.prefix;
+ prefix->prefixlen = fec->u.ipv4.prefixlen;
+ break;
+ case FEC_TYPE_IPV6:
+ prefix->family = AF_INET6;
+ prefix->u.prefix6 = fec->u.ipv6.prefix;
+ prefix->prefixlen = fec->u.ipv6.prefixlen;
+ break;
+ default:
+ prefix->family = AF_UNSPEC;
+ break;
+ }
+}
+
+void
+lde_prefix2fec(const struct prefix *prefix, struct fec *fec)
+{
+ memset(fec, 0, sizeof(*fec));
+ switch (prefix->family) {
+ case AF_INET:
+ fec->type = FEC_TYPE_IPV4;
+ fec->u.ipv4.prefix = prefix->u.prefix4;
+ fec->u.ipv4.prefixlen = prefix->prefixlen;
+ break;
+ case AF_INET6:
+ fec->type = FEC_TYPE_IPV6;
+ fec->u.ipv6.prefix = prefix->u.prefix6;
+ fec->u.ipv6.prefixlen = prefix->prefixlen;
+ break;
+ default:
+ fatalx("lde_prefix2fec: unknown af");
+ break;
+ }
+}
+
void
lde_fec2map(struct fec *fec, struct map *map)
{
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ /* Update RLFA clients. */
+ lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
LIST_FOREACH(fnh, &fn->nexthops, entry) {
switch (f->type) {
case FEC_TYPE_IPV4:
void lde_free_label(uint32_t label);
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
void lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
+void lde_fec2prefix(const struct fec *fec, struct prefix *prefix);
+void lde_prefix2fec(const struct prefix *prefix, struct fec *fec);
void lde_fec2map(struct fec *, struct map *);
void lde_map2fec(struct map *, struct in_addr, struct fec *);
void lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
#include "ldpe.h"
#include "lde.h"
#include "log.h"
+#include "rlfa.h"
#include "mpls.h"
break;
}
}
+
+ /* Update RLFA clients. */
+ lde_rlfa_update_clients(&fec, ln, map->label);
+
/* LMp.13 & LMp.16: Record the mapping from this peer */
if (me == NULL)
me = lde_map_add(ln, fn, 0);
fnh->remote_label = NO_LABEL;
}
+ /* Update RLFA clients. */
+ lde_rlfa_update_clients(&fec, ln, MPLS_INVALID_LABEL);
+
/* LWd.2: send label release */
lde_send_labelrelease(ln, fn, NULL, map->label);
fnh->remote_label = NO_LABEL;
}
+ /* Update RLFA clients. */
+ lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
/* LWd.3: check previously received label mapping */
if (me && (map->label == NO_LABEL ||
map->label == me->map.label))
ldp_zebra_opaque_register(void)
{
zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+ zclient_register_opaque(zclient, LDP_RLFA_REGISTER);
+ zclient_register_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
}
static void
ldp_zebra_opaque_unregister(void)
{
zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+ zclient_unregister_opaque(zclient, LDP_RLFA_REGISTER);
+ zclient_unregister_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
}
int
return 0;
}
+int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *rlfa_labels)
+{
+ int ret;
+
+ ret = zclient_send_opaque(zclient, LDP_RLFA_LABELS,
+ (const uint8_t *)rlfa_labels,
+ sizeof(*rlfa_labels));
+ if (ret == ZCLIENT_SEND_FAILURE) {
+ log_warn("failed to send RLFA labels to IGP");
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
{
struct stream *s;
struct zapi_opaque_msg info;
struct ldp_igp_sync_if_state_req state_req;
+ struct zapi_rlfa_igp igp;
+ struct zapi_rlfa_request rlfa;
s = zclient->ibuf;
main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
sizeof(state_req));
break;
+ case LDP_RLFA_REGISTER:
+ STREAM_GET(&rlfa, s, sizeof(rlfa));
+ main_imsg_compose_both(IMSG_RLFA_REG, &rlfa, sizeof(rlfa));
+ break;
+ case LDP_RLFA_UNREGISTER_ALL:
+ STREAM_GET(&igp, s, sizeof(igp));
+ main_imsg_compose_both(IMSG_RLFA_UNREG_ALL, &igp, sizeof(igp));
+ break;
default:
break;
}
struct imsg imsg;
ssize_t n;
int shut = 0;
+ struct zapi_rlfa_response *rlfa_labels;
iev->ev_read = NULL;
fatalx("IMSG_ACL_CHECK imsg with wrong len");
ldp_acl_reply(iev, (struct acl_check *)imsg.data);
break;
+ case IMSG_RLFA_LABELS:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_rlfa_response)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ rlfa_labels = imsg.data;
+ ldp_zebra_send_rlfa_labels(rlfa_labels);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
IMSG_FILTER_UPDATE,
IMSG_NBR_SHUTDOWN,
IMSG_LDP_SYNC_IF_STATE_REQUEST,
- IMSG_LDP_SYNC_IF_STATE_UPDATE
+ IMSG_LDP_SYNC_IF_STATE_UPDATE,
+ IMSG_RLFA_REG,
+ IMSG_RLFA_UNREG_ALL,
+ IMSG_RLFA_LABELS,
};
struct ldpd_init {
union ldpd_addr addr;
int state;
uint16_t pw_count;
+ uint32_t rlfa_count;
uint8_t flags;
QOBJ_FIELDS
};
void ldp_zebra_init(struct thread_master *);
void ldp_zebra_destroy(void);
int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
+int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
+ rlfa_labels);
/* compatibility */
#ifndef __OpenBSD__
#include "control.h"
#include "log.h"
#include "ldp_debug.h"
+#include "rlfa.h"
#include <lib/log.h>
#include "memory.h"
int n, shut = 0;
struct ldp_access *laccess;
struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
-
+ struct ldp_rlfa_node *rnode, *rntmp;
+ struct ldp_rlfa_client *rclient;
+ struct zapi_rlfa_request *rlfa_req;
+ struct zapi_rlfa_igp *rlfa_igp;
+
iev->ev_read = NULL;
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
ldp_sync_if_state_req = imsg.data;
ldp_sync_fsm_state_req(ldp_sync_if_state_req);
break;
+ case IMSG_RLFA_REG:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_rlfa_request)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ rlfa_req = imsg.data;
+
+ rnode = rlfa_node_find(&rlfa_req->destination,
+ rlfa_req->pq_address);
+ if (!rnode)
+ rnode = rlfa_node_new(&rlfa_req->destination,
+ rlfa_req->pq_address);
+ rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+ if (rclient)
+ /* RLFA already registered - do nothing */
+ break;
+ rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+ ldpe_rlfa_init(rclient);
+ break;
+ case IMSG_RLFA_UNREG_ALL:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct zapi_rlfa_igp)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ rlfa_igp = imsg.data;
+
+ RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+ &rlfa_node_tree, rntmp) {
+ rclient = rlfa_client_find(rnode, rlfa_igp);
+ if (!rclient)
+ continue;
+
+ ldpe_rlfa_exit(rclient);
+ rlfa_client_del(rclient);
+ }
+ break;
default:
log_debug("ldpe_dispatch_main: error handling imsg %d",
imsg.hdr.type);
--- /dev/null
+/*
+ * Copyright (C) 2020 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "ldpd.h"
+#include "lde.h"
+#include "ldpe.h"
+#include "log.h"
+#include "ldp_debug.h"
+#include "rlfa.h"
+
+#include <lib/log.h>
+
+struct ldp_rlfa_node_head rlfa_node_tree;
+
+static int ldp_rlfa_client_compare(const struct ldp_rlfa_client *a,
+ const struct ldp_rlfa_client *b)
+{
+ if (a->igp.vrf_id < b->igp.vrf_id)
+ return -1;
+ if (a->igp.vrf_id > b->igp.vrf_id)
+ return 1;
+
+ if (a->igp.protocol < b->igp.protocol)
+ return -1;
+ if (a->igp.protocol > b->igp.protocol)
+ return 1;
+
+ if (a->igp.isis.spf.tree_id < b->igp.isis.spf.tree_id)
+ return -1;
+ if (a->igp.isis.spf.tree_id > b->igp.isis.spf.tree_id)
+ return 1;
+
+ if (a->igp.isis.spf.level < b->igp.isis.spf.level)
+ return -1;
+ if (a->igp.isis.spf.level > b->igp.isis.spf.level)
+ return 1;
+
+ return 0;
+}
+RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+ ldp_rlfa_client_compare)
+
+static int ldp_rlfa_node_compare(const struct ldp_rlfa_node *a,
+ const struct ldp_rlfa_node *b)
+{
+ if (ntohl(a->pq_address.s_addr) < ntohl(b->pq_address.s_addr))
+ return -1;
+ if (ntohl(a->pq_address.s_addr) > ntohl(b->pq_address.s_addr))
+ return 1;
+
+ return prefix_cmp(&a->destination, &b->destination);
+}
+RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
+
+struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+ struct zapi_rlfa_igp *igp)
+{
+ struct ldp_rlfa_client *rclient;
+
+ if ((rclient = calloc(1, sizeof(*rclient))) == NULL)
+ fatal(__func__);
+
+ rclient->igp = *igp;
+ rclient->node = rnode;
+ RB_INSERT(ldp_rlfa_client_head, &rnode->clients, rclient);
+
+ return rclient;
+}
+
+void rlfa_client_del(struct ldp_rlfa_client *rclient)
+{
+ struct ldp_rlfa_node *rnode = rclient->node;
+
+ RB_REMOVE(ldp_rlfa_client_head, &rnode->clients, rclient);
+ free(rclient);
+
+ /* Delete RLFA node if it's empty. */
+ if (RB_EMPTY(ldp_rlfa_client_head, &rnode->clients))
+ rlfa_node_del(rnode);
+}
+
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+ struct zapi_rlfa_igp *igp)
+{
+ struct ldp_rlfa_client rclient;
+
+ rclient.igp = *igp;
+ return RB_FIND(ldp_rlfa_client_head, &rnode->clients, &rclient);
+}
+
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+ struct in_addr pq_address)
+{
+ struct ldp_rlfa_node *rnode;
+
+ if ((rnode = calloc(1, sizeof(*rnode))) == NULL)
+ fatal(__func__);
+
+ rnode->destination = *destination;
+ rnode->pq_address = pq_address;
+ rnode->pq_label = MPLS_INVALID_LABEL;
+ RB_INIT(ldp_rlfa_client_head, &rnode->clients);
+ RB_INSERT(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+
+ return rnode;
+}
+
+void rlfa_node_del(struct ldp_rlfa_node *rnode)
+{
+ /* Delete RLFA clients. */
+ while (!RB_EMPTY(ldp_rlfa_client_head, &rnode->clients)) {
+ struct ldp_rlfa_client *rclient;
+
+ rclient = RB_ROOT(ldp_rlfa_client_head, &rnode->clients);
+ rlfa_client_del(rclient);
+ }
+
+ RB_REMOVE(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+ free(rnode);
+}
+
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+ struct in_addr pq_address)
+{
+ struct ldp_rlfa_node rnode = {};
+
+ rnode.destination = *destination;
+ rnode.pq_address = pq_address;
+ return RB_FIND(ldp_rlfa_node_head, &rlfa_node_tree, &rnode);
+}
+
+void lde_rlfa_client_send(struct ldp_rlfa_client *rclient)
+{
+ struct ldp_rlfa_node *rnode = rclient->node;
+ struct zapi_rlfa_response rlfa_labels = {};
+ struct fec fec;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ int i = 0;
+
+ /* Fill in inner label (allocated by PQ node). */
+ rlfa_labels.igp = rclient->igp;
+ rlfa_labels.destination = rnode->destination;
+ rlfa_labels.pq_label = rnode->pq_label;
+
+ /* Fill in outer label(s) (allocated by the nexthop routers). */
+ fec.type = FEC_TYPE_IPV4;
+ fec.u.ipv4.prefix = rnode->pq_address;
+ fec.u.ipv4.prefixlen = IPV4_MAX_BITLEN;
+ fn = (struct fec_node *)fec_find(&ft, &fec);
+ if (!fn)
+ return;
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ if (fnh->remote_label == NO_LABEL)
+ continue;
+
+ rlfa_labels.nexthops[i].family = fnh->af;
+ switch (fnh->af) {
+ case AF_INET:
+ rlfa_labels.nexthops[i].gate.ipv4 = fnh->nexthop.v4;
+ break;
+ case AF_INET6:
+ rlfa_labels.nexthops[i].gate.ipv6 = fnh->nexthop.v6;
+ break;
+ default:
+ continue;
+ }
+ rlfa_labels.nexthops[i].label = fnh->remote_label;
+ i++;
+ }
+ rlfa_labels.nexthop_num = i;
+
+ lde_imsg_compose_parent(IMSG_RLFA_LABELS, 0, &rlfa_labels,
+ sizeof(rlfa_labels));
+}
+
+void lde_rlfa_label_update(const struct fec *fec)
+{
+ struct ldp_rlfa_node *rnode;
+
+ if (fec->type != FEC_TYPE_IPV4
+ || fec->u.ipv4.prefixlen != IPV4_MAX_BITLEN)
+ return;
+
+ /*
+ * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
+ * that were effectivelly affected by the label update.
+ */
+ RB_FOREACH (rnode, ldp_rlfa_node_head, &rlfa_node_tree) {
+ struct ldp_rlfa_client *rclient;
+
+ if (!IPV4_ADDR_SAME(&rnode->pq_address, &fec->u.ipv4.prefix))
+ continue;
+
+ RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+ lde_rlfa_client_send(rclient);
+ }
+}
+
+void lde_rlfa_check(struct ldp_rlfa_client *rclient)
+{
+ struct lde_nbr *ln;
+ struct lde_map *me;
+ struct fec fec;
+ union ldpd_addr pq_address = {};
+
+ pq_address.v4 = rclient->node->pq_address;
+ ln = lde_nbr_find_by_addr(AF_INET, &pq_address);
+ if (!ln)
+ return;
+
+ lde_prefix2fec(&rclient->node->destination, &fec);
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fec);
+ if (!me)
+ return;
+
+ rclient->node->pq_label = me->map.label;
+ lde_rlfa_client_send(rclient);
+}
+
+/*
+ * Check if there's any registered RLFA client for this prefix/neighbor (PQ
+ * node) and notify about the updated label.
+ */
+void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+ uint32_t label)
+{
+ struct prefix rlfa_dest;
+ struct ldp_rlfa_node *rnode;
+
+ lde_fec2prefix(fec, &rlfa_dest);
+ rnode = rlfa_node_find(&rlfa_dest, ln->id);
+ if (rnode) {
+ struct ldp_rlfa_client *rclient;
+
+ rnode->pq_label = label;
+ RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+ lde_rlfa_client_send(rclient);
+ } else
+ lde_rlfa_label_update(fec);
+}
+
+void ldpe_rlfa_init(struct ldp_rlfa_client *rclient)
+{
+ struct tnbr *tnbr;
+ union ldpd_addr pq_address = {};
+
+ pq_address.v4 = rclient->node->pq_address;
+ tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+ if (tnbr == NULL) {
+ tnbr = tnbr_new(AF_INET, &pq_address);
+ tnbr_update(tnbr);
+ RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
+ }
+
+ tnbr->rlfa_count++;
+}
+
+void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient)
+{
+ struct tnbr *tnbr;
+ union ldpd_addr pq_address = {};
+
+ pq_address.v4 = rclient->node->pq_address;
+ tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+ if (tnbr) {
+ tnbr->rlfa_count--;
+ tnbr_check(leconf, tnbr);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2020 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LDPD_RLFA_H_
+#define _LDPD_RLFA_H_
+
+#include "openbsd-tree.h"
+#include "zclient.h"
+
+struct ldp_rlfa_client {
+ RB_ENTRY(ldp_rlfa_client) entry;
+
+ /* IGP instance data. */
+ struct zapi_rlfa_igp igp;
+
+ /* Backpointer to RLFA node. */
+ struct ldp_rlfa_node *node;
+};
+RB_HEAD(ldp_rlfa_client_head, ldp_rlfa_client);
+RB_PROTOTYPE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+ ldp_rlfa_client_compare);
+
+struct ldp_rlfa_node {
+ RB_ENTRY(ldp_rlfa_node) entry;
+
+ /* Destination prefix. */
+ struct prefix destination;
+
+ /* PQ node address. */
+ struct in_addr pq_address;
+
+ /* RLFA clients. */
+ struct ldp_rlfa_client_head clients;
+
+ /* Label allocated by the PQ node to the RLFA destination. */
+ mpls_label_t pq_label;
+};
+RB_HEAD(ldp_rlfa_node_head, ldp_rlfa_node);
+RB_PROTOTYPE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare);
+
+extern struct ldp_rlfa_node_head rlfa_node_tree;
+
+/* prototypes */
+struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+ struct zapi_rlfa_igp *igp);
+void rlfa_client_del(struct ldp_rlfa_client *rclient);
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+ struct zapi_rlfa_igp *igp);
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+ struct in_addr pq_address);
+void rlfa_node_del(struct ldp_rlfa_node *rnode);
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+ struct in_addr pq_address);
+void lde_rlfa_check(struct ldp_rlfa_client *rclient);
+void lde_rlfa_client_send(struct ldp_rlfa_client *rclient);
+void lde_rlfa_label_update(const struct fec *fec);
+void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+ uint32_t label);
+void ldpe_rlfa_init(struct ldp_rlfa_client *rclient);
+void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient);
+
+#endif /* _LDPD_RLFA_H_ */
ldpd/notification.c \
ldpd/packet.c \
ldpd/pfkey.c \
+ ldpd/rlfa.c \
ldpd/socket.c \
ldpd/util.c \
# end
ldpd/ldpd.h \
ldpd/ldpe.h \
ldpd/log.h \
+ ldpd/rlfa.h \
# end
ldpd_ldpd_SOURCES = ldpd/ldpd.c
uint32_t status;
};
+/* IGP instance data associated to a RLFA. */
+struct zapi_rlfa_igp {
+ vrf_id_t vrf_id;
+ int protocol;
+ union {
+ struct {
+ char area_tag[32];
+ struct {
+ int tree_id;
+ int level;
+ unsigned int run_id;
+ } spf;
+ } isis;
+ };
+};
+
+/* IGP -> LDP RLFA (un)registration message. */
+struct zapi_rlfa_request {
+ /* IGP instance data. */
+ struct zapi_rlfa_igp igp;
+
+ /* Destination prefix. */
+ struct prefix destination;
+
+ /* PQ node address. */
+ struct in_addr pq_address;
+};
+
+/* LDP -> IGP RLFA label update. */
+struct zapi_rlfa_response {
+ /* IGP instance data. */
+ struct zapi_rlfa_igp igp;
+
+ /* Destination prefix. */
+ struct prefix destination;
+
+ /* Resolved LDP labels. */
+ mpls_label_t pq_label;
+ uint16_t nexthop_num;
+ struct {
+ int family;
+ union g_addr gate;
+ mpls_label_t label;
+ } nexthops[MULTIPATH_NUM];
+};
+
enum zapi_route_notify_owner {
ZAPI_ROUTE_FAIL_INSTALL,
ZAPI_ROUTE_BETTER_ADMIN_WON,
LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
/* Announce that LDP is up */
LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
+ /* Register RLFA with LDP */
+ LDP_RLFA_REGISTER = 7,
+ /* Unregister all RLFAs with LDP */
+ LDP_RLFA_UNREGISTER_ALL = 8,
+ /* Announce LDP labels associated to a previously registered RLFA */
+ LDP_RLFA_LABELS = 9,
};
/* Send the hello message.