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