]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_srte.c
lib: msg: refactor common connection code from mgmtd
[mirror_frr.git] / zebra / zebra_srte.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
31f937fb
SM
2/* Zebra SR-TE code
3 * Copyright (C) 2020 NetDEF, Inc.
31f937fb
SM
4 */
5
6#include <zebra.h>
7
8#include "lib/zclient.h"
9#include "lib/lib_errors.h"
10
11#include "zebra/zebra_srte.h"
31f937fb
SM
12#include "zebra/zebra_mpls.h"
13#include "zebra/zebra_rnh.h"
14#include "zebra/zapi_msg.h"
15
bf8d3d6a 16DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy");
31f937fb
SM
17
18static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
19
20/* Generate rb-tree of SR Policy instances. */
21static inline int
22zebra_sr_policy_instance_compare(const struct zebra_sr_policy *a,
23 const struct zebra_sr_policy *b)
24{
25 return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
26 b->color);
27}
28RB_GENERATE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
29 zebra_sr_policy_instance_compare)
30
31struct zebra_sr_policy_instance_head zebra_sr_policy_instances =
32 RB_INITIALIZER(&zebra_sr_policy_instances);
33
34struct zebra_sr_policy *zebra_sr_policy_add(uint32_t color,
35 struct ipaddr *endpoint, char *name)
36{
37 struct zebra_sr_policy *policy;
38
39 policy = XCALLOC(MTYPE_ZEBRA_SR_POLICY, sizeof(*policy));
40 policy->color = color;
41 policy->endpoint = *endpoint;
42 strlcpy(policy->name, name, sizeof(policy->name));
43 policy->status = ZEBRA_SR_POLICY_DOWN;
44 RB_INSERT(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
45 policy);
46
47 return policy;
48}
49
50void zebra_sr_policy_del(struct zebra_sr_policy *policy)
51{
52 if (policy->status == ZEBRA_SR_POLICY_UP)
53 zebra_sr_policy_deactivate(policy);
54 RB_REMOVE(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
55 policy);
56 XFREE(MTYPE_ZEBRA_SR_POLICY, policy);
57}
58
59struct zebra_sr_policy *zebra_sr_policy_find(uint32_t color,
60 struct ipaddr *endpoint)
61{
62 struct zebra_sr_policy policy = {};
63
64 policy.color = color;
65 policy.endpoint = *endpoint;
66 return RB_FIND(zebra_sr_policy_instance_head,
67 &zebra_sr_policy_instances, &policy);
68}
69
70struct zebra_sr_policy *zebra_sr_policy_find_by_name(char *name)
71{
72 struct zebra_sr_policy *policy;
73
74 // TODO: create index for policy names
75 RB_FOREACH (policy, zebra_sr_policy_instance_head,
76 &zebra_sr_policy_instances) {
77 if (strcmp(policy->name, name) == 0)
78 return policy;
79 }
80
81 return NULL;
82}
83
84static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
85 struct zserv *client)
86{
f2595bd5 87 const struct zebra_nhlfe *nhlfe;
31f937fb
SM
88 struct stream *s;
89 uint32_t message = 0;
90 unsigned long nump = 0;
91 uint8_t num;
92 struct zapi_nexthop znh;
93 int ret;
94
95 /* Get output stream. */
96 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
97
98 zclient_create_header(s, ZEBRA_NEXTHOP_UPDATE, zvrf_id(policy->zvrf));
99
100 /* Message flags. */
101 SET_FLAG(message, ZAPI_MESSAGE_SRTE);
102 stream_putl(s, message);
103
027db469 104 stream_putw(s, SAFI_UNICAST);
06e4e901
DS
105 /*
106 * The prefix is copied twice because the ZEBRA_NEXTHOP_UPDATE
107 * code was modified to send back both the matched against
108 * as well as the actual matched. There does not appear to
109 * be an equivalent here so just send the same thing twice.
110 */
31f937fb
SM
111 switch (policy->endpoint.ipa_type) {
112 case IPADDR_V4:
06e4e901
DS
113 stream_putw(s, AF_INET);
114 stream_putc(s, IPV4_MAX_BITLEN);
115 stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
31f937fb
SM
116 stream_putw(s, AF_INET);
117 stream_putc(s, IPV4_MAX_BITLEN);
118 stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
119 break;
120 case IPADDR_V6:
06e4e901
DS
121 stream_putw(s, AF_INET6);
122 stream_putc(s, IPV6_MAX_BITLEN);
123 stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
31f937fb
SM
124 stream_putw(s, AF_INET6);
125 stream_putc(s, IPV6_MAX_BITLEN);
126 stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
127 break;
a98701f0 128 case IPADDR_NONE:
31f937fb
SM
129 flog_warn(EC_LIB_DEVELOPMENT,
130 "%s: unknown policy endpoint address family: %u",
131 __func__, policy->endpoint.ipa_type);
132 exit(1);
133 }
134 stream_putl(s, policy->color);
135
136 num = 0;
137 frr_each (nhlfe_list_const, &policy->lsp->nhlfe_list, nhlfe) {
138 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
139 || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
140 continue;
141
142 if (num == 0) {
143 stream_putc(s, re_type_from_lsp_type(nhlfe->type));
144 stream_putw(s, 0); /* instance - not available */
145 stream_putc(s, nhlfe->distance);
146 stream_putl(s, 0); /* metric - not available */
147 nump = stream_get_endp(s);
148 stream_putc(s, 0);
149 }
150
151 zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop);
152 ret = zapi_nexthop_encode(s, &znh, 0, message);
153 if (ret < 0)
154 goto failure;
155
156 num++;
157 }
158 stream_putc_at(s, nump, num);
159 stream_putw_at(s, 0, stream_get_endp(s));
160
161 client->nh_last_upd_time = monotime(NULL);
31f937fb
SM
162 return zserv_send_message(client, s);
163
164failure:
165
166 stream_free(s);
167 return -1;
168}
169
170static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy)
171{
172 struct rnh *rnh;
173 struct prefix p = {};
174 struct zebra_vrf *zvrf;
175 struct listnode *node;
176 struct zserv *client;
177
178 zvrf = policy->zvrf;
179 switch (policy->endpoint.ipa_type) {
180 case IPADDR_V4:
181 p.family = AF_INET;
182 p.prefixlen = IPV4_MAX_BITLEN;
183 p.u.prefix4 = policy->endpoint.ipaddr_v4;
184 break;
185 case IPADDR_V6:
186 p.family = AF_INET6;
187 p.prefixlen = IPV6_MAX_BITLEN;
188 p.u.prefix6 = policy->endpoint.ipaddr_v6;
189 break;
a98701f0 190 case IPADDR_NONE:
31f937fb
SM
191 flog_warn(EC_LIB_DEVELOPMENT,
192 "%s: unknown policy endpoint address family: %u",
193 __func__, policy->endpoint.ipa_type);
194 exit(1);
195 }
196
d597533a 197 rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), SAFI_UNICAST);
31f937fb
SM
198 if (!rnh)
199 return;
200
201 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
202 if (policy->status == ZEBRA_SR_POLICY_UP)
203 zebra_sr_policy_notify_update_client(policy, client);
204 else
205 /* Fallback to the IGP shortest path. */
6071e5e9
DS
206 zebra_send_rnh_update(rnh, client, zvrf_id(zvrf),
207 policy->color);
31f937fb
SM
208 }
209}
210
211static void zebra_sr_policy_activate(struct zebra_sr_policy *policy,
8f74a383 212 struct zebra_lsp *lsp)
31f937fb
SM
213{
214 policy->status = ZEBRA_SR_POLICY_UP;
215 policy->lsp = lsp;
216 (void)zebra_sr_policy_bsid_install(policy);
217 zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
218 policy->name, ZEBRA_SR_POLICY_UP);
219 zebra_sr_policy_notify_update(policy);
220}
221
222static void zebra_sr_policy_update(struct zebra_sr_policy *policy,
8f74a383 223 struct zebra_lsp *lsp,
31f937fb
SM
224 struct zapi_srte_tunnel *old_tunnel)
225{
226 bool bsid_changed;
227 bool segment_list_changed;
228
229 policy->lsp = lsp;
230
231 bsid_changed =
232 policy->segment_list.local_label != old_tunnel->local_label;
233 segment_list_changed =
234 policy->segment_list.label_num != old_tunnel->label_num
235 || memcmp(policy->segment_list.labels, old_tunnel->labels,
236 sizeof(mpls_label_t)
237 * policy->segment_list.label_num);
238
239 /* Re-install label stack if necessary. */
240 if (bsid_changed || segment_list_changed) {
241 zebra_sr_policy_bsid_uninstall(policy, old_tunnel->local_label);
242 (void)zebra_sr_policy_bsid_install(policy);
243 }
244
245 zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
246 policy->name, ZEBRA_SR_POLICY_UP);
247
248 /* Handle segment-list update. */
249 if (segment_list_changed)
250 zebra_sr_policy_notify_update(policy);
251}
252
253static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy)
254{
255 policy->status = ZEBRA_SR_POLICY_DOWN;
256 policy->lsp = NULL;
257 zebra_sr_policy_bsid_uninstall(policy,
258 policy->segment_list.local_label);
259 zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
260 policy->name, ZEBRA_SR_POLICY_DOWN);
261 zebra_sr_policy_notify_update(policy);
262}
263
264int zebra_sr_policy_validate(struct zebra_sr_policy *policy,
265 struct zapi_srte_tunnel *new_tunnel)
266{
267 struct zapi_srte_tunnel old_tunnel = policy->segment_list;
8f74a383 268 struct zebra_lsp *lsp;
31f937fb
SM
269
270 if (new_tunnel)
271 policy->segment_list = *new_tunnel;
272
273 /* Try to resolve the Binding-SID nexthops. */
274 lsp = mpls_lsp_find(policy->zvrf, policy->segment_list.labels[0]);
275 if (!lsp || !lsp->best_nhlfe
276 || lsp->addr_family != ipaddr_family(&policy->endpoint)) {
277 if (policy->status == ZEBRA_SR_POLICY_UP)
278 zebra_sr_policy_deactivate(policy);
279 return -1;
280 }
281
282 /* First label was resolved successfully. */
283 if (policy->status == ZEBRA_SR_POLICY_DOWN)
284 zebra_sr_policy_activate(policy, lsp);
285 else
286 zebra_sr_policy_update(policy, lsp, &old_tunnel);
287
288 return 0;
289}
290
291int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy)
292{
293 struct zapi_srte_tunnel *zt = &policy->segment_list;
f2595bd5 294 struct zebra_nhlfe *nhlfe;
31f937fb
SM
295
296 if (zt->local_label == MPLS_LABEL_NONE)
297 return 0;
298
299 frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list, nhlfe) {
300 uint8_t num_out_labels;
301 mpls_label_t *out_labels;
302 mpls_label_t null_label = MPLS_LABEL_IMPLICIT_NULL;
303
304 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
305 || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
306 continue;
307
308 /*
309 * Don't push the first SID if the corresponding action in the
310 * LFIB is POP.
311 */
312 if (!nhlfe->nexthop->nh_label
313 || !nhlfe->nexthop->nh_label->num_labels
314 || nhlfe->nexthop->nh_label->label[0]
315 == MPLS_LABEL_IMPLICIT_NULL) {
316 if (zt->label_num > 1) {
317 num_out_labels = zt->label_num - 1;
318 out_labels = &zt->labels[1];
319 } else {
320 num_out_labels = 1;
321 out_labels = &null_label;
322 }
323 } else {
324 num_out_labels = zt->label_num;
325 out_labels = zt->labels;
326 }
327
328 if (mpls_lsp_install(
329 policy->zvrf, zt->type, zt->local_label,
330 num_out_labels, out_labels, nhlfe->nexthop->type,
331 &nhlfe->nexthop->gate, nhlfe->nexthop->ifindex)
332 < 0)
333 return -1;
334 }
335
336 return 0;
337}
338
339void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy *policy,
340 mpls_label_t old_bsid)
341{
342 struct zapi_srte_tunnel *zt = &policy->segment_list;
343
344 mpls_lsp_uninstall_all_vrf(policy->zvrf, zt->type, old_bsid);
345}
346
347int zebra_sr_policy_label_update(mpls_label_t label,
348 enum zebra_sr_policy_update_label_mode mode)
349{
350 struct zebra_sr_policy *policy;
351
352 RB_FOREACH (policy, zebra_sr_policy_instance_head,
353 &zebra_sr_policy_instances) {
354 mpls_label_t next_hop_label;
355
356 next_hop_label = policy->segment_list.labels[0];
357 if (next_hop_label != label)
358 continue;
359
360 switch (mode) {
361 case ZEBRA_SR_POLICY_LABEL_CREATED:
362 case ZEBRA_SR_POLICY_LABEL_UPDATED:
363 case ZEBRA_SR_POLICY_LABEL_REMOVED:
364 zebra_sr_policy_validate(policy, NULL);
365 break;
366 }
367 }
368
369 return 0;
370}
371
6082fb42
PG
372static int zebra_srte_client_close_cleanup(struct zserv *client)
373{
374 int sock = client->sock;
22efe557 375 struct zebra_sr_policy *policy, *policy_temp;
6082fb42
PG
376
377 if (!sock)
378 return 0;
379
22efe557
CS
380 RB_FOREACH_SAFE (policy, zebra_sr_policy_instance_head,
381 &zebra_sr_policy_instances, policy_temp) {
6082fb42
PG
382 if (policy->sock == sock)
383 zebra_sr_policy_del(policy);
384 }
385 return 1;
386}
387
31f937fb
SM
388void zebra_srte_init(void)
389{
6082fb42 390 hook_register(zserv_client_close, zebra_srte_client_close_cleanup);
31f937fb 391}