]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/rlfa.c
697ec08af86102b202b1470e4c342104cf5fe182
[mirror_frr.git] / ldpd / rlfa.c
1 /*
2 * Copyright (C) 2020 NetDEF, Inc.
3 * Renato Westphal
4 *
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)
8 * any later version.
9 *
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
13 * more details.
14 *
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
18 */
19
20 #include <zebra.h>
21
22 #include "ldpd.h"
23 #include "lde.h"
24 #include "ldpe.h"
25 #include "log.h"
26 #include "ldp_debug.h"
27 #include "rlfa.h"
28
29 #include <lib/log.h>
30
31 struct ldp_rlfa_node_head rlfa_node_tree;
32
33 static int ldp_rlfa_client_compare(const struct ldp_rlfa_client *a,
34 const struct ldp_rlfa_client *b)
35 {
36 if (a->igp.vrf_id < b->igp.vrf_id)
37 return -1;
38 if (a->igp.vrf_id > b->igp.vrf_id)
39 return 1;
40
41 if (a->igp.protocol < b->igp.protocol)
42 return -1;
43 if (a->igp.protocol > b->igp.protocol)
44 return 1;
45
46 if (a->igp.isis.spf.tree_id < b->igp.isis.spf.tree_id)
47 return -1;
48 if (a->igp.isis.spf.tree_id > b->igp.isis.spf.tree_id)
49 return 1;
50
51 if (a->igp.isis.spf.level < b->igp.isis.spf.level)
52 return -1;
53 if (a->igp.isis.spf.level > b->igp.isis.spf.level)
54 return 1;
55
56 return 0;
57 }
58 RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
59 ldp_rlfa_client_compare)
60
61 static int ldp_rlfa_node_compare(const struct ldp_rlfa_node *a,
62 const struct ldp_rlfa_node *b)
63 {
64 if (ntohl(a->pq_address.s_addr) < ntohl(b->pq_address.s_addr))
65 return -1;
66 if (ntohl(a->pq_address.s_addr) > ntohl(b->pq_address.s_addr))
67 return 1;
68
69 return prefix_cmp(&a->destination, &b->destination);
70 }
71 RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
72
73 struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
74 struct zapi_rlfa_igp *igp)
75 {
76 struct ldp_rlfa_client *rclient;
77
78 if ((rclient = calloc(1, sizeof(*rclient))) == NULL)
79 fatal(__func__);
80
81 rclient->igp = *igp;
82 rclient->node = rnode;
83 RB_INSERT(ldp_rlfa_client_head, &rnode->clients, rclient);
84
85 return rclient;
86 }
87
88 void rlfa_client_del(struct ldp_rlfa_client *rclient)
89 {
90 struct ldp_rlfa_node *rnode = rclient->node;
91
92 RB_REMOVE(ldp_rlfa_client_head, &rnode->clients, rclient);
93 free(rclient);
94
95 /* Delete RLFA node if it's empty. */
96 if (RB_EMPTY(ldp_rlfa_client_head, &rnode->clients))
97 rlfa_node_del(rnode);
98 }
99
100 struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
101 struct zapi_rlfa_igp *igp)
102 {
103 struct ldp_rlfa_client rclient;
104
105 rclient.igp = *igp;
106 return RB_FIND(ldp_rlfa_client_head, &rnode->clients, &rclient);
107 }
108
109 struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
110 struct in_addr pq_address)
111 {
112 struct ldp_rlfa_node *rnode;
113
114 if ((rnode = calloc(1, sizeof(*rnode))) == NULL)
115 fatal(__func__);
116
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);
122
123 return rnode;
124 }
125
126 void rlfa_node_del(struct ldp_rlfa_node *rnode)
127 {
128 /* Delete RLFA clients. */
129 while (!RB_EMPTY(ldp_rlfa_client_head, &rnode->clients)) {
130 struct ldp_rlfa_client *rclient;
131
132 rclient = RB_ROOT(ldp_rlfa_client_head, &rnode->clients);
133 rlfa_client_del(rclient);
134 }
135
136 RB_REMOVE(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
137 free(rnode);
138 }
139
140 struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
141 struct in_addr pq_address)
142 {
143 struct ldp_rlfa_node rnode = {};
144
145 rnode.destination = *destination;
146 rnode.pq_address = pq_address;
147 return RB_FIND(ldp_rlfa_node_head, &rlfa_node_tree, &rnode);
148 }
149
150 void lde_rlfa_client_send(struct ldp_rlfa_client *rclient)
151 {
152 struct ldp_rlfa_node *rnode = rclient->node;
153 struct zapi_rlfa_response rlfa_labels = {};
154 struct fec fec;
155 struct fec_node *fn;
156 struct fec_nh *fnh;
157 int i = 0;
158
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;
163
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);
169 if (!fn)
170 return;
171 LIST_FOREACH(fnh, &fn->nexthops, entry) {
172 if (fnh->remote_label == NO_LABEL)
173 continue;
174
175 rlfa_labels.nexthops[i].family = fnh->af;
176 switch (fnh->af) {
177 case AF_INET:
178 rlfa_labels.nexthops[i].gate.ipv4 = fnh->nexthop.v4;
179 break;
180 case AF_INET6:
181 rlfa_labels.nexthops[i].gate.ipv6 = fnh->nexthop.v6;
182 break;
183 default:
184 continue;
185 }
186 rlfa_labels.nexthops[i].label = fnh->remote_label;
187 i++;
188 }
189 rlfa_labels.nexthop_num = i;
190
191 lde_imsg_compose_parent(IMSG_RLFA_LABELS, 0, &rlfa_labels,
192 sizeof(rlfa_labels));
193 }
194
195 void lde_rlfa_label_update(const struct fec *fec)
196 {
197 struct ldp_rlfa_node *rnode;
198
199 if (fec->type != FEC_TYPE_IPV4
200 || fec->u.ipv4.prefixlen != IPV4_MAX_BITLEN)
201 return;
202
203 /*
204 * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
205 * that were effectivelly affected by the label update.
206 */
207 RB_FOREACH (rnode, ldp_rlfa_node_head, &rlfa_node_tree) {
208 struct ldp_rlfa_client *rclient;
209
210 if (!IPV4_ADDR_SAME(&rnode->pq_address, &fec->u.ipv4.prefix))
211 continue;
212
213 RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
214 lde_rlfa_client_send(rclient);
215 }
216 }
217
218 void lde_rlfa_check(struct ldp_rlfa_client *rclient)
219 {
220 struct lde_nbr *ln;
221 struct lde_map *me;
222 struct fec fec;
223 union ldpd_addr pq_address = {};
224
225 pq_address.v4 = rclient->node->pq_address;
226 ln = lde_nbr_find_by_addr(AF_INET, &pq_address);
227 if (!ln)
228 return;
229
230 lde_prefix2fec(&rclient->node->destination, &fec);
231 me = (struct lde_map *)fec_find(&ln->recv_map, &fec);
232 if (!me)
233 return;
234
235 rclient->node->pq_label = me->map.label;
236 lde_rlfa_client_send(rclient);
237 }
238
239 /*
240 * Check if there's any registered RLFA client for this prefix/neighbor (PQ
241 * node) and notify about the updated label.
242 */
243 void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
244 uint32_t label)
245 {
246 struct prefix rlfa_dest;
247 struct ldp_rlfa_node *rnode;
248
249 lde_fec2prefix(fec, &rlfa_dest);
250 rnode = rlfa_node_find(&rlfa_dest, ln->id);
251 if (rnode) {
252 struct ldp_rlfa_client *rclient;
253
254 rnode->pq_label = label;
255 RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
256 lde_rlfa_client_send(rclient);
257 } else
258 lde_rlfa_label_update(fec);
259 }
260
261 void ldpe_rlfa_init(struct ldp_rlfa_client *rclient)
262 {
263 struct tnbr *tnbr;
264 union ldpd_addr pq_address = {};
265
266 pq_address.v4 = rclient->node->pq_address;
267 tnbr = tnbr_find(leconf, AF_INET, &pq_address);
268 if (tnbr == NULL) {
269 tnbr = tnbr_new(AF_INET, &pq_address);
270 tnbr_update(tnbr);
271 RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
272 }
273
274 tnbr->rlfa_count++;
275 }
276
277 void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient)
278 {
279 struct tnbr *tnbr;
280 union ldpd_addr pq_address = {};
281
282 pq_address.v4 = rclient->node->pq_address;
283 tnbr = tnbr_find(leconf, AF_INET, &pq_address);
284 if (tnbr) {
285 tnbr->rlfa_count--;
286 tnbr_check(leconf, tnbr);
287 }
288 }