]> git.proxmox.com Git - mirror_frr.git/blame - staticd/static_zebra.c
doc: add frr_{each,with} to coding style
[mirror_frr.git] / staticd / static_zebra.c
CommitLineData
7e24fdf3
DS
1/*
2 * Zebra connect code.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
8d5cbee9
DS
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.
7e24fdf3 10 *
8d5cbee9
DS
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.
7e24fdf3
DS
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"
74f0a94e 37#include "hash.h"
f591b309 38#include "jhash.h"
7e24fdf3
DS
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
6f5db0b1
DS
46bool debug;
47
7e24fdf3
DS
48/* Zebra structure to hold current status. */
49struct zclient *zclient;
74f0a94e 50static struct hash *static_nht_hash;
7e24fdf3 51
a36898e7 52static struct interface *zebra_interface_if_lookup(struct stream *s)
7e24fdf3
DS
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. */
a36898e7 60 return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
7e24fdf3
DS
61}
62
63/* Inteface addition message from zebra. */
121f9dee 64static int interface_add(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
65{
66 struct interface *ifp;
67
68 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
69
70 if (!ifp)
71 return 0;
72
73 static_ifindex_update(ifp, true);
74 return 0;
75}
76
121f9dee 77static int interface_delete(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
78{
79 struct interface *ifp;
80 struct stream *s;
81
82 s = zclient->ibuf;
83 /* zebra_interface_state_read () updates interface structure in iflist
84 */
85 ifp = zebra_interface_state_read(s, vrf_id);
86
87 if (ifp == NULL)
88 return 0;
89
90 if_set_index(ifp, IFINDEX_INTERNAL);
91
92 static_ifindex_update(ifp, false);
93 return 0;
94}
95
121f9dee 96static int interface_address_add(ZAPI_CALLBACK_ARGS)
7e24fdf3 97{
121f9dee 98 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
7e24fdf3
DS
99
100 return 0;
101}
102
121f9dee 103static int interface_address_delete(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
104{
105 struct connected *c;
106
121f9dee 107 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
7e24fdf3
DS
108
109 if (!c)
110 return 0;
111
112 connected_free(c);
113 return 0;
114}
115
121f9dee 116static int interface_state_up(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
117{
118 struct interface *ifp;
119
a36898e7 120 ifp = zebra_interface_if_lookup(zclient->ibuf);
7e24fdf3 121
a9be49bc
DS
122 if (ifp) {
123 if (if_is_vrf(ifp)) {
124 struct static_vrf *svrf =
125 static_vrf_lookup_by_id(vrf_id);
7e24fdf3 126
a9be49bc
DS
127 static_fixup_vrf_ids(svrf);
128 static_config_install_delayed_routes(svrf);
129 }
130
131 /* Install any static reliant on this interface coming up */
132 static_install_intf_nh(ifp);
7e24fdf3
DS
133 }
134
135 return 0;
136}
137
121f9dee 138static int interface_state_down(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
139{
140 zebra_interface_state_read(zclient->ibuf, vrf_id);
141
142 return 0;
143}
144
121f9dee 145static int route_notify_owner(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
146{
147 struct prefix p;
148 enum zapi_route_notify_owner note;
149 uint32_t table_id;
150 char buf[PREFIX_STRLEN];
151
7e24fdf3
DS
152 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
153 return -1;
154
4a582888
DS
155 prefix2str(&p, buf, sizeof(buf));
156
7e24fdf3
DS
157 switch (note) {
158 case ZAPI_ROUTE_FAIL_INSTALL:
9fafbd15 159 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
7e24fdf3
DS
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:
9fafbd15 164 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
7e24fdf3
DS
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:
9fafbd15 169 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
7e24fdf3
DS
170 break;
171 case ZAPI_ROUTE_REMOVED:
9fafbd15 172 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
7e24fdf3
DS
173 break;
174 case ZAPI_ROUTE_REMOVE_FAIL:
9fafbd15 175 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
7e24fdf3
DS
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}
183static void zebra_connected(struct zclient *zclient)
184{
185 zclient_send_reg_requests(zclient, VRF_DEFAULT);
186}
187
74f0a94e
DS
188struct static_nht_data {
189 struct prefix *nh;
f591b309
DS
190
191 vrf_id_t nh_vrf_id;
192
74f0a94e
DS
193 uint32_t refcount;
194 uint8_t nh_num;
195};
7e24fdf3 196
121f9dee 197static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
7e24fdf3 198{
74f0a94e 199 struct static_nht_data *nhtd, lookup;
7e24fdf3
DS
200 struct zapi_route nhr;
201 afi_t afi = AFI_IP;
202
203 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
204 zlog_warn("Failure to decode nexthop update message");
205 return 1;
206 }
207
208 if (nhr.prefix.family == AF_INET6)
209 afi = AFI_IP6;
210
74f0a94e
DS
211 memset(&lookup, 0, sizeof(lookup));
212 lookup.nh = &nhr.prefix;
f591b309 213 lookup.nh_vrf_id = vrf_id;
74f0a94e
DS
214
215 nhtd = hash_lookup(static_nht_hash, &lookup);
f591b309
DS
216
217 if (nhtd) {
74f0a94e
DS
218 nhtd->nh_num = nhr.nexthop_num;
219
9fafbd15 220 static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id);
27da3044 221 static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi,
f591b309
DS
222 nhtd->nh_vrf_id);
223 } else
224 zlog_err("No nhtd?");
74f0a94e 225
7e24fdf3
DS
226 return 1;
227}
228
229static void static_zebra_capabilities(struct zclient_capabilities *cap)
230{
231 mpls_enabled = cap->mpls_enabled;
232}
233
d8b87afe 234static unsigned int static_nht_hash_key(const void *data)
74f0a94e 235{
d8b87afe 236 const struct static_nht_data *nhtd = data;
f591b309 237 unsigned int key = 0;
74f0a94e 238
f591b309
DS
239 key = prefix_hash_key(nhtd->nh);
240 return jhash_1word(nhtd->nh_vrf_id, key);
74f0a94e
DS
241}
242
74df8d6d 243static bool static_nht_hash_cmp(const void *d1, const void *d2)
74f0a94e
DS
244{
245 const struct static_nht_data *nhtd1 = d1;
246 const struct static_nht_data *nhtd2 = d2;
247
f591b309 248 if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
74df8d6d 249 return false;
f591b309 250
74f0a94e
DS
251 return prefix_same(nhtd1->nh, nhtd2->nh);
252}
253
254static void *static_nht_hash_alloc(void *data)
255{
256 struct static_nht_data *copy = data;
257 struct static_nht_data *new;
258
259 new = XMALLOC(MTYPE_TMP, sizeof(*new));
260
261 new->nh = prefix_new();
262 prefix_copy(new->nh, copy->nh);
263 new->refcount = 0;
264 new->nh_num = 0;
f591b309 265 new->nh_vrf_id = copy->nh_vrf_id;
74f0a94e
DS
266
267 return new;
268}
269
270static void static_nht_hash_free(void *data)
271{
272 struct static_nht_data *nhtd = data;
273
274 prefix_free(nhtd->nh);
275 XFREE(MTYPE_TMP, nhtd);
276}
277
27da3044
DS
278void static_zebra_nht_register(struct route_node *rn,
279 struct static_route *si, bool reg)
7e24fdf3 280{
74f0a94e 281 struct static_nht_data *nhtd, lookup;
7e24fdf3
DS
282 uint32_t cmd;
283 struct prefix p;
74f0a94e 284 afi_t afi = AFI_IP;
7e24fdf3
DS
285
286 cmd = (reg) ?
287 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
288
289 if (si->nh_registered && reg)
290 return;
291
292 if (!si->nh_registered && !reg)
293 return;
294
295 memset(&p, 0, sizeof(p));
296 switch (si->type) {
7e24fdf3
DS
297 case STATIC_IFNAME:
298 case STATIC_BLACKHOLE:
7e24fdf3
DS
299 return;
300 case STATIC_IPV4_GATEWAY:
88a90016 301 case STATIC_IPV4_GATEWAY_IFNAME:
7e24fdf3
DS
302 p.family = AF_INET;
303 p.prefixlen = IPV4_MAX_BITLEN;
304 p.u.prefix4 = si->addr.ipv4;
74f0a94e 305 afi = AFI_IP;
7e24fdf3
DS
306 break;
307 case STATIC_IPV6_GATEWAY:
88a90016 308 case STATIC_IPV6_GATEWAY_IFNAME:
7e24fdf3
DS
309 p.family = AF_INET6;
310 p.prefixlen = IPV6_MAX_BITLEN;
311 p.u.prefix6 = si->addr.ipv6;
74f0a94e 312 afi = AFI_IP6;
7e24fdf3
DS
313 break;
314 }
315
74f0a94e
DS
316 memset(&lookup, 0, sizeof(lookup));
317 lookup.nh = &p;
f591b309 318 lookup.nh_vrf_id = si->nh_vrf_id;
74f0a94e
DS
319
320 si->nh_registered = reg;
321
322 if (reg) {
323 nhtd = hash_get(static_nht_hash, &lookup,
324 static_nht_hash_alloc);
325 nhtd->refcount++;
326
6f5db0b1
DS
327 if (debug)
328 zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p,
329 rn, nhtd->nh_num);
330 if (nhtd->refcount > 1 && nhtd->nh_num) {
27da3044 331 static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num,
74f0a94e
DS
332 afi, si->nh_vrf_id);
333 return;
334 }
335 } else {
336 nhtd = hash_lookup(static_nht_hash, &lookup);
337 if (!nhtd)
338 return;
339
340 nhtd->refcount--;
341 if (nhtd->refcount >= 1)
342 return;
343
344 hash_release(static_nht_hash, nhtd);
345 static_nht_hash_free(nhtd);
346 }
347
7e24fdf3
DS
348 if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
349 zlog_warn("%s: Failure to send nexthop to zebra",
350 __PRETTY_FUNCTION__);
7e24fdf3
DS
351}
352
8bc8de2c
DS
353extern void static_zebra_route_add(struct route_node *rn,
354 struct static_route *si_changed,
355 vrf_id_t vrf_id, safi_t safi, bool install)
7e24fdf3
DS
356{
357 struct static_route *si = rn->info;
358 const struct prefix *p, *src_pp;
359 struct zapi_nexthop *api_nh;
360 struct zapi_route api;
361 uint32_t nh_num = 0;
362
363 p = src_pp = NULL;
364 srcdest_rnode_prefixes(rn, &p, &src_pp);
365
366 memset(&api, 0, sizeof(api));
367 api.vrf_id = vrf_id;
368 api.type = ZEBRA_ROUTE_STATIC;
369 api.safi = safi;
370 memcpy(&api.prefix, p, sizeof(api.prefix));
371
372 if (src_pp) {
373 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
374 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
375 }
8bc8de2c 376 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
7e24fdf3 377 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
8bc8de2c
DS
378 if (si_changed->distance) {
379 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
380 api.distance = si_changed->distance;
381 }
382 if (si_changed->tag) {
383 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
384 api.tag = si_changed->tag;
385 }
31d4a8e5
PG
386 if (si_changed->table_id != 0) {
387 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
388 api.tableid = si_changed->table_id;
389 }
7e24fdf3
DS
390 for (/*loaded above*/; si; si = si->next) {
391 api_nh = &api.nexthops[nh_num];
392 if (si->nh_vrf_id == VRF_UNKNOWN)
393 continue;
394
8bc8de2c
DS
395 if (si->distance != si_changed->distance)
396 continue;
7e24fdf3 397
95cdbe5d
DS
398 if (si->table_id != si_changed->table_id)
399 continue;
400
7e24fdf3 401 api_nh->vrf_id = si->nh_vrf_id;
fe85601c
DS
402 api_nh->onlink = si->onlink;
403
9fafbd15
DS
404 si->state = STATIC_SENT_TO_ZEBRA;
405
7e24fdf3
DS
406 switch (si->type) {
407 case STATIC_IFNAME:
408 if (si->ifindex == IFINDEX_INTERNAL)
409 continue;
410 api_nh->ifindex = si->ifindex;
411 api_nh->type = NEXTHOP_TYPE_IFINDEX;
412 break;
413 case STATIC_IPV4_GATEWAY:
414 if (!si->nh_valid)
415 continue;
416 api_nh->type = NEXTHOP_TYPE_IPV4;
417 api_nh->gate = si->addr;
418 break;
419 case STATIC_IPV4_GATEWAY_IFNAME:
420 if (si->ifindex == IFINDEX_INTERNAL)
421 continue;
422 api_nh->ifindex = si->ifindex;
423 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
424 api_nh->gate = si->addr;
425 break;
426 case STATIC_IPV6_GATEWAY:
427 if (!si->nh_valid)
428 continue;
429 api_nh->type = NEXTHOP_TYPE_IPV6;
430 api_nh->gate = si->addr;
431 break;
432 case STATIC_IPV6_GATEWAY_IFNAME:
433 if (si->ifindex == IFINDEX_INTERNAL)
434 continue;
435 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
436 api_nh->ifindex = si->ifindex;
437 api_nh->gate = si->addr;
438 break;
439 case STATIC_BLACKHOLE:
440 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
441 switch (si->bh_type) {
442 case STATIC_BLACKHOLE_DROP:
443 case STATIC_BLACKHOLE_NULL:
444 api_nh->bh_type = BLACKHOLE_NULL;
445 break;
446 case STATIC_BLACKHOLE_REJECT:
447 api_nh->bh_type = BLACKHOLE_REJECT;
448 }
449 break;
450 }
451
452 if (si->snh_label.num_labels) {
453 int i;
454
455 SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
456 api_nh->label_num = si->snh_label.num_labels;
457 for (i = 0; i < api_nh->label_num; i++)
458 api_nh->labels[i] = si->snh_label.label[i];
459 }
460 nh_num++;
461 }
462
463 api.nexthop_num = nh_num;
464
465 /*
466 * If we have been given an install but nothing is valid
467 * go ahead and delete the route for double plus fun
468 */
469 if (!nh_num && install)
470 install = false;
471
472 zclient_route_send(install ?
473 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
474 zclient, &api);
475}
476void static_zebra_init(void)
477{
478 struct zclient_options opt = { .receive_notify = true };
479
26f63a1e 480 zclient = zclient_new(master, &opt);
7e24fdf3
DS
481
482 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
483 zclient->zebra_capabilities = static_zebra_capabilities;
484 zclient->zebra_connected = zebra_connected;
485 zclient->interface_add = interface_add;
486 zclient->interface_delete = interface_delete;
487 zclient->interface_up = interface_state_up;
488 zclient->interface_down = interface_state_down;
489 zclient->interface_address_add = interface_address_add;
490 zclient->interface_address_delete = interface_address_delete;
491 zclient->route_notify_owner = route_notify_owner;
492 zclient->nexthop_update = static_zebra_nexthop_update;
74f0a94e
DS
493
494 static_nht_hash = hash_create(static_nht_hash_key,
495 static_nht_hash_cmp,
496 "Static Nexthop Tracking hash");
7e24fdf3 497}