1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
10 #include "lib_errors.h"
21 #include "pathd/pathd.h"
22 #include "pathd/path_ted.h"
23 #include "pathd/path_zebra.h"
24 #include "lib/command.h"
25 #include "lib/link_state.h"
27 static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS
);
29 struct zclient
*zclient
;
30 static struct zclient
*zclient_sync
;
32 /* Global Variables */
33 bool g_has_router_id_v4
= false;
34 bool g_has_router_id_v6
= false;
35 struct in_addr g_router_id_v4
;
36 struct in6_addr g_router_id_v6
;
37 pthread_mutex_t g_router_id_v4_mtx
= PTHREAD_MUTEX_INITIALIZER
;
38 pthread_mutex_t g_router_id_v6_mtx
= PTHREAD_MUTEX_INITIALIZER
;
41 * Gives the IPv4 router ID received from Zebra.
43 * @param router_id The in_addr strucure where to store the router id
44 * @return true if the router ID was available, false otherwise
46 bool get_ipv4_router_id(struct in_addr
*router_id
)
49 assert(router_id
!= NULL
);
50 pthread_mutex_lock(&g_router_id_v4_mtx
);
51 if (g_has_router_id_v4
) {
52 memcpy(router_id
, &g_router_id_v4
, sizeof(*router_id
));
55 pthread_mutex_unlock(&g_router_id_v4_mtx
);
60 * Gives the IPv6 router ID received from Zebra.
62 * @param router_id The in6_addr strucure where to store the router id
63 * @return true if the router ID was available, false otherwise
65 bool get_ipv6_router_id(struct in6_addr
*router_id
)
68 assert(router_id
!= NULL
);
69 pthread_mutex_lock(&g_router_id_v6_mtx
);
70 if (g_has_router_id_v6
) {
71 memcpy(router_id
, &g_router_id_v6
, sizeof(*router_id
));
74 pthread_mutex_unlock(&g_router_id_v6_mtx
);
78 static void path_zebra_connected(struct zclient
*zclient
)
80 struct srte_policy
*policy
;
82 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
83 zclient_send_router_id_update(zclient
, ZEBRA_ROUTER_ID_ADD
, AFI_IP6
,
86 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
87 struct srte_candidate
*candidate
;
88 struct srte_segment_list
*segment_list
;
90 candidate
= policy
->best_candidate
;
94 segment_list
= candidate
->lsp
->segment_list
;
98 path_zebra_add_sr_policy(policy
, segment_list
);
102 static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS
)
104 struct zapi_sr_policy zapi_sr_policy
;
105 struct srte_policy
*policy
;
106 struct srte_candidate
*best_candidate_path
;
108 if (zapi_sr_policy_notify_status_decode(zclient
->ibuf
, &zapi_sr_policy
))
111 policy
= srte_policy_find(zapi_sr_policy
.color
,
112 &zapi_sr_policy
.endpoint
);
116 best_candidate_path
= policy
->best_candidate
;
117 if (!best_candidate_path
)
120 srte_candidate_status_update(best_candidate_path
,
121 zapi_sr_policy
.status
);
126 /* Router-id update message from zebra. */
127 static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS
)
131 char buf
[PREFIX2STR_BUFFER
];
132 zebra_router_id_update_read(zclient
->ibuf
, &pref
);
133 if (pref
.family
== AF_INET
) {
134 pthread_mutex_lock(&g_router_id_v4_mtx
);
135 memcpy(&g_router_id_v4
, &pref
.u
.prefix4
,
136 sizeof(g_router_id_v4
));
137 g_has_router_id_v4
= true;
138 inet_ntop(AF_INET
, &g_router_id_v4
, buf
, sizeof(buf
));
139 pthread_mutex_unlock(&g_router_id_v4_mtx
);
141 } else if (pref
.family
== AF_INET6
) {
142 pthread_mutex_lock(&g_router_id_v6_mtx
);
143 memcpy(&g_router_id_v6
, &pref
.u
.prefix6
,
144 sizeof(g_router_id_v6
));
145 g_has_router_id_v6
= true;
146 inet_ntop(AF_INET6
, &g_router_id_v6
, buf
, sizeof(buf
));
147 pthread_mutex_unlock(&g_router_id_v6_mtx
);
150 zlog_warn("Unexpected router ID address family for vrf %u: %u",
151 vrf_id
, pref
.family
);
154 zlog_info("%s Router Id updated for VRF %u: %s", family
, vrf_id
, buf
);
159 * Adds a segment routing policy to Zebra.
161 * @param policy The policy to add
162 * @param segment_list The segment list for the policy
164 void path_zebra_add_sr_policy(struct srte_policy
*policy
,
165 struct srte_segment_list
*segment_list
)
167 struct zapi_sr_policy zp
= {};
168 struct srte_segment_entry
*segment
;
170 zp
.color
= policy
->color
;
171 zp
.endpoint
= policy
->endpoint
;
172 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
173 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
174 zp
.segment_list
.local_label
= policy
->binding_sid
;
175 zp
.segment_list
.label_num
= 0;
176 RB_FOREACH (segment
, srte_segment_entry_head
, &segment_list
->segments
)
177 zp
.segment_list
.labels
[zp
.segment_list
.label_num
++] =
179 policy
->status
= SRTE_POLICY_STATUS_GOING_UP
;
181 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_SET
, &zp
);
185 * Deletes a segment policy from Zebra.
187 * @param policy The policy to remove
189 void path_zebra_delete_sr_policy(struct srte_policy
*policy
)
191 struct zapi_sr_policy zp
= {};
193 zp
.color
= policy
->color
;
194 zp
.endpoint
= policy
->endpoint
;
195 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
196 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
197 zp
.segment_list
.local_label
= policy
->binding_sid
;
198 zp
.segment_list
.label_num
= 0;
199 policy
->status
= SRTE_POLICY_STATUS_DOWN
;
201 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_DELETE
, &zp
);
205 * Allocates a label from Zebra's label manager.
207 * @param label the label to be allocated
208 * @return 0 if the label has been allocated, -1 otherwise
210 int path_zebra_request_label(mpls_label_t label
)
215 ret
= lm_get_label_chunk(zclient_sync
, 0, label
, 1, &start
, &end
);
217 zlog_warn("%s: error getting label range!", __func__
);
225 * Releases a previously allocated label from Zebra's label manager.
227 * @param label The label to release
228 * @return 0 ifthe label has beel released, -1 otherwise
230 void path_zebra_release_label(mpls_label_t label
)
234 ret
= lm_release_label_chunk(zclient_sync
, label
, label
);
236 zlog_warn("%s: error releasing label range!", __func__
);
239 static void path_zebra_label_manager_connect(void)
241 /* Connect to label manager. */
242 while (zclient_socket_connect(zclient_sync
) < 0) {
243 zlog_warn("%s: error connecting synchronous zclient!",
247 set_nonblocking(zclient_sync
->sock
);
249 /* Send hello to notify zebra this is a synchronous client */
250 while (zclient_send_hello(zclient_sync
) < 0) {
251 zlog_warn("%s: Error sending hello for synchronous zclient!",
256 while (lm_label_manager_connect(zclient_sync
, 0) != 0) {
257 zlog_warn("%s: error connecting to label manager!", __func__
);
262 static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS
)
266 struct zapi_opaque_msg info
;
270 if (zclient_opaque_decode(s
, &info
) != 0)
274 case LINK_STATE_UPDATE
:
275 case LINK_STATE_SYNC
:
276 /* Start receiving ls data so cancel request sync timer */
277 path_ted_timer_sync_cancel();
279 struct ls_message
*msg
= ls_parse_msg(s
);
282 zlog_debug("%s: [rcv ted] ls (%s) msg (%s)-(%s) !",
284 info
.type
== LINK_STATE_UPDATE
285 ? "LINK_STATE_UPDATE"
287 LS_MSG_TYPE_PRINT(msg
->type
),
288 LS_MSG_EVENT_PRINT(msg
->event
));
291 "%s: [rcv ted] Could not parse LinkState stream message.",
296 ret
= path_ted_rcvd_message(msg
);
298 /* Update local configuration after process update. */
299 path_ted_segment_list_refresh();
302 zlog_debug("%s: [rcv ted] unknown opaque event (%d) !",
303 __func__
, info
.type
);
310 static zclient_handler
*const path_handlers
[] = {
311 [ZEBRA_SR_POLICY_NOTIFY_STATUS
] = path_zebra_sr_policy_notify_status
,
312 [ZEBRA_ROUTER_ID_UPDATE
] = path_zebra_router_id_update
,
313 [ZEBRA_OPAQUE_MESSAGE
] = path_zebra_opaque_msg_handler
,
317 * Initializes Zebra asynchronous connection.
319 * @param master The master thread
321 void path_zebra_init(struct event_loop
*master
)
323 struct zclient_options options
= zclient_options_default
;
324 options
.synchronous
= true;
326 /* Initialize asynchronous zclient. */
327 zclient
= zclient_new(master
, &zclient_options_default
, path_handlers
,
328 array_size(path_handlers
));
329 zclient_init(zclient
, ZEBRA_ROUTE_SRTE
, 0, &pathd_privs
);
330 zclient
->zebra_connected
= path_zebra_connected
;
332 /* Initialize special zclient for synchronous message exchanges. */
333 zclient_sync
= zclient_new(master
, &options
, NULL
, 0);
334 zclient_sync
->sock
= -1;
335 zclient_sync
->redist_default
= ZEBRA_ROUTE_SRTE
;
336 zclient_sync
->instance
= 1;
337 zclient_sync
->privs
= &pathd_privs
;
339 /* Connect to the LM. */
340 path_zebra_label_manager_connect();
343 void path_zebra_stop(void)
345 zclient_stop(zclient
);
346 zclient_free(zclient
);