]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_zebra.c
Merge pull request #7652 from adharkar/frr-vni_switch
[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 zlog_warn("Unexpected router ID address family for vrf %u: %u",
157 vrf_id, pref.family);
158 return 0;
159 }
160 zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
161 return 0;
162 }
163
164 /**
165 * Adds a segment routing policy to Zebra.
166 *
167 * @param policy The policy to add
168 * @param segment_list The segment list for the policy
169 */
170 void path_zebra_add_sr_policy(struct srte_policy *policy,
171 struct srte_segment_list *segment_list)
172 {
173 struct zapi_sr_policy zp = {};
174 struct srte_segment_entry *segment;
175
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++] =
184 segment->sid_value;
185 policy->status = SRTE_POLICY_STATUS_GOING_UP;
186
187 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
188 }
189
190 /**
191 * Deletes a segment policy from Zebra.
192 *
193 * @param policy The policy to remove
194 */
195 void path_zebra_delete_sr_policy(struct srte_policy *policy)
196 {
197 struct zapi_sr_policy zp = {};
198
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;
206
207 (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
208 }
209
210 /**
211 * Allocates a label from Zebra's label manager.
212 *
213 * @param label the label to be allocated
214 * @return 0 if the label has been allocated, -1 otherwise
215 */
216 int path_zebra_request_label(mpls_label_t label)
217 {
218 int ret;
219 uint32_t start, end;
220
221 ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
222 if (ret < 0) {
223 zlog_warn("%s: error getting label range!", __func__);
224 return -1;
225 }
226
227 return 0;
228 }
229
230 /**
231 * Releases a previously allocated label from Zebra's label manager.
232 *
233 * @param label The label to release
234 * @return 0 ifthe label has beel released, -1 otherwise
235 */
236 void path_zebra_release_label(mpls_label_t label)
237 {
238 int ret;
239
240 ret = lm_release_label_chunk(zclient_sync, label, label);
241 if (ret < 0)
242 zlog_warn("%s: error releasing label range!", __func__);
243 }
244
245 static void path_zebra_label_manager_connect(void)
246 {
247 /* Connect to label manager. */
248 while (zclient_socket_connect(zclient_sync) < 0) {
249 zlog_warn("%s: error connecting synchronous zclient!",
250 __func__);
251 sleep(1);
252 }
253 set_nonblocking(zclient_sync->sock);
254
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!",
258 __func__);
259 sleep(1);
260 }
261
262 while (lm_label_manager_connect(zclient_sync, 0) != 0) {
263 zlog_warn("%s: error connecting to label manager!", __func__);
264 sleep(1);
265 }
266 }
267
268 /**
269 * Initializes Zebra asynchronous connection.
270 *
271 * @param master The master thread
272 */
273 void path_zebra_init(struct thread_master *master)
274 {
275 struct zclient_options options = zclient_options_default;
276 options.synchronous = true;
277
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;
284
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;
291
292 /* Connect to the LM. */
293 path_zebra_label_manager_connect();
294 }