2 * Zebra SRv6 definitions
3 * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
4 * Copyright (C) 2020 Masakazu Asama
6 * This program 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 Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
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
27 #include "zebra/debug.h"
28 #include "zebra/zapi_msg.h"
29 #include "zebra/zserv.h"
30 #include "zebra/zebra_router.h"
31 #include "zebra/zebra_srv6.h"
32 #include "zebra/zebra_errors.h"
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
46 DEFINE_MGROUP(SRV6_MGR
, "SRv6 Manager");
47 DEFINE_MTYPE_STATIC(SRV6_MGR
, SRV6M_CHUNK
, "SRv6 Manager Chunk");
49 /* define hooks for the basic API, so that it can be specialized or served
53 DEFINE_HOOK(srv6_manager_client_connect
,
54 (struct zserv
*client
, vrf_id_t vrf_id
),
56 DEFINE_HOOK(srv6_manager_client_disconnect
,
57 (struct zserv
*client
), (client
));
58 DEFINE_HOOK(srv6_manager_get_chunk
,
59 (struct srv6_locator
**loc
,
61 const char *locator_name
,
63 (loc
, client
, locator_name
, vrf_id
));
64 DEFINE_HOOK(srv6_manager_release_chunk
,
65 (struct zserv
*client
,
66 const char *locator_name
,
68 (client
, locator_name
, vrf_id
));
70 /* define wrappers to be called in zapi_msg.c (as hooks must be called in
71 * source file where they were defined)
74 void srv6_manager_client_connect_call(struct zserv
*client
, vrf_id_t vrf_id
)
76 hook_call(srv6_manager_client_connect
, client
, vrf_id
);
79 void srv6_manager_get_locator_chunk_call(struct srv6_locator
**loc
,
81 const char *locator_name
,
84 hook_call(srv6_manager_get_chunk
, loc
, client
, locator_name
, vrf_id
);
87 void srv6_manager_release_locator_chunk_call(struct zserv
*client
,
88 const char *locator_name
,
91 hook_call(srv6_manager_release_chunk
, client
, locator_name
, vrf_id
);
94 int srv6_manager_client_disconnect_cb(struct zserv
*client
)
96 hook_call(srv6_manager_client_disconnect
, client
);
100 static int zebra_srv6_cleanup(struct zserv
*client
)
105 void zebra_srv6_locator_add(struct srv6_locator
*locator
)
107 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
108 struct srv6_locator
*tmp
;
109 struct listnode
*node
;
110 struct zserv
*client
;
112 tmp
= zebra_srv6_locator_lookup(locator
->name
);
114 listnode_add(srv6
->locators
, locator
);
117 * Notify new locator info to zclients.
119 * The srv6 locators and their prefixes are managed by zserv(zebra).
120 * And an actual configuration the srv6 sid in the srv6 locator is done
121 * by zclient(bgpd, isisd, etc). The configuration of each locator
122 * allocation and specify it by zserv and zclient should be
123 * asynchronous. For that, zclient should be received the event via
124 * ZAPI when a srv6 locator is added on zebra.
125 * Basically, in SRv6, adding/removing SRv6 locators is performed less
126 * frequently than adding rib entries, so a broad to all zclients will
127 * not degrade the overall performance of FRRouting.
129 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
))
130 zsend_zebra_srv6_locator_add(client
, locator
);
133 void zebra_srv6_locator_delete(struct srv6_locator
*locator
)
136 struct srv6_locator_chunk
*c
;
137 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
138 struct zserv
*client
;
141 * Notify deleted locator info to zclients if needed.
143 * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
144 * uses it for its own purpose. For example, in the case of BGP L3VPN,
145 * the SID assigned to vpn unicast rib will be given.
146 * And when the locator is deleted by zserv(zebra), those SIDs need to
147 * be withdrawn. The zclient must initiate the withdrawal of the SIDs
148 * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
149 * owner of each chunk.
151 for (ALL_LIST_ELEMENTS_RO((struct list
*)locator
->chunks
, n
, c
)) {
152 if (c
->proto
== ZEBRA_ROUTE_SYSTEM
)
154 client
= zserv_find_client(c
->proto
, c
->instance
);
157 "%s: Not found zclient(proto=%u, instance=%u).",
158 __func__
, c
->proto
, c
->instance
);
161 zsend_zebra_srv6_locator_delete(client
, locator
);
164 listnode_delete(srv6
->locators
, locator
);
165 srv6_locator_free(locator
);
168 struct srv6_locator
*zebra_srv6_locator_lookup(const char *name
)
170 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
171 struct srv6_locator
*locator
;
172 struct listnode
*node
;
174 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
))
175 if (!strncmp(name
, locator
->name
, SRV6_LOCNAME_SIZE
))
180 void zebra_notify_srv6_locator_add(struct srv6_locator
*locator
)
182 struct listnode
*node
;
183 struct zserv
*client
;
186 * Notify new locator info to zclients.
188 * The srv6 locators and their prefixes are managed by zserv(zebra).
189 * And an actual configuration the srv6 sid in the srv6 locator is done
190 * by zclient(bgpd, isisd, etc). The configuration of each locator
191 * allocation and specify it by zserv and zclient should be
192 * asynchronous. For that, zclient should be received the event via
193 * ZAPI when a srv6 locator is added on zebra.
194 * Basically, in SRv6, adding/removing SRv6 locators is performed less
195 * frequently than adding rib entries, so a broad to all zclients will
196 * not degrade the overall performance of FRRouting.
198 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
, node
, client
))
199 zsend_zebra_srv6_locator_add(client
, locator
);
202 void zebra_notify_srv6_locator_delete(struct srv6_locator
*locator
)
205 struct srv6_locator_chunk
*c
;
206 struct zserv
*client
;
209 * Notify deleted locator info to zclients if needed.
211 * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
212 * uses it for its own purpose. For example, in the case of BGP L3VPN,
213 * the SID assigned to vpn unicast rib will be given.
214 * And when the locator is deleted by zserv(zebra), those SIDs need to
215 * be withdrawn. The zclient must initiate the withdrawal of the SIDs
216 * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
217 * owner of each chunk.
219 for (ALL_LIST_ELEMENTS_RO((struct list
*)locator
->chunks
, n
, c
)) {
220 if (c
->proto
== ZEBRA_ROUTE_SYSTEM
)
222 client
= zserv_find_client(c
->proto
, c
->instance
);
224 zlog_warn("Not found zclient(proto=%u, instance=%u).",
225 c
->proto
, c
->instance
);
228 zsend_zebra_srv6_locator_delete(client
, locator
);
232 struct zebra_srv6
*zebra_srv6_get_default(void)
234 static struct zebra_srv6 srv6
;
235 static bool first_execution
= true;
237 if (first_execution
) {
238 first_execution
= false;
239 srv6
.locators
= list_new();
245 * Core function, assigns srv6-locator chunks
247 * It first searches through the list to check if there's one available
248 * (previously released). Otherwise it creates and assigns a new one
250 * @param proto Daemon protocol of client, to identify the owner
251 * @param instance Instance, to identify the owner
252 * @param session_id SessionID of client
253 * @param name Name of SRv6-locator
254 * @return Pointer to the assigned srv6-locator chunk,
255 * or NULL if the request could not be satisfied
257 static struct srv6_locator
*
258 assign_srv6_locator_chunk(uint8_t proto
,
261 const char *locator_name
)
263 bool chunk_found
= false;
264 struct listnode
*node
= NULL
;
265 struct srv6_locator
*loc
= NULL
;
266 struct srv6_locator_chunk
*chunk
= NULL
;
268 loc
= zebra_srv6_locator_lookup(locator_name
);
270 zlog_info("%s: locator %s was not found",
271 __func__
, locator_name
);
275 for (ALL_LIST_ELEMENTS_RO((struct list
*)loc
->chunks
, node
, chunk
)) {
276 if (chunk
->proto
!= NO_PROTO
&& chunk
->proto
!= proto
)
283 zlog_info("%s: locator is already owned", __func__
);
287 chunk
->proto
= proto
;
288 chunk
->instance
= instance
;
289 chunk
->session_id
= session_id
;
293 static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator
**loc
,
294 struct zserv
*client
,
295 const char *locator_name
,
300 *loc
= assign_srv6_locator_chunk(client
->proto
, client
->instance
,
301 client
->session_id
, locator_name
);
304 zlog_err("Unable to assign locator chunk to %s instance %u",
305 zebra_route_string(client
->proto
), client
->instance
);
306 else if (IS_ZEBRA_DEBUG_PACKET
)
307 zlog_info("Assigned locator chunk %s to %s instance %u",
308 (*loc
)->name
, zebra_route_string(client
->proto
),
311 if (*loc
&& (*loc
)->status_up
)
312 ret
= zsend_srv6_manager_get_locator_chunk_response(client
,
319 * Core function, release no longer used srv6-locator chunks
321 * @param proto Daemon protocol of client, to identify the owner
322 * @param instance Instance, to identify the owner
323 * @param session_id Zclient session ID, to identify the zclient session
324 * @param locator_name SRv6-locator name, to identify the actual locator
325 * @return 0 on success, -1 otherwise
327 static int release_srv6_locator_chunk(uint8_t proto
, uint16_t instance
,
329 const char *locator_name
)
332 struct listnode
*node
;
333 struct srv6_locator_chunk
*chunk
;
334 struct srv6_locator
*loc
= NULL
;
336 loc
= zebra_srv6_locator_lookup(locator_name
);
340 if (IS_ZEBRA_DEBUG_PACKET
)
341 zlog_debug("%s: Releasing srv6-locator on %s", __func__
,
344 for (ALL_LIST_ELEMENTS_RO((struct list
*)loc
->chunks
, node
, chunk
)) {
345 if (chunk
->proto
!= proto
||
346 chunk
->instance
!= instance
||
347 chunk
->session_id
!= session_id
)
349 chunk
->proto
= NO_PROTO
;
351 chunk
->session_id
= 0;
358 flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK
,
359 "%s: SRv6 locator chunk not released", __func__
);
364 static int zebra_srv6_manager_release_locator_chunk(struct zserv
*client
,
365 const char *locator_name
,
368 if (vrf_id
!= VRF_DEFAULT
) {
369 zlog_err("SRv6 locator doesn't support vrf");
373 return release_srv6_locator_chunk(client
->proto
, client
->instance
,
374 client
->session_id
, locator_name
);
378 * Release srv6-locator chunks from a client.
380 * Called on client disconnection or reconnection. It only releases chunks
381 * with empty keep value.
383 * @param proto Daemon protocol of client, to identify the owner
384 * @param instance Instance, to identify the owner
385 * @return Number of chunks released
387 int release_daemon_srv6_locator_chunks(struct zserv
*client
)
391 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
392 struct listnode
*loc_node
;
393 struct listnode
*chunk_node
;
394 struct srv6_locator
*loc
;
395 struct srv6_locator_chunk
*chunk
;
397 if (IS_ZEBRA_DEBUG_PACKET
)
398 zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
399 __func__
, zebra_route_string(client
->proto
),
400 client
->instance
, client
->session_id
);
402 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, loc_node
, loc
)) {
403 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
, chunk
)) {
404 if (chunk
->proto
== client
->proto
&&
405 chunk
->instance
== client
->instance
&&
406 chunk
->session_id
== client
->session_id
&&
408 ret
= release_srv6_locator_chunk(
409 chunk
->proto
, chunk
->instance
,
410 chunk
->session_id
, loc
->name
);
417 if (IS_ZEBRA_DEBUG_PACKET
)
418 zlog_debug("%s: Released %d srv6-locator chunks",
424 void zebra_srv6_init(void)
426 hook_register(zserv_client_close
, zebra_srv6_cleanup
);
427 hook_register(srv6_manager_get_chunk
,
428 zebra_srv6_manager_get_locator_chunk
);
429 hook_register(srv6_manager_release_chunk
,
430 zebra_srv6_manager_release_locator_chunk
);
433 bool zebra_srv6_is_enable(void)
435 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
437 return listcount(srv6
->locators
);