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