]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/rlfa.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / ldpd / rlfa.c
CommitLineData
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
18struct ldp_rlfa_node_head rlfa_node_tree;
19
20static 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}
45RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
46 ldp_rlfa_client_compare)
47
48static 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}
58RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
59
60struct 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
75void 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
87struct 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
96struct 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
113void 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
127struct 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
137void 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
182void 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
205void 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 */
230void 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
248void 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
264void 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}