1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
13 #include "ldp_debug.h"
18 struct ldp_rlfa_node_head rlfa_node_tree
;
20 static int ldp_rlfa_client_compare(const struct ldp_rlfa_client
*a
,
21 const struct ldp_rlfa_client
*b
)
23 if (a
->igp
.vrf_id
< b
->igp
.vrf_id
)
25 if (a
->igp
.vrf_id
> b
->igp
.vrf_id
)
28 if (a
->igp
.protocol
< b
->igp
.protocol
)
30 if (a
->igp
.protocol
> b
->igp
.protocol
)
33 if (a
->igp
.isis
.spf
.tree_id
< b
->igp
.isis
.spf
.tree_id
)
35 if (a
->igp
.isis
.spf
.tree_id
> b
->igp
.isis
.spf
.tree_id
)
38 if (a
->igp
.isis
.spf
.level
< b
->igp
.isis
.spf
.level
)
40 if (a
->igp
.isis
.spf
.level
> b
->igp
.isis
.spf
.level
)
45 RB_GENERATE(ldp_rlfa_client_head
, ldp_rlfa_client
, entry
,
46 ldp_rlfa_client_compare
)
48 static int ldp_rlfa_node_compare(const struct ldp_rlfa_node
*a
,
49 const struct ldp_rlfa_node
*b
)
51 if (ntohl(a
->pq_address
.s_addr
) < ntohl(b
->pq_address
.s_addr
))
53 if (ntohl(a
->pq_address
.s_addr
) > ntohl(b
->pq_address
.s_addr
))
56 return prefix_cmp(&a
->destination
, &b
->destination
);
58 RB_GENERATE(ldp_rlfa_node_head
, ldp_rlfa_node
, entry
, ldp_rlfa_node_compare
)
60 struct ldp_rlfa_client
*rlfa_client_new(struct ldp_rlfa_node
*rnode
,
61 struct zapi_rlfa_igp
*igp
)
63 struct ldp_rlfa_client
*rclient
;
65 if ((rclient
= calloc(1, sizeof(*rclient
))) == NULL
)
69 rclient
->node
= rnode
;
70 RB_INSERT(ldp_rlfa_client_head
, &rnode
->clients
, rclient
);
75 void rlfa_client_del(struct ldp_rlfa_client
*rclient
)
77 struct ldp_rlfa_node
*rnode
= rclient
->node
;
79 RB_REMOVE(ldp_rlfa_client_head
, &rnode
->clients
, rclient
);
82 /* Delete RLFA node if it's empty. */
83 if (RB_EMPTY(ldp_rlfa_client_head
, &rnode
->clients
))
87 struct ldp_rlfa_client
*rlfa_client_find(struct ldp_rlfa_node
*rnode
,
88 struct zapi_rlfa_igp
*igp
)
90 struct ldp_rlfa_client rclient
;
93 return RB_FIND(ldp_rlfa_client_head
, &rnode
->clients
, &rclient
);
96 struct ldp_rlfa_node
*rlfa_node_new(const struct prefix
*destination
,
97 struct in_addr pq_address
)
99 struct ldp_rlfa_node
*rnode
;
101 if ((rnode
= calloc(1, sizeof(*rnode
))) == NULL
)
104 rnode
->destination
= *destination
;
105 rnode
->pq_address
= pq_address
;
106 rnode
->pq_label
= MPLS_INVALID_LABEL
;
107 RB_INIT(ldp_rlfa_client_head
, &rnode
->clients
);
108 RB_INSERT(ldp_rlfa_node_head
, &rlfa_node_tree
, rnode
);
113 void rlfa_node_del(struct ldp_rlfa_node
*rnode
)
115 /* Delete RLFA clients. */
116 while (!RB_EMPTY(ldp_rlfa_client_head
, &rnode
->clients
)) {
117 struct ldp_rlfa_client
*rclient
;
119 rclient
= RB_ROOT(ldp_rlfa_client_head
, &rnode
->clients
);
120 rlfa_client_del(rclient
);
123 RB_REMOVE(ldp_rlfa_node_head
, &rlfa_node_tree
, rnode
);
127 struct ldp_rlfa_node
*rlfa_node_find(const struct prefix
*destination
,
128 struct in_addr pq_address
)
130 struct ldp_rlfa_node rnode
= {};
132 rnode
.destination
= *destination
;
133 rnode
.pq_address
= pq_address
;
134 return RB_FIND(ldp_rlfa_node_head
, &rlfa_node_tree
, &rnode
);
137 void lde_rlfa_client_send(struct ldp_rlfa_client
*rclient
)
139 struct ldp_rlfa_node
*rnode
= rclient
->node
;
140 struct zapi_rlfa_response rlfa_labels
= {};
146 /* Fill in inner label (allocated by PQ node). */
147 rlfa_labels
.igp
= rclient
->igp
;
148 rlfa_labels
.destination
= rnode
->destination
;
149 rlfa_labels
.pq_label
= rnode
->pq_label
;
151 /* Fill in outer label(s) (allocated by the nexthop routers). */
152 fec
.type
= FEC_TYPE_IPV4
;
153 fec
.u
.ipv4
.prefix
= rnode
->pq_address
;
154 fec
.u
.ipv4
.prefixlen
= IPV4_MAX_BITLEN
;
155 fn
= (struct fec_node
*)fec_find(&ft
, &fec
);
158 LIST_FOREACH(fnh
, &fn
->nexthops
, entry
) {
159 if (fnh
->remote_label
== NO_LABEL
)
162 rlfa_labels
.nexthops
[i
].family
= fnh
->af
;
165 rlfa_labels
.nexthops
[i
].gate
.ipv4
= fnh
->nexthop
.v4
;
168 rlfa_labels
.nexthops
[i
].gate
.ipv6
= fnh
->nexthop
.v6
;
173 rlfa_labels
.nexthops
[i
].label
= fnh
->remote_label
;
176 rlfa_labels
.nexthop_num
= i
;
178 lde_imsg_compose_parent(IMSG_RLFA_LABELS
, 0, &rlfa_labels
,
179 sizeof(rlfa_labels
));
182 void lde_rlfa_label_update(const struct fec
*fec
)
184 struct ldp_rlfa_node
*rnode
;
186 if (fec
->type
!= FEC_TYPE_IPV4
187 || fec
->u
.ipv4
.prefixlen
!= IPV4_MAX_BITLEN
)
191 * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
192 * that were effectivelly affected by the label update.
194 RB_FOREACH (rnode
, ldp_rlfa_node_head
, &rlfa_node_tree
) {
195 struct ldp_rlfa_client
*rclient
;
197 if (!IPV4_ADDR_SAME(&rnode
->pq_address
, &fec
->u
.ipv4
.prefix
))
200 RB_FOREACH (rclient
, ldp_rlfa_client_head
, &rnode
->clients
)
201 lde_rlfa_client_send(rclient
);
205 void lde_rlfa_check(struct ldp_rlfa_client
*rclient
)
210 union ldpd_addr pq_address
= {};
212 pq_address
.v4
= rclient
->node
->pq_address
;
213 ln
= lde_nbr_find_by_addr(AF_INET
, &pq_address
);
217 lde_prefix2fec(&rclient
->node
->destination
, &fec
);
218 me
= (struct lde_map
*)fec_find(&ln
->recv_map
, &fec
);
222 rclient
->node
->pq_label
= me
->map
.label
;
223 lde_rlfa_client_send(rclient
);
227 * Check if there's any registered RLFA client for this prefix/neighbor (PQ
228 * node) and notify about the updated label.
230 void lde_rlfa_update_clients(struct fec
*fec
, struct lde_nbr
*ln
,
233 struct prefix rlfa_dest
;
234 struct ldp_rlfa_node
*rnode
;
236 lde_fec2prefix(fec
, &rlfa_dest
);
237 rnode
= rlfa_node_find(&rlfa_dest
, ln
->id
);
239 struct ldp_rlfa_client
*rclient
;
241 rnode
->pq_label
= label
;
242 RB_FOREACH (rclient
, ldp_rlfa_client_head
, &rnode
->clients
)
243 lde_rlfa_client_send(rclient
);
245 lde_rlfa_label_update(fec
);
248 void ldpe_rlfa_init(struct ldp_rlfa_client
*rclient
)
251 union ldpd_addr pq_address
= {};
253 pq_address
.v4
= rclient
->node
->pq_address
;
254 tnbr
= tnbr_find(leconf
, AF_INET
, &pq_address
);
256 tnbr
= tnbr_new(AF_INET
, &pq_address
);
258 RB_INSERT(tnbr_head
, &leconf
->tnbr_tree
, tnbr
);
264 void ldpe_rlfa_exit(struct ldp_rlfa_client
*rclient
)
267 union ldpd_addr pq_address
= {};
269 pq_address
.v4
= rclient
->node
->pq_address
;
270 tnbr
= tnbr_find(leconf
, AF_INET
, &pq_address
);
273 tnbr_check(leconf
, tnbr
);