mpls_routes.c revision 1.1 1 1.1 kefren /* $NetBSD: mpls_routes.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
2 1.1 kefren
3 1.1 kefren /*-
4 1.1 kefren * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 1.1 kefren * All rights reserved.
6 1.1 kefren *
7 1.1 kefren * This code is derived from software contributed to The NetBSD Foundation
8 1.1 kefren * by Mihai Chelaru <kefren (at) NetBSD.org>
9 1.1 kefren *
10 1.1 kefren * Redistribution and use in source and binary forms, with or without
11 1.1 kefren * modification, are permitted provided that the following conditions
12 1.1 kefren * are met:
13 1.1 kefren * 1. Redistributions of source code must retain the above copyright
14 1.1 kefren * notice, this list of conditions and the following disclaimer.
15 1.1 kefren * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 kefren * notice, this list of conditions and the following disclaimer in the
17 1.1 kefren * documentation and/or other materials provided with the distribution.
18 1.1 kefren *
19 1.1 kefren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 kefren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 kefren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 kefren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 kefren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 kefren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 kefren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 kefren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 kefren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 kefren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 kefren * POSSIBILITY OF SUCH DAMAGE.
30 1.1 kefren */
31 1.1 kefren
32 1.1 kefren #include <sys/types.h>
33 1.1 kefren #include <sys/socket.h>
34 1.1 kefren #include <sys/param.h>
35 1.1 kefren #include <sys/sysctl.h>
36 1.1 kefren #include <net/if.h>
37 1.1 kefren #include <net/route.h>
38 1.1 kefren #include <netinet/in.h>
39 1.1 kefren #include <netmpls/mpls.h>
40 1.1 kefren
41 1.1 kefren #include <arpa/inet.h>
42 1.1 kefren
43 1.1 kefren #include <assert.h>
44 1.1 kefren #include <stdlib.h>
45 1.1 kefren #include <errno.h>
46 1.1 kefren #include <stdio.h>
47 1.1 kefren #include <string.h>
48 1.1 kefren #include <unistd.h>
49 1.1 kefren
50 1.1 kefren #include "ldp.h"
51 1.1 kefren #include "ldp_errors.h"
52 1.1 kefren #include "ldp_peer.h"
53 1.1 kefren #include "mpls_interface.h"
54 1.1 kefren #include "tlv_stack.h"
55 1.1 kefren #include "label.h"
56 1.1 kefren #include "mpls_routes.h"
57 1.1 kefren
58 1.1 kefren extern int route_socket;
59 1.1 kefren int rt_seq = 0;
60 1.1 kefren int dont_catch = 0;
61 1.1 kefren
62 1.1 kefren struct rt_msg replay_rt[REPLAY_MAX];
63 1.1 kefren int replay_index = 0;
64 1.1 kefren
65 1.1 kefren int read_route_socket(char *, int);
66 1.1 kefren void mask_addr(union sockunion *);
67 1.1 kefren int compare_sockunion(union sockunion *, union sockunion *);
68 1.1 kefren char * mpls_ntoa(union mpls_shim);
69 1.1 kefren
70 1.1 kefren extern struct sockaddr mplssockaddr;
71 1.1 kefren
72 1.1 kefren /* Many lines inspired or shamelessly stolen from sbin/route/route.c */
73 1.1 kefren
74 1.1 kefren #define ROUNDUP(a) \
75 1.1 kefren ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
76 1.1 kefren #define NEXTADDR(u) \
77 1.1 kefren do { l = ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l; } while(0);
78 1.1 kefren #define NEXTADDR2(u) \
79 1.1 kefren do { l = ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0);
80 1.1 kefren #define GETNEXT(sunion) \
81 1.1 kefren (union sockunion *) ((char *) (sunion) + ROUNDUP((sunion)->sa.sa_len))
82 1.1 kefren
83 1.1 kefren int
84 1.1 kefren read_route_socket(char *s, int max)
85 1.1 kefren {
86 1.1 kefren int rv, to_read;
87 1.1 kefren fd_set fs;
88 1.1 kefren struct timeval tv;
89 1.1 kefren struct rt_msghdr *rhdr;
90 1.1 kefren
91 1.1 kefren tv.tv_sec = 0;
92 1.1 kefren tv.tv_usec = 5000;
93 1.1 kefren
94 1.1 kefren FD_ZERO(&fs);
95 1.1 kefren FD_SET(route_socket, &fs);
96 1.1 kefren
97 1.1 kefren errno = 0;
98 1.1 kefren
99 1.1 kefren do {
100 1.1 kefren rv = select(route_socket + 1, &fs, NULL, &fs, &tv);
101 1.1 kefren } while ((rv == -1) && (errno == EINTR));
102 1.1 kefren
103 1.1 kefren if (rv < 1) {
104 1.1 kefren if (rv == 0) {
105 1.1 kefren fatalp("read_route_socket: select timeout\n");
106 1.1 kefren } else
107 1.1 kefren fatalp("read_route_socket: select: %s",
108 1.1 kefren strerror(errno));
109 1.1 kefren return 0;
110 1.1 kefren }
111 1.1 kefren
112 1.1 kefren do {
113 1.1 kefren rv = recv(route_socket, s, max, MSG_PEEK);
114 1.1 kefren } while((rv == -1) && (errno == EINTR));
115 1.1 kefren
116 1.1 kefren if (rv < 1) {
117 1.1 kefren debugp("read_route_socket: recv error\n");
118 1.1 kefren return 0;
119 1.1 kefren }
120 1.1 kefren if (rv > max) {
121 1.1 kefren rv = max;
122 1.1 kefren debugp("read_route_socket: rv > max\n");
123 1.1 kefren }
124 1.1 kefren
125 1.1 kefren rhdr = (struct rt_msghdr *)s;
126 1.1 kefren to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen;
127 1.1 kefren rv = 0;
128 1.1 kefren
129 1.1 kefren do {
130 1.1 kefren rv += recv(route_socket, s, to_read - rv, 0);
131 1.1 kefren } while (rv != to_read);
132 1.1 kefren
133 1.1 kefren return rv;
134 1.1 kefren }
135 1.1 kefren
136 1.1 kefren /* Recalculate length */
137 1.1 kefren void
138 1.1 kefren mask_addr(union sockunion * su)
139 1.1 kefren {
140 1.1 kefren /*
141 1.1 kefren int olen = su->sa.sa_len;
142 1.1 kefren char *cp1 = olen + (char *) su;
143 1.1 kefren
144 1.1 kefren for (su->sa.sa_len = 0; cp1 > (char *) su;)
145 1.1 kefren if (*--cp1 != 0) {
146 1.1 kefren su->sa.sa_len = 1 + cp1 - (char *) su;
147 1.1 kefren break;
148 1.1 kefren }
149 1.1 kefren */
150 1.1 kefren /* Let's use INET only version for the moment */
151 1.1 kefren su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 +
152 1.1 kefren ( from_union_to_cidr(su) % 8 ? 1 : 0 );
153 1.1 kefren }
154 1.1 kefren
155 1.1 kefren /* creates a sockunion from an IP address */
156 1.1 kefren union sockunion *
157 1.1 kefren make_inet_union(char *s)
158 1.1 kefren {
159 1.1 kefren union sockunion *so_inet;
160 1.1 kefren
161 1.1 kefren so_inet = (union sockunion *) malloc(sizeof(union sockunion));
162 1.1 kefren
163 1.1 kefren if (!so_inet) {
164 1.1 kefren fatalp("make_inet_union: malloc problem\n");
165 1.1 kefren return NULL;
166 1.1 kefren }
167 1.1 kefren
168 1.1 kefren memset(so_inet, 0, sizeof(union sockunion));
169 1.1 kefren
170 1.1 kefren so_inet->sin.sin_len = sizeof(struct sockaddr_in);
171 1.1 kefren so_inet->sin.sin_family = AF_INET;
172 1.1 kefren inet_aton(s, &so_inet->sin.sin_addr);
173 1.1 kefren
174 1.1 kefren return so_inet;
175 1.1 kefren }
176 1.1 kefren
177 1.1 kefren /* creates a sockunion from a label */
178 1.1 kefren union sockunion *
179 1.1 kefren make_mpls_union(uint32_t label)
180 1.1 kefren {
181 1.1 kefren union sockunion *so_mpls;
182 1.1 kefren
183 1.1 kefren so_mpls = (union sockunion *) malloc(sizeof(union sockunion));
184 1.1 kefren
185 1.1 kefren if (!so_mpls) {
186 1.1 kefren fatalp("make_mpls_union: malloc problem\n");
187 1.1 kefren return NULL;
188 1.1 kefren }
189 1.1 kefren
190 1.1 kefren memset(so_mpls, 0, sizeof(union sockunion));
191 1.1 kefren
192 1.1 kefren so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls);
193 1.1 kefren so_mpls->smpls.smpls_family = AF_MPLS;
194 1.1 kefren so_mpls->smpls.smpls_addr.shim.label = label;
195 1.1 kefren
196 1.1 kefren so_mpls->smpls.smpls_addr.s_addr =
197 1.1 kefren htonl(so_mpls->smpls.smpls_addr.s_addr);
198 1.1 kefren
199 1.1 kefren return so_mpls;
200 1.1 kefren }
201 1.1 kefren
202 1.1 kefren int
203 1.1 kefren compare_sockunion(union sockunion * __restrict a,
204 1.1 kefren union sockunion * __restrict b)
205 1.1 kefren {
206 1.1 kefren if (a->sa.sa_len != b->sa.sa_len)
207 1.1 kefren return 1;
208 1.1 kefren return memcmp(a, b, a->sa.sa_len);
209 1.1 kefren }
210 1.1 kefren
211 1.1 kefren union sockunion *
212 1.1 kefren from_cidr_to_union(uint8_t prefixlen)
213 1.1 kefren {
214 1.1 kefren union sockunion *u;
215 1.1 kefren int32_t n = -1;
216 1.1 kefren uint32_t *m = (uint32_t*)&n;
217 1.1 kefren
218 1.1 kefren *m = (*m >> (32 - prefixlen) ) << (32 - prefixlen);
219 1.1 kefren *m = ntohl(*m);
220 1.1 kefren
221 1.1 kefren u = (union sockunion *) malloc(sizeof(union sockunion));
222 1.1 kefren
223 1.1 kefren if (!u) {
224 1.1 kefren fatalp("from_cidr_to_union: malloc problem\n");
225 1.1 kefren return NULL;
226 1.1 kefren }
227 1.1 kefren
228 1.1 kefren memset (u, 0, sizeof(union sockunion));
229 1.1 kefren
230 1.1 kefren u->sin.sin_len = sizeof(struct sockaddr_in);
231 1.1 kefren u->sin.sin_family = AF_INET;
232 1.1 kefren u->sin.sin_addr.s_addr = *m;
233 1.1 kefren
234 1.1 kefren return u;
235 1.1 kefren
236 1.1 kefren }
237 1.1 kefren
238 1.1 kefren uint8_t
239 1.1 kefren from_mask_to_cidr(char *mask)
240 1.1 kefren {
241 1.1 kefren /* LoL (although I don't think about something faster right now) */
242 1.1 kefren char mtest[20];
243 1.1 kefren uint8_t i;
244 1.1 kefren
245 1.1 kefren for (i = 1; i < 32; i++) {
246 1.1 kefren from_cidr_to_mask(i, mtest);
247 1.1 kefren if (!strcmp(mask, mtest))
248 1.1 kefren break;
249 1.1 kefren }
250 1.1 kefren return i;
251 1.1 kefren }
252 1.1 kefren
253 1.1 kefren uint8_t
254 1.1 kefren from_union_to_cidr(union sockunion *so_pref)
255 1.1 kefren {
256 1.1 kefren struct sockaddr_in *sin = (struct sockaddr_in*)so_pref;
257 1.1 kefren uint32_t a;
258 1.1 kefren uint8_t r;
259 1.1 kefren
260 1.1 kefren a = ntohl(sin->sin_addr.s_addr);
261 1.1 kefren for (r=0; a ; a = a << 1, r++);
262 1.1 kefren
263 1.1 kefren return r;
264 1.1 kefren }
265 1.1 kefren
266 1.1 kefren /* returns in mask the netmask created from CIDR prefixlen */
267 1.1 kefren void
268 1.1 kefren from_cidr_to_mask(uint8_t prefixlen, char *mask)
269 1.1 kefren {
270 1.1 kefren uint32_t a = 0, p = prefixlen;
271 1.1 kefren if (prefixlen > 32) {
272 1.1 kefren strlcpy(mask, "255.255.255.255", 16);
273 1.1 kefren return;
274 1.1 kefren }
275 1.1 kefren for (; p > 0; p--) {
276 1.1 kefren a = a >> (p - 1);
277 1.1 kefren a += 1;
278 1.1 kefren a = a << (p - 1);
279 1.1 kefren }
280 1.1 kefren /* is this OK ? */
281 1.1 kefren #if _BYTE_ORDER == _LITTLE_ENDIAN
282 1.1 kefren a = a << (32 - prefixlen);
283 1.1 kefren #endif
284 1.1 kefren
285 1.1 kefren snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24,
286 1.1 kefren (a << 16) >> 24, (a << 24) >> 24);
287 1.1 kefren }
288 1.1 kefren
289 1.1 kefren char *
290 1.1 kefren mpls_ntoa(union mpls_shim ms)
291 1.1 kefren {
292 1.1 kefren static char ret[255];
293 1.1 kefren union mpls_shim ms2;
294 1.1 kefren
295 1.1 kefren ms2.s_addr = ntohl(ms.s_addr);
296 1.1 kefren snprintf(ret, sizeof(ret), "%d", ms2.shim.label);
297 1.1 kefren return ret;
298 1.1 kefren }
299 1.1 kefren
300 1.1 kefren char *
301 1.1 kefren union_ntoa(union sockunion * so)
302 1.1 kefren {
303 1.1 kefren static char defret[] = "Unknown family address";
304 1.1 kefren switch (so->sa.sa_family) {
305 1.1 kefren case AF_INET:
306 1.1 kefren return inet_ntoa(so->sin.sin_addr);
307 1.1 kefren case AF_LINK:
308 1.1 kefren return link_ntoa(&so->sdl);
309 1.1 kefren case AF_MPLS:
310 1.1 kefren return mpls_ntoa(so->smpls.smpls_addr);
311 1.1 kefren }
312 1.1 kefren fatalp("Unknown family address in union_ntoa: %d\n",
313 1.1 kefren so->sa.sa_family);
314 1.1 kefren return defret;
315 1.1 kefren }
316 1.1 kefren
317 1.1 kefren /* From src/sbin/route/route.c */
318 1.1 kefren static const char *
319 1.1 kefren route_strerror(int error)
320 1.1 kefren {
321 1.1 kefren
322 1.1 kefren switch (error) {
323 1.1 kefren case ESRCH:
324 1.1 kefren return "not in table";
325 1.1 kefren case EBUSY:
326 1.1 kefren return "entry in use";
327 1.1 kefren case ENOBUFS:
328 1.1 kefren return "routing table overflow";
329 1.1 kefren default:
330 1.1 kefren return strerror(error);
331 1.1 kefren }
332 1.1 kefren }
333 1.1 kefren
334 1.1 kefren
335 1.1 kefren /* Adds a route. Or changes it. */
336 1.1 kefren int
337 1.1 kefren add_route(union sockunion *so_dest, union sockunion *so_prefix,
338 1.1 kefren union sockunion *so_gate, union sockunion *so_ifa, union sockunion *so_tag,
339 1.1 kefren int fr, int optype)
340 1.1 kefren {
341 1.1 kefren int l, rlen, rv = LDP_E_OK;
342 1.1 kefren struct rt_msg rm;
343 1.1 kefren char *cp;
344 1.1 kefren
345 1.1 kefren if(dont_catch)
346 1.1 kefren return LDP_E_OK;
347 1.1 kefren
348 1.1 kefren memset(&rm, 0, sizeof(rm));
349 1.1 kefren cp = rm.m_space;
350 1.1 kefren
351 1.1 kefren rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype;
352 1.1 kefren rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
353 1.1 kefren
354 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
355 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq;
356 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST;
357 1.1 kefren if (so_gate)
358 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_GATEWAY;
359 1.1 kefren
360 1.1 kefren assert(so_dest);
361 1.1 kefren
362 1.1 kefren /* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */
363 1.1 kefren NEXTADDR(so_dest);
364 1.1 kefren if (so_gate)
365 1.1 kefren NEXTADDR(so_gate);
366 1.1 kefren
367 1.1 kefren if (so_prefix) {
368 1.1 kefren mask_addr(so_prefix);
369 1.1 kefren NEXTADDR(so_prefix);
370 1.1 kefren /* XXX: looks like nobody cares about this */
371 1.1 kefren rm.m_rtm.rtm_flags |= RTF_MASK;
372 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK;
373 1.1 kefren } else
374 1.1 kefren rm.m_rtm.rtm_flags |= RTF_HOST;
375 1.1 kefren
376 1.1 kefren /* route to mpls interface */
377 1.1 kefren if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) {
378 1.1 kefren NEXTADDR2(mplssockaddr);
379 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFP;
380 1.1 kefren }
381 1.1 kefren
382 1.1 kefren if (so_ifa != NULL) {
383 1.1 kefren NEXTADDR(so_ifa);
384 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFA;
385 1.1 kefren }
386 1.1 kefren
387 1.1 kefren if (so_tag) {
388 1.1 kefren NEXTADDR(so_tag);
389 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_TAG;
390 1.1 kefren }
391 1.1 kefren
392 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
393 1.1 kefren
394 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
395 1.1 kefren warnp("Error adding a route: %s\n", route_strerror(errno));
396 1.1 kefren warnp("Destination was: %s\n", union_ntoa(so_dest));
397 1.1 kefren if (so_prefix)
398 1.1 kefren warnp("Prefix was: %s\n", union_ntoa(so_prefix));
399 1.1 kefren if (so_gate)
400 1.1 kefren warnp("Gateway was: %s\n", union_ntoa(so_gate));
401 1.1 kefren rv = LDP_E_ROUTE_ERROR;
402 1.1 kefren }
403 1.1 kefren if (fr) {
404 1.1 kefren free(so_dest);
405 1.1 kefren if (so_prefix)
406 1.1 kefren free(so_prefix);
407 1.1 kefren if (so_gate)
408 1.1 kefren free(so_gate);
409 1.1 kefren if (so_ifa)
410 1.1 kefren free(so_ifa);
411 1.1 kefren if (so_tag)
412 1.1 kefren free(so_tag);
413 1.1 kefren }
414 1.1 kefren
415 1.1 kefren return rv;
416 1.1 kefren }
417 1.1 kefren
418 1.1 kefren /* Deletes a route */
419 1.1 kefren int
420 1.1 kefren delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso)
421 1.1 kefren {
422 1.1 kefren int l, rlen;
423 1.1 kefren struct rt_msg rm;
424 1.1 kefren char *cp;
425 1.1 kefren
426 1.1 kefren if(dont_catch)
427 1.1 kefren return LDP_E_OK;
428 1.1 kefren
429 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg));
430 1.1 kefren cp = rm.m_space;
431 1.1 kefren
432 1.1 kefren rm.m_rtm.rtm_type = RTM_DELETE;
433 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
434 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq;
435 1.1 kefren if (so_pref)
436 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
437 1.1 kefren else
438 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST;
439 1.1 kefren
440 1.1 kefren /* destination, gateway, netmask, genmask, ifp, ifa */
441 1.1 kefren
442 1.1 kefren NEXTADDR(so_dest);
443 1.1 kefren
444 1.1 kefren if (so_pref) {
445 1.1 kefren mask_addr(so_pref);
446 1.1 kefren NEXTADDR(so_pref);
447 1.1 kefren }
448 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
449 1.1 kefren
450 1.1 kefren if (freeso == FREESO) {
451 1.1 kefren free(so_dest);
452 1.1 kefren if (so_pref)
453 1.1 kefren free(so_pref);
454 1.1 kefren }
455 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
456 1.1 kefren if(so_pref) {
457 1.1 kefren char spreftmp[INET_ADDRSTRLEN];
458 1.1 kefren strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
459 1.1 kefren INET_ADDRSTRLEN);
460 1.1 kefren warnp("Error deleting route(%s): %s/%s",
461 1.1 kefren route_strerror(errno), union_ntoa(so_dest),
462 1.1 kefren spreftmp);
463 1.1 kefren } else
464 1.1 kefren warnp("Error deleting route(%s) : %s",
465 1.1 kefren route_strerror(errno), union_ntoa(so_dest));
466 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
467 1.1 kefren }
468 1.1 kefren return LDP_E_OK;
469 1.1 kefren }
470 1.1 kefren
471 1.1 kefren /*
472 1.1 kefren * Check for a route and returns it in rg
473 1.1 kefren * If exact_match is set it compares also the so_dest and so_pref
474 1.1 kefren * with the returned result
475 1.1 kefren */
476 1.1 kefren int
477 1.1 kefren get_route(struct rt_msg * rg, union sockunion * so_dest,
478 1.1 kefren union sockunion * so_pref, int exact_match)
479 1.1 kefren {
480 1.1 kefren int l, rlen, myseq;
481 1.1 kefren struct rt_msg rm;
482 1.1 kefren char *cp;
483 1.1 kefren union sockunion *su;
484 1.1 kefren
485 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg));
486 1.1 kefren cp = rm.m_space;
487 1.1 kefren
488 1.1 kefren myseq = ++rt_seq;
489 1.1 kefren
490 1.1 kefren rm.m_rtm.rtm_type = RTM_GET;
491 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
492 1.1 kefren rm.m_rtm.rtm_seq = myseq;
493 1.1 kefren
494 1.1 kefren /*
495 1.1 kefren * rtm_addrs should contain what we provide into this message but
496 1.1 kefren * RTA_DST | RTA_IFP trick is allowed in order to find out the
497 1.1 kefren * interface.
498 1.1 kefren */
499 1.1 kefren
500 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP;
501 1.1 kefren
502 1.1 kefren /*
503 1.1 kefren * ORDER of fields is: destination, gateway, netmask, genmask, ifp,
504 1.1 kefren * ifa
505 1.1 kefren */
506 1.1 kefren
507 1.1 kefren NEXTADDR(so_dest);
508 1.1 kefren if (so_pref) {
509 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK;
510 1.1 kefren mask_addr(so_pref);
511 1.1 kefren NEXTADDR(so_pref);
512 1.1 kefren }
513 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
514 1.1 kefren
515 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
516 1.1 kefren debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
517 1.1 kefren rlen, l, strerror(errno));
518 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
519 1.1 kefren } else
520 1.1 kefren do {
521 1.1 kefren rlen = read_route_socket((char *) rg,
522 1.1 kefren sizeof(struct rt_msg));
523 1.1 kefren if (rlen < 1)
524 1.1 kefren break;
525 1.1 kefren /*
526 1.1 kefren * We might lose important messages here. WORKAROUND:
527 1.1 kefren * For now I just try to save this messages and replay
528 1.1 kefren * them later
529 1.1 kefren */
530 1.1 kefren if ((rg->m_rtm.rtm_pid != getpid()) ||
531 1.1 kefren (rg->m_rtm.rtm_seq != myseq)) {
532 1.1 kefren /*
533 1.1 kefren * Shortcut: my pid but not
534 1.1 kefren * the expected sequence
535 1.1 kefren */
536 1.1 kefren if (rg->m_rtm.rtm_pid == getpid())
537 1.1 kefren continue;
538 1.1 kefren
539 1.1 kefren debugp("Added to replay PID: %d, SEQ: %d\n",
540 1.1 kefren rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
541 1.1 kefren memcpy(&replay_rt[replay_index], rg,
542 1.1 kefren sizeof(struct rt_msg));
543 1.1 kefren if (replay_index < REPLAY_MAX - 1)
544 1.1 kefren replay_index++;
545 1.1 kefren continue;
546 1.1 kefren }
547 1.1 kefren } while ((rg->m_rtm.rtm_seq != myseq) ||
548 1.1 kefren (rg->m_rtm.rtm_pid != getpid()));
549 1.1 kefren
550 1.1 kefren if ((uint)rlen <= sizeof(struct rt_msghdr)) {
551 1.1 kefren debugp("Got only %d bytes, expecting at least %u\n", rlen,
552 1.1 kefren sizeof(struct rt_msghdr));
553 1.1 kefren return LDP_E_ROUTE_ERROR;
554 1.1 kefren }
555 1.1 kefren
556 1.1 kefren /* Check if we don't have a less specific route */
557 1.1 kefren if (exact_match) {
558 1.1 kefren su = (union sockunion*)(rg->m_space);
559 1.1 kefren if (compare_sockunion(so_dest, su)) {
560 1.1 kefren debugp("Dest %s ", union_ntoa(so_dest));
561 1.1 kefren debugp("not like %s\n", union_ntoa(su));
562 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
563 1.1 kefren }
564 1.1 kefren }
565 1.1 kefren
566 1.1 kefren return LDP_E_OK;
567 1.1 kefren }
568 1.1 kefren
569 1.1 kefren
570 1.1 kefren /* triggered when a route event occurs */
571 1.1 kefren int
572 1.1 kefren check_route(struct rt_msg * rg, uint rlen)
573 1.1 kefren {
574 1.1 kefren union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
575 1.1 kefren int so_pref_allocated = 0;
576 1.1 kefren int prefixlen;
577 1.1 kefren struct peer_map *pm;
578 1.1 kefren struct label *lab;
579 1.1 kefren char dest[50], gate[50], pref[50], oper[50];
580 1.1 kefren dest[0] = 0;
581 1.1 kefren gate[0] = 0;
582 1.1 kefren pref[0] = 0;
583 1.1 kefren
584 1.1 kefren if (rlen <= sizeof(struct rt_msghdr))
585 1.1 kefren return LDP_E_ROUTE_ERROR;
586 1.1 kefren
587 1.1 kefren if (rg->m_rtm.rtm_version != RTM_VERSION)
588 1.1 kefren return LDP_E_ROUTE_ERROR;
589 1.1 kefren
590 1.1 kefren if ((rg->m_rtm.rtm_flags & RTF_DONE) == 0)
591 1.1 kefren return LDP_E_OK;
592 1.1 kefren
593 1.1 kefren if (rg->m_rtm.rtm_pid == getpid()) /* We did it.. */
594 1.1 kefren return LDP_E_OK;
595 1.1 kefren else
596 1.1 kefren debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
597 1.1 kefren
598 1.1 kefren so_dest = (union sockunion *) rg->m_space;
599 1.1 kefren
600 1.1 kefren if (so_dest->sa.sa_family != AF_INET)
601 1.1 kefren return LDP_E_OK;/* We don't care about non-IP changes */
602 1.1 kefren
603 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
604 1.1 kefren so_gate = GETNEXT(so_dest);
605 1.1 kefren if ((so_gate->sa.sa_family != AF_INET) &&
606 1.1 kefren (so_gate->sa.sa_family != AF_MPLS))
607 1.1 kefren return LDP_E_OK;
608 1.1 kefren }
609 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
610 1.1 kefren if (so_gate)
611 1.1 kefren so_pref = so_gate;
612 1.1 kefren else
613 1.1 kefren so_pref = so_dest;
614 1.1 kefren so_pref = GETNEXT(so_pref);
615 1.1 kefren }
616 1.1 kefren if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY)) {
617 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_GENMASK) {
618 1.1 kefren debugp("Used GENMASK\n");
619 1.1 kefren } else
620 1.1 kefren debugp("No GENMASK to use\n");
621 1.1 kefren }
622 1.1 kefren /* Calculate prefixlen */
623 1.1 kefren if (so_pref)
624 1.1 kefren prefixlen = from_mask_to_cidr(inet_ntoa(so_pref->sin.sin_addr));
625 1.1 kefren else {
626 1.1 kefren prefixlen = 32;
627 1.1 kefren so_pref = from_cidr_to_union(32);
628 1.1 kefren so_pref_allocated = 1;
629 1.1 kefren }
630 1.1 kefren
631 1.1 kefren so_pref->sa.sa_family = AF_INET;
632 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in);
633 1.1 kefren
634 1.1 kefren switch (rg->m_rtm.rtm_type) {
635 1.1 kefren case RTM_CHANGE:
636 1.1 kefren warnp("XXX: RTM_CHANGE\n");
637 1.1 kefren /* Fallthrough */
638 1.1 kefren case RTM_ADD:
639 1.1 kefren /*
640 1.1 kefren * Check if the route is connected. If so, bind it to
641 1.1 kefren * POP_LABEL and send announce. If not, check if the prefix
642 1.1 kefren * was announced by a LDP neighbour and route it there
643 1.1 kefren */
644 1.1 kefren
645 1.1 kefren /* First of all check if we already know this one */
646 1.1 kefren lab = label_get(so_dest, so_pref);
647 1.1 kefren if (!lab) {
648 1.1 kefren if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY))
649 1.1 kefren lab = label_add(so_dest, so_pref, NULL,
650 1.1 kefren MPLS_LABEL_IMPLNULL, NULL, 0);
651 1.1 kefren else {
652 1.1 kefren pm = ldp_test_mapping(&so_dest->sin.sin_addr,
653 1.1 kefren prefixlen, &so_gate->sin.sin_addr);
654 1.1 kefren if (pm) {
655 1.1 kefren lab = label_add(so_dest, so_pref,
656 1.1 kefren so_gate, 0, NULL, 0);
657 1.1 kefren mpls_add_label(pm->peer, rg,
658 1.1 kefren &so_dest->sin.sin_addr, prefixlen,
659 1.1 kefren pm->lm->label, ROUTE_LOOKUP_LOOP);
660 1.1 kefren free(pm);
661 1.1 kefren } else
662 1.1 kefren lab = label_add(so_dest, so_pref,
663 1.1 kefren so_gate, MPLS_LABEL_IMPLNULL,
664 1.1 kefren NULL, 0);
665 1.1 kefren }
666 1.1 kefren } else /* We already know about this prefix */
667 1.1 kefren debugp("Binding already there for prefix %s/%d !\n",
668 1.1 kefren union_ntoa(so_dest), prefixlen);
669 1.1 kefren break;
670 1.1 kefren case RTM_DELETE:
671 1.1 kefren if (!so_gate)
672 1.1 kefren break; /* Non-existent route XXX ?! */
673 1.1 kefren /*
674 1.1 kefren * Send withdraw check the binding, delete the route, delete
675 1.1 kefren * the binding
676 1.1 kefren */
677 1.1 kefren lab = label_get(so_dest, so_pref);
678 1.1 kefren if (!lab)
679 1.1 kefren break;
680 1.1 kefren send_withdraw_tlv_to_all(&so_dest->sin.sin_addr, prefixlen);
681 1.1 kefren /* No readd as IPv4. Also don't even try to delete it */
682 1.1 kefren label_reattach_route(lab, LDP_READD_NODEL);
683 1.1 kefren label_del(lab);
684 1.1 kefren break;
685 1.1 kefren }
686 1.1 kefren
687 1.1 kefren /* Rest is just for debug */
688 1.1 kefren
689 1.1 kefren if (so_dest)
690 1.1 kefren strlcpy(dest, union_ntoa(so_dest), 16);
691 1.1 kefren if (so_pref)
692 1.1 kefren snprintf(pref, 3, "%d", prefixlen);
693 1.1 kefren if (so_gate)
694 1.1 kefren strlcpy(gate, union_ntoa(so_gate), 16);
695 1.1 kefren
696 1.1 kefren switch (rg->m_rtm.rtm_type) {
697 1.1 kefren case RTM_ADD:
698 1.1 kefren strlcpy(oper, "added", 20);
699 1.1 kefren break;
700 1.1 kefren case RTM_DELETE:
701 1.1 kefren strlcpy(oper, "delete", 20);
702 1.1 kefren break;
703 1.1 kefren case RTM_GET:
704 1.1 kefren strlcpy(oper, "get", 20);
705 1.1 kefren break;
706 1.1 kefren case RTM_CHANGE:
707 1.1 kefren strlcpy(oper, "change", 20);
708 1.1 kefren break;
709 1.1 kefren case RTM_LOSING:
710 1.1 kefren strlcpy(oper, "losing", 20);
711 1.1 kefren break;
712 1.1 kefren case RTM_NEWADDR:
713 1.1 kefren strlcpy(oper, "new address", 20);
714 1.1 kefren break;
715 1.1 kefren case RTM_DELADDR:
716 1.1 kefren strlcpy(oper, "del address", 20);
717 1.1 kefren break;
718 1.1 kefren default:
719 1.1 kefren snprintf(oper, 50, "unknown 0x%X operation",
720 1.1 kefren rg->m_rtm.rtm_type);
721 1.1 kefren }
722 1.1 kefren
723 1.1 kefren warnp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
724 1.1 kefren pref, gate, rg->m_rtm.rtm_pid);
725 1.1 kefren
726 1.1 kefren if(so_pref_allocated)
727 1.1 kefren free(so_pref);
728 1.1 kefren return LDP_E_OK;
729 1.1 kefren }
730 1.1 kefren
731 1.1 kefren int
732 1.1 kefren bind_current_routes()
733 1.1 kefren {
734 1.1 kefren size_t needed;
735 1.1 kefren int mib[6];
736 1.1 kefren char *buf, *next, *lim;
737 1.1 kefren struct rt_msghdr *rtmes;
738 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate;
739 1.1 kefren struct label *lab;
740 1.1 kefren
741 1.1 kefren mib[0] = CTL_NET;
742 1.1 kefren mib[1] = PF_ROUTE;
743 1.1 kefren mib[2] = 0;
744 1.1 kefren mib[3] = 0;
745 1.1 kefren mib[4] = NET_RT_DUMP;
746 1.1 kefren mib[5] = 0;
747 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
748 1.1 kefren fatalp("route-sysctl-estimate: %s",
749 1.1 kefren strerror(errno));
750 1.1 kefren return LDP_E_ROUTE_ERROR;
751 1.1 kefren }
752 1.1 kefren if ((buf = malloc(needed)) == 0)
753 1.1 kefren return LDP_E_ROUTE_ERROR;
754 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
755 1.1 kefren free(buf);
756 1.1 kefren return LDP_E_ROUTE_ERROR;
757 1.1 kefren }
758 1.1 kefren lim = buf + needed;
759 1.1 kefren
760 1.1 kefren for (next = buf; next < lim; next += rtmes->rtm_msglen) {
761 1.1 kefren rtmes = (struct rt_msghdr *) next;
762 1.1 kefren so_pref = NULL;
763 1.1 kefren so_gate = NULL;
764 1.1 kefren if (rtmes->rtm_flags & RTF_LLINFO) /* No need for arps */
765 1.1 kefren continue;
766 1.1 kefren if (!(rtmes->rtm_addrs & RTA_DST)) {
767 1.1 kefren debugp("No dst\n");
768 1.1 kefren continue;
769 1.1 kefren }
770 1.1 kefren
771 1.1 kefren so_dst = (union sockunion *) & rtmes[1];
772 1.1 kefren
773 1.1 kefren /*
774 1.1 kefren * As this function is call only at startup use this ocassion
775 1.1 kefren * to delete all MPLS routes
776 1.1 kefren */
777 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) {
778 1.1 kefren delete_route(so_dst, NULL, NO_FREESO);
779 1.1 kefren debugp("MPLS route deleted.\n");
780 1.1 kefren continue;
781 1.1 kefren }
782 1.1 kefren
783 1.1 kefren if (so_dst->sa.sa_family != AF_INET) {
784 1.1 kefren debugp("sa_dst is not AF_INET\n");
785 1.1 kefren continue;
786 1.1 kefren }
787 1.1 kefren
788 1.1 kefren /* Check if it's the default gateway */
789 1.1 kefren if (so_dst->sin.sin_addr.s_addr == 0)
790 1.1 kefren continue;
791 1.1 kefren
792 1.1 kefren /* XXX: Check if it's loopback */
793 1.1 kefren if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
794 1.1 kefren continue;
795 1.1 kefren
796 1.1 kefren /* Get Gateway */
797 1.1 kefren if (rtmes->rtm_addrs & RTA_GATEWAY)
798 1.1 kefren so_gate = GETNEXT(so_dst);
799 1.1 kefren
800 1.1 kefren /* Get prefix */
801 1.1 kefren if (rtmes->rtm_flags & RTF_HOST)
802 1.1 kefren so_pref = from_cidr_to_union(32);
803 1.1 kefren else if (rtmes->rtm_addrs & RTA_GATEWAY)
804 1.1 kefren so_pref = GETNEXT(so_gate);
805 1.1 kefren else
806 1.1 kefren so_pref = GETNEXT(so_dst);
807 1.1 kefren
808 1.1 kefren so_pref->sa.sa_family = AF_INET;
809 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in);
810 1.1 kefren
811 1.1 kefren /* Also deletes when dest is IPv4 and gateway MPLS */
812 1.1 kefren if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
813 1.1 kefren (so_gate->sa.sa_family == AF_MPLS)) {
814 1.1 kefren debugp("MPLS route to %s deleted.\n",
815 1.1 kefren inet_ntoa(so_dst->sin.sin_addr));
816 1.1 kefren delete_route(so_dst, so_pref, NO_FREESO);
817 1.1 kefren if (rtmes->rtm_flags & RTF_HOST)
818 1.1 kefren free(so_pref);
819 1.1 kefren continue;
820 1.1 kefren }
821 1.1 kefren if (so_gate->sa.sa_family == AF_INET)
822 1.1 kefren lab = label_add(so_dst, so_pref, so_gate,
823 1.1 kefren MPLS_LABEL_IMPLNULL, NULL, 0);
824 1.1 kefren
825 1.1 kefren if (rtmes->rtm_flags & RTF_HOST)
826 1.1 kefren free(so_pref);
827 1.1 kefren }
828 1.1 kefren free(buf);
829 1.1 kefren return LDP_E_OK;
830 1.1 kefren }
831 1.1 kefren
832 1.1 kefren int
833 1.1 kefren flush_mpls_routes()
834 1.1 kefren {
835 1.1 kefren size_t needed;
836 1.1 kefren int mib[6];
837 1.1 kefren char *buf, *next, *lim;
838 1.1 kefren struct rt_msghdr *rtm;
839 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate;
840 1.1 kefren
841 1.1 kefren mib[0] = CTL_NET;
842 1.1 kefren mib[1] = PF_ROUTE;
843 1.1 kefren mib[2] = 0;
844 1.1 kefren mib[3] = 0;
845 1.1 kefren mib[4] = NET_RT_DUMP;
846 1.1 kefren mib[5] = 0;
847 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
848 1.1 kefren fatalp("route-sysctl-estimate: %s", strerror(errno));
849 1.1 kefren return LDP_E_ROUTE_ERROR;
850 1.1 kefren }
851 1.1 kefren if ((buf = malloc(needed)) == 0)
852 1.1 kefren return LDP_E_ROUTE_ERROR;
853 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
854 1.1 kefren free(buf);
855 1.1 kefren return LDP_E_ROUTE_ERROR;
856 1.1 kefren }
857 1.1 kefren lim = buf + needed;
858 1.1 kefren
859 1.1 kefren for (next = buf; next < lim; next += rtm->rtm_msglen) {
860 1.1 kefren rtm = (struct rt_msghdr *) next;
861 1.1 kefren so_pref = NULL;
862 1.1 kefren so_gate = NULL;
863 1.1 kefren if (rtm->rtm_flags & RTF_LLINFO) /* No need for arps */
864 1.1 kefren continue;
865 1.1 kefren if (!(rtm->rtm_addrs & RTA_DST)) {
866 1.1 kefren debugp("No dst\n");
867 1.1 kefren continue;
868 1.1 kefren }
869 1.1 kefren so_dst = (union sockunion *) & rtm[1];
870 1.1 kefren
871 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) {
872 1.1 kefren delete_route(so_dst, NULL, NO_FREESO);
873 1.1 kefren debugp("MPLS route deleted.\n");
874 1.1 kefren continue;
875 1.1 kefren }
876 1.1 kefren
877 1.1 kefren if (rtm->rtm_addrs & RTA_GATEWAY) {
878 1.1 kefren so_gate = GETNEXT(so_dst);
879 1.1 kefren so_pref = GETNEXT(so_gate);
880 1.1 kefren } else
881 1.1 kefren so_pref = GETNEXT(so_dst);
882 1.1 kefren
883 1.1 kefren if (so_gate->sa.sa_family == AF_MPLS) {
884 1.1 kefren debugp("MPLS route to %s deleted.\n",
885 1.1 kefren inet_ntoa(so_dst->sin.sin_addr));
886 1.1 kefren delete_route(so_dst, so_pref, NO_FREESO);
887 1.1 kefren continue;
888 1.1 kefren }
889 1.1 kefren
890 1.1 kefren }
891 1.1 kefren free(buf);
892 1.1 kefren return LDP_E_OK;
893 1.1 kefren }
894