]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_route.c
Merge pull request #9878 from pguibert6WIND/resolver_vrf
[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 default:
143 SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
144 break;
145 }
146 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
147
148 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
149 api.nexthop_num = 1;
150 api_nh = &api.nexthops[0];
151 api_nh->vrf_id = VRF_DEFAULT;
152
153 switch (api.prefix.family) {
154 case AF_INET:
155 if (api.prefix.prefixlen == IPV4_MAX_BITLEN &&
156 nexthop_ref &&
157 memcmp(&nexthop_ref->sin.sin_addr, &api.prefix.u.prefix4,
158 sizeof(struct in_addr)) == 0) {
159 nexthop_ref = NULL;
160 }
161 if (nexthop_ref) {
162 api_nh->gate.ipv4 = nexthop_ref->sin.sin_addr;
163 api_nh->type = NEXTHOP_TYPE_IPV4;
164 }
165 if (ifp) {
166 api_nh->ifindex = ifp->ifindex;
167 if (api_nh->type == NEXTHOP_TYPE_IPV4)
168 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
169 else
170 api_nh->type = NEXTHOP_TYPE_IFINDEX;
171 }
172 break;
173 case AF_INET6:
174 if (api.prefix.prefixlen == IPV6_MAX_BITLEN &&
175 nexthop_ref &&
176 memcmp(&nexthop_ref->sin6.sin6_addr, &api.prefix.u.prefix6,
177 sizeof(struct in6_addr)) == 0) {
178 nexthop_ref = NULL;
179 }
180 if (nexthop_ref) {
181 api_nh->gate.ipv6 = nexthop_ref->sin6.sin6_addr;
182 api_nh->type = NEXTHOP_TYPE_IPV6;
183 }
184 if (ifp) {
185 api_nh->ifindex = ifp->ifindex;
186 if (api_nh->type == NEXTHOP_TYPE_IPV6)
187 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
188 else
189 api_nh->type = NEXTHOP_TYPE_IFINDEX;
190 }
191 break;
192 }
193 if (mtu) {
194 SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
195 api.mtu = mtu;
196 }
197
198 if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
199 char buf[PREFIX_STRLEN];
200
201 zlog_debug(
202 "Zebra send: route %s %pFX nexthop %s metric %u count %d dev %s",
203 add ? "add" : "del", &api.prefix,
204 nexthop_ref ? inet_ntop(api.prefix.family,
205 &api_nh->gate,
206 buf, sizeof(buf))
207 : "<onlink>",
208 api.metric, api.nexthop_num, ifp ? ifp->name : "none");
209 }
210
211 zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient,
212 &api);
213 }
214
215 int nhrp_route_read(ZAPI_CALLBACK_ARGS)
216 {
217 struct zapi_route api;
218 struct zapi_nexthop *api_nh;
219 struct interface *ifp = NULL;
220 union sockunion nexthop_addr;
221 int added;
222
223 if (zapi_route_decode(zclient->ibuf, &api) < 0)
224 return -1;
225
226 /* we completely ignore srcdest routes for now. */
227 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
228 return 0;
229
230 /* ignore our routes */
231 if (api.type == ZEBRA_ROUTE_NHRP)
232 return 0;
233
234 sockunion_family(&nexthop_addr) = AF_UNSPEC;
235 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
236 api_nh = &api.nexthops[0];
237
238 nexthop_addr.sa.sa_family = api.prefix.family;
239 switch (nexthop_addr.sa.sa_family) {
240 case AF_INET:
241 nexthop_addr.sin.sin_addr = api_nh->gate.ipv4;
242 break;
243 case AF_INET6:
244 nexthop_addr.sin6.sin6_addr = api_nh->gate.ipv6;
245 break;
246 }
247
248 if (api_nh->ifindex != IFINDEX_INTERNAL)
249 ifp = if_lookup_by_index(api_nh->ifindex, VRF_DEFAULT);
250 }
251
252 added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
253 debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %pFX via %pSU dev %s",
254 added ? "add" : "del", &api.prefix, &nexthop_addr,
255 ifp ? ifp->name : "(none)");
256
257 nhrp_route_update_zebra(&api.prefix, &nexthop_addr, added ? ifp : NULL);
258 nhrp_shortcut_prefix_change(&api.prefix, !added);
259
260 return 0;
261 }
262
263 int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
264 union sockunion *via, struct interface **ifp)
265 {
266 struct route_node *rn;
267 struct route_info *ri;
268 struct prefix lookup;
269 afi_t afi = family2afi(sockunion_family(addr));
270
271 sockunion2hostprefix(addr, &lookup);
272
273 rn = route_node_match(zebra_rib[afi], &lookup);
274 if (!rn)
275 return 0;
276
277 ri = rn->info;
278 if (ri->nhrp_ifp) {
279 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: nhrp_if=%s", &lookup,
280 ri->nhrp_ifp->name);
281
282 if (via)
283 sockunion_family(via) = AF_UNSPEC;
284 if (ifp)
285 *ifp = ri->nhrp_ifp;
286 } else {
287 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: zebra route dev %s",
288 &lookup, ri->ifp ? ri->ifp->name : "(none)");
289
290 if (via)
291 *via = ri->via;
292 if (ifp)
293 *ifp = ri->ifp;
294 }
295 if (p)
296 *p = rn->p;
297 route_unlock_node(rn);
298 return 1;
299 }
300
301 enum nhrp_route_type nhrp_route_address(struct interface *in_ifp,
302 union sockunion *addr, struct prefix *p,
303 struct nhrp_peer **peer)
304 {
305 struct interface *ifp = in_ifp;
306 struct nhrp_interface *nifp;
307 struct nhrp_cache *c;
308 union sockunion via[4];
309 uint32_t network_id = 0;
310 afi_t afi = family2afi(sockunion_family(addr));
311 int i;
312
313 if (ifp) {
314 nifp = ifp->info;
315 network_id = nifp->afi[afi].network_id;
316
317 c = nhrp_cache_get(ifp, addr, 0);
318 if (c && c->cur.type == NHRP_CACHE_LOCAL) {
319 if (p)
320 memset(p, 0, sizeof(*p));
321 return NHRP_ROUTE_LOCAL;
322 }
323 }
324
325 for (i = 0; i < 4; i++) {
326 if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp))
327 return NHRP_ROUTE_BLACKHOLE;
328 if (ifp) {
329 /* Departing from nbma network? */
330 nifp = ifp->info;
331 if (network_id
332 && network_id != nifp->afi[afi].network_id)
333 return NHRP_ROUTE_OFF_NBMA;
334 }
335 if (sockunion_family(&via[i]) == AF_UNSPEC)
336 break;
337 /* Resolve via node, but return the prefix of first match */
338 addr = &via[i];
339 p = NULL;
340 }
341
342 if (ifp) {
343 c = nhrp_cache_get(ifp, addr, 0);
344 if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) {
345 if (p)
346 memset(p, 0, sizeof(*p));
347 if (c->cur.type == NHRP_CACHE_LOCAL)
348 return NHRP_ROUTE_LOCAL;
349 if (peer)
350 *peer = nhrp_peer_ref(c->cur.peer);
351 return NHRP_ROUTE_NBMA_NEXTHOP;
352 }
353 }
354
355 return NHRP_ROUTE_BLACKHOLE;
356 }
357
358 static void nhrp_zebra_connected(struct zclient *zclient)
359 {
360 zclient_send_reg_requests(zclient, VRF_DEFAULT);
361 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
362 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
363 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
364 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
365 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true);
366 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true);
367 }
368
369 static zclient_handler *const nhrp_handlers[] = {
370 [ZEBRA_INTERFACE_ADDRESS_ADD] = nhrp_interface_address_add,
371 [ZEBRA_INTERFACE_ADDRESS_DELETE] = nhrp_interface_address_delete,
372 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = nhrp_route_read,
373 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = nhrp_route_read,
374 [ZEBRA_NHRP_NEIGH_ADDED] = nhrp_neighbor_operation,
375 [ZEBRA_NHRP_NEIGH_REMOVED] = nhrp_neighbor_operation,
376 [ZEBRA_NHRP_NEIGH_GET] = nhrp_neighbor_operation,
377 [ZEBRA_GRE_UPDATE] = nhrp_gre_update,
378 };
379
380 void nhrp_zebra_init(void)
381 {
382 zebra_rib[AFI_IP] = route_table_init();
383 zebra_rib[AFI_IP6] = route_table_init();
384
385 zclient = zclient_new(master, &zclient_options_default, nhrp_handlers,
386 array_size(nhrp_handlers));
387 zclient->zebra_connected = nhrp_zebra_connected;
388 zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
389 }
390
391 static void nhrp_table_node_cleanup(struct route_table *table,
392 struct route_node *node)
393 {
394 if (!node->info)
395 return;
396
397 XFREE(MTYPE_NHRP_ROUTE, node->info);
398 }
399
400 void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
401 {
402 struct stream *s;
403
404 if (!zclient || zclient->sock < 0) {
405 debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready",
406 __func__);
407 return;
408 }
409 s = zclient->obuf;
410 stream_reset(s);
411 zclient_create_header(s, ZEBRA_CONFIGURE_ARP, ifp->vrf->vrf_id);
412 stream_putc(s, family);
413 stream_putl(s, ifp->ifindex);
414 stream_putw_at(s, 0, stream_get_endp(s));
415 zclient_send_message(zclient);
416 }
417
418 void nhrp_send_zebra_gre_source_set(struct interface *ifp,
419 unsigned int link_idx,
420 vrf_id_t link_vrf_id)
421 {
422 struct stream *s;
423
424 if (!zclient || zclient->sock < 0) {
425 zlog_err("%s : zclient not ready", __func__);
426 return;
427 }
428 if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) {
429 /* silently ignore */
430 return;
431 }
432 s = zclient->obuf;
433 stream_reset(s);
434 zclient_create_header(s, ZEBRA_GRE_SOURCE_SET, ifp->vrf->vrf_id);
435 stream_putl(s, ifp->ifindex);
436 stream_putl(s, link_idx);
437 stream_putl(s, link_vrf_id);
438 stream_putl(s, 0); /* mtu provisioning */
439 stream_putw_at(s, 0, stream_get_endp(s));
440 zclient_send_message(zclient);
441 }
442
443 void nhrp_send_zebra_nbr(union sockunion *in,
444 union sockunion *out,
445 struct interface *ifp)
446 {
447 struct stream *s;
448
449 if (!zclient || zclient->sock < 0)
450 return;
451 s = zclient->obuf;
452 stream_reset(s);
453 zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD :
454 ZEBRA_NEIGH_IP_DEL, in, out,
455 ifp, out ? ZEBRA_NEIGH_STATE_REACHABLE
456 : ZEBRA_NEIGH_STATE_FAILED);
457 stream_putw_at(s, 0, stream_get_endp(s));
458 zclient_send_message(zclient);
459 }
460
461 int nhrp_send_zebra_gre_request(struct interface *ifp)
462 {
463 return zclient_send_zebra_gre_request(zclient, ifp);
464 }
465
466 void nhrp_zebra_terminate(void)
467 {
468 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
469 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false);
470 zclient_stop(zclient);
471 zclient_free(zclient);
472
473 zebra_rib[AFI_IP]->cleanup = nhrp_table_node_cleanup;
474 zebra_rib[AFI_IP6]->cleanup = nhrp_table_node_cleanup;
475 route_table_finish(zebra_rib[AFI_IP]);
476 route_table_finish(zebra_rib[AFI_IP6]);
477 }
478
479 int nhrp_gre_update(ZAPI_CALLBACK_ARGS)
480 {
481 struct stream *s;
482 struct nhrp_gre_info gre_info, *val;
483 struct interface *ifp;
484
485 /* result */
486 s = zclient->ibuf;
487 if (vrf_id != VRF_DEFAULT)
488 return 0;
489
490 /* read GRE information */
491 STREAM_GETL(s, gre_info.ifindex);
492 STREAM_GETL(s, gre_info.ikey);
493 STREAM_GETL(s, gre_info.okey);
494 STREAM_GETL(s, gre_info.ifindex_link);
495 STREAM_GETL(s, gre_info.vrfid_link);
496 STREAM_GETL(s, gre_info.vtep_ip.s_addr);
497 STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr);
498 if (gre_info.ifindex == IFINDEX_INTERNAL)
499 val = NULL;
500 else
501 val = hash_lookup(nhrp_gre_list, &gre_info);
502 if (val) {
503 if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr ||
504 gre_info.vrfid_link != val->vrfid_link ||
505 gre_info.ifindex_link != val->ifindex_link ||
506 gre_info.ikey != val->ikey ||
507 gre_info.okey != val->okey) {
508 /* update */
509 memcpy(val, &gre_info, sizeof(struct nhrp_gre_info));
510 }
511 } else {
512 val = nhrp_gre_info_alloc(&gre_info);
513 }
514 ifp = if_lookup_by_index(gre_info.ifindex, vrf_id);
515 debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system",
516 ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id);
517 if (ifp)
518 nhrp_interface_update_nbma(ifp, val);
519 return 0;
520
521 stream_failure:
522 zlog_err("%s(): error reading response ..", __func__);
523 return -1;
524 }