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