]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_zebra.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pathd / path_zebra.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020 NetDEF, Inc.
4 */
5
6 #include <zebra.h>
7
8 #include "frrevent.h"
9 #include "log.h"
10 #include "lib_errors.h"
11 #include "if.h"
12 #include "prefix.h"
13 #include "zclient.h"
14 #include "network.h"
15 #include "stream.h"
16 #include "linklist.h"
17 #include "nexthop.h"
18 #include "vrf.h"
19 #include "typesafe.h"
20
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"
26
27 static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
28
29 struct zclient *zclient;
30 static struct zclient *zclient_sync;
31
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;
39
40 /**
41 * Gives the IPv4 router ID received from Zebra.
42 *
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
45 */
46 bool get_ipv4_router_id(struct in_addr *router_id)
47 {
48 bool retval = false;
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));
53 retval = true;
54 }
55 pthread_mutex_unlock(&g_router_id_v4_mtx);
56 return retval;
57 }
58
59 /**
60 * Gives the IPv6 router ID received from Zebra.
61 *
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
64 */
65 bool get_ipv6_router_id(struct in6_addr *router_id)
66 {
67 bool retval = false;
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));
72 retval = true;
73 }
74 pthread_mutex_unlock(&g_router_id_v6_mtx);
75 return retval;
76 }
77
78 static void path_zebra_connected(struct zclient *zclient)
79 {
80 struct srte_policy *policy;
81
82 zclient_send_reg_requests(zclient, VRF_DEFAULT);
83 zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
84 VRF_DEFAULT);
85
86 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
87 struct srte_candidate *candidate;
88 struct srte_segment_list *segment_list;
89
90 candidate = policy->best_candidate;
91 if (!candidate)
92 continue;
93
94 segment_list = candidate->lsp->segment_list;
95 if (!segment_list)
96 continue;
97
98 path_zebra_add_sr_policy(policy, segment_list);
99 }
100 }
101
102 static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
103 {
104 struct zapi_sr_policy zapi_sr_policy;
105 struct srte_policy *policy;
106 struct srte_candidate *best_candidate_path;
107
108 if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
109 return -1;
110
111 policy = srte_policy_find(zapi_sr_policy.color,
112 &zapi_sr_policy.endpoint);
113 if (!policy)
114 return -1;
115
116 best_candidate_path = policy->best_candidate;
117 if (!best_candidate_path)
118 return -1;
119
120 srte_candidate_status_update(best_candidate_path,
121 zapi_sr_policy.status);
122
123 return 0;
124 }
125
126 /* Router-id update message from zebra. */
127 static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
128 {
129 struct prefix pref;
130 const char *family;
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);
140 family = "IPv4";
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);
148 family = "IPv6";
149 } else {
150 zlog_warn("Unexpected router ID address family for vrf %u: %u",
151 vrf_id, pref.family);
152 return 0;
153 }
154 zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
155 return 0;
156 }
157
158 /**
159 * Adds a segment routing policy to Zebra.
160 *
161 * @param policy The policy to add
162 * @param segment_list The segment list for the policy
163 */
164 void path_zebra_add_sr_policy(struct srte_policy *policy,
165 struct srte_segment_list *segment_list)
166 {
167 struct zapi_sr_policy zp = {};
168 struct srte_segment_entry *segment;
169
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++] =
178 segment->sid_value;
179 policy->status = SRTE_POLICY_STATUS_GOING_UP;
180
181 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
182 }
183
184 /**
185 * Deletes a segment policy from Zebra.
186 *
187 * @param policy The policy to remove
188 */
189 void path_zebra_delete_sr_policy(struct srte_policy *policy)
190 {
191 struct zapi_sr_policy zp = {};
192
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;
200
201 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
202 }
203
204 /**
205 * Allocates a label from Zebra's label manager.
206 *
207 * @param label the label to be allocated
208 * @return 0 if the label has been allocated, -1 otherwise
209 */
210 int path_zebra_request_label(mpls_label_t label)
211 {
212 int ret;
213 uint32_t start, end;
214
215 ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
216 if (ret < 0) {
217 zlog_warn("%s: error getting label range!", __func__);
218 return -1;
219 }
220
221 return 0;
222 }
223
224 /**
225 * Releases a previously allocated label from Zebra's label manager.
226 *
227 * @param label The label to release
228 * @return 0 ifthe label has beel released, -1 otherwise
229 */
230 void path_zebra_release_label(mpls_label_t label)
231 {
232 int ret;
233
234 ret = lm_release_label_chunk(zclient_sync, label, label);
235 if (ret < 0)
236 zlog_warn("%s: error releasing label range!", __func__);
237 }
238
239 static void path_zebra_label_manager_connect(void)
240 {
241 /* Connect to label manager. */
242 while (zclient_socket_connect(zclient_sync) < 0) {
243 zlog_warn("%s: error connecting synchronous zclient!",
244 __func__);
245 sleep(1);
246 }
247 set_nonblocking(zclient_sync->sock);
248
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!",
252 __func__);
253 sleep(1);
254 }
255
256 while (lm_label_manager_connect(zclient_sync, 0) != 0) {
257 zlog_warn("%s: error connecting to label manager!", __func__);
258 sleep(1);
259 }
260 }
261
262 static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
263 {
264 int ret = 0;
265 struct stream *s;
266 struct zapi_opaque_msg info;
267
268 s = zclient->ibuf;
269
270 if (zclient_opaque_decode(s, &info) != 0)
271 return -1;
272
273 switch (info.type) {
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();
278
279 struct ls_message *msg = ls_parse_msg(s);
280
281 if (msg) {
282 zlog_debug("%s: [rcv ted] ls (%s) msg (%s)-(%s) !",
283 __func__,
284 info.type == LINK_STATE_UPDATE
285 ? "LINK_STATE_UPDATE"
286 : "LINK_STATE_SYNC",
287 LS_MSG_TYPE_PRINT(msg->type),
288 LS_MSG_EVENT_PRINT(msg->event));
289 } else {
290 zlog_err(
291 "%s: [rcv ted] Could not parse LinkState stream message.",
292 __func__);
293 return -1;
294 }
295
296 ret = path_ted_rcvd_message(msg);
297 ls_delete_msg(msg);
298 /* Update local configuration after process update. */
299 path_ted_segment_list_refresh();
300 break;
301 default:
302 zlog_debug("%s: [rcv ted] unknown opaque event (%d) !",
303 __func__, info.type);
304 break;
305 }
306
307 return ret;
308 }
309
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,
314 };
315
316 /**
317 * Initializes Zebra asynchronous connection.
318 *
319 * @param master The master thread
320 */
321 void path_zebra_init(struct event_loop *master)
322 {
323 struct zclient_options options = zclient_options_default;
324 options.synchronous = true;
325
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;
331
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;
338
339 /* Connect to the LM. */
340 path_zebra_label_manager_connect();
341 }
342
343 void path_zebra_stop(void)
344 {
345 zclient_stop(zclient);
346 zclient_free(zclient);
347 }