]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - nhrpd/nhrp_route.c
New upstream release and new maintainer
[quagga-debian.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 #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 static struct zclient *zclient;
18 static struct route_table *zebra_rib[AFI_MAX];
19
20 struct route_info {
21         union sockunion via;
22         struct interface *ifp;
23         struct interface *nhrp_ifp;
24 };
25
26 static void nhrp_zebra_connected(struct zclient *zclient)
27 {
28         /* No real VRF support yet -- bind only to the default vrf */
29         zclient_send_requests (zclient, VRF_DEFAULT);
30 }
31
32 static struct route_node *nhrp_route_update_get(const struct prefix *p, int create)
33 {
34         struct route_node *rn;
35         afi_t afi = family2afi(PREFIX_FAMILY(p));
36
37         if (!zebra_rib[afi])
38                 return NULL;
39
40         if (create) {
41                 rn = route_node_get(zebra_rib[afi], p);
42                 if (!rn->info) {
43                         rn->info = XCALLOC(MTYPE_NHRP_ROUTE, sizeof(struct route_info));
44                         route_lock_node(rn);
45                 }
46                 return rn;
47         } else {
48                 return route_node_lookup(zebra_rib[afi], p);
49         }
50 }
51
52 static void nhrp_route_update_put(struct route_node *rn)
53 {
54         struct route_info *ri = rn->info;
55
56         if (!ri->ifp && !ri->nhrp_ifp && sockunion_family(&ri->via) == AF_UNSPEC) {
57                 XFREE(MTYPE_NHRP_ROUTE, rn->info);
58                 rn->info = NULL;
59                 route_unlock_node(rn);
60         }
61         route_unlock_node(rn);
62 }
63
64 static void nhrp_route_update_zebra(const struct prefix *p, union sockunion *nexthop, struct interface *ifp)
65 {
66         struct route_node *rn;
67         struct route_info *ri;
68
69         rn = nhrp_route_update_get(p, (sockunion_family(nexthop) != AF_UNSPEC) || 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 void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp)
79 {
80         struct route_node *rn;
81         struct route_info *ri;
82
83         rn = nhrp_route_update_get(p, ifp != NULL);
84         if (rn) {
85                 ri = rn->info;
86                 ri->nhrp_ifp = ifp;
87                 nhrp_route_update_put(rn);
88         }
89 }
90
91 void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu)
92 {
93         int flags = 0;
94
95         if (zclient->sock < 0)
96                 return;
97
98         switch (type) {
99         case NHRP_CACHE_NEGATIVE:
100                 SET_FLAG(flags, ZEBRA_FLAG_REJECT);
101                 break;
102         case NHRP_CACHE_DYNAMIC:
103         case NHRP_CACHE_NHS:
104         case NHRP_CACHE_STATIC:
105                 /* Regular route, so these are announced
106                  * to other routing daemons */
107                 break;
108         default:
109                 SET_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE);
110                 break;
111         }
112         SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
113
114         if (p->family == AF_INET) {
115                 struct in_addr *nexthop_ipv4;
116                 struct zapi_ipv4 api;
117
118                 memset(&api, 0, sizeof(api));
119                 api.flags = flags;
120                 api.type = ZEBRA_ROUTE_NHRP;
121                 api.safi = SAFI_UNICAST;
122
123                 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
124                 if (nexthop) {
125                         nexthop_ipv4 = (struct in_addr *) sockunion_get_addr(nexthop);
126                         api.nexthop_num = 1;
127                         api.nexthop = &nexthop_ipv4;
128                 }
129                 if (ifp) {
130                         SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
131                         api.ifindex_num = 1;
132                         api.ifindex = &ifp->ifindex;
133                 }
134                 if (mtu) {
135                         SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
136                         api.mtu = mtu;
137                 }
138
139                 if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
140                         char buf[2][INET_ADDRSTRLEN];
141                         zlog_debug("Zebra send: IPv4 route %s %s/%d nexthop %s metric %u"
142                                 " count %d dev %s",
143                                 add ? "add" : "del",
144                                 inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
145                                 p->prefixlen,
146                                 nexthop ? inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])) : "<onlink>",
147                                 api.metric, api.nexthop_num, ifp->name);
148                 }
149
150                 zapi_ipv4_route(
151                         add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE,
152                         zclient, (struct prefix_ipv4 *) p, &api);
153         } else if (p->family == AF_INET6) {
154                 struct in6_addr *nexthop_ipv6;
155                 struct zapi_ipv6 api;
156
157                 memset(&api, 0, sizeof(api));
158                 api.flags = flags;
159                 api.type = ZEBRA_ROUTE_NHRP;
160                 api.safi = SAFI_UNICAST;
161
162                 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
163                 if (nexthop) {
164                         nexthop_ipv6 = (struct in6_addr *) sockunion_get_addr(nexthop);
165                         api.nexthop_num = 1;
166                         api.nexthop = &nexthop_ipv6;
167                 }
168                 if (ifp) {
169                         SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
170                         api.ifindex_num = 1;
171                         api.ifindex = &ifp->ifindex;
172                 }
173                 if (mtu) {
174                         SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
175                         api.mtu = mtu;
176                 }
177
178                 if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
179                         char buf[2][INET6_ADDRSTRLEN];
180                         zlog_debug("Zebra send: IPv6 route %s %s/%d nexthop %s metric %u"
181                                 " count %d dev %s",
182                                 add ? "add" : "del",
183                                 inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
184                                 p->prefixlen,
185                                 nexthop ? inet_ntop(AF_INET6, api.nexthop[0], buf[1], sizeof(buf[1])) : "<onlink>",
186                                 api.metric, api.nexthop_num, ifp->name);
187                 }
188
189                 zapi_ipv6_route(
190                         add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
191                         zclient, (struct prefix_ipv6 *) p, &api);
192         }
193 }
194
195 int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id)
196 {
197         struct stream *s;
198         struct interface *ifp = NULL;
199         struct prefix prefix;
200         union sockunion nexthop_addr;
201         unsigned char message, nexthop_num, ifindex_num;
202         unsigned ifindex;
203         char buf[2][PREFIX_STRLEN];
204         int i, afaddrlen, added;
205
206         s = zclient->ibuf;
207         memset(&prefix, 0, sizeof(prefix));
208         sockunion_family(&nexthop_addr) = AF_UNSPEC;
209
210         /* Type, flags, message. */
211         /*type =*/ stream_getc(s);
212         /*flags =*/ stream_getc(s);
213         message = stream_getc(s);
214
215         /* Prefix */
216         switch (cmd) {
217         case ZEBRA_IPV4_ROUTE_ADD:
218         case ZEBRA_IPV4_ROUTE_DELETE:
219                 prefix.family = AF_INET;
220                 break;
221         case ZEBRA_IPV6_ROUTE_ADD:
222         case ZEBRA_IPV6_ROUTE_DELETE:
223                 prefix.family = AF_INET6;
224                 break;
225         default:
226                 return -1;
227         }
228         afaddrlen = family2addrsize(prefix.family);
229         prefix.prefixlen = stream_getc(s);
230         stream_get(&prefix.u.val, s, PSIZE(prefix.prefixlen));
231
232         /* Nexthop, ifindex, distance, metric. */
233         if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX)) {
234                 nexthop_num = stream_getc(s);
235                 for (i = 0; i < nexthop_num; i++) {
236                         stream_get(buf[0], s, afaddrlen);
237                         if (i == 0) sockunion_set(&nexthop_addr, prefix.family, (u_char*) buf[0], afaddrlen);
238                 }
239                 ifindex_num = stream_getc(s);
240                 for (i = 0; i < ifindex_num; i++) {
241                         ifindex = stream_getl(s);
242                         if (i == 0 && ifindex != IFINDEX_INTERNAL)
243                                 ifp = if_lookup_by_index(ifindex);
244                 }
245         }
246         if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
247                 /*distance =*/ stream_getc(s);
248         if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
249                 /*metric =*/ stream_getl(s);
250
251         added = (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD);
252         debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s",
253                 added ? "add" : "del",
254                 prefix2str(&prefix, buf[0], sizeof buf[0]),
255                 sockunion2str(&nexthop_addr, buf[1], sizeof buf[1]),
256                 ifp ? ifp->name : "(none)");
257
258         nhrp_route_update_zebra(&prefix, &nexthop_addr, ifp);
259         nhrp_shortcut_prefix_change(&prefix, !added);
260
261         return 0;
262 }
263
264 int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, 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         char buf[PREFIX_STRLEN];
271
272         sockunion2hostprefix(addr, &lookup);
273
274         rn = route_node_match(zebra_rib[afi], &lookup);
275         if (!rn) return 0;
276
277         ri = rn->info;
278         if (ri->nhrp_ifp) {
279                 debugf(NHRP_DEBUG_ROUTE, "lookup %s: nhrp_if=%s",
280                         prefix2str(&lookup, buf, sizeof buf),
281                         ri->nhrp_ifp->name);
282
283                 if (via) sockunion_family(via) = AF_UNSPEC;
284                 if (ifp) *ifp = ri->nhrp_ifp;
285         } else {
286                 debugf(NHRP_DEBUG_ROUTE, "lookup %s: zebra route dev %s",
287                         prefix2str(&lookup, buf, sizeof buf),
288                         ri->ifp ? ri->ifp->name : "(none)");
289
290                 if (via) *via = ri->via;
291                 if (ifp) *ifp = ri->ifp;
292         }
293         if (p) *p = rn->p;
294         route_unlock_node(rn);
295         return 1;
296 }
297
298 enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer)
299 {
300         struct interface *ifp = in_ifp;
301         struct nhrp_interface *nifp;
302         struct nhrp_cache *c;
303         union sockunion via[4];
304         uint32_t network_id = 0;
305         afi_t afi = family2afi(sockunion_family(addr));
306         int i;
307
308         if (ifp) {
309                 nifp = ifp->info;
310                 network_id = nifp->afi[afi].network_id;
311
312                 c = nhrp_cache_get(ifp, addr, 0);
313                 if (c && c->cur.type == NHRP_CACHE_LOCAL) {
314                         if (p) memset(p, 0, sizeof(*p));
315                         return NHRP_ROUTE_LOCAL;
316                 }
317         }
318
319         for (i = 0; i < 4; i++) {
320                 if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp))
321                         return NHRP_ROUTE_BLACKHOLE;
322                 if (ifp) {
323                         /* Departing from nbma network? */
324                         nifp = ifp->info;
325                         if (network_id && network_id != nifp->afi[afi].network_id)
326                                 return NHRP_ROUTE_OFF_NBMA;
327                 }
328                 if (sockunion_family(&via[i]) == AF_UNSPEC)
329                         break;
330                 /* Resolve via node, but return the prefix of first match */
331                 addr = &via[i];
332                 p = NULL;
333         }
334
335         if (ifp) {
336                 c = nhrp_cache_get(ifp, addr, 0);
337                 if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) {
338                         if (p) memset(p, 0, sizeof(*p));
339                         if (c->cur.type == NHRP_CACHE_LOCAL)
340                                 return NHRP_ROUTE_LOCAL;
341                         if (peer) *peer = nhrp_peer_ref(c->cur.peer);
342                         return NHRP_ROUTE_NBMA_NEXTHOP;
343                 }
344         }
345
346         return NHRP_ROUTE_BLACKHOLE;
347 }
348
349 void nhrp_zebra_init(void)
350 {
351         zebra_rib[AFI_IP] = route_table_init();
352         zebra_rib[AFI_IP6] = route_table_init();
353
354         zclient = zclient_new(master);
355         zclient->zebra_connected = nhrp_zebra_connected;
356         zclient->interface_add = nhrp_interface_add;
357         zclient->interface_delete = nhrp_interface_delete;
358         zclient->interface_up = nhrp_interface_up;
359         zclient->interface_down = nhrp_interface_down;
360         zclient->interface_address_add = nhrp_interface_address_add;
361         zclient->interface_address_delete = nhrp_interface_address_delete;
362         zclient->ipv4_route_add = nhrp_route_read;
363         zclient->ipv4_route_delete = nhrp_route_read;
364         zclient->ipv6_route_add = nhrp_route_read;
365         zclient->ipv6_route_delete = nhrp_route_read;
366
367         zclient_init(zclient, ZEBRA_ROUTE_NHRP);
368         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_KERNEL, VRF_DEFAULT);
369         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_CONNECT, VRF_DEFAULT);
370         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_STATIC, VRF_DEFAULT);
371         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_RIP, VRF_DEFAULT);
372         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_OSPF, VRF_DEFAULT);
373         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_ISIS, VRF_DEFAULT);
374         zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_BGP, VRF_DEFAULT);
375 }
376
377 void nhrp_zebra_terminate(void)
378 {
379         zclient_stop(zclient);
380         route_table_finish(zebra_rib[AFI_IP]);
381         route_table_finish(zebra_rib[AFI_IP6]);
382 }
383