2 * Copyright (C) 2020 NetDEF, Inc.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "ldp_debug.h"
31 struct ldp_rlfa_node_head rlfa_node_tree
;
33 static int ldp_rlfa_client_compare(const struct ldp_rlfa_client
*a
,
34 const struct ldp_rlfa_client
*b
)
36 if (a
->igp
.vrf_id
< b
->igp
.vrf_id
)
38 if (a
->igp
.vrf_id
> b
->igp
.vrf_id
)
41 if (a
->igp
.protocol
< b
->igp
.protocol
)
43 if (a
->igp
.protocol
> b
->igp
.protocol
)
46 if (a
->igp
.isis
.spf
.tree_id
< b
->igp
.isis
.spf
.tree_id
)
48 if (a
->igp
.isis
.spf
.tree_id
> b
->igp
.isis
.spf
.tree_id
)
51 if (a
->igp
.isis
.spf
.level
< b
->igp
.isis
.spf
.level
)
53 if (a
->igp
.isis
.spf
.level
> b
->igp
.isis
.spf
.level
)
58 RB_GENERATE(ldp_rlfa_client_head
, ldp_rlfa_client
, entry
,
59 ldp_rlfa_client_compare
)
61 static int ldp_rlfa_node_compare(const struct ldp_rlfa_node
*a
,
62 const struct ldp_rlfa_node
*b
)
64 if (ntohl(a
->pq_address
.s_addr
) < ntohl(b
->pq_address
.s_addr
))
66 if (ntohl(a
->pq_address
.s_addr
) > ntohl(b
->pq_address
.s_addr
))
69 return prefix_cmp(&a
->destination
, &b
->destination
);
71 RB_GENERATE(ldp_rlfa_node_head
, ldp_rlfa_node
, entry
, ldp_rlfa_node_compare
)
73 struct ldp_rlfa_client
*rlfa_client_new(struct ldp_rlfa_node
*rnode
,
74 struct zapi_rlfa_igp
*igp
)
76 struct ldp_rlfa_client
*rclient
;
78 if ((rclient
= calloc(1, sizeof(*rclient
))) == NULL
)
82 rclient
->node
= rnode
;
83 RB_INSERT(ldp_rlfa_client_head
, &rnode
->clients
, rclient
);
88 void rlfa_client_del(struct ldp_rlfa_client
*rclient
)
90 struct ldp_rlfa_node
*rnode
= rclient
->node
;
92 RB_REMOVE(ldp_rlfa_client_head
, &rnode
->clients
, rclient
);
95 /* Delete RLFA node if it's empty. */
96 if (RB_EMPTY(ldp_rlfa_client_head
, &rnode
->clients
))
100 struct ldp_rlfa_client
*rlfa_client_find(struct ldp_rlfa_node
*rnode
,
101 struct zapi_rlfa_igp
*igp
)
103 struct ldp_rlfa_client rclient
;
106 return RB_FIND(ldp_rlfa_client_head
, &rnode
->clients
, &rclient
);
109 struct ldp_rlfa_node
*rlfa_node_new(const struct prefix
*destination
,
110 struct in_addr pq_address
)
112 struct ldp_rlfa_node
*rnode
;
114 if ((rnode
= calloc(1, sizeof(*rnode
))) == NULL
)
117 rnode
->destination
= *destination
;
118 rnode
->pq_address
= pq_address
;
119 rnode
->pq_label
= MPLS_INVALID_LABEL
;
120 RB_INIT(ldp_rlfa_client_head
, &rnode
->clients
);
121 RB_INSERT(ldp_rlfa_node_head
, &rlfa_node_tree
, rnode
);
126 void rlfa_node_del(struct ldp_rlfa_node
*rnode
)
128 /* Delete RLFA clients. */
129 while (!RB_EMPTY(ldp_rlfa_client_head
, &rnode
->clients
)) {
130 struct ldp_rlfa_client
*rclient
;
132 rclient
= RB_ROOT(ldp_rlfa_client_head
, &rnode
->clients
);
133 rlfa_client_del(rclient
);
136 RB_REMOVE(ldp_rlfa_node_head
, &rlfa_node_tree
, rnode
);
140 struct ldp_rlfa_node
*rlfa_node_find(const struct prefix
*destination
,
141 struct in_addr pq_address
)
143 struct ldp_rlfa_node rnode
= {};
145 rnode
.destination
= *destination
;
146 rnode
.pq_address
= pq_address
;
147 return RB_FIND(ldp_rlfa_node_head
, &rlfa_node_tree
, &rnode
);
150 void lde_rlfa_client_send(struct ldp_rlfa_client
*rclient
)
152 struct ldp_rlfa_node
*rnode
= rclient
->node
;
153 struct zapi_rlfa_response rlfa_labels
= {};
159 /* Fill in inner label (allocated by PQ node). */
160 rlfa_labels
.igp
= rclient
->igp
;
161 rlfa_labels
.destination
= rnode
->destination
;
162 rlfa_labels
.pq_label
= rnode
->pq_label
;
164 /* Fill in outer label(s) (allocated by the nexthop routers). */
165 fec
.type
= FEC_TYPE_IPV4
;
166 fec
.u
.ipv4
.prefix
= rnode
->pq_address
;
167 fec
.u
.ipv4
.prefixlen
= IPV4_MAX_BITLEN
;
168 fn
= (struct fec_node
*)fec_find(&ft
, &fec
);
171 LIST_FOREACH(fnh
, &fn
->nexthops
, entry
) {
172 if (fnh
->remote_label
== NO_LABEL
)
175 rlfa_labels
.nexthops
[i
].family
= fnh
->af
;
178 rlfa_labels
.nexthops
[i
].gate
.ipv4
= fnh
->nexthop
.v4
;
181 rlfa_labels
.nexthops
[i
].gate
.ipv6
= fnh
->nexthop
.v6
;
186 rlfa_labels
.nexthops
[i
].label
= fnh
->remote_label
;
189 rlfa_labels
.nexthop_num
= i
;
191 lde_imsg_compose_parent(IMSG_RLFA_LABELS
, 0, &rlfa_labels
,
192 sizeof(rlfa_labels
));
195 void lde_rlfa_label_update(const struct fec
*fec
)
197 struct ldp_rlfa_node
*rnode
;
199 if (fec
->type
!= FEC_TYPE_IPV4
200 || fec
->u
.ipv4
.prefixlen
!= IPV4_MAX_BITLEN
)
204 * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
205 * that were effectivelly affected by the label update.
207 RB_FOREACH (rnode
, ldp_rlfa_node_head
, &rlfa_node_tree
) {
208 struct ldp_rlfa_client
*rclient
;
210 if (!IPV4_ADDR_SAME(&rnode
->pq_address
, &fec
->u
.ipv4
.prefix
))
213 RB_FOREACH (rclient
, ldp_rlfa_client_head
, &rnode
->clients
)
214 lde_rlfa_client_send(rclient
);
218 void lde_rlfa_check(struct ldp_rlfa_client
*rclient
)
223 union ldpd_addr pq_address
= {};
225 pq_address
.v4
= rclient
->node
->pq_address
;
226 ln
= lde_nbr_find_by_addr(AF_INET
, &pq_address
);
230 lde_prefix2fec(&rclient
->node
->destination
, &fec
);
231 me
= (struct lde_map
*)fec_find(&ln
->recv_map
, &fec
);
235 rclient
->node
->pq_label
= me
->map
.label
;
236 lde_rlfa_client_send(rclient
);
240 * Check if there's any registered RLFA client for this prefix/neighbor (PQ
241 * node) and notify about the updated label.
243 void lde_rlfa_update_clients(struct fec
*fec
, struct lde_nbr
*ln
,
246 struct prefix rlfa_dest
;
247 struct ldp_rlfa_node
*rnode
;
249 lde_fec2prefix(fec
, &rlfa_dest
);
250 rnode
= rlfa_node_find(&rlfa_dest
, ln
->id
);
252 struct ldp_rlfa_client
*rclient
;
254 rnode
->pq_label
= label
;
255 RB_FOREACH (rclient
, ldp_rlfa_client_head
, &rnode
->clients
)
256 lde_rlfa_client_send(rclient
);
258 lde_rlfa_label_update(fec
);
261 void ldpe_rlfa_init(struct ldp_rlfa_client
*rclient
)
264 union ldpd_addr pq_address
= {};
266 pq_address
.v4
= rclient
->node
->pq_address
;
267 tnbr
= tnbr_find(leconf
, AF_INET
, &pq_address
);
269 tnbr
= tnbr_new(AF_INET
, &pq_address
);
271 RB_INSERT(tnbr_head
, &leconf
->tnbr_tree
, tnbr
);
277 void ldpe_rlfa_exit(struct ldp_rlfa_client
*rclient
)
280 union ldpd_addr pq_address
= {};
282 pq_address
.v4
= rclient
->node
->pq_address
;
283 tnbr
= tnbr_find(leconf
, AF_INET
, &pq_address
);
286 tnbr_check(leconf
, tnbr
);