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