1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
8 #include "lib/zclient.h"
9 #include "lib/lib_errors.h"
11 #include "zebra/zebra_srte.h"
12 #include "zebra/zebra_mpls.h"
13 #include "zebra/zebra_rnh.h"
14 #include "zebra/zapi_msg.h"
16 DEFINE_MTYPE_STATIC(ZEBRA
, ZEBRA_SR_POLICY
, "SR Policy");
18 static void zebra_sr_policy_deactivate(struct zebra_sr_policy
*policy
);
20 /* Generate rb-tree of SR Policy instances. */
22 zebra_sr_policy_instance_compare(const struct zebra_sr_policy
*a
,
23 const struct zebra_sr_policy
*b
)
25 return sr_policy_compare(&a
->endpoint
, &b
->endpoint
, a
->color
,
28 RB_GENERATE(zebra_sr_policy_instance_head
, zebra_sr_policy
, entry
,
29 zebra_sr_policy_instance_compare
)
31 struct zebra_sr_policy_instance_head zebra_sr_policy_instances
=
32 RB_INITIALIZER(&zebra_sr_policy_instances
);
34 struct zebra_sr_policy
*zebra_sr_policy_add(uint32_t color
,
35 struct ipaddr
*endpoint
, char *name
)
37 struct zebra_sr_policy
*policy
;
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
,
50 void zebra_sr_policy_del(struct zebra_sr_policy
*policy
)
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
,
56 XFREE(MTYPE_ZEBRA_SR_POLICY
, policy
);
59 struct zebra_sr_policy
*zebra_sr_policy_find(uint32_t color
,
60 struct ipaddr
*endpoint
)
62 struct zebra_sr_policy policy
= {};
65 policy
.endpoint
= *endpoint
;
66 return RB_FIND(zebra_sr_policy_instance_head
,
67 &zebra_sr_policy_instances
, &policy
);
70 struct zebra_sr_policy
*zebra_sr_policy_find_by_name(char *name
)
72 struct zebra_sr_policy
*policy
;
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)
84 static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy
*policy
,
87 const struct zebra_nhlfe
*nhlfe
;
90 unsigned long nump
= 0;
92 struct zapi_nexthop znh
;
95 /* Get output stream. */
96 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
98 zclient_create_header(s
, ZEBRA_NEXTHOP_UPDATE
, zvrf_id(policy
->zvrf
));
101 SET_FLAG(message
, ZAPI_MESSAGE_SRTE
);
102 stream_putl(s
, message
);
104 stream_putw(s
, SAFI_UNICAST
);
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.
111 switch (policy
->endpoint
.ipa_type
) {
113 stream_putw(s
, AF_INET
);
114 stream_putc(s
, IPV4_MAX_BITLEN
);
115 stream_put_in_addr(s
, &policy
->endpoint
.ipaddr_v4
);
116 stream_putw(s
, AF_INET
);
117 stream_putc(s
, IPV4_MAX_BITLEN
);
118 stream_put_in_addr(s
, &policy
->endpoint
.ipaddr_v4
);
121 stream_putw(s
, AF_INET6
);
122 stream_putc(s
, IPV6_MAX_BITLEN
);
123 stream_put(s
, &policy
->endpoint
.ipaddr_v6
, IPV6_MAX_BYTELEN
);
124 stream_putw(s
, AF_INET6
);
125 stream_putc(s
, IPV6_MAX_BITLEN
);
126 stream_put(s
, &policy
->endpoint
.ipaddr_v6
, IPV6_MAX_BYTELEN
);
129 flog_warn(EC_LIB_DEVELOPMENT
,
130 "%s: unknown policy endpoint address family: %u",
131 __func__
, policy
->endpoint
.ipa_type
);
134 stream_putl(s
, policy
->color
);
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
))
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
);
151 zapi_nexthop_from_nexthop(&znh
, nhlfe
->nexthop
);
152 ret
= zapi_nexthop_encode(s
, &znh
, 0, message
);
158 stream_putc_at(s
, nump
, num
);
159 stream_putw_at(s
, 0, stream_get_endp(s
));
161 client
->nh_last_upd_time
= monotime(NULL
);
162 return zserv_send_message(client
, s
);
170 static void zebra_sr_policy_notify_update(struct zebra_sr_policy
*policy
)
173 struct prefix p
= {};
174 struct zebra_vrf
*zvrf
;
175 struct listnode
*node
;
176 struct zserv
*client
;
179 switch (policy
->endpoint
.ipa_type
) {
182 p
.prefixlen
= IPV4_MAX_BITLEN
;
183 p
.u
.prefix4
= policy
->endpoint
.ipaddr_v4
;
187 p
.prefixlen
= IPV6_MAX_BITLEN
;
188 p
.u
.prefix6
= policy
->endpoint
.ipaddr_v6
;
191 flog_warn(EC_LIB_DEVELOPMENT
,
192 "%s: unknown policy endpoint address family: %u",
193 __func__
, policy
->endpoint
.ipa_type
);
197 rnh
= zebra_lookup_rnh(&p
, zvrf_id(zvrf
), SAFI_UNICAST
);
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
);
205 /* Fallback to the IGP shortest path. */
206 zebra_send_rnh_update(rnh
, client
, zvrf_id(zvrf
),
211 static void zebra_sr_policy_activate(struct zebra_sr_policy
*policy
,
212 struct zebra_lsp
*lsp
)
214 policy
->status
= ZEBRA_SR_POLICY_UP
;
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
);
222 static void zebra_sr_policy_update(struct zebra_sr_policy
*policy
,
223 struct zebra_lsp
*lsp
,
224 struct zapi_srte_tunnel
*old_tunnel
)
227 bool segment_list_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
,
237 * policy
->segment_list
.label_num
);
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
);
245 zsend_sr_policy_notify_status(policy
->color
, &policy
->endpoint
,
246 policy
->name
, ZEBRA_SR_POLICY_UP
);
248 /* Handle segment-list update. */
249 if (segment_list_changed
)
250 zebra_sr_policy_notify_update(policy
);
253 static void zebra_sr_policy_deactivate(struct zebra_sr_policy
*policy
)
255 policy
->status
= ZEBRA_SR_POLICY_DOWN
;
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
);
264 int zebra_sr_policy_validate(struct zebra_sr_policy
*policy
,
265 struct zapi_srte_tunnel
*new_tunnel
)
267 struct zapi_srte_tunnel old_tunnel
= policy
->segment_list
;
268 struct zebra_lsp
*lsp
;
271 policy
->segment_list
= *new_tunnel
;
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
);
282 /* First label was resolved successfully. */
283 if (policy
->status
== ZEBRA_SR_POLICY_DOWN
)
284 zebra_sr_policy_activate(policy
, lsp
);
286 zebra_sr_policy_update(policy
, lsp
, &old_tunnel
);
291 int zebra_sr_policy_bsid_install(struct zebra_sr_policy
*policy
)
293 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
294 struct zebra_nhlfe
*nhlfe
;
296 if (zt
->local_label
== MPLS_LABEL_NONE
)
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
;
304 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)
305 || CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
))
309 * Don't push the first SID if the corresponding action in the
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];
321 out_labels
= &null_label
;
324 num_out_labels
= zt
->label_num
;
325 out_labels
= zt
->labels
;
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
)
339 void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy
*policy
,
340 mpls_label_t old_bsid
)
342 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
344 mpls_lsp_uninstall_all_vrf(policy
->zvrf
, zt
->type
, old_bsid
);
347 int zebra_sr_policy_label_update(mpls_label_t label
,
348 enum zebra_sr_policy_update_label_mode mode
)
350 struct zebra_sr_policy
*policy
;
352 RB_FOREACH (policy
, zebra_sr_policy_instance_head
,
353 &zebra_sr_policy_instances
) {
354 mpls_label_t next_hop_label
;
356 next_hop_label
= policy
->segment_list
.labels
[0];
357 if (next_hop_label
!= label
)
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
);
372 static int zebra_srte_client_close_cleanup(struct zserv
*client
)
374 int sock
= client
->sock
;
375 struct zebra_sr_policy
*policy
, *policy_temp
;
380 RB_FOREACH_SAFE (policy
, zebra_sr_policy_instance_head
,
381 &zebra_sr_policy_instances
, policy_temp
) {
382 if (policy
->sock
== sock
)
383 zebra_sr_policy_del(policy
);
388 void zebra_srte_init(void)
390 hook_register(zserv_client_close
, zebra_srte_client_close_cleanup
);