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