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