]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_route.c
Merge pull request #12707 from donaldsharp/missed_enums
[mirror_frr.git] / nhrpd / nhrp_route.c
1 /* NHRP routing functions
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "nhrpd.h"
15 #include "table.h"
16 #include "memory.h"
17 #include "stream.h"
18 #include "log.h"
19 #include "zclient.h"
20
21 DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry");
22
23 static struct zclient *zclient;
24 static struct route_table *zebra_rib[AFI_MAX];
25
26 struct route_info {
27 union sockunion via;
28 struct interface *ifp;
29 struct interface *nhrp_ifp;
30 };
31
32 static struct route_node *nhrp_route_update_get(const struct prefix *p,
33 int create)
34 {
35 struct route_node *rn;
36 afi_t afi = family2afi(PREFIX_FAMILY(p));
37
38 if (!zebra_rib[afi])
39 return NULL;
40
41 if (create) {
42 rn = route_node_get(zebra_rib[afi], p);
43 if (!rn->info) {
44 rn->info = XCALLOC(MTYPE_NHRP_ROUTE,
45 sizeof(struct route_info));
46 route_lock_node(rn);
47 }
48 return rn;
49 } else {
50 return route_node_lookup(zebra_rib[afi], p);
51 }
52 }
53
54 static void nhrp_route_update_put(struct route_node *rn)
55 {
56 struct route_info *ri = rn->info;
57
58 if (!ri->ifp && !ri->nhrp_ifp
59 && sockunion_is_null(&ri->via)) {
60 XFREE(MTYPE_NHRP_ROUTE, rn->info);
61 route_unlock_node(rn);
62 }
63 route_unlock_node(rn);
64 }
65
66 static void nhrp_route_update_zebra(const struct prefix *p,
67 union sockunion *nexthop,
68 struct interface *ifp)
69 {
70 struct route_node *rn;
71 struct route_info *ri;
72
73 rn = nhrp_route_update_get(p, !sockunion_is_null(nexthop) || ifp);
74 if (rn) {
75 ri = rn->info;
76 ri->via = *nexthop;
77 ri->ifp = ifp;
78 nhrp_route_update_put(rn);
79 }
80 }
81
82 static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg)
83 {
84 struct stream *s;
85
86 if (!zclient || zclient->sock < 0)
87 return;
88
89 s = zclient->obuf;
90 stream_reset(s);
91
92 zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER :
93 ZEBRA_NHRP_NEIGH_UNREGISTER,
94 vrf_id);
95 stream_putw(s, afi);
96 stream_putw_at(s, 0, stream_get_endp(s));
97 zclient_send_message(zclient);
98 }
99
100 void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp)
101 {
102 struct route_node *rn;
103 struct route_info *ri;
104
105 rn = nhrp_route_update_get(p, ifp != NULL);
106 if (rn) {
107 ri = rn->info;
108 ri->nhrp_ifp = ifp;
109 nhrp_route_update_put(rn);
110 }
111 }
112
113 void nhrp_route_announce(int add, enum nhrp_cache_type type,
114 const struct prefix *p, struct interface *ifp,
115 const union sockunion *nexthop, uint32_t mtu)
116 {
117 struct zapi_route api;
118 struct zapi_nexthop *api_nh;
119 union sockunion *nexthop_ref = (union sockunion *)nexthop;
120
121 if (zclient->sock < 0)
122 return;
123
124 memset(&api, 0, sizeof(api));
125 api.type = ZEBRA_ROUTE_NHRP;
126 api.safi = SAFI_UNICAST;
127 api.vrf_id = VRF_DEFAULT;
128 api.prefix = *p;
129
130 switch (type) {
131 case NHRP_CACHE_NEGATIVE:
132 zapi_route_set_blackhole(&api, BLACKHOLE_REJECT);
133 ifp = NULL;
134 nexthop = NULL;
135 break;
136 case NHRP_CACHE_DYNAMIC:
137 case NHRP_CACHE_NHS:
138 case NHRP_CACHE_STATIC:
139 /* Regular route, so these are announced
140 * to other routing daemons */
141 break;
142 case NHRP_CACHE_INVALID:
143 case NHRP_CACHE_INCOMPLETE:
144 /*
145 * I cannot believe that we want to set a FIB_OVERRIDE
146 * for invalid state or incomplete. But this matches
147 * the original code. Someone will probably notice
148 * the problem eventually
149 */
150 case NHRP_CACHE_CACHED:
151 case NHRP_CACHE_LOCAL:
152 case NHRP_CACHE_NUM_TYPES:
153 SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
154 break;
155 }
156 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
157
158 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
159 api.nexthop_num = 1;
160 api_nh = &api.nexthops[0];
161 api_nh->vrf_id = VRF_DEFAULT;
162
163 switch (api.prefix.family) {
164 case AF_INET:
165 if (api.prefix.prefixlen == IPV4_MAX_BITLEN &&
166 nexthop_ref &&
167 memcmp(&nexthop_ref->sin.sin_addr, &api.prefix.u.prefix4,
168 sizeof(struct in_addr)) == 0) {
169 nexthop_ref = NULL;
170 }
171 if (nexthop_ref) {
172 api_nh->gate.ipv4 = nexthop_ref->sin.sin_addr;
173 api_nh->type = NEXTHOP_TYPE_IPV4;
174 }
175 if (ifp) {
176 api_nh->ifindex = ifp->ifindex;
177 if (api_nh->type == NEXTHOP_TYPE_IPV4)
178 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
179 else
180 api_nh->type = NEXTHOP_TYPE_IFINDEX;
181 }
182 break;
183 case AF_INET6:
184 if (api.prefix.prefixlen == IPV6_MAX_BITLEN &&
185 nexthop_ref &&
186 memcmp(&nexthop_ref->sin6.sin6_addr, &api.prefix.u.prefix6,
187 sizeof(struct in6_addr)) == 0) {
188 nexthop_ref = NULL;
189 }
190 if (nexthop_ref) {
191 api_nh->gate.ipv6 = nexthop_ref->sin6.sin6_addr;
192 api_nh->type = NEXTHOP_TYPE_IPV6;
193 }
194 if (ifp) {
195 api_nh->ifindex = ifp->ifindex;
196 if (api_nh->type == NEXTHOP_TYPE_IPV6)
197 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
198 else
199 api_nh->type = NEXTHOP_TYPE_IFINDEX;
200 }
201 break;
202 }
203 if (mtu) {
204 SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
205 api.mtu = mtu;
206 }
207
208 if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
209 char buf[PREFIX_STRLEN];
210
211 zlog_debug(
212 "Zebra send: route %s %pFX nexthop %s metric %u count %d dev %s",
213 add ? "add" : "del", &api.prefix,
214 nexthop_ref ? inet_ntop(api.prefix.family,
215 &api_nh->gate,
216 buf, sizeof(buf))
217 : "<onlink>",
218 api.metric, api.nexthop_num, ifp ? ifp->name : "none");
219 }
220
221 zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient,
222 &api);
223 }
224
225 int nhrp_route_read(ZAPI_CALLBACK_ARGS)
226 {
227 struct zapi_route api;
228 struct zapi_nexthop *api_nh;
229 struct interface *ifp = NULL;
230 union sockunion nexthop_addr;
231 int added;
232
233 if (zapi_route_decode(zclient->ibuf, &api) < 0)
234 return -1;
235
236 /* we completely ignore srcdest routes for now. */
237 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
238 return 0;
239
240 /* ignore our routes */
241 if (api.type == ZEBRA_ROUTE_NHRP)
242 return 0;
243
244 sockunion_family(&nexthop_addr) = AF_UNSPEC;
245 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
246 api_nh = &api.nexthops[0];
247
248 nexthop_addr.sa.sa_family = api.prefix.family;
249 switch (nexthop_addr.sa.sa_family) {
250 case AF_INET:
251 nexthop_addr.sin.sin_addr = api_nh->gate.ipv4;
252 break;
253 case AF_INET6:
254 nexthop_addr.sin6.sin6_addr = api_nh->gate.ipv6;
255 break;
256 }
257
258 if (api_nh->ifindex != IFINDEX_INTERNAL)
259 ifp = if_lookup_by_index(api_nh->ifindex, VRF_DEFAULT);
260 }
261
262 added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
263 debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %pFX via %pSU dev %s",
264 added ? "add" : "del", &api.prefix, &nexthop_addr,
265 ifp ? ifp->name : "(none)");
266
267 nhrp_route_update_zebra(&api.prefix, &nexthop_addr, added ? ifp : NULL);
268 nhrp_shortcut_prefix_change(&api.prefix, !added);
269
270 return 0;
271 }
272
273 int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
274 union sockunion *via, struct interface **ifp)
275 {
276 struct route_node *rn;
277 struct route_info *ri;
278 struct prefix lookup;
279 afi_t afi = family2afi(sockunion_family(addr));
280
281 sockunion2hostprefix(addr, &lookup);
282
283 rn = route_node_match(zebra_rib[afi], &lookup);
284 if (!rn)
285 return 0;
286
287 ri = rn->info;
288 if (ri->nhrp_ifp) {
289 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: nhrp_if=%s", &lookup,
290 ri->nhrp_ifp->name);
291
292 if (via)
293 sockunion_family(via) = AF_UNSPEC;
294 if (ifp)
295 *ifp = ri->nhrp_ifp;
296 } else {
297 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: zebra route dev %s",
298 &lookup, ri->ifp ? ri->ifp->name : "(none)");
299
300 if (via)
301 *via = ri->via;
302 if (ifp)
303 *ifp = ri->ifp;
304 }
305 if (p)
306 *p = rn->p;
307 route_unlock_node(rn);
308 return 1;
309 }
310
311 enum nhrp_route_type nhrp_route_address(struct interface *in_ifp,
312 union sockunion *addr, struct prefix *p,
313 struct nhrp_peer **peer)
314 {
315 struct interface *ifp = in_ifp;
316 struct nhrp_interface *nifp;
317 struct nhrp_cache *c;
318 union sockunion via[4];
319 uint32_t network_id = 0;
320 afi_t afi = family2afi(sockunion_family(addr));
321 int i;
322
323 if (ifp) {
324 nifp = ifp->info;
325 network_id = nifp->afi[afi].network_id;
326
327 c = nhrp_cache_get(ifp, addr, 0);
328 if (c && c->cur.type == NHRP_CACHE_LOCAL) {
329 if (p)
330 memset(p, 0, sizeof(*p));
331 return NHRP_ROUTE_LOCAL;
332 }
333 }
334
335 for (i = 0; i < 4; i++) {
336 if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp))
337 return NHRP_ROUTE_BLACKHOLE;
338 if (ifp) {
339 /* Departing from nbma network? */
340 nifp = ifp->info;
341 if (network_id
342 && network_id != nifp->afi[afi].network_id)
343 return NHRP_ROUTE_OFF_NBMA;
344 }
345 if (sockunion_family(&via[i]) == AF_UNSPEC)
346 break;
347 /* Resolve via node, but return the prefix of first match */
348 addr = &via[i];
349 p = NULL;
350 }
351
352 if (ifp) {
353 c = nhrp_cache_get(ifp, addr, 0);
354 if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) {
355 if (p)
356 memset(p, 0, sizeof(*p));
357 if (c->cur.type == NHRP_CACHE_LOCAL)
358 return NHRP_ROUTE_LOCAL;
359 if (peer)
360 *peer = nhrp_peer_ref(c->cur.peer);
361 return NHRP_ROUTE_NBMA_NEXTHOP;
362 }
363 }
364
365 return NHRP_ROUTE_BLACKHOLE;
366 }
367
368 static void nhrp_zebra_connected(struct zclient *zclient)
369 {
370 zclient_send_reg_requests(zclient, VRF_DEFAULT);
371 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
372 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
373 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
374 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
375 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true);
376 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true);
377 }
378
379 static zclient_handler *const nhrp_handlers[] = {
380 [ZEBRA_INTERFACE_ADDRESS_ADD] = nhrp_interface_address_add,
381 [ZEBRA_INTERFACE_ADDRESS_DELETE] = nhrp_interface_address_delete,
382 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = nhrp_route_read,
383 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = nhrp_route_read,
384 [ZEBRA_NHRP_NEIGH_ADDED] = nhrp_neighbor_operation,
385 [ZEBRA_NHRP_NEIGH_REMOVED] = nhrp_neighbor_operation,
386 [ZEBRA_NHRP_NEIGH_GET] = nhrp_neighbor_operation,
387 [ZEBRA_GRE_UPDATE] = nhrp_gre_update,
388 };
389
390 void nhrp_zebra_init(void)
391 {
392 zebra_rib[AFI_IP] = route_table_init();
393 zebra_rib[AFI_IP6] = route_table_init();
394
395 zclient = zclient_new(master, &zclient_options_default, nhrp_handlers,
396 array_size(nhrp_handlers));
397 zclient->zebra_connected = nhrp_zebra_connected;
398 zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
399 }
400
401 static void nhrp_table_node_cleanup(struct route_table *table,
402 struct route_node *node)
403 {
404 if (!node->info)
405 return;
406
407 XFREE(MTYPE_NHRP_ROUTE, node->info);
408 }
409
410 void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
411 {
412 struct stream *s;
413
414 if (!zclient || zclient->sock < 0) {
415 debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready",
416 __func__);
417 return;
418 }
419 s = zclient->obuf;
420 stream_reset(s);
421 zclient_create_header(s, ZEBRA_CONFIGURE_ARP, ifp->vrf->vrf_id);
422 stream_putc(s, family);
423 stream_putl(s, ifp->ifindex);
424 stream_putw_at(s, 0, stream_get_endp(s));
425 zclient_send_message(zclient);
426 }
427
428 void nhrp_send_zebra_gre_source_set(struct interface *ifp,
429 unsigned int link_idx,
430 vrf_id_t link_vrf_id)
431 {
432 struct stream *s;
433
434 if (!zclient || zclient->sock < 0) {
435 zlog_err("%s : zclient not ready", __func__);
436 return;
437 }
438 if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) {
439 /* silently ignore */
440 return;
441 }
442 s = zclient->obuf;
443 stream_reset(s);
444 zclient_create_header(s, ZEBRA_GRE_SOURCE_SET, ifp->vrf->vrf_id);
445 stream_putl(s, ifp->ifindex);
446 stream_putl(s, link_idx);
447 stream_putl(s, link_vrf_id);
448 stream_putl(s, 0); /* mtu provisioning */
449 stream_putw_at(s, 0, stream_get_endp(s));
450 zclient_send_message(zclient);
451 }
452
453 void nhrp_send_zebra_nbr(union sockunion *in,
454 union sockunion *out,
455 struct interface *ifp)
456 {
457 struct stream *s;
458
459 if (!zclient || zclient->sock < 0)
460 return;
461 s = zclient->obuf;
462 stream_reset(s);
463 zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD :
464 ZEBRA_NEIGH_IP_DEL, in, out,
465 ifp, out ? ZEBRA_NEIGH_STATE_REACHABLE
466 : ZEBRA_NEIGH_STATE_FAILED);
467 stream_putw_at(s, 0, stream_get_endp(s));
468 zclient_send_message(zclient);
469 }
470
471 int nhrp_send_zebra_gre_request(struct interface *ifp)
472 {
473 return zclient_send_zebra_gre_request(zclient, ifp);
474 }
475
476 void nhrp_zebra_terminate(void)
477 {
478 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
479 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false);
480 zclient_stop(zclient);
481 zclient_free(zclient);
482
483 zebra_rib[AFI_IP]->cleanup = nhrp_table_node_cleanup;
484 zebra_rib[AFI_IP6]->cleanup = nhrp_table_node_cleanup;
485 route_table_finish(zebra_rib[AFI_IP]);
486 route_table_finish(zebra_rib[AFI_IP6]);
487 }
488
489 int nhrp_gre_update(ZAPI_CALLBACK_ARGS)
490 {
491 struct stream *s;
492 struct nhrp_gre_info gre_info, *val;
493 struct interface *ifp;
494
495 /* result */
496 s = zclient->ibuf;
497 if (vrf_id != VRF_DEFAULT)
498 return 0;
499
500 /* read GRE information */
501 STREAM_GETL(s, gre_info.ifindex);
502 STREAM_GETL(s, gre_info.ikey);
503 STREAM_GETL(s, gre_info.okey);
504 STREAM_GETL(s, gre_info.ifindex_link);
505 STREAM_GETL(s, gre_info.vrfid_link);
506 STREAM_GETL(s, gre_info.vtep_ip.s_addr);
507 STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr);
508 if (gre_info.ifindex == IFINDEX_INTERNAL)
509 val = NULL;
510 else
511 val = hash_lookup(nhrp_gre_list, &gre_info);
512 if (val) {
513 if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr ||
514 gre_info.vrfid_link != val->vrfid_link ||
515 gre_info.ifindex_link != val->ifindex_link ||
516 gre_info.ikey != val->ikey ||
517 gre_info.okey != val->okey) {
518 /* update */
519 memcpy(val, &gre_info, sizeof(struct nhrp_gre_info));
520 }
521 } else {
522 val = nhrp_gre_info_alloc(&gre_info);
523 }
524 ifp = if_lookup_by_index(gre_info.ifindex, vrf_id);
525 debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system",
526 ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id);
527 if (ifp)
528 nhrp_interface_update_nbma(ifp, val);
529 return 0;
530
531 stream_failure:
532 zlog_err("%s(): error reading response ..", __func__);
533 return -1;
534 }