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 zlog_warn("Unexpected router ID address family for vrf %u: %u",
157 vrf_id
, pref
.family
);
160 zlog_info("%s Router Id updated for VRF %u: %s", family
, vrf_id
, buf
);
165 * Adds a segment routing policy to Zebra.
167 * @param policy The policy to add
168 * @param segment_list The segment list for the policy
170 void path_zebra_add_sr_policy(struct srte_policy
*policy
,
171 struct srte_segment_list
*segment_list
)
173 struct zapi_sr_policy zp
= {};
174 struct srte_segment_entry
*segment
;
176 zp
.color
= policy
->color
;
177 zp
.endpoint
= policy
->endpoint
;
178 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
179 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
180 zp
.segment_list
.local_label
= policy
->binding_sid
;
181 zp
.segment_list
.label_num
= 0;
182 RB_FOREACH (segment
, srte_segment_entry_head
, &segment_list
->segments
)
183 zp
.segment_list
.labels
[zp
.segment_list
.label_num
++] =
185 policy
->status
= SRTE_POLICY_STATUS_GOING_UP
;
187 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_SET
, &zp
);
191 * Deletes a segment policy from Zebra.
193 * @param policy The policy to remove
195 void path_zebra_delete_sr_policy(struct srte_policy
*policy
)
197 struct zapi_sr_policy zp
= {};
199 zp
.color
= policy
->color
;
200 zp
.endpoint
= policy
->endpoint
;
201 strlcpy(zp
.name
, policy
->name
, sizeof(zp
.name
));
202 zp
.segment_list
.type
= ZEBRA_LSP_SRTE
;
203 zp
.segment_list
.local_label
= policy
->binding_sid
;
204 zp
.segment_list
.label_num
= 0;
205 policy
->status
= SRTE_POLICY_STATUS_DOWN
;
207 (void)zebra_send_sr_policy(zclient
, ZEBRA_SR_POLICY_DELETE
, &zp
);
211 * Allocates a label from Zebra's label manager.
213 * @param label the label to be allocated
214 * @return 0 if the label has been allocated, -1 otherwise
216 int path_zebra_request_label(mpls_label_t label
)
221 ret
= lm_get_label_chunk(zclient_sync
, 0, label
, 1, &start
, &end
);
223 zlog_warn("%s: error getting label range!", __func__
);
231 * Releases a previously allocated label from Zebra's label manager.
233 * @param label The label to release
234 * @return 0 ifthe label has beel released, -1 otherwise
236 void path_zebra_release_label(mpls_label_t label
)
240 ret
= lm_release_label_chunk(zclient_sync
, label
, label
);
242 zlog_warn("%s: error releasing label range!", __func__
);
245 static void path_zebra_label_manager_connect(void)
247 /* Connect to label manager. */
248 while (zclient_socket_connect(zclient_sync
) < 0) {
249 zlog_warn("%s: error connecting synchronous zclient!",
253 set_nonblocking(zclient_sync
->sock
);
255 /* Send hello to notify zebra this is a synchronous client */
256 while (zclient_send_hello(zclient_sync
) < 0) {
257 zlog_warn("%s: Error sending hello for synchronous zclient!",
262 while (lm_label_manager_connect(zclient_sync
, 0) != 0) {
263 zlog_warn("%s: error connecting to label manager!", __func__
);
269 * Initializes Zebra asynchronous connection.
271 * @param master The master thread
273 void path_zebra_init(struct thread_master
*master
)
275 struct zclient_options options
= zclient_options_default
;
276 options
.synchronous
= true;
278 /* Initialize asynchronous zclient. */
279 zclient
= zclient_new(master
, &zclient_options_default
);
280 zclient_init(zclient
, ZEBRA_ROUTE_SRTE
, 0, &pathd_privs
);
281 zclient
->zebra_connected
= path_zebra_connected
;
282 zclient
->sr_policy_notify_status
= path_zebra_sr_policy_notify_status
;
283 zclient
->router_id_update
= path_zebra_router_id_update
;
285 /* Initialize special zclient for synchronous message exchanges. */
286 zclient_sync
= zclient_new(master
, &options
);
287 zclient_sync
->sock
= -1;
288 zclient_sync
->redist_default
= ZEBRA_ROUTE_SRTE
;
289 zclient_sync
->instance
= 1;
290 zclient_sync
->privs
= &pathd_privs
;
292 /* Connect to the LM. */
293 path_zebra_label_manager_connect();