]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_zebra.c
2a6bfbd60145c169795212611e0306db3b23ed38
[mirror_frr.git] / staticd / static_zebra.c
1 /*
2 * Zebra connect code.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 #include <zebra.h>
21
22 #include "thread.h"
23 #include "command.h"
24 #include "network.h"
25 #include "prefix.h"
26 #include "routemap.h"
27 #include "table.h"
28 #include "srcdest_table.h"
29 #include "stream.h"
30 #include "memory.h"
31 #include "zclient.h"
32 #include "filter.h"
33 #include "plist.h"
34 #include "log.h"
35 #include "nexthop.h"
36 #include "nexthop_group.h"
37 #include "hash.h"
38 #include "jhash.h"
39
40 #include "static_vrf.h"
41 #include "static_routes.h"
42 #include "static_zebra.h"
43 #include "static_nht.h"
44 #include "static_vty.h"
45
46 bool debug;
47
48 /* Zebra structure to hold current status. */
49 struct zclient *zclient;
50 static struct hash *static_nht_hash;
51
52 static struct interface *zebra_interface_if_lookup(struct stream *s)
53 {
54 char ifname_tmp[INTERFACE_NAMSIZ];
55
56 /* Read interface name. */
57 stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
58
59 /* And look it up. */
60 return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
61 }
62
63 /* Inteface addition message from zebra. */
64 static int static_ifp_create(struct interface *ifp)
65 {
66 static_ifindex_update(ifp, true);
67
68 return 0;
69 }
70
71 static int interface_delete(ZAPI_CALLBACK_ARGS)
72 {
73 struct interface *ifp;
74 struct stream *s;
75
76 s = zclient->ibuf;
77 /* zebra_interface_state_read () updates interface structure in iflist
78 */
79 ifp = zebra_interface_state_read(s, vrf_id);
80
81 if (ifp == NULL)
82 return 0;
83
84 if_set_index(ifp, IFINDEX_INTERNAL);
85
86 static_ifindex_update(ifp, false);
87 return 0;
88 }
89
90 static int interface_address_add(ZAPI_CALLBACK_ARGS)
91 {
92 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
93
94 return 0;
95 }
96
97 static int interface_address_delete(ZAPI_CALLBACK_ARGS)
98 {
99 struct connected *c;
100
101 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
102
103 if (!c)
104 return 0;
105
106 connected_free(c);
107 return 0;
108 }
109
110 static int interface_state_up(ZAPI_CALLBACK_ARGS)
111 {
112 struct interface *ifp;
113
114 ifp = zebra_interface_if_lookup(zclient->ibuf);
115
116 if (ifp) {
117 if (if_is_vrf(ifp)) {
118 struct static_vrf *svrf =
119 static_vrf_lookup_by_id(vrf_id);
120
121 static_fixup_vrf_ids(svrf);
122 static_config_install_delayed_routes(svrf);
123 }
124
125 /* Install any static reliant on this interface coming up */
126 static_install_intf_nh(ifp);
127 static_ifindex_update(ifp, true);
128 }
129
130 return 0;
131 }
132
133 static int interface_state_down(ZAPI_CALLBACK_ARGS)
134 {
135 struct interface *ifp;
136
137 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
138
139 if (ifp)
140 static_ifindex_update(ifp, false);
141
142 return 0;
143 }
144
145 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
146 {
147 struct prefix p;
148 enum zapi_route_notify_owner note;
149 uint32_t table_id;
150 char buf[PREFIX_STRLEN];
151
152 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
153 return -1;
154
155 prefix2str(&p, buf, sizeof(buf));
156
157 switch (note) {
158 case ZAPI_ROUTE_FAIL_INSTALL:
159 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
160 zlog_warn("%s: Route %s failed to install for table: %u",
161 __PRETTY_FUNCTION__, buf, table_id);
162 break;
163 case ZAPI_ROUTE_BETTER_ADMIN_WON:
164 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
165 zlog_warn("%s: Route %s over-ridden by better route for table: %u",
166 __PRETTY_FUNCTION__, buf, table_id);
167 break;
168 case ZAPI_ROUTE_INSTALLED:
169 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
170 break;
171 case ZAPI_ROUTE_REMOVED:
172 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
173 break;
174 case ZAPI_ROUTE_REMOVE_FAIL:
175 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
176 zlog_warn("%s: Route %s failure to remove for table: %u",
177 __PRETTY_FUNCTION__, buf, table_id);
178 break;
179 }
180
181 return 0;
182 }
183 static void zebra_connected(struct zclient *zclient)
184 {
185 zclient_send_reg_requests(zclient, VRF_DEFAULT);
186 }
187
188 struct static_nht_data {
189 struct prefix *nh;
190
191 vrf_id_t nh_vrf_id;
192
193 uint32_t refcount;
194 uint8_t nh_num;
195 };
196
197 /* API to check whether the configured nexthop address is
198 * one of its local connected address or not.
199 */
200 static bool
201 static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family)
202 {
203 if (family == AF_INET) {
204 if (if_lookup_exact_address(&addr->u.prefix4,
205 AF_INET,
206 vrfid))
207 return true;
208 } else if (family == AF_INET6) {
209 if (if_lookup_exact_address(&addr->u.prefix6,
210 AF_INET6,
211 vrfid))
212 return true;
213 }
214 return false;
215 }
216 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
217 {
218 struct static_nht_data *nhtd, lookup;
219 struct zapi_route nhr;
220 afi_t afi = AFI_IP;
221
222 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
223 zlog_warn("Failure to decode nexthop update message");
224 return 1;
225 }
226
227 if (nhr.prefix.family == AF_INET6)
228 afi = AFI_IP6;
229
230 if (nhr.type == ZEBRA_ROUTE_CONNECT) {
231 if (static_nexthop_is_local(vrf_id, &nhr.prefix,
232 nhr.prefix.family))
233 nhr.nexthop_num = 0;
234 }
235
236 memset(&lookup, 0, sizeof(lookup));
237 lookup.nh = &nhr.prefix;
238 lookup.nh_vrf_id = vrf_id;
239
240 nhtd = hash_lookup(static_nht_hash, &lookup);
241
242 if (nhtd) {
243 nhtd->nh_num = nhr.nexthop_num;
244
245 static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id);
246 static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi,
247 nhtd->nh_vrf_id);
248 } else
249 zlog_err("No nhtd?");
250
251 return 1;
252 }
253
254 static void static_zebra_capabilities(struct zclient_capabilities *cap)
255 {
256 mpls_enabled = cap->mpls_enabled;
257 }
258
259 static unsigned int static_nht_hash_key(const void *data)
260 {
261 const struct static_nht_data *nhtd = data;
262 unsigned int key = 0;
263
264 key = prefix_hash_key(nhtd->nh);
265 return jhash_1word(nhtd->nh_vrf_id, key);
266 }
267
268 static bool static_nht_hash_cmp(const void *d1, const void *d2)
269 {
270 const struct static_nht_data *nhtd1 = d1;
271 const struct static_nht_data *nhtd2 = d2;
272
273 if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
274 return false;
275
276 return prefix_same(nhtd1->nh, nhtd2->nh);
277 }
278
279 static void *static_nht_hash_alloc(void *data)
280 {
281 struct static_nht_data *copy = data;
282 struct static_nht_data *new;
283
284 new = XMALLOC(MTYPE_TMP, sizeof(*new));
285
286 new->nh = prefix_new();
287 prefix_copy(new->nh, copy->nh);
288 new->refcount = 0;
289 new->nh_num = 0;
290 new->nh_vrf_id = copy->nh_vrf_id;
291
292 return new;
293 }
294
295 static void static_nht_hash_free(void *data)
296 {
297 struct static_nht_data *nhtd = data;
298
299 prefix_free(nhtd->nh);
300 XFREE(MTYPE_TMP, nhtd);
301 }
302
303 void static_zebra_nht_register(struct route_node *rn,
304 struct static_route *si, bool reg)
305 {
306 struct static_nht_data *nhtd, lookup;
307 uint32_t cmd;
308 struct prefix p;
309 afi_t afi = AFI_IP;
310
311 cmd = (reg) ?
312 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
313
314 if (si->nh_registered && reg)
315 return;
316
317 if (!si->nh_registered && !reg)
318 return;
319
320 memset(&p, 0, sizeof(p));
321 switch (si->type) {
322 case STATIC_IFNAME:
323 case STATIC_BLACKHOLE:
324 return;
325 case STATIC_IPV4_GATEWAY:
326 case STATIC_IPV4_GATEWAY_IFNAME:
327 p.family = AF_INET;
328 p.prefixlen = IPV4_MAX_BITLEN;
329 p.u.prefix4 = si->addr.ipv4;
330 afi = AFI_IP;
331 break;
332 case STATIC_IPV6_GATEWAY:
333 case STATIC_IPV6_GATEWAY_IFNAME:
334 p.family = AF_INET6;
335 p.prefixlen = IPV6_MAX_BITLEN;
336 p.u.prefix6 = si->addr.ipv6;
337 afi = AFI_IP6;
338 break;
339 }
340
341 memset(&lookup, 0, sizeof(lookup));
342 lookup.nh = &p;
343 lookup.nh_vrf_id = si->nh_vrf_id;
344
345 si->nh_registered = reg;
346
347 if (reg) {
348 nhtd = hash_get(static_nht_hash, &lookup,
349 static_nht_hash_alloc);
350 nhtd->refcount++;
351
352 if (debug)
353 zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p,
354 rn, nhtd->nh_num);
355 if (nhtd->refcount > 1 && nhtd->nh_num) {
356 static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num,
357 afi, si->nh_vrf_id);
358 return;
359 }
360 } else {
361 nhtd = hash_lookup(static_nht_hash, &lookup);
362 if (!nhtd)
363 return;
364
365 nhtd->refcount--;
366 if (nhtd->refcount >= 1)
367 return;
368
369 hash_release(static_nht_hash, nhtd);
370 static_nht_hash_free(nhtd);
371 }
372
373 if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
374 zlog_warn("%s: Failure to send nexthop to zebra",
375 __PRETTY_FUNCTION__);
376 }
377
378 extern void static_zebra_route_add(struct route_node *rn,
379 struct static_route *si_changed,
380 vrf_id_t vrf_id, safi_t safi, bool install)
381 {
382 struct static_route *si = rn->info;
383 const struct prefix *p, *src_pp;
384 struct zapi_nexthop *api_nh;
385 struct zapi_route api;
386 uint32_t nh_num = 0;
387
388 p = src_pp = NULL;
389 srcdest_rnode_prefixes(rn, &p, &src_pp);
390
391 memset(&api, 0, sizeof(api));
392 api.vrf_id = vrf_id;
393 api.type = ZEBRA_ROUTE_STATIC;
394 api.safi = safi;
395 memcpy(&api.prefix, p, sizeof(api.prefix));
396
397 if (src_pp) {
398 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
399 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
400 }
401 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
402 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
403 if (si_changed->distance) {
404 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
405 api.distance = si_changed->distance;
406 }
407 if (si_changed->tag) {
408 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
409 api.tag = si_changed->tag;
410 }
411 if (si_changed->table_id != 0) {
412 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
413 api.tableid = si_changed->table_id;
414 }
415 for (/*loaded above*/; si; si = si->next) {
416 api_nh = &api.nexthops[nh_num];
417 if (si->nh_vrf_id == VRF_UNKNOWN)
418 continue;
419
420 if (si->distance != si_changed->distance)
421 continue;
422
423 if (si->table_id != si_changed->table_id)
424 continue;
425
426 api_nh->vrf_id = si->nh_vrf_id;
427 api_nh->onlink = si->onlink;
428
429 si->state = STATIC_SENT_TO_ZEBRA;
430
431 switch (si->type) {
432 case STATIC_IFNAME:
433 if (si->ifindex == IFINDEX_INTERNAL)
434 continue;
435 api_nh->ifindex = si->ifindex;
436 api_nh->type = NEXTHOP_TYPE_IFINDEX;
437 break;
438 case STATIC_IPV4_GATEWAY:
439 if (!si->nh_valid)
440 continue;
441 api_nh->type = NEXTHOP_TYPE_IPV4;
442 api_nh->gate = si->addr;
443 break;
444 case STATIC_IPV4_GATEWAY_IFNAME:
445 if (si->ifindex == IFINDEX_INTERNAL)
446 continue;
447 api_nh->ifindex = si->ifindex;
448 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
449 api_nh->gate = si->addr;
450 break;
451 case STATIC_IPV6_GATEWAY:
452 if (!si->nh_valid)
453 continue;
454 api_nh->type = NEXTHOP_TYPE_IPV6;
455 api_nh->gate = si->addr;
456 break;
457 case STATIC_IPV6_GATEWAY_IFNAME:
458 if (si->ifindex == IFINDEX_INTERNAL)
459 continue;
460 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
461 api_nh->ifindex = si->ifindex;
462 api_nh->gate = si->addr;
463 break;
464 case STATIC_BLACKHOLE:
465 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
466 switch (si->bh_type) {
467 case STATIC_BLACKHOLE_DROP:
468 case STATIC_BLACKHOLE_NULL:
469 api_nh->bh_type = BLACKHOLE_NULL;
470 break;
471 case STATIC_BLACKHOLE_REJECT:
472 api_nh->bh_type = BLACKHOLE_REJECT;
473 }
474 break;
475 }
476
477 if (si->snh_label.num_labels) {
478 int i;
479
480 SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
481 api_nh->label_num = si->snh_label.num_labels;
482 for (i = 0; i < api_nh->label_num; i++)
483 api_nh->labels[i] = si->snh_label.label[i];
484 }
485 nh_num++;
486 }
487
488 api.nexthop_num = nh_num;
489
490 /*
491 * If we have been given an install but nothing is valid
492 * go ahead and delete the route for double plus fun
493 */
494 if (!nh_num && install)
495 install = false;
496
497 zclient_route_send(install ?
498 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
499 zclient, &api);
500 }
501
502 static int static_ifp_up(struct interface *ifp)
503 {
504 return 0;
505 }
506
507 static int static_ifp_down(struct interface *ifp)
508 {
509 return 0;
510 }
511
512 static int static_ifp_destroy(struct interface *ifp)
513 {
514 return 0;
515 }
516
517 void static_zebra_init(void)
518 {
519 struct zclient_options opt = { .receive_notify = true };
520
521 if_zapi_callbacks(static_ifp_create, static_ifp_up,
522 static_ifp_down, static_ifp_destroy);
523
524 zclient = zclient_new(master, &opt);
525
526 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
527 zclient->zebra_capabilities = static_zebra_capabilities;
528 zclient->zebra_connected = zebra_connected;
529 zclient->interface_delete = interface_delete;
530 zclient->interface_up = interface_state_up;
531 zclient->interface_down = interface_state_down;
532 zclient->interface_address_add = interface_address_add;
533 zclient->interface_address_delete = interface_address_delete;
534 zclient->route_notify_owner = route_notify_owner;
535 zclient->nexthop_update = static_zebra_nexthop_update;
536
537 static_nht_hash = hash_create(static_nht_hash_key,
538 static_nht_hash_cmp,
539 "Static Nexthop Tracking hash");
540 }