]>
Commit | Line | Data |
---|---|---|
4d7b695d SM |
1 | /* |
2 | * Copyright (C) 2020 NetDEF, Inc. | |
3 | * | |
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) | |
7 | * any later version. | |
8 | * | |
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 | |
12 | * more details. | |
13 | * | |
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 | |
17 | */ | |
18 | ||
1f8031f7 DL |
19 | #include <zebra.h> |
20 | ||
4d7b695d SM |
21 | #include "thread.h" |
22 | #include "log.h" | |
23 | #include "lib_errors.h" | |
24 | #include "if.h" | |
25 | #include "prefix.h" | |
26 | #include "zclient.h" | |
27 | #include "network.h" | |
28 | #include "stream.h" | |
29 | #include "linklist.h" | |
30 | #include "nexthop.h" | |
31 | #include "vrf.h" | |
32 | #include "typesafe.h" | |
33 | ||
34 | #include "pathd/pathd.h" | |
75c69d15 | 35 | #include "pathd/path_ted.h" |
4d7b695d | 36 | #include "pathd/path_zebra.h" |
75c69d15 JG |
37 | #include "lib/command.h" |
38 | #include "lib/link_state.h" | |
4d7b695d | 39 | |
75c69d15 JG |
40 | static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS); |
41 | ||
42 | struct zclient *zclient; | |
4d7b695d SM |
43 | static struct zclient *zclient_sync; |
44 | ||
45 | /* Global Variables */ | |
46 | bool g_has_router_id_v4 = false; | |
47 | bool g_has_router_id_v6 = false; | |
48 | struct in_addr g_router_id_v4; | |
49 | struct in6_addr g_router_id_v6; | |
50 | pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER; | |
51 | pthread_mutex_t g_router_id_v6_mtx = PTHREAD_MUTEX_INITIALIZER; | |
52 | ||
53 | /** | |
54 | * Gives the IPv4 router ID received from Zebra. | |
55 | * | |
56 | * @param router_id The in_addr strucure where to store the router id | |
57 | * @return true if the router ID was available, false otherwise | |
58 | */ | |
59 | bool get_ipv4_router_id(struct in_addr *router_id) | |
60 | { | |
61 | bool retval = false; | |
62 | assert(router_id != NULL); | |
63 | pthread_mutex_lock(&g_router_id_v4_mtx); | |
64 | if (g_has_router_id_v4) { | |
65 | memcpy(router_id, &g_router_id_v4, sizeof(*router_id)); | |
66 | retval = true; | |
67 | } | |
68 | pthread_mutex_unlock(&g_router_id_v4_mtx); | |
69 | return retval; | |
70 | } | |
71 | ||
72 | /** | |
73 | * Gives the IPv6 router ID received from Zebra. | |
74 | * | |
75 | * @param router_id The in6_addr strucure where to store the router id | |
76 | * @return true if the router ID was available, false otherwise | |
77 | */ | |
78 | bool get_ipv6_router_id(struct in6_addr *router_id) | |
79 | { | |
80 | bool retval = false; | |
81 | assert(router_id != NULL); | |
82 | pthread_mutex_lock(&g_router_id_v6_mtx); | |
83 | if (g_has_router_id_v6) { | |
84 | memcpy(router_id, &g_router_id_v6, sizeof(*router_id)); | |
85 | retval = true; | |
86 | } | |
87 | pthread_mutex_unlock(&g_router_id_v6_mtx); | |
88 | return retval; | |
89 | } | |
90 | ||
91 | static void path_zebra_connected(struct zclient *zclient) | |
92 | { | |
93 | struct srte_policy *policy; | |
94 | ||
95 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
96 | zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6, | |
97 | VRF_DEFAULT); | |
98 | ||
99 | RB_FOREACH (policy, srte_policy_head, &srte_policies) { | |
100 | struct srte_candidate *candidate; | |
101 | struct srte_segment_list *segment_list; | |
102 | ||
103 | candidate = policy->best_candidate; | |
104 | if (!candidate) | |
105 | continue; | |
106 | ||
107 | segment_list = candidate->lsp->segment_list; | |
108 | if (!segment_list) | |
109 | continue; | |
110 | ||
111 | path_zebra_add_sr_policy(policy, segment_list); | |
112 | } | |
113 | } | |
114 | ||
115 | static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS) | |
116 | { | |
117 | struct zapi_sr_policy zapi_sr_policy; | |
118 | struct srte_policy *policy; | |
119 | struct srte_candidate *best_candidate_path; | |
120 | ||
121 | if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy)) | |
122 | return -1; | |
123 | ||
124 | policy = srte_policy_find(zapi_sr_policy.color, | |
125 | &zapi_sr_policy.endpoint); | |
126 | if (!policy) | |
127 | return -1; | |
128 | ||
129 | best_candidate_path = policy->best_candidate; | |
130 | if (!best_candidate_path) | |
131 | return -1; | |
132 | ||
133 | srte_candidate_status_update(best_candidate_path, | |
134 | zapi_sr_policy.status); | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | /* Router-id update message from zebra. */ | |
140 | static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS) | |
141 | { | |
142 | struct prefix pref; | |
143 | const char *family; | |
144 | char buf[PREFIX2STR_BUFFER]; | |
145 | zebra_router_id_update_read(zclient->ibuf, &pref); | |
146 | if (pref.family == AF_INET) { | |
147 | pthread_mutex_lock(&g_router_id_v4_mtx); | |
148 | memcpy(&g_router_id_v4, &pref.u.prefix4, | |
149 | sizeof(g_router_id_v4)); | |
150 | g_has_router_id_v4 = true; | |
151 | inet_ntop(AF_INET, &g_router_id_v4, buf, sizeof(buf)); | |
152 | pthread_mutex_unlock(&g_router_id_v4_mtx); | |
153 | family = "IPv4"; | |
154 | } else if (pref.family == AF_INET6) { | |
155 | pthread_mutex_lock(&g_router_id_v6_mtx); | |
156 | memcpy(&g_router_id_v6, &pref.u.prefix6, | |
157 | sizeof(g_router_id_v6)); | |
158 | g_has_router_id_v6 = true; | |
159 | inet_ntop(AF_INET6, &g_router_id_v6, buf, sizeof(buf)); | |
160 | pthread_mutex_unlock(&g_router_id_v6_mtx); | |
161 | family = "IPv6"; | |
162 | } else { | |
4d7b695d SM |
163 | zlog_warn("Unexpected router ID address family for vrf %u: %u", |
164 | vrf_id, pref.family); | |
165 | return 0; | |
166 | } | |
4d7b695d SM |
167 | zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf); |
168 | return 0; | |
169 | } | |
170 | ||
171 | /** | |
172 | * Adds a segment routing policy to Zebra. | |
173 | * | |
174 | * @param policy The policy to add | |
175 | * @param segment_list The segment list for the policy | |
176 | */ | |
177 | void path_zebra_add_sr_policy(struct srte_policy *policy, | |
178 | struct srte_segment_list *segment_list) | |
179 | { | |
180 | struct zapi_sr_policy zp = {}; | |
181 | struct srte_segment_entry *segment; | |
182 | ||
183 | zp.color = policy->color; | |
184 | zp.endpoint = policy->endpoint; | |
185 | strlcpy(zp.name, policy->name, sizeof(zp.name)); | |
186 | zp.segment_list.type = ZEBRA_LSP_SRTE; | |
187 | zp.segment_list.local_label = policy->binding_sid; | |
188 | zp.segment_list.label_num = 0; | |
189 | RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments) | |
190 | zp.segment_list.labels[zp.segment_list.label_num++] = | |
191 | segment->sid_value; | |
192 | policy->status = SRTE_POLICY_STATUS_GOING_UP; | |
193 | ||
194 | (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp); | |
195 | } | |
196 | ||
197 | /** | |
198 | * Deletes a segment policy from Zebra. | |
199 | * | |
200 | * @param policy The policy to remove | |
201 | */ | |
202 | void path_zebra_delete_sr_policy(struct srte_policy *policy) | |
203 | { | |
204 | struct zapi_sr_policy zp = {}; | |
205 | ||
206 | zp.color = policy->color; | |
207 | zp.endpoint = policy->endpoint; | |
208 | strlcpy(zp.name, policy->name, sizeof(zp.name)); | |
209 | zp.segment_list.type = ZEBRA_LSP_SRTE; | |
210 | zp.segment_list.local_label = policy->binding_sid; | |
211 | zp.segment_list.label_num = 0; | |
212 | policy->status = SRTE_POLICY_STATUS_DOWN; | |
213 | ||
214 | (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp); | |
215 | } | |
216 | ||
217 | /** | |
218 | * Allocates a label from Zebra's label manager. | |
219 | * | |
220 | * @param label the label to be allocated | |
221 | * @return 0 if the label has been allocated, -1 otherwise | |
222 | */ | |
223 | int path_zebra_request_label(mpls_label_t label) | |
224 | { | |
225 | int ret; | |
226 | uint32_t start, end; | |
227 | ||
228 | ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end); | |
229 | if (ret < 0) { | |
230 | zlog_warn("%s: error getting label range!", __func__); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | /** | |
238 | * Releases a previously allocated label from Zebra's label manager. | |
239 | * | |
240 | * @param label The label to release | |
241 | * @return 0 ifthe label has beel released, -1 otherwise | |
242 | */ | |
243 | void path_zebra_release_label(mpls_label_t label) | |
244 | { | |
245 | int ret; | |
246 | ||
247 | ret = lm_release_label_chunk(zclient_sync, label, label); | |
248 | if (ret < 0) | |
249 | zlog_warn("%s: error releasing label range!", __func__); | |
250 | } | |
251 | ||
252 | static void path_zebra_label_manager_connect(void) | |
253 | { | |
254 | /* Connect to label manager. */ | |
255 | while (zclient_socket_connect(zclient_sync) < 0) { | |
256 | zlog_warn("%s: error connecting synchronous zclient!", | |
257 | __func__); | |
258 | sleep(1); | |
259 | } | |
260 | set_nonblocking(zclient_sync->sock); | |
261 | ||
262 | /* Send hello to notify zebra this is a synchronous client */ | |
263 | while (zclient_send_hello(zclient_sync) < 0) { | |
264 | zlog_warn("%s: Error sending hello for synchronous zclient!", | |
265 | __func__); | |
266 | sleep(1); | |
267 | } | |
268 | ||
269 | while (lm_label_manager_connect(zclient_sync, 0) != 0) { | |
270 | zlog_warn("%s: error connecting to label manager!", __func__); | |
271 | sleep(1); | |
272 | } | |
273 | } | |
274 | ||
75c69d15 JG |
275 | static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS) |
276 | { | |
277 | int ret = 0; | |
278 | struct stream *s; | |
279 | struct zapi_opaque_msg info; | |
280 | ||
281 | s = zclient->ibuf; | |
282 | ||
283 | if (zclient_opaque_decode(s, &info) != 0) | |
284 | return -1; | |
285 | ||
286 | switch (info.type) { | |
287 | case LINK_STATE_UPDATE: | |
288 | case LINK_STATE_SYNC: | |
289 | /* Start receiving ls data so cancel request sync timer */ | |
290 | path_ted_timer_sync_cancel(); | |
291 | ||
292 | struct ls_message *msg = ls_parse_msg(s); | |
293 | ||
294 | if (msg) { | |
295 | zlog_debug("%s: [rcv ted] ls (%s) msg (%s)-(%s) !", | |
296 | __func__, | |
297 | info.type == LINK_STATE_UPDATE | |
298 | ? "LINK_STATE_UPDATE" | |
299 | : "LINK_STATE_SYNC", | |
300 | LS_MSG_TYPE_PRINT(msg->type), | |
301 | LS_MSG_EVENT_PRINT(msg->event)); | |
302 | } else { | |
303 | zlog_err( | |
304 | "%s: [rcv ted] Could not parse LinkState stream message.", | |
305 | __func__); | |
306 | return -1; | |
307 | } | |
308 | ||
309 | ret = path_ted_rcvd_message(msg); | |
310 | ls_delete_msg(msg); | |
311 | /* Update local configuration after process update. */ | |
312 | path_ted_segment_list_refresh(); | |
313 | break; | |
314 | default: | |
315 | zlog_debug("%s: [rcv ted] unknown opaque event (%d) !", | |
316 | __func__, info.type); | |
317 | break; | |
318 | } | |
319 | ||
320 | return ret; | |
321 | } | |
322 | ||
a243d1db DL |
323 | static zclient_handler *const path_handlers[] = { |
324 | [ZEBRA_SR_POLICY_NOTIFY_STATUS] = path_zebra_sr_policy_notify_status, | |
325 | [ZEBRA_ROUTER_ID_UPDATE] = path_zebra_router_id_update, | |
326 | [ZEBRA_OPAQUE_MESSAGE] = path_zebra_opaque_msg_handler, | |
327 | }; | |
328 | ||
4d7b695d SM |
329 | /** |
330 | * Initializes Zebra asynchronous connection. | |
331 | * | |
332 | * @param master The master thread | |
333 | */ | |
334 | void path_zebra_init(struct thread_master *master) | |
335 | { | |
336 | struct zclient_options options = zclient_options_default; | |
337 | options.synchronous = true; | |
338 | ||
339 | /* Initialize asynchronous zclient. */ | |
a243d1db DL |
340 | zclient = zclient_new(master, &zclient_options_default, path_handlers, |
341 | array_size(path_handlers)); | |
4d7b695d SM |
342 | zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs); |
343 | zclient->zebra_connected = path_zebra_connected; | |
4d7b695d SM |
344 | |
345 | /* Initialize special zclient for synchronous message exchanges. */ | |
a243d1db | 346 | zclient_sync = zclient_new(master, &options, NULL, 0); |
4d7b695d SM |
347 | zclient_sync->sock = -1; |
348 | zclient_sync->redist_default = ZEBRA_ROUTE_SRTE; | |
349 | zclient_sync->instance = 1; | |
350 | zclient_sync->privs = &pathd_privs; | |
351 | ||
352 | /* Connect to the LM. */ | |
353 | path_zebra_label_manager_connect(); | |
354 | } |