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 switch (policy
->endpoint
.ipa_type
) {
121 stream_putw(s
, AF_INET
);
122 stream_putc(s
, IPV4_MAX_BITLEN
);
123 stream_put_in_addr(s
, &policy
->endpoint
.ipaddr_v4
);
126 stream_putw(s
, AF_INET6
);
127 stream_putc(s
, IPV6_MAX_BITLEN
);
128 stream_put(s
, &policy
->endpoint
.ipaddr_v6
, IPV6_MAX_BYTELEN
);
131 flog_warn(EC_LIB_DEVELOPMENT
,
132 "%s: unknown policy endpoint address family: %u",
133 __func__
, policy
->endpoint
.ipa_type
);
136 stream_putl(s
, policy
->color
);
139 frr_each (nhlfe_list_const
, &policy
->lsp
->nhlfe_list
, nhlfe
) {
140 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)
141 || CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
))
145 stream_putc(s
, re_type_from_lsp_type(nhlfe
->type
));
146 stream_putw(s
, 0); /* instance - not available */
147 stream_putc(s
, nhlfe
->distance
);
148 stream_putl(s
, 0); /* metric - not available */
149 nump
= stream_get_endp(s
);
153 zapi_nexthop_from_nexthop(&znh
, nhlfe
->nexthop
);
154 ret
= zapi_nexthop_encode(s
, &znh
, 0, message
);
160 stream_putc_at(s
, nump
, num
);
161 stream_putw_at(s
, 0, stream_get_endp(s
));
163 client
->nh_last_upd_time
= monotime(NULL
);
164 return zserv_send_message(client
, s
);
172 static void zebra_sr_policy_notify_update(struct zebra_sr_policy
*policy
)
175 struct prefix p
= {};
176 struct zebra_vrf
*zvrf
;
177 struct listnode
*node
;
178 struct zserv
*client
;
181 switch (policy
->endpoint
.ipa_type
) {
184 p
.prefixlen
= IPV4_MAX_BITLEN
;
185 p
.u
.prefix4
= policy
->endpoint
.ipaddr_v4
;
189 p
.prefixlen
= IPV6_MAX_BITLEN
;
190 p
.u
.prefix6
= policy
->endpoint
.ipaddr_v6
;
193 flog_warn(EC_LIB_DEVELOPMENT
,
194 "%s: unknown policy endpoint address family: %u",
195 __func__
, policy
->endpoint
.ipa_type
);
199 rnh
= zebra_lookup_rnh(&p
, zvrf_id(zvrf
), RNH_NEXTHOP_TYPE
);
203 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
)) {
204 if (policy
->status
== ZEBRA_SR_POLICY_UP
)
205 zebra_sr_policy_notify_update_client(policy
, client
);
207 /* Fallback to the IGP shortest path. */
208 zebra_send_rnh_update(rnh
, client
, RNH_NEXTHOP_TYPE
,
209 zvrf_id(zvrf
), policy
->color
);
213 static void zebra_sr_policy_activate(struct zebra_sr_policy
*policy
,
214 struct zebra_lsp
*lsp
)
216 policy
->status
= ZEBRA_SR_POLICY_UP
;
218 (void)zebra_sr_policy_bsid_install(policy
);
219 zsend_sr_policy_notify_status(policy
->color
, &policy
->endpoint
,
220 policy
->name
, ZEBRA_SR_POLICY_UP
);
221 zebra_sr_policy_notify_update(policy
);
224 static void zebra_sr_policy_update(struct zebra_sr_policy
*policy
,
225 struct zebra_lsp
*lsp
,
226 struct zapi_srte_tunnel
*old_tunnel
)
229 bool segment_list_changed
;
234 policy
->segment_list
.local_label
!= old_tunnel
->local_label
;
235 segment_list_changed
=
236 policy
->segment_list
.label_num
!= old_tunnel
->label_num
237 || memcmp(policy
->segment_list
.labels
, old_tunnel
->labels
,
239 * policy
->segment_list
.label_num
);
241 /* Re-install label stack if necessary. */
242 if (bsid_changed
|| segment_list_changed
) {
243 zebra_sr_policy_bsid_uninstall(policy
, old_tunnel
->local_label
);
244 (void)zebra_sr_policy_bsid_install(policy
);
247 zsend_sr_policy_notify_status(policy
->color
, &policy
->endpoint
,
248 policy
->name
, ZEBRA_SR_POLICY_UP
);
250 /* Handle segment-list update. */
251 if (segment_list_changed
)
252 zebra_sr_policy_notify_update(policy
);
255 static void zebra_sr_policy_deactivate(struct zebra_sr_policy
*policy
)
257 policy
->status
= ZEBRA_SR_POLICY_DOWN
;
259 zebra_sr_policy_bsid_uninstall(policy
,
260 policy
->segment_list
.local_label
);
261 zsend_sr_policy_notify_status(policy
->color
, &policy
->endpoint
,
262 policy
->name
, ZEBRA_SR_POLICY_DOWN
);
263 zebra_sr_policy_notify_update(policy
);
266 int zebra_sr_policy_validate(struct zebra_sr_policy
*policy
,
267 struct zapi_srte_tunnel
*new_tunnel
)
269 struct zapi_srte_tunnel old_tunnel
= policy
->segment_list
;
270 struct zebra_lsp
*lsp
;
273 policy
->segment_list
= *new_tunnel
;
275 /* Try to resolve the Binding-SID nexthops. */
276 lsp
= mpls_lsp_find(policy
->zvrf
, policy
->segment_list
.labels
[0]);
277 if (!lsp
|| !lsp
->best_nhlfe
278 || lsp
->addr_family
!= ipaddr_family(&policy
->endpoint
)) {
279 if (policy
->status
== ZEBRA_SR_POLICY_UP
)
280 zebra_sr_policy_deactivate(policy
);
284 /* First label was resolved successfully. */
285 if (policy
->status
== ZEBRA_SR_POLICY_DOWN
)
286 zebra_sr_policy_activate(policy
, lsp
);
288 zebra_sr_policy_update(policy
, lsp
, &old_tunnel
);
293 int zebra_sr_policy_bsid_install(struct zebra_sr_policy
*policy
)
295 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
296 struct zebra_nhlfe
*nhlfe
;
298 if (zt
->local_label
== MPLS_LABEL_NONE
)
301 frr_each_safe (nhlfe_list
, &policy
->lsp
->nhlfe_list
, nhlfe
) {
302 uint8_t num_out_labels
;
303 mpls_label_t
*out_labels
;
304 mpls_label_t null_label
= MPLS_LABEL_IMPLICIT_NULL
;
306 if (!CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)
307 || CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_DELETED
))
311 * Don't push the first SID if the corresponding action in the
314 if (!nhlfe
->nexthop
->nh_label
315 || !nhlfe
->nexthop
->nh_label
->num_labels
316 || nhlfe
->nexthop
->nh_label
->label
[0]
317 == MPLS_LABEL_IMPLICIT_NULL
) {
318 if (zt
->label_num
> 1) {
319 num_out_labels
= zt
->label_num
- 1;
320 out_labels
= &zt
->labels
[1];
323 out_labels
= &null_label
;
326 num_out_labels
= zt
->label_num
;
327 out_labels
= zt
->labels
;
330 if (mpls_lsp_install(
331 policy
->zvrf
, zt
->type
, zt
->local_label
,
332 num_out_labels
, out_labels
, nhlfe
->nexthop
->type
,
333 &nhlfe
->nexthop
->gate
, nhlfe
->nexthop
->ifindex
)
341 void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy
*policy
,
342 mpls_label_t old_bsid
)
344 struct zapi_srte_tunnel
*zt
= &policy
->segment_list
;
346 mpls_lsp_uninstall_all_vrf(policy
->zvrf
, zt
->type
, old_bsid
);
349 int zebra_sr_policy_label_update(mpls_label_t label
,
350 enum zebra_sr_policy_update_label_mode mode
)
352 struct zebra_sr_policy
*policy
;
354 RB_FOREACH (policy
, zebra_sr_policy_instance_head
,
355 &zebra_sr_policy_instances
) {
356 mpls_label_t next_hop_label
;
358 next_hop_label
= policy
->segment_list
.labels
[0];
359 if (next_hop_label
!= label
)
363 case ZEBRA_SR_POLICY_LABEL_CREATED
:
364 case ZEBRA_SR_POLICY_LABEL_UPDATED
:
365 case ZEBRA_SR_POLICY_LABEL_REMOVED
:
366 zebra_sr_policy_validate(policy
, NULL
);
374 void zebra_srte_init(void)