2 * Copyright (C) 2020 NetDEF, Inc.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "lib_errors.h"
32 #include "pathd/pathd.h"
33 #include "pathd/path_zebra.h"
35 static struct zclient
*zclient
;
36 static struct zclient
*zclient_sync
;
38 /* Global Variables */
39 bool g_has_router_id_v4
= false;
40 bool g_has_router_id_v6
= false;
41 struct in_addr g_router_id_v4
;
42 struct in6_addr g_router_id_v6
;
43 pthread_mutex_t g_router_id_v4_mtx
= PTHREAD_MUTEX_INITIALIZER
;
44 pthread_mutex_t g_router_id_v6_mtx
= PTHREAD_MUTEX_INITIALIZER
;
47 * Gives the IPv4 router ID received from Zebra.
49 * @param router_id The in_addr strucure where to store the router id
50 * @return true if the router ID was available, false otherwise
52 bool get_ipv4_router_id(struct in_addr
*router_id
)
55 assert(router_id
!= NULL
);
56 pthread_mutex_lock(&g_router_id_v4_mtx
);
57 if (g_has_router_id_v4
) {
58 memcpy(router_id
, &g_router_id_v4
, sizeof(*router_id
));
61 pthread_mutex_unlock(&g_router_id_v4_mtx
);
66 * Gives the IPv6 router ID received from Zebra.
68 * @param router_id The in6_addr strucure where to store the router id
69 * @return true if the router ID was available, false otherwise
71 bool get_ipv6_router_id(struct in6_addr
*router_id
)
74 assert(router_id
!= NULL
);
75 pthread_mutex_lock(&g_router_id_v6_mtx
);
76 if (g_has_router_id_v6
) {
77 memcpy(router_id
, &g_router_id_v6
, sizeof(*router_id
));
80 pthread_mutex_unlock(&g_router_id_v6_mtx
);
84 static void path_zebra_connected(struct zclient
*zclient
)
86 struct srte_policy
*policy
;
88 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
89 zclient_send_router_id_update(zclient
, ZEBRA_ROUTER_ID_ADD
, AFI_IP6
,
92 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
93 struct srte_candidate
*candidate
;
94 struct srte_segment_list
*segment_list
;
96 candidate
= policy
->best_candidate
;
100 segment_list
= candidate
->lsp
->segment_list
;
104 path_zebra_add_sr_policy(policy
, segment_list
);
108 static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS
)
110 struct zapi_sr_policy zapi_sr_policy
;
111 struct srte_policy
*policy
;
112 struct srte_candidate
*best_candidate_path
;
114 if (zapi_sr_policy_notify_status_decode(zclient
->ibuf
, &zapi_sr_policy
))
117 policy
= srte_policy_find(zapi_sr_policy
.color
,
118 &zapi_sr_policy
.endpoint
);
122 best_candidate_path
= policy
->best_candidate
;
123 if (!best_candidate_path
)
126 srte_candidate_status_update(best_candidate_path
,
127 zapi_sr_policy
.status
);
132 /* Router-id update message from zebra. */
133 static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS
)
137 char buf
[PREFIX2STR_BUFFER
];
138 zebra_router_id_update_read(zclient
->ibuf
, &pref
);
139 if (pref
.family
== AF_INET
) {
140 pthread_mutex_lock(&g_router_id_v4_mtx
);
141 memcpy(&g_router_id_v4
, &pref
.u
.prefix4
,
142 sizeof(g_router_id_v4
));
143 g_has_router_id_v4
= true;
144 inet_ntop(AF_INET
, &g_router_id_v4
, buf
, sizeof(buf
));
145 pthread_mutex_unlock(&g_router_id_v4_mtx
);
147 } else if (pref
.family
== AF_INET6
) {
148 pthread_mutex_lock(&g_router_id_v6_mtx
);
149 memcpy(&g_router_id_v6
, &pref
.u
.prefix6
,
150 sizeof(g_router_id_v6
));
151 g_has_router_id_v6
= true;
152 inet_ntop(AF_INET6
, &g_router_id_v6
, buf
, sizeof(buf
));
153 pthread_mutex_unlock(&g_router_id_v6_mtx
);
156 pthread_mutex_unlock(&g_router_id_v4_mtx
);
157 zlog_warn("Unexpected router ID address family for vrf %u: %u",
158 vrf_id
, pref
.family
);
161 pthread_mutex_unlock(&g_router_id_v4_mtx
);
162 zlog_info("%s Router Id updated for VRF %u: %s", family
, vrf_id
, buf
);
167 * Adds a segment routing policy to Zebra.
169 * @param policy The policy to add
170 * @param segment_list The segment list for the policy
172 void path_zebra_add_sr_policy(struct srte_policy
*policy
,
173 struct srte_segment_list
*segment_list
)
175 struct zapi_sr_policy zp
= {};
176 struct srte_segment_entry
*segment
;
178 zp
.color
= policy
->color
;
179 zp
.endpoint
= policy
->endpoint
;
180 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
181 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
182 zp
.segment_list
.local_label
= policy
->binding_sid
;
183 zp
.segment_list
.label_num
= 0;
184 RB_FOREACH (segment
, srte_segment_entry_head
, &segment_list
->segments
)
185 zp
.segment_list
.labels
[zp
.segment_list
.label_num
++] =
187 policy
->status
= SRTE_POLICY_STATUS_GOING_UP
;
189 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_SET
, &zp
);
193 * Deletes a segment policy from Zebra.
195 * @param policy The policy to remove
197 void path_zebra_delete_sr_policy(struct srte_policy
*policy
)
199 struct zapi_sr_policy zp
= {};
201 zp
.color
= policy
->color
;
202 zp
.endpoint
= policy
->endpoint
;
203 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
204 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
205 zp
.segment_list
.local_label
= policy
->binding_sid
;
206 zp
.segment_list
.label_num
= 0;
207 policy
->status
= SRTE_POLICY_STATUS_DOWN
;
209 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_DELETE
, &zp
);
213 * Allocates a label from Zebra's label manager.
215 * @param label the label to be allocated
216 * @return 0 if the label has been allocated, -1 otherwise
218 int path_zebra_request_label(mpls_label_t label
)
223 ret
= lm_get_label_chunk(zclient_sync
, 0, label
, 1, &start
, &end
);
225 zlog_warn("%s: error getting label range!", __func__
);
233 * Releases a previously allocated label from Zebra's label manager.
235 * @param label The label to release
236 * @return 0 ifthe label has beel released, -1 otherwise
238 void path_zebra_release_label(mpls_label_t label
)
242 ret
= lm_release_label_chunk(zclient_sync
, label
, label
);
244 zlog_warn("%s: error releasing label range!", __func__
);
247 static void path_zebra_label_manager_connect(void)
249 /* Connect to label manager. */
250 while (zclient_socket_connect(zclient_sync
) < 0) {
251 zlog_warn("%s: error connecting synchronous zclient!",
255 set_nonblocking(zclient_sync
->sock
);
257 /* Send hello to notify zebra this is a synchronous client */
258 while (zclient_send_hello(zclient_sync
) < 0) {
259 zlog_warn("%s: Error sending hello for synchronous zclient!",
264 while (lm_label_manager_connect(zclient_sync
, 0) != 0) {
265 zlog_warn("%s: error connecting to label manager!", __func__
);
271 * Initializes Zebra asynchronous connection.
273 * @param master The master thread
275 void path_zebra_init(struct thread_master
*master
)
277 struct zclient_options options
= zclient_options_default
;
278 options
.synchronous
= true;
280 /* Initialize asynchronous zclient. */
281 zclient
= zclient_new(master
, &zclient_options_default
);
282 zclient_init(zclient
, ZEBRA_ROUTE_SRTE
, 0, &pathd_privs
);
283 zclient
->zebra_connected
= path_zebra_connected
;
284 zclient
->sr_policy_notify_status
= path_zebra_sr_policy_notify_status
;
285 zclient
->router_id_update
= path_zebra_router_id_update
;
287 /* Initialize special zclient for synchronous message exchanges. */
288 zclient_sync
= zclient_new(master
, &options
);
289 zclient_sync
->sock
= -1;
290 zclient_sync
->redist_default
= ZEBRA_ROUTE_SRTE
;
291 zclient_sync
->instance
= 1;
292 zclient_sync
->privs
= &pathd_privs
;
294 /* Connect to the LM. */
295 path_zebra_label_manager_connect();