1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zebra SRv6 definitions
4 * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
5 * Copyright (C) 2020 Masakazu Asama
14 #include "zebra/debug.h"
15 #include "zebra/zapi_msg.h"
16 #include "zebra/zserv.h"
17 #include "zebra/zebra_router.h"
18 #include "zebra/zebra_srv6.h"
19 #include "zebra/zebra_errors.h"
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
33 DEFINE_MGROUP(SRV6_MGR
, "SRv6 Manager");
34 DEFINE_MTYPE_STATIC(SRV6_MGR
, SRV6M_CHUNK
, "SRv6 Manager Chunk");
36 /* define hooks for the basic API, so that it can be specialized or served
40 DEFINE_HOOK(srv6_manager_client_connect
,
41 (struct zserv
*client
, vrf_id_t vrf_id
),
43 DEFINE_HOOK(srv6_manager_client_disconnect
,
44 (struct zserv
*client
), (client
));
45 DEFINE_HOOK(srv6_manager_get_chunk
,
46 (struct srv6_locator
**loc
,
48 const char *locator_name
,
50 (loc
, client
, locator_name
, vrf_id
));
51 DEFINE_HOOK(srv6_manager_release_chunk
,
52 (struct zserv
*client
,
53 const char *locator_name
,
55 (client
, locator_name
, vrf_id
));
57 /* define wrappers to be called in zapi_msg.c (as hooks must be called in
58 * source file where they were defined)
61 void srv6_manager_client_connect_call(struct zserv
*client
, vrf_id_t vrf_id
)
63 hook_call(srv6_manager_client_connect
, client
, vrf_id
);
66 void srv6_manager_get_locator_chunk_call(struct srv6_locator
**loc
,
68 const char *locator_name
,
71 hook_call(srv6_manager_get_chunk
, loc
, client
, locator_name
, vrf_id
);
74 void srv6_manager_release_locator_chunk_call(struct zserv
*client
,
75 const char *locator_name
,
78 hook_call(srv6_manager_release_chunk
, client
, locator_name
, vrf_id
);
81 int srv6_manager_client_disconnect_cb(struct zserv
*client
)
83 hook_call(srv6_manager_client_disconnect
, client
);
87 static int zebra_srv6_cleanup(struct zserv
*client
)
92 void zebra_srv6_locator_add(struct srv6_locator
*locator
)
94 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
95 struct srv6_locator
*tmp
;
96 struct listnode
*node
;
99 tmp
= zebra_srv6_locator_lookup(locator
->name
);
101 listnode_add(srv6
->locators
, locator
);
104 * Notify new locator info to zclients.
106 * The srv6 locators and their prefixes are managed by zserv(zebra).
107 * And an actual configuration the srv6 sid in the srv6 locator is done
108 * by zclient(bgpd, isisd, etc). The configuration of each locator
109 * allocation and specify it by zserv and zclient should be
110 * asynchronous. For that, zclient should be received the event via
111 * ZAPI when a srv6 locator is added on zebra.
112 * Basically, in SRv6, adding/removing SRv6 locators is performed less
113 * frequently than adding rib entries, so a broad to all zclients will
114 * not degrade the overall performance of FRRouting.
116 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
))
117 zsend_zebra_srv6_locator_add(client
, locator
);
120 void zebra_srv6_locator_delete(struct srv6_locator
*locator
)
123 struct srv6_locator_chunk
*c
;
124 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
125 struct zserv
*client
;
128 * Notify deleted locator info to zclients if needed.
130 * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
131 * uses it for its own purpose. For example, in the case of BGP L3VPN,
132 * the SID assigned to vpn unicast rib will be given.
133 * And when the locator is deleted by zserv(zebra), those SIDs need to
134 * be withdrawn. The zclient must initiate the withdrawal of the SIDs
135 * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
136 * owner of each chunk.
138 for (ALL_LIST_ELEMENTS_RO((struct list
*)locator
->chunks
, n
, c
)) {
139 if (c
->proto
== ZEBRA_ROUTE_SYSTEM
)
141 client
= zserv_find_client(c
->proto
, c
->instance
);
144 "%s: Not found zclient(proto=%u, instance=%u).",
145 __func__
, c
->proto
, c
->instance
);
148 zsend_zebra_srv6_locator_delete(client
, locator
);
151 listnode_delete(srv6
->locators
, locator
);
152 srv6_locator_free(locator
);
155 struct srv6_locator
*zebra_srv6_locator_lookup(const char *name
)
157 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
158 struct srv6_locator
*locator
;
159 struct listnode
*node
;
161 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
))
162 if (!strncmp(name
, locator
->name
, SRV6_LOCNAME_SIZE
))
167 void zebra_notify_srv6_locator_add(struct srv6_locator
*locator
)
169 struct listnode
*node
;
170 struct zserv
*client
;
173 * Notify new locator info to zclients.
175 * The srv6 locators and their prefixes are managed by zserv(zebra).
176 * And an actual configuration the srv6 sid in the srv6 locator is done
177 * by zclient(bgpd, isisd, etc). The configuration of each locator
178 * allocation and specify it by zserv and zclient should be
179 * asynchronous. For that, zclient should be received the event via
180 * ZAPI when a srv6 locator is added on zebra.
181 * Basically, in SRv6, adding/removing SRv6 locators is performed less
182 * frequently than adding rib entries, so a broad to all zclients will
183 * not degrade the overall performance of FRRouting.
185 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
))
186 zsend_zebra_srv6_locator_add(client
, locator
);
189 void zebra_notify_srv6_locator_delete(struct srv6_locator
*locator
)
192 struct srv6_locator_chunk
*c
;
193 struct zserv
*client
;
196 * Notify deleted locator info to zclients if needed.
198 * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
199 * uses it for its own purpose. For example, in the case of BGP L3VPN,
200 * the SID assigned to vpn unicast rib will be given.
201 * And when the locator is deleted by zserv(zebra), those SIDs need to
202 * be withdrawn. The zclient must initiate the withdrawal of the SIDs
203 * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
204 * owner of each chunk.
206 for (ALL_LIST_ELEMENTS_RO((struct list
*)locator
->chunks
, n
, c
)) {
207 if (c
->proto
== ZEBRA_ROUTE_SYSTEM
)
209 client
= zserv_find_client(c
->proto
, c
->instance
);
211 zlog_warn("Not found zclient(proto=%u, instance=%u).",
212 c
->proto
, c
->instance
);
215 zsend_zebra_srv6_locator_delete(client
, locator
);
219 struct zebra_srv6
*zebra_srv6_get_default(void)
221 static struct zebra_srv6 srv6
;
222 static bool first_execution
= true;
224 if (first_execution
) {
225 first_execution
= false;
226 srv6
.locators
= list_new();
232 * Core function, assigns srv6-locator chunks
234 * It first searches through the list to check if there's one available
235 * (previously released). Otherwise it creates and assigns a new one
237 * @param proto Daemon protocol of client, to identify the owner
238 * @param instance Instance, to identify the owner
239 * @param session_id SessionID of client
240 * @param name Name of SRv6-locator
241 * @return Pointer to the assigned srv6-locator chunk,
242 * or NULL if the request could not be satisfied
244 static struct srv6_locator
*
245 assign_srv6_locator_chunk(uint8_t proto
,
248 const char *locator_name
)
250 bool chunk_found
= false;
251 struct listnode
*node
= NULL
;
252 struct srv6_locator
*loc
= NULL
;
253 struct srv6_locator_chunk
*chunk
= NULL
;
255 loc
= zebra_srv6_locator_lookup(locator_name
);
257 zlog_info("%s: locator %s was not found",
258 __func__
, locator_name
);
262 for (ALL_LIST_ELEMENTS_RO((struct list
*)loc
->chunks
, node
, chunk
)) {
263 if (chunk
->proto
!= NO_PROTO
&& chunk
->proto
!= proto
)
270 zlog_info("%s: locator is already owned", __func__
);
274 chunk
->proto
= proto
;
275 chunk
->instance
= instance
;
276 chunk
->session_id
= session_id
;
280 static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator
**loc
,
281 struct zserv
*client
,
282 const char *locator_name
,
287 *loc
= assign_srv6_locator_chunk(client
->proto
, client
->instance
,
288 client
->session_id
, locator_name
);
291 zlog_err("Unable to assign locator chunk to %s instance %u",
292 zebra_route_string(client
->proto
), client
->instance
);
293 else if (IS_ZEBRA_DEBUG_PACKET
)
294 zlog_info("Assigned locator chunk %s to %s instance %u",
295 (*loc
)->name
, zebra_route_string(client
->proto
),
298 if (*loc
&& (*loc
)->status_up
)
299 ret
= zsend_srv6_manager_get_locator_chunk_response(client
,
306 * Core function, release no longer used srv6-locator chunks
308 * @param proto Daemon protocol of client, to identify the owner
309 * @param instance Instance, to identify the owner
310 * @param session_id Zclient session ID, to identify the zclient session
311 * @param locator_name SRv6-locator name, to identify the actual locator
312 * @return 0 on success, -1 otherwise
314 static int release_srv6_locator_chunk(uint8_t proto
, uint16_t instance
,
316 const char *locator_name
)
319 struct listnode
*node
;
320 struct srv6_locator_chunk
*chunk
;
321 struct srv6_locator
*loc
= NULL
;
323 loc
= zebra_srv6_locator_lookup(locator_name
);
327 if (IS_ZEBRA_DEBUG_PACKET
)
328 zlog_debug("%s: Releasing srv6-locator on %s", __func__
,
331 for (ALL_LIST_ELEMENTS_RO((struct list
*)loc
->chunks
, node
, chunk
)) {
332 if (chunk
->proto
!= proto
||
333 chunk
->instance
!= instance
||
334 chunk
->session_id
!= session_id
)
336 chunk
->proto
= NO_PROTO
;
338 chunk
->session_id
= 0;
345 flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK
,
346 "%s: SRv6 locator chunk not released", __func__
);
351 static int zebra_srv6_manager_release_locator_chunk(struct zserv
*client
,
352 const char *locator_name
,
355 if (vrf_id
!= VRF_DEFAULT
) {
356 zlog_err("SRv6 locator doesn't support vrf");
360 return release_srv6_locator_chunk(client
->proto
, client
->instance
,
361 client
->session_id
, locator_name
);
365 * Release srv6-locator chunks from a client.
367 * Called on client disconnection or reconnection. It only releases chunks
368 * with empty keep value.
370 * @param proto Daemon protocol of client, to identify the owner
371 * @param instance Instance, to identify the owner
372 * @return Number of chunks released
374 int release_daemon_srv6_locator_chunks(struct zserv
*client
)
378 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
379 struct listnode
*loc_node
;
380 struct listnode
*chunk_node
;
381 struct srv6_locator
*loc
;
382 struct srv6_locator_chunk
*chunk
;
384 if (IS_ZEBRA_DEBUG_PACKET
)
385 zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
386 __func__
, zebra_route_string(client
->proto
),
387 client
->instance
, client
->session_id
);
389 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, loc_node
, loc
)) {
390 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
, chunk
)) {
391 if (chunk
->proto
== client
->proto
&&
392 chunk
->instance
== client
->instance
&&
393 chunk
->session_id
== client
->session_id
&&
395 ret
= release_srv6_locator_chunk(
396 chunk
->proto
, chunk
->instance
,
397 chunk
->session_id
, loc
->name
);
404 if (IS_ZEBRA_DEBUG_PACKET
)
405 zlog_debug("%s: Released %d srv6-locator chunks",
411 void zebra_srv6_init(void)
413 hook_register(zserv_client_close
, zebra_srv6_cleanup
);
414 hook_register(srv6_manager_get_chunk
,
415 zebra_srv6_manager_get_locator_chunk
);
416 hook_register(srv6_manager_release_chunk
,
417 zebra_srv6_manager_release_locator_chunk
);
420 bool zebra_srv6_is_enable(void)
422 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
424 return listcount(srv6
->locators
);