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