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