]> git.proxmox.com Git - mirror_frr.git/blame - pathd/path_zebra.c
Merge pull request #12390 from sigeryang/vrrp-interop
[mirror_frr.git] / pathd / path_zebra.c
CommitLineData
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
40static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
41
42struct zclient *zclient;
4d7b695d
SM
43static struct zclient *zclient_sync;
44
45/* Global Variables */
46bool g_has_router_id_v4 = false;
47bool g_has_router_id_v6 = false;
48struct in_addr g_router_id_v4;
49struct in6_addr g_router_id_v6;
50pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER;
51pthread_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 */
59bool 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 */
78bool 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
91static 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
115static 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. */
140static 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 */
177void 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 */
202void 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 */
223int 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 */
243void 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
252static 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
275static 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
323static 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 */
334void 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}
e6d41136
PG
355
356void path_zebra_stop(void)
357{
358 zclient_stop(zclient);
359 zclient_free(zclient);
360}