2 * Copyright (C) 2020 NetDEF, Inc.
4 * This file is part of GNU Zebra.
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
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.
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
23 #include "lib/zclient.h"
24 #include "lib/lib_errors.h"
26 #include "zebra/zebra_srte.h"
27 #include "zebra/zebra_mpls.h"
28 #include "zebra/zebra_rnh.h"
29 #include "zebra/zapi_msg.h"
31 DEFINE_MTYPE_STATIC(ZEBRA
, ZEBRA_SR_POLICY
, "SR Policy");
33 static void zebra_sr_policy_deactivate(struct zebra_sr_policy
*policy
);
35 /* Generate rb-tree of SR Policy instances. */
37 zebra_sr_policy_instance_compare(const struct zebra_sr_policy
*a
,
38 const struct zebra_sr_policy
*b
)
40 return sr_policy_compare(&a
->endpoint
, &b
->endpoint
, a
->color
,
43 RB_GENERATE(zebra_sr_policy_instance_head
, zebra_sr_policy
, entry
,
44 zebra_sr_policy_instance_compare
)
46 struct zebra_sr_policy_instance_head zebra_sr_policy_instances
=
47 RB_INITIALIZER(&zebra_sr_policy_instances
);
49 struct zebra_sr_policy
*zebra_sr_policy_add(uint32_t color
,
50 struct ipaddr
*endpoint
, char *name
)
52 struct zebra_sr_policy
*policy
;
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
,
65 void zebra_sr_policy_del(struct zebra_sr_policy
*policy
)
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
,
71 XFREE(MTYPE_ZEBRA_SR_POLICY
, policy
);
74 struct zebra_sr_policy
*zebra_sr_policy_find(uint32_t color
,
75 struct ipaddr
*endpoint
)
77 struct zebra_sr_policy policy
= {};
80 policy
.endpoint
= *endpoint
;
81 return RB_FIND(zebra_sr_policy_instance_head
,
82 &zebra_sr_policy_instances
, &policy
);
85 struct zebra_sr_policy
*zebra_sr_policy_find_by_name(char *name
)
87 struct zebra_sr_policy
*policy
;
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)
99 static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy
*policy
,
100 struct zserv
*client
)
102 const struct zebra_nhlfe
*nhlfe
;
104 uint32_t message
= 0;
105 unsigned long nump
= 0;
107 struct zapi_nexthop znh
;
110 /* Get output stream. */
111 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
113 zclient_create_header(s
, ZEBRA_NEXTHOP_UPDATE
, zvrf_id(policy
->zvrf
));
116 SET_FLAG(message
, ZAPI_MESSAGE_SRTE
);
117 stream_putl(s
, message
);
119 stream_putw(s
, SAFI_UNICAST
);
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.
126 switch (policy
->endpoint
.ipa_type
) {
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
);
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
);
144 flog_warn(EC_LIB_DEVELOPMENT
,
145 "%s: unknown policy endpoint address family: %u",
146 __func__
, policy
->endpoint
.ipa_type
);
149 stream_putl(s
, policy
->color
);
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
))
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
);
166 zapi_nexthop_from_nexthop(&znh
, nhlfe
->nexthop
);
167 ret
= zapi_nexthop_encode(s
, &znh
, 0, message
);
173 stream_putc_at(s
, nump
, num
);
174 stream_putw_at(s
, 0, stream_get_endp(s
));
176 client
->nh_last_upd_time
= monotime(NULL
);
177 return zserv_send_message(client
, s
);
185 static void zebra_sr_policy_notify_update(struct zebra_sr_policy
*policy
)
188 struct prefix p
= {};
189 struct zebra_vrf
*zvrf
;
190 struct listnode
*node
;
191 struct zserv
*client
;
194 switch (policy
->endpoint
.ipa_type
) {
197 p
.prefixlen
= IPV4_MAX_BITLEN
;
198 p
.u
.prefix4
= policy
->endpoint
.ipaddr_v4
;
202 p
.prefixlen
= IPV6_MAX_BITLEN
;
203 p
.u
.prefix6
= policy
->endpoint
.ipaddr_v6
;
206 flog_warn(EC_LIB_DEVELOPMENT
,
207 "%s: unknown policy endpoint address family: %u",
208 __func__
, policy
->endpoint
.ipa_type
);
212 rnh
= zebra_lookup_rnh(&p
, zvrf_id(zvrf
), SAFI_UNICAST
);
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
);
220 /* Fallback to the IGP shortest path. */
221 zebra_send_rnh_update(rnh
, client
, zvrf_id(zvrf
),
226 static void zebra_sr_policy_activate(struct zebra_sr_policy
*policy
,
227 struct zebra_lsp
*lsp
)
229 policy
->status
= ZEBRA_SR_POLICY_UP
;
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
);
237 static void zebra_sr_policy_update(struct zebra_sr_policy
*policy
,
238 struct zebra_lsp
*lsp
,
239 struct zapi_srte_tunnel
*old_tunnel
)
242 bool segment_list_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
,
252 * policy
->segment_list
.label_num
);
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
);
260 zsend_sr_policy_notify_status(policy
->color
, &policy
->endpoint
,
261 policy
->name
, ZEBRA_SR_POLICY_UP
);
263 /* Handle segment-list update. */
264 if (segment_list_changed
)
265 zebra_sr_policy_notify_update(policy
);
268 static void zebra_sr_policy_deactivate(struct zebra_sr_policy
*policy
)
270 policy
->status
= ZEBRA_SR_POLICY_DOWN
;
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
);
279 int zebra_sr_policy_validate(struct zebra_sr_policy
*policy
,
280 struct zapi_srte_tunnel
*new_tunnel
)
282 struct zapi_srte_tunnel old_tunnel
= policy
->segment_list
;
283 struct zebra_lsp
*lsp
;
286 policy
->segment_list
= *new_tunnel
;
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
);
297 /* First label was resolved successfully. */
298 if (policy
->status
== ZEBRA_SR_POLICY_DOWN
)
299 zebra_sr_policy_activate(policy
, lsp
);
301 zebra_sr_policy_update(policy
, lsp
, &old_tunnel
);
306 int zebra_sr_policy_bsid_install(struct zebra_sr_policy
*policy
)
308 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
309 struct zebra_nhlfe
*nhlfe
;
311 if (zt
->local_label
== MPLS_LABEL_NONE
)
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
;
319 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)
320 || CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
))
324 * Don't push the first SID if the corresponding action in the
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];
336 out_labels
= &null_label
;
339 num_out_labels
= zt
->label_num
;
340 out_labels
= zt
->labels
;
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
)
354 void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy
*policy
,
355 mpls_label_t old_bsid
)
357 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
359 mpls_lsp_uninstall_all_vrf(policy
->zvrf
, zt
->type
, old_bsid
);
362 int zebra_sr_policy_label_update(mpls_label_t label
,
363 enum zebra_sr_policy_update_label_mode mode
)
365 struct zebra_sr_policy
*policy
;
367 RB_FOREACH (policy
, zebra_sr_policy_instance_head
,
368 &zebra_sr_policy_instances
) {
369 mpls_label_t next_hop_label
;
371 next_hop_label
= policy
->segment_list
.labels
[0];
372 if (next_hop_label
!= label
)
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
);
387 void zebra_srte_init(void)