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 
32 DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy")
33 
34 static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
35 
36 /* Generate rb-tree of SR Policy instances. */
37 static inline int
zebra_sr_policy_instance_compare(const struct zebra_sr_policy * a,const struct zebra_sr_policy * b)38 zebra_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 }
44 RB_GENERATE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
45 	    zebra_sr_policy_instance_compare)
46 
47 struct zebra_sr_policy_instance_head zebra_sr_policy_instances =
48 	RB_INITIALIZER(&zebra_sr_policy_instances);
49 
zebra_sr_policy_add(uint32_t color,struct ipaddr * endpoint,char * name)50 struct 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 
zebra_sr_policy_del(struct zebra_sr_policy * policy)66 void 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 
zebra_sr_policy_find(uint32_t color,struct ipaddr * endpoint)75 struct 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 
zebra_sr_policy_find_by_name(char * name)86 struct 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 
zebra_sr_policy_notify_update_client(struct zebra_sr_policy * policy,struct zserv * client)100 static 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 
168 failure:
169 
170 	stream_free(s);
171 	return -1;
172 }
173 
zebra_sr_policy_notify_update(struct zebra_sr_policy * policy)174 static 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 
zebra_sr_policy_activate(struct zebra_sr_policy * policy,zebra_lsp_t * lsp)215 static 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 
zebra_sr_policy_update(struct zebra_sr_policy * policy,zebra_lsp_t * lsp,struct zapi_srte_tunnel * old_tunnel)226 static 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 
zebra_sr_policy_deactivate(struct zebra_sr_policy * policy)257 static 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 
zebra_sr_policy_validate(struct zebra_sr_policy * policy,struct zapi_srte_tunnel * new_tunnel)268 int 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 
zebra_sr_policy_bsid_install(struct zebra_sr_policy * policy)295 int 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 
zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy * policy,mpls_label_t old_bsid)343 void 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 
zebra_sr_policy_label_update(mpls_label_t label,enum zebra_sr_policy_update_label_mode mode)351 int 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 
zebra_srte_init(void)376 void zebra_srte_init(void)
377 {
378 }
379