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