]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_zebra.c
Merge pull request #2898 from donaldsharp/vrf_bitmap_is_whack
[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
39 #include "static_vrf.h"
40 #include "static_routes.h"
41 #include "static_zebra.h"
42 #include "static_nht.h"
43 #include "static_vty.h"
44
45 /* Zebra structure to hold current status. */
46 struct zclient *zclient;
47 static struct hash *static_nht_hash;
48
49 static struct interface *zebra_interface_if_lookup(struct stream *s)
50 {
51 char ifname_tmp[INTERFACE_NAMSIZ];
52
53 /* Read interface name. */
54 stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
55
56 /* And look it up. */
57 return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
58 }
59
60 /* Inteface addition message from zebra. */
61 static int interface_add(int command, struct zclient *zclient,
62 zebra_size_t length, vrf_id_t vrf_id)
63 {
64 struct interface *ifp;
65
66 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
67
68 if (!ifp)
69 return 0;
70
71 static_ifindex_update(ifp, true);
72 return 0;
73 }
74
75 static int interface_delete(int command, struct zclient *zclient,
76 zebra_size_t length, vrf_id_t vrf_id)
77 {
78 struct interface *ifp;
79 struct stream *s;
80
81 s = zclient->ibuf;
82 /* zebra_interface_state_read () updates interface structure in iflist
83 */
84 ifp = zebra_interface_state_read(s, vrf_id);
85
86 if (ifp == NULL)
87 return 0;
88
89 if_set_index(ifp, IFINDEX_INTERNAL);
90
91 static_ifindex_update(ifp, false);
92 return 0;
93 }
94
95 static int interface_address_add(int command, struct zclient *zclient,
96 zebra_size_t length, vrf_id_t vrf_id)
97 {
98 zebra_interface_address_read(command, zclient->ibuf, vrf_id);
99
100 return 0;
101 }
102
103 static int interface_address_delete(int command, struct zclient *zclient,
104 zebra_size_t length, vrf_id_t vrf_id)
105 {
106 struct connected *c;
107
108 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
109
110 if (!c)
111 return 0;
112
113 connected_free(c);
114 return 0;
115 }
116
117 static int interface_state_up(int command, struct zclient *zclient,
118 zebra_size_t length, vrf_id_t vrf_id)
119 {
120 struct interface *ifp;
121
122 ifp = zebra_interface_if_lookup(zclient->ibuf);
123
124 if (ifp && if_is_vrf(ifp)) {
125 struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
126
127 static_fixup_vrf_ids(svrf);
128 static_config_install_delayed_routes(svrf);
129 }
130
131 return 0;
132 }
133
134 static int interface_state_down(int command, struct zclient *zclient,
135 zebra_size_t length, vrf_id_t vrf_id)
136 {
137 zebra_interface_state_read(zclient->ibuf, vrf_id);
138
139 return 0;
140 }
141
142 static int route_notify_owner(int command, struct zclient *zclient,
143 zebra_size_t length, vrf_id_t vrf_id)
144 {
145 struct prefix p;
146 enum zapi_route_notify_owner note;
147 uint32_t table_id;
148 char buf[PREFIX_STRLEN];
149
150 prefix2str(&p, buf, sizeof(buf));
151
152 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
153 return -1;
154
155 switch (note) {
156 case ZAPI_ROUTE_FAIL_INSTALL:
157 zlog_warn("%s: Route %s failed to install for table: %u",
158 __PRETTY_FUNCTION__, buf, table_id);
159 break;
160 case ZAPI_ROUTE_BETTER_ADMIN_WON:
161 zlog_warn("%s: Route %s over-ridden by better route for table: %u",
162 __PRETTY_FUNCTION__, buf, table_id);
163 break;
164 case ZAPI_ROUTE_INSTALLED:
165 break;
166 case ZAPI_ROUTE_REMOVED:
167 break;
168 case ZAPI_ROUTE_REMOVE_FAIL:
169 zlog_warn("%s: Route %s failure to remove for table: %u",
170 __PRETTY_FUNCTION__, buf, table_id);
171 break;
172 }
173
174 return 0;
175 }
176 static void zebra_connected(struct zclient *zclient)
177 {
178 zclient_send_reg_requests(zclient, VRF_DEFAULT);
179 }
180
181 struct static_nht_data {
182 struct prefix *nh;
183 uint32_t refcount;
184 uint8_t nh_num;
185 };
186
187 static int static_zebra_nexthop_update(int command, struct zclient *zclient,
188 zebra_size_t length, vrf_id_t vrf_id)
189 {
190 struct static_nht_data *nhtd, lookup;
191 struct zapi_route nhr;
192 afi_t afi = AFI_IP;
193
194 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
195 zlog_warn("Failure to decode nexthop update message");
196 return 1;
197 }
198
199 if (nhr.prefix.family == AF_INET6)
200 afi = AFI_IP6;
201
202 memset(&lookup, 0, sizeof(lookup));
203 lookup.nh = &nhr.prefix;
204
205 nhtd = hash_lookup(static_nht_hash, &lookup);
206 if (nhtd)
207 nhtd->nh_num = nhr.nexthop_num;
208
209
210 static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
211 return 1;
212 }
213
214 static void static_zebra_capabilities(struct zclient_capabilities *cap)
215 {
216 mpls_enabled = cap->mpls_enabled;
217 }
218
219 static unsigned int static_nht_hash_key(void *data)
220 {
221 struct static_nht_data *nhtd = data;
222
223 return prefix_hash_key(nhtd->nh);
224 }
225
226 static int static_nht_hash_cmp(const void *d1, const void *d2)
227 {
228 const struct static_nht_data *nhtd1 = d1;
229 const struct static_nht_data *nhtd2 = d2;
230
231 return prefix_same(nhtd1->nh, nhtd2->nh);
232 }
233
234 static void *static_nht_hash_alloc(void *data)
235 {
236 struct static_nht_data *copy = data;
237 struct static_nht_data *new;
238
239 new = XMALLOC(MTYPE_TMP, sizeof(*new));
240
241 new->nh = prefix_new();
242 prefix_copy(new->nh, copy->nh);
243 new->refcount = 0;
244 new->nh_num = 0;
245
246 return new;
247 }
248
249 static void static_nht_hash_free(void *data)
250 {
251 struct static_nht_data *nhtd = data;
252
253 prefix_free(nhtd->nh);
254 XFREE(MTYPE_TMP, nhtd);
255 }
256
257 void static_zebra_nht_register(struct static_route *si, bool reg)
258 {
259 struct static_nht_data *nhtd, lookup;
260 uint32_t cmd;
261 struct prefix p;
262 afi_t afi = AFI_IP;
263
264 cmd = (reg) ?
265 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
266
267 if (si->nh_registered && reg)
268 return;
269
270 if (!si->nh_registered && !reg)
271 return;
272
273 memset(&p, 0, sizeof(p));
274 switch (si->type) {
275 case STATIC_IFNAME:
276 case STATIC_BLACKHOLE:
277 return;
278 case STATIC_IPV4_GATEWAY:
279 case STATIC_IPV4_GATEWAY_IFNAME:
280 p.family = AF_INET;
281 p.prefixlen = IPV4_MAX_BITLEN;
282 p.u.prefix4 = si->addr.ipv4;
283 afi = AFI_IP;
284 break;
285 case STATIC_IPV6_GATEWAY:
286 case STATIC_IPV6_GATEWAY_IFNAME:
287 p.family = AF_INET6;
288 p.prefixlen = IPV6_MAX_BITLEN;
289 p.u.prefix6 = si->addr.ipv6;
290 afi = AFI_IP6;
291 break;
292 }
293
294 memset(&lookup, 0, sizeof(lookup));
295 lookup.nh = &p;
296
297 si->nh_registered = reg;
298
299 if (reg) {
300 nhtd = hash_get(static_nht_hash, &lookup,
301 static_nht_hash_alloc);
302 nhtd->refcount++;
303
304 if (nhtd->refcount > 1) {
305 static_nht_update(nhtd->nh, nhtd->nh_num,
306 afi, si->nh_vrf_id);
307 return;
308 }
309 } else {
310 nhtd = hash_lookup(static_nht_hash, &lookup);
311 if (!nhtd)
312 return;
313
314 nhtd->refcount--;
315 if (nhtd->refcount >= 1)
316 return;
317
318 hash_release(static_nht_hash, nhtd);
319 static_nht_hash_free(nhtd);
320 }
321
322 if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
323 zlog_warn("%s: Failure to send nexthop to zebra",
324 __PRETTY_FUNCTION__);
325 }
326
327 extern void static_zebra_route_add(struct route_node *rn,
328 struct static_route *si_changed,
329 vrf_id_t vrf_id, safi_t safi, bool install)
330 {
331 struct static_route *si = rn->info;
332 const struct prefix *p, *src_pp;
333 struct zapi_nexthop *api_nh;
334 struct zapi_route api;
335 uint32_t nh_num = 0;
336
337 p = src_pp = NULL;
338 srcdest_rnode_prefixes(rn, &p, &src_pp);
339
340 memset(&api, 0, sizeof(api));
341 api.vrf_id = vrf_id;
342 api.type = ZEBRA_ROUTE_STATIC;
343 api.safi = safi;
344 memcpy(&api.prefix, p, sizeof(api.prefix));
345
346 if (src_pp) {
347 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
348 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
349 }
350 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
351 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
352 if (si_changed->distance) {
353 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
354 api.distance = si_changed->distance;
355 }
356 if (si_changed->tag) {
357 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
358 api.tag = si_changed->tag;
359 }
360 if (si_changed->table_id != 0) {
361 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
362 api.tableid = si_changed->table_id;
363 }
364 for (/*loaded above*/; si; si = si->next) {
365 api_nh = &api.nexthops[nh_num];
366 if (si->nh_vrf_id == VRF_UNKNOWN)
367 continue;
368
369 if (si->distance != si_changed->distance)
370 continue;
371
372 api_nh->vrf_id = si->nh_vrf_id;
373 switch (si->type) {
374 case STATIC_IFNAME:
375 if (si->ifindex == IFINDEX_INTERNAL)
376 continue;
377 api_nh->ifindex = si->ifindex;
378 api_nh->type = NEXTHOP_TYPE_IFINDEX;
379 break;
380 case STATIC_IPV4_GATEWAY:
381 if (!si->nh_valid)
382 continue;
383 api_nh->type = NEXTHOP_TYPE_IPV4;
384 api_nh->gate = si->addr;
385 break;
386 case STATIC_IPV4_GATEWAY_IFNAME:
387 if (si->ifindex == IFINDEX_INTERNAL)
388 continue;
389 api_nh->ifindex = si->ifindex;
390 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
391 api_nh->gate = si->addr;
392 break;
393 case STATIC_IPV6_GATEWAY:
394 if (!si->nh_valid)
395 continue;
396 api_nh->type = NEXTHOP_TYPE_IPV6;
397 api_nh->gate = si->addr;
398 break;
399 case STATIC_IPV6_GATEWAY_IFNAME:
400 if (si->ifindex == IFINDEX_INTERNAL)
401 continue;
402 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
403 api_nh->ifindex = si->ifindex;
404 api_nh->gate = si->addr;
405 break;
406 case STATIC_BLACKHOLE:
407 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
408 switch (si->bh_type) {
409 case STATIC_BLACKHOLE_DROP:
410 case STATIC_BLACKHOLE_NULL:
411 api_nh->bh_type = BLACKHOLE_NULL;
412 break;
413 case STATIC_BLACKHOLE_REJECT:
414 api_nh->bh_type = BLACKHOLE_REJECT;
415 }
416 break;
417 }
418
419 if (si->snh_label.num_labels) {
420 int i;
421
422 SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
423 api_nh->label_num = si->snh_label.num_labels;
424 for (i = 0; i < api_nh->label_num; i++)
425 api_nh->labels[i] = si->snh_label.label[i];
426 }
427 nh_num++;
428 }
429
430 api.nexthop_num = nh_num;
431
432 /*
433 * If we have been given an install but nothing is valid
434 * go ahead and delete the route for double plus fun
435 */
436 if (!nh_num && install)
437 install = false;
438
439 zclient_route_send(install ?
440 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
441 zclient, &api);
442 }
443 void static_zebra_init(void)
444 {
445 struct zclient_options opt = { .receive_notify = true };
446
447 zclient = zclient_new_notify(master, &opt);
448
449 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
450 zclient->zebra_capabilities = static_zebra_capabilities;
451 zclient->zebra_connected = zebra_connected;
452 zclient->interface_add = interface_add;
453 zclient->interface_delete = interface_delete;
454 zclient->interface_up = interface_state_up;
455 zclient->interface_down = interface_state_down;
456 zclient->interface_address_add = interface_address_add;
457 zclient->interface_address_delete = interface_address_delete;
458 zclient->route_notify_owner = route_notify_owner;
459 zclient->nexthop_update = static_zebra_nexthop_update;
460
461 static_nht_hash = hash_create(static_nht_hash_key,
462 static_nht_hash_cmp,
463 "Static Nexthop Tracking hash");
464 }