]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_zebra.c
pathd: New SR-TE policy management daemon
[mirror_frr.git] / pathd / path_zebra.c
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
19 #include "thread.h"
20 #include "log.h"
21 #include "lib_errors.h"
22 #include "if.h"
23 #include "prefix.h"
24 #include "zclient.h"
25 #include "network.h"
26 #include "stream.h"
27 #include "linklist.h"
28 #include "nexthop.h"
29 #include "vrf.h"
30 #include "typesafe.h"
31
32 #include "pathd/pathd.h"
33 #include "pathd/path_zebra.h"
34
35 static struct zclient *zclient;
36 static struct zclient *zclient_sync;
37
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;
45
46 /**
47 * Gives the IPv4 router ID received from Zebra.
48 *
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
51 */
52 bool get_ipv4_router_id(struct in_addr *router_id)
53 {
54 bool retval = false;
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));
59 retval = true;
60 }
61 pthread_mutex_unlock(&g_router_id_v4_mtx);
62 return retval;
63 }
64
65 /**
66 * Gives the IPv6 router ID received from Zebra.
67 *
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
70 */
71 bool get_ipv6_router_id(struct in6_addr *router_id)
72 {
73 bool retval = false;
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));
78 retval = true;
79 }
80 pthread_mutex_unlock(&g_router_id_v6_mtx);
81 return retval;
82 }
83
84 static void path_zebra_connected(struct zclient *zclient)
85 {
86 struct srte_policy *policy;
87
88 zclient_send_reg_requests(zclient, VRF_DEFAULT);
89 zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
90 VRF_DEFAULT);
91
92 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
93 struct srte_candidate *candidate;
94 struct srte_segment_list *segment_list;
95
96 candidate = policy->best_candidate;
97 if (!candidate)
98 continue;
99
100 segment_list = candidate->lsp->segment_list;
101 if (!segment_list)
102 continue;
103
104 path_zebra_add_sr_policy(policy, segment_list);
105 }
106 }
107
108 static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
109 {
110 struct zapi_sr_policy zapi_sr_policy;
111 struct srte_policy *policy;
112 struct srte_candidate *best_candidate_path;
113
114 if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
115 return -1;
116
117 policy = srte_policy_find(zapi_sr_policy.color,
118 &zapi_sr_policy.endpoint);
119 if (!policy)
120 return -1;
121
122 best_candidate_path = policy->best_candidate;
123 if (!best_candidate_path)
124 return -1;
125
126 srte_candidate_status_update(best_candidate_path,
127 zapi_sr_policy.status);
128
129 return 0;
130 }
131
132 /* Router-id update message from zebra. */
133 static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
134 {
135 struct prefix pref;
136 const char *family;
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);
146 family = "IPv4";
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);
154 family = "IPv6";
155 } else {
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);
159 return 0;
160 }
161 pthread_mutex_unlock(&g_router_id_v4_mtx);
162 zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
163 return 0;
164 }
165
166 /**
167 * Adds a segment routing policy to Zebra.
168 *
169 * @param policy The policy to add
170 * @param segment_list The segment list for the policy
171 */
172 void path_zebra_add_sr_policy(struct srte_policy *policy,
173 struct srte_segment_list *segment_list)
174 {
175 struct zapi_sr_policy zp = {};
176 struct srte_segment_entry *segment;
177
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++] =
186 segment->sid_value;
187 policy->status = SRTE_POLICY_STATUS_GOING_UP;
188
189 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
190 }
191
192 /**
193 * Deletes a segment policy from Zebra.
194 *
195 * @param policy The policy to remove
196 */
197 void path_zebra_delete_sr_policy(struct srte_policy *policy)
198 {
199 struct zapi_sr_policy zp = {};
200
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;
208
209 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
210 }
211
212 /**
213 * Allocates a label from Zebra's label manager.
214 *
215 * @param label the label to be allocated
216 * @return 0 if the label has been allocated, -1 otherwise
217 */
218 int path_zebra_request_label(mpls_label_t label)
219 {
220 int ret;
221 uint32_t start, end;
222
223 ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
224 if (ret < 0) {
225 zlog_warn("%s: error getting label range!", __func__);
226 return -1;
227 }
228
229 return 0;
230 }
231
232 /**
233 * Releases a previously allocated label from Zebra's label manager.
234 *
235 * @param label The label to release
236 * @return 0 ifthe label has beel released, -1 otherwise
237 */
238 void path_zebra_release_label(mpls_label_t label)
239 {
240 int ret;
241
242 ret = lm_release_label_chunk(zclient_sync, label, label);
243 if (ret < 0)
244 zlog_warn("%s: error releasing label range!", __func__);
245 }
246
247 static void path_zebra_label_manager_connect(void)
248 {
249 /* Connect to label manager. */
250 while (zclient_socket_connect(zclient_sync) < 0) {
251 zlog_warn("%s: error connecting synchronous zclient!",
252 __func__);
253 sleep(1);
254 }
255 set_nonblocking(zclient_sync->sock);
256
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!",
260 __func__);
261 sleep(1);
262 }
263
264 while (lm_label_manager_connect(zclient_sync, 0) != 0) {
265 zlog_warn("%s: error connecting to label manager!", __func__);
266 sleep(1);
267 }
268 }
269
270 /**
271 * Initializes Zebra asynchronous connection.
272 *
273 * @param master The master thread
274 */
275 void path_zebra_init(struct thread_master *master)
276 {
277 struct zclient_options options = zclient_options_default;
278 options.synchronous = true;
279
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;
286
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;
293
294 /* Connect to the LM. */
295 path_zebra_label_manager_connect();
296 }