1 1.25 andvar /* $NetBSD: mpls_routes.c,v 1.25 2022/04/07 19:33:38 andvar 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.17 kefren #include <poll.h> 47 1.1 kefren #include <stdio.h> 48 1.1 kefren #include <string.h> 49 1.1 kefren #include <unistd.h> 50 1.1 kefren 51 1.1 kefren #include "ldp.h" 52 1.1 kefren #include "ldp_errors.h" 53 1.1 kefren #include "ldp_peer.h" 54 1.1 kefren #include "mpls_interface.h" 55 1.1 kefren #include "tlv_stack.h" 56 1.1 kefren #include "label.h" 57 1.1 kefren #include "mpls_routes.h" 58 1.13 kefren #include "socketops.h" 59 1.1 kefren 60 1.1 kefren extern int route_socket; 61 1.17 kefren int rt_seq = 200; 62 1.1 kefren int dont_catch = 0; 63 1.6 kefren extern int no_default_route; 64 1.7 kefren extern int debug_f, warn_f; 65 1.21 kefren static int my_pid = 0; 66 1.1 kefren 67 1.1 kefren struct rt_msg replay_rt[REPLAY_MAX]; 68 1.1 kefren int replay_index = 0; 69 1.1 kefren 70 1.18 kefren #if 0 71 1.7 kefren static int read_route_socket(char *, int); 72 1.18 kefren #endif 73 1.1 kefren void mask_addr(union sockunion *); 74 1.12 kefren int compare_sockunion(const union sockunion *, const union sockunion *); 75 1.14 kefren static int check_if_addr_updown(struct rt_msg *, uint); 76 1.1 kefren 77 1.1 kefren extern struct sockaddr mplssockaddr; 78 1.1 kefren 79 1.1 kefren /* Many lines inspired or shamelessly stolen from sbin/route/route.c */ 80 1.1 kefren 81 1.1 kefren #define NEXTADDR(u) \ 82 1.14 kefren do { l = RT_ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l;} while(0); 83 1.1 kefren #define NEXTADDR2(u) \ 84 1.4 kefren do { l = RT_ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0); 85 1.15 kefren 86 1.15 kefren #define CHECK_LEN(sunion) \ 87 1.15 kefren if (size_cp + sunion->sa.sa_len > rlen) \ 88 1.15 kefren return LDP_E_ROUTE_ERROR; \ 89 1.15 kefren else \ 90 1.15 kefren size_cp += sunion->sa.sa_len; 91 1.15 kefren 92 1.15 kefren #define CHECK_MINSA \ 93 1.15 kefren if (size_cp + sizeof(sa_family_t) + sizeof(uint8_t) > rlen) \ 94 1.15 kefren return LDP_E_ROUTE_ERROR; 95 1.15 kefren 96 1.15 kefren #define GETNEXT(dstunion, origunion) \ 97 1.15 kefren do { \ 98 1.15 kefren CHECK_MINSA \ 99 1.15 kefren dstunion = (union sockunion *) ((char *) (origunion) + \ 100 1.15 kefren RT_ROUNDUP((origunion)->sa.sa_len)); \ 101 1.15 kefren CHECK_LEN(dstunion) \ 102 1.15 kefren } while (0); 103 1.15 kefren 104 1.18 kefren #if 0 105 1.7 kefren static int 106 1.1 kefren read_route_socket(char *s, int max) 107 1.1 kefren { 108 1.1 kefren int rv, to_read; 109 1.1 kefren struct rt_msghdr *rhdr; 110 1.17 kefren struct pollfd pfd; 111 1.1 kefren 112 1.17 kefren pfd.fd = route_socket; 113 1.17 kefren pfd.events = POLLRDNORM; 114 1.17 kefren pfd.revents = 0; 115 1.1 kefren 116 1.1 kefren errno = 0; 117 1.1 kefren 118 1.1 kefren do { 119 1.17 kefren rv = poll(&pfd, 1, 100); 120 1.17 kefren } while (rv == -1 && errno == EINTR); 121 1.1 kefren 122 1.1 kefren if (rv < 1) { 123 1.1 kefren if (rv == 0) { 124 1.17 kefren fatalp("read_route_socket: poll timeout\n"); 125 1.1 kefren } else 126 1.17 kefren fatalp("read_route_socket: poll: %s", 127 1.1 kefren strerror(errno)); 128 1.1 kefren return 0; 129 1.1 kefren } 130 1.1 kefren 131 1.1 kefren do { 132 1.1 kefren rv = recv(route_socket, s, max, MSG_PEEK); 133 1.17 kefren } while(rv == -1 && errno == EINTR); 134 1.1 kefren 135 1.1 kefren if (rv < 1) { 136 1.1 kefren debugp("read_route_socket: recv error\n"); 137 1.1 kefren return 0; 138 1.1 kefren } 139 1.1 kefren if (rv > max) { 140 1.1 kefren rv = max; 141 1.1 kefren debugp("read_route_socket: rv > max\n"); 142 1.1 kefren } 143 1.1 kefren 144 1.1 kefren rhdr = (struct rt_msghdr *)s; 145 1.1 kefren to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen; 146 1.1 kefren rv = 0; 147 1.1 kefren 148 1.1 kefren do { 149 1.1 kefren rv += recv(route_socket, s, to_read - rv, 0); 150 1.1 kefren } while (rv != to_read); 151 1.1 kefren 152 1.1 kefren return rv; 153 1.1 kefren } 154 1.18 kefren #endif /* 0 */ 155 1.1 kefren 156 1.1 kefren /* Recalculate length */ 157 1.1 kefren void 158 1.1 kefren mask_addr(union sockunion * su) 159 1.1 kefren { 160 1.1 kefren /* 161 1.1 kefren int olen = su->sa.sa_len; 162 1.1 kefren char *cp1 = olen + (char *) su; 163 1.1 kefren 164 1.1 kefren for (su->sa.sa_len = 0; cp1 > (char *) su;) 165 1.1 kefren if (*--cp1 != 0) { 166 1.1 kefren su->sa.sa_len = 1 + cp1 - (char *) su; 167 1.1 kefren break; 168 1.1 kefren } 169 1.1 kefren */ 170 1.1 kefren /* Let's use INET only version for the moment */ 171 1.1 kefren su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 + 172 1.1 kefren ( from_union_to_cidr(su) % 8 ? 1 : 0 ); 173 1.1 kefren } 174 1.1 kefren 175 1.1 kefren /* creates a sockunion from an IP address */ 176 1.1 kefren union sockunion * 177 1.10 kefren make_inet_union(const char *s) 178 1.1 kefren { 179 1.1 kefren union sockunion *so_inet; 180 1.1 kefren 181 1.2 christos so_inet = calloc(1, sizeof(*so_inet)); 182 1.1 kefren 183 1.1 kefren if (!so_inet) { 184 1.1 kefren fatalp("make_inet_union: malloc problem\n"); 185 1.1 kefren return NULL; 186 1.2 christos } 187 1.1 kefren 188 1.1 kefren so_inet->sin.sin_len = sizeof(struct sockaddr_in); 189 1.1 kefren so_inet->sin.sin_family = AF_INET; 190 1.1 kefren inet_aton(s, &so_inet->sin.sin_addr); 191 1.1 kefren 192 1.1 kefren return so_inet; 193 1.1 kefren } 194 1.1 kefren 195 1.1 kefren /* creates a sockunion from a label */ 196 1.1 kefren union sockunion * 197 1.1 kefren make_mpls_union(uint32_t label) 198 1.1 kefren { 199 1.1 kefren union sockunion *so_mpls; 200 1.1 kefren 201 1.2 christos so_mpls = calloc(1, sizeof(*so_mpls)); 202 1.1 kefren 203 1.1 kefren if (!so_mpls) { 204 1.1 kefren fatalp("make_mpls_union: malloc problem\n"); 205 1.1 kefren return NULL; 206 1.2 christos } 207 1.1 kefren 208 1.1 kefren so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls); 209 1.1 kefren so_mpls->smpls.smpls_family = AF_MPLS; 210 1.1 kefren so_mpls->smpls.smpls_addr.shim.label = label; 211 1.1 kefren 212 1.1 kefren so_mpls->smpls.smpls_addr.s_addr = 213 1.1 kefren htonl(so_mpls->smpls.smpls_addr.s_addr); 214 1.1 kefren 215 1.1 kefren return so_mpls; 216 1.1 kefren } 217 1.1 kefren 218 1.1 kefren int 219 1.12 kefren compare_sockunion(const union sockunion * __restrict a, 220 1.12 kefren const union sockunion * __restrict b) 221 1.1 kefren { 222 1.1 kefren if (a->sa.sa_len != b->sa.sa_len) 223 1.1 kefren return 1; 224 1.1 kefren return memcmp(a, b, a->sa.sa_len); 225 1.1 kefren } 226 1.1 kefren 227 1.1 kefren union sockunion * 228 1.1 kefren from_cidr_to_union(uint8_t prefixlen) 229 1.1 kefren { 230 1.1 kefren union sockunion *u; 231 1.8 kefren uint32_t m = 0xFFFFFFFF; 232 1.1 kefren 233 1.2 christos u = calloc(1, sizeof(*u)); 234 1.1 kefren 235 1.1 kefren if (!u) { 236 1.1 kefren fatalp("from_cidr_to_union: malloc problem\n"); 237 1.1 kefren return NULL; 238 1.1 kefren } 239 1.1 kefren u->sin.sin_len = sizeof(struct sockaddr_in); 240 1.1 kefren u->sin.sin_family = AF_INET; 241 1.8 kefren if (prefixlen != 0) { 242 1.8 kefren m = (m >> (32 - prefixlen) ) << (32 - prefixlen); 243 1.8 kefren m = ntohl(m); 244 1.8 kefren u->sin.sin_addr.s_addr = m; 245 1.8 kefren } 246 1.1 kefren return u; 247 1.1 kefren } 248 1.1 kefren 249 1.1 kefren uint8_t 250 1.12 kefren from_mask_to_cidr(const char *mask) 251 1.1 kefren { 252 1.11 kefren struct in_addr addr; 253 1.11 kefren uint8_t plen = 0; 254 1.11 kefren 255 1.11 kefren if (inet_aton(mask, &addr) != 0) 256 1.11 kefren for (; addr.s_addr; plen++) 257 1.11 kefren addr.s_addr &= addr.s_addr - 1; 258 1.11 kefren return plen; 259 1.1 kefren } 260 1.1 kefren 261 1.1 kefren uint8_t 262 1.12 kefren from_union_to_cidr(const union sockunion *so_pref) 263 1.1 kefren { 264 1.12 kefren const struct sockaddr_in *sin = (const struct sockaddr_in*) so_pref; 265 1.1 kefren uint32_t a; 266 1.1 kefren uint8_t r; 267 1.1 kefren 268 1.1 kefren a = ntohl(sin->sin_addr.s_addr); 269 1.1 kefren for (r=0; a ; a = a << 1, r++); 270 1.1 kefren 271 1.1 kefren return r; 272 1.1 kefren } 273 1.1 kefren 274 1.1 kefren /* returns in mask the netmask created from CIDR prefixlen */ 275 1.1 kefren void 276 1.1 kefren from_cidr_to_mask(uint8_t prefixlen, char *mask) 277 1.1 kefren { 278 1.11 kefren uint32_t a = 0; 279 1.11 kefren uint8_t plen = prefixlen < 32 ? prefixlen : 32; 280 1.1 kefren 281 1.11 kefren if (plen != 0) 282 1.11 kefren a = (0xffffffff >> (32 - plen)) << (32 - plen); 283 1.1 kefren snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24, 284 1.11 kefren (a << 16) >> 24, (a << 24) >> 24); 285 1.1 kefren } 286 1.1 kefren 287 1.1 kefren /* From src/sbin/route/route.c */ 288 1.1 kefren static const char * 289 1.1 kefren route_strerror(int error) 290 1.1 kefren { 291 1.1 kefren 292 1.1 kefren switch (error) { 293 1.1 kefren case ESRCH: 294 1.1 kefren return "not in table"; 295 1.1 kefren case EBUSY: 296 1.1 kefren return "entry in use"; 297 1.1 kefren case ENOBUFS: 298 1.1 kefren return "routing table overflow"; 299 1.1 kefren default: 300 1.1 kefren return strerror(error); 301 1.1 kefren } 302 1.1 kefren } 303 1.1 kefren 304 1.1 kefren 305 1.1 kefren /* Adds a route. Or changes it. */ 306 1.1 kefren int 307 1.1 kefren add_route(union sockunion *so_dest, union sockunion *so_prefix, 308 1.12 kefren union sockunion *so_gate, union sockunion *so_ifa, 309 1.12 kefren union sockunion *so_tag, int fr, int optype) 310 1.1 kefren { 311 1.1 kefren int l, rlen, rv = LDP_E_OK; 312 1.1 kefren struct rt_msg rm; 313 1.1 kefren char *cp; 314 1.1 kefren 315 1.1 kefren if(dont_catch) 316 1.1 kefren return LDP_E_OK; 317 1.1 kefren 318 1.1 kefren memset(&rm, 0, sizeof(rm)); 319 1.1 kefren cp = rm.m_space; 320 1.1 kefren 321 1.1 kefren rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype; 322 1.1 kefren rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 323 1.1 kefren 324 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION; 325 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq; 326 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST; 327 1.1 kefren if (so_gate) 328 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_GATEWAY; 329 1.1 kefren 330 1.1 kefren assert(so_dest); 331 1.1 kefren 332 1.1 kefren /* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */ 333 1.1 kefren NEXTADDR(so_dest); 334 1.1 kefren if (so_gate) 335 1.1 kefren NEXTADDR(so_gate); 336 1.1 kefren 337 1.1 kefren if (so_prefix) { 338 1.12 kefren union sockunion *so_prefix_temp = so_prefix; 339 1.12 kefren 340 1.12 kefren if (fr != FREESO) { 341 1.12 kefren /* don't modify so_prefix */ 342 1.12 kefren so_prefix_temp = calloc(1, so_prefix->sa.sa_len); 343 1.12 kefren if (so_prefix_temp == NULL) 344 1.12 kefren return LDP_E_MEMORY; 345 1.12 kefren memcpy(so_prefix_temp, so_prefix, so_prefix->sa.sa_len); 346 1.12 kefren } 347 1.12 kefren mask_addr(so_prefix_temp); 348 1.12 kefren NEXTADDR(so_prefix_temp); 349 1.12 kefren if (fr != FREESO) 350 1.12 kefren free(so_prefix_temp); 351 1.1 kefren /* XXX: looks like nobody cares about this */ 352 1.1 kefren rm.m_rtm.rtm_flags |= RTF_MASK; 353 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK; 354 1.1 kefren } else 355 1.1 kefren rm.m_rtm.rtm_flags |= RTF_HOST; 356 1.1 kefren 357 1.1 kefren /* route to mpls interface */ 358 1.1 kefren if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) { 359 1.1 kefren NEXTADDR2(mplssockaddr); 360 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFP; 361 1.1 kefren } 362 1.1 kefren 363 1.1 kefren if (so_ifa != NULL) { 364 1.1 kefren NEXTADDR(so_ifa); 365 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFA; 366 1.1 kefren } 367 1.1 kefren 368 1.1 kefren if (so_tag) { 369 1.1 kefren NEXTADDR(so_tag); 370 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_TAG; 371 1.1 kefren } 372 1.1 kefren 373 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm; 374 1.1 kefren 375 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) { 376 1.1 kefren warnp("Error adding a route: %s\n", route_strerror(errno)); 377 1.15 kefren warnp("Destination was: %s\n", satos(&so_dest->sa)); 378 1.1 kefren if (so_prefix) 379 1.15 kefren warnp("Prefix was: %s\n", satos(&so_prefix->sa)); 380 1.1 kefren if (so_gate) 381 1.15 kefren warnp("Gateway was: %s\n", satos(&so_gate->sa)); 382 1.1 kefren rv = LDP_E_ROUTE_ERROR; 383 1.1 kefren } 384 1.12 kefren if (fr == FREESO) { 385 1.1 kefren free(so_dest); 386 1.1 kefren if (so_prefix) 387 1.1 kefren free(so_prefix); 388 1.1 kefren if (so_gate) 389 1.1 kefren free(so_gate); 390 1.1 kefren if (so_ifa) 391 1.1 kefren free(so_ifa); 392 1.1 kefren if (so_tag) 393 1.1 kefren free(so_tag); 394 1.1 kefren } 395 1.1 kefren 396 1.1 kefren return rv; 397 1.1 kefren } 398 1.1 kefren 399 1.1 kefren /* Deletes a route */ 400 1.1 kefren int 401 1.1 kefren delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso) 402 1.1 kefren { 403 1.1 kefren int l, rlen; 404 1.1 kefren struct rt_msg rm; 405 1.1 kefren char *cp; 406 1.1 kefren 407 1.1 kefren if(dont_catch) 408 1.1 kefren return LDP_E_OK; 409 1.1 kefren 410 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg)); 411 1.1 kefren cp = rm.m_space; 412 1.1 kefren 413 1.1 kefren rm.m_rtm.rtm_type = RTM_DELETE; 414 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION; 415 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq; 416 1.1 kefren if (so_pref) 417 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 418 1.20 kefren else { 419 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST; 420 1.20 kefren rm.m_rtm.rtm_flags |= RTF_HOST; 421 1.20 kefren } 422 1.1 kefren 423 1.1 kefren /* destination, gateway, netmask, genmask, ifp, ifa */ 424 1.1 kefren 425 1.1 kefren NEXTADDR(so_dest); 426 1.1 kefren 427 1.1 kefren if (so_pref) { 428 1.12 kefren union sockunion *so_pref_temp = so_pref; 429 1.12 kefren if (freeso != FREESO) { 430 1.12 kefren /* don't modify the original prefix */ 431 1.12 kefren so_pref_temp = calloc(1, so_pref->sa.sa_len); 432 1.12 kefren if (so_pref_temp == NULL) 433 1.12 kefren return LDP_E_MEMORY; 434 1.12 kefren memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len); 435 1.12 kefren } 436 1.12 kefren mask_addr(so_pref_temp); 437 1.12 kefren NEXTADDR(so_pref_temp); 438 1.12 kefren if (freeso != FREESO) 439 1.12 kefren free(so_pref_temp); 440 1.1 kefren } 441 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm; 442 1.1 kefren 443 1.1 kefren if (freeso == FREESO) { 444 1.1 kefren free(so_dest); 445 1.1 kefren if (so_pref) 446 1.1 kefren free(so_pref); 447 1.1 kefren } 448 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) { 449 1.1 kefren if(so_pref) { 450 1.1 kefren char spreftmp[INET_ADDRSTRLEN]; 451 1.1 kefren strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr), 452 1.1 kefren INET_ADDRSTRLEN); 453 1.1 kefren warnp("Error deleting route(%s): %s/%s", 454 1.15 kefren route_strerror(errno), satos(&so_dest->sa), 455 1.1 kefren spreftmp); 456 1.1 kefren } else 457 1.1 kefren warnp("Error deleting route(%s) : %s", 458 1.15 kefren route_strerror(errno), satos(&so_dest->sa)); 459 1.1 kefren return LDP_E_NO_SUCH_ROUTE; 460 1.1 kefren } 461 1.1 kefren return LDP_E_OK; 462 1.1 kefren } 463 1.1 kefren 464 1.18 kefren #if 0 465 1.1 kefren /* 466 1.1 kefren * Check for a route and returns it in rg 467 1.1 kefren * If exact_match is set it compares also the so_dest and so_pref 468 1.1 kefren * with the returned result 469 1.1 kefren */ 470 1.1 kefren int 471 1.12 kefren get_route(struct rt_msg * rg, const union sockunion * so_dest, 472 1.12 kefren const union sockunion * so_pref, int exact_match) 473 1.1 kefren { 474 1.1 kefren int l, rlen, myseq; 475 1.1 kefren struct rt_msg rm; 476 1.1 kefren char *cp; 477 1.1 kefren union sockunion *su; 478 1.1 kefren 479 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg)); 480 1.1 kefren cp = rm.m_space; 481 1.1 kefren 482 1.1 kefren myseq = ++rt_seq; 483 1.1 kefren 484 1.1 kefren rm.m_rtm.rtm_type = RTM_GET; 485 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION; 486 1.1 kefren rm.m_rtm.rtm_seq = myseq; 487 1.1 kefren 488 1.1 kefren /* 489 1.1 kefren * rtm_addrs should contain what we provide into this message but 490 1.1 kefren * RTA_DST | RTA_IFP trick is allowed in order to find out the 491 1.1 kefren * interface. 492 1.1 kefren */ 493 1.1 kefren 494 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP; 495 1.1 kefren 496 1.1 kefren /* 497 1.1 kefren * ORDER of fields is: destination, gateway, netmask, genmask, ifp, 498 1.1 kefren * ifa 499 1.1 kefren */ 500 1.1 kefren 501 1.1 kefren NEXTADDR(so_dest); 502 1.1 kefren if (so_pref) { 503 1.12 kefren union sockunion *so_pref_temp = calloc(1, so_pref->sa.sa_len); 504 1.12 kefren 505 1.12 kefren if (so_pref_temp == NULL) 506 1.12 kefren return LDP_E_MEMORY; 507 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK; 508 1.12 kefren memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len); 509 1.12 kefren mask_addr(so_pref_temp); 510 1.12 kefren NEXTADDR(so_pref_temp); 511 1.12 kefren free(so_pref_temp); 512 1.1 kefren } 513 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm; 514 1.1 kefren 515 1.17 kefren setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){1}, 516 1.17 kefren sizeof(int)); 517 1.17 kefren rlen = write(route_socket, (char *) &rm, l); 518 1.17 kefren setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0}, 519 1.17 kefren sizeof(int)); 520 1.17 kefren 521 1.17 kefren if (rlen < l) { 522 1.1 kefren debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n", 523 1.1 kefren rlen, l, strerror(errno)); 524 1.1 kefren return LDP_E_NO_SUCH_ROUTE; 525 1.1 kefren } else 526 1.7 kefren for ( ; ; ) { 527 1.1 kefren rlen = read_route_socket((char *) rg, 528 1.1 kefren sizeof(struct rt_msg)); 529 1.1 kefren if (rlen < 1) 530 1.1 kefren break; 531 1.1 kefren /* 532 1.1 kefren * We might lose important messages here. WORKAROUND: 533 1.1 kefren * For now I just try to save this messages and replay 534 1.1 kefren * them later 535 1.1 kefren */ 536 1.7 kefren if (rg->m_rtm.rtm_pid == getpid() && 537 1.7 kefren rg->m_rtm.rtm_seq == myseq) 538 1.7 kefren break; 539 1.17 kefren /* Fast skip */ 540 1.17 kefren if (rg->m_rtm.rtm_type != RTM_ADD && 541 1.17 kefren rg->m_rtm.rtm_type != RTM_DELETE && 542 1.17 kefren rg->m_rtm.rtm_type != RTM_CHANGE && 543 1.17 kefren rg->m_rtm.rtm_type != RTM_NEWADDR && 544 1.17 kefren rg->m_rtm.rtm_type != RTM_DELADDR) 545 1.17 kefren continue; 546 1.17 kefren warnp("Added to replay PID: %d, SEQ: %d\n", 547 1.7 kefren rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq); 548 1.7 kefren memcpy(&replay_rt[replay_index], rg, 549 1.7 kefren sizeof(struct rt_msg)); 550 1.7 kefren if (replay_index < REPLAY_MAX - 1) 551 1.7 kefren replay_index++; 552 1.7 kefren else 553 1.7 kefren fatalp("Replay index is full\n"); 554 1.7 kefren } 555 1.1 kefren 556 1.7 kefren if (rlen <= (int)sizeof(struct rt_msghdr)) { 557 1.9 joerg debugp("Got only %d bytes, expecting at least %zu\n", rlen, 558 1.1 kefren sizeof(struct rt_msghdr)); 559 1.1 kefren return LDP_E_ROUTE_ERROR; 560 1.1 kefren } 561 1.1 kefren 562 1.1 kefren /* Check if we don't have a less specific route */ 563 1.1 kefren if (exact_match) { 564 1.1 kefren su = (union sockunion*)(rg->m_space); 565 1.1 kefren if (compare_sockunion(so_dest, su)) { 566 1.15 kefren debugp("Dest %s ", satos(&so_dest->sa)); 567 1.15 kefren debugp("not like %s\n", satos(&su->sa)); 568 1.1 kefren return LDP_E_NO_SUCH_ROUTE; 569 1.1 kefren } 570 1.1 kefren } 571 1.1 kefren 572 1.1 kefren return LDP_E_OK; 573 1.1 kefren } 574 1.1 kefren 575 1.18 kefren #endif /* 0 */ 576 1.18 kefren 577 1.1 kefren /* triggered when a route event occurs */ 578 1.1 kefren int 579 1.1 kefren check_route(struct rt_msg * rg, uint rlen) 580 1.1 kefren { 581 1.1 kefren union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL; 582 1.1 kefren int so_pref_allocated = 0; 583 1.1 kefren int prefixlen; 584 1.15 kefren size_t size_cp; 585 1.1 kefren struct peer_map *pm; 586 1.1 kefren struct label *lab; 587 1.1 kefren char dest[50], gate[50], pref[50], oper[50]; 588 1.1 kefren dest[0] = 0; 589 1.1 kefren gate[0] = 0; 590 1.1 kefren pref[0] = 0; 591 1.1 kefren 592 1.21 kefren if (rlen <= offsetof(struct rt_msghdr, rtm_type) || 593 1.21 kefren rg->m_rtm.rtm_version != RTM_VERSION) 594 1.1 kefren return LDP_E_ROUTE_ERROR; 595 1.1 kefren 596 1.13 kefren if (rg->m_rtm.rtm_type == RTM_NEWADDR || 597 1.13 kefren rg->m_rtm.rtm_type == RTM_DELADDR) 598 1.14 kefren return check_if_addr_updown(rg, rlen); 599 1.14 kefren 600 1.15 kefren size_cp = sizeof(struct rt_msghdr); 601 1.15 kefren CHECK_MINSA; 602 1.14 kefren 603 1.21 kefren if (my_pid == 0) 604 1.21 kefren my_pid = getpid(); 605 1.21 kefren assert(my_pid != 0); 606 1.21 kefren 607 1.21 kefren if (rg->m_rtm.rtm_pid == my_pid || 608 1.21 kefren (rg->m_rtm.rtm_pid != 0 && (rg->m_rtm.rtm_flags & RTF_DONE) == 0) || 609 1.21 kefren (rg->m_rtm.rtm_type != RTM_ADD && 610 1.21 kefren rg->m_rtm.rtm_type != RTM_DELETE && 611 1.21 kefren rg->m_rtm.rtm_type != RTM_CHANGE)) 612 1.1 kefren return LDP_E_OK; 613 1.1 kefren 614 1.13 kefren debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid); 615 1.1 kefren 616 1.21 kefren if (rg->m_rtm.rtm_addrs & RTA_DST) 617 1.21 kefren so_dest = (union sockunion *) rg->m_space; 618 1.21 kefren else 619 1.21 kefren return LDP_E_ROUTE_ERROR; 620 1.1 kefren 621 1.1 kefren if (so_dest->sa.sa_family != AF_INET) 622 1.1 kefren return LDP_E_OK;/* We don't care about non-IP changes */ 623 1.1 kefren 624 1.15 kefren CHECK_LEN(so_dest); 625 1.15 kefren 626 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) { 627 1.15 kefren GETNEXT(so_gate, so_dest); 628 1.24 ozaki if ((rg->m_rtm.rtm_flags & RTF_CONNECTED) == 0 && 629 1.21 kefren so_gate->sa.sa_family != AF_INET && 630 1.21 kefren so_gate->sa.sa_family != AF_MPLS) 631 1.1 kefren return LDP_E_OK; 632 1.1 kefren } 633 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_NETMASK) { 634 1.17 kefren if (so_gate != NULL) { 635 1.17 kefren GETNEXT(so_pref, so_gate); 636 1.1 kefren } else 637 1.17 kefren GETNEXT(so_pref, so_dest); 638 1.1 kefren } 639 1.1 kefren /* Calculate prefixlen */ 640 1.1 kefren if (so_pref) 641 1.17 kefren prefixlen = from_union_to_cidr(so_pref); 642 1.1 kefren else { 643 1.1 kefren prefixlen = 32; 644 1.3 kefren if ((so_pref = from_cidr_to_union(32)) == NULL) 645 1.3 kefren return LDP_E_MEMORY; 646 1.1 kefren so_pref_allocated = 1; 647 1.1 kefren } 648 1.1 kefren 649 1.1 kefren so_pref->sa.sa_family = AF_INET; 650 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in); 651 1.23 kefren so_pref->sin.sin_port = 0; 652 1.23 kefren memset(&so_pref->sin.sin_zero, 0, sizeof(so_pref->sin.sin_zero)); 653 1.1 kefren 654 1.24 ozaki if (rg->m_rtm.rtm_flags & RTF_CONNECTED) 655 1.21 kefren so_gate = NULL; 656 1.21 kefren 657 1.1 kefren switch (rg->m_rtm.rtm_type) { 658 1.1 kefren case RTM_CHANGE: 659 1.6 kefren lab = label_get(so_dest, so_pref); 660 1.6 kefren if (lab) { 661 1.10 kefren send_withdraw_tlv_to_all(&so_dest->sa, 662 1.6 kefren prefixlen); 663 1.18 kefren label_reattach_route(lab, REATT_INET_DEL); 664 1.6 kefren label_del(lab); 665 1.6 kefren } 666 1.1 kefren /* Fallthrough */ 667 1.1 kefren case RTM_ADD: 668 1.1 kefren /* 669 1.1 kefren * Check if the route is connected. If so, bind it to 670 1.1 kefren * POP_LABEL and send announce. If not, check if the prefix 671 1.1 kefren * was announced by a LDP neighbour and route it there 672 1.1 kefren */ 673 1.1 kefren 674 1.1 kefren /* First of all check if we already know this one */ 675 1.5 kefren if (label_get(so_dest, so_pref) == NULL) { 676 1.17 kefren /* Just add an IMPLNULL label */ 677 1.17 kefren if (so_gate == NULL) 678 1.5 kefren label_add(so_dest, so_pref, NULL, 679 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0, 680 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST); 681 1.1 kefren else { 682 1.10 kefren pm = ldp_test_mapping(&so_dest->sa, 683 1.10 kefren prefixlen, &so_gate->sa); 684 1.1 kefren if (pm) { 685 1.18 kefren /* create an implnull label as it 686 1.18 kefren * gets rewritten in mpls_add_label */ 687 1.17 kefren lab = label_add(so_dest, so_pref, 688 1.18 kefren so_gate, MPLS_LABEL_IMPLNULL, 689 1.20 kefren pm->peer, pm->lm->label, 690 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST); 691 1.17 kefren if (lab != NULL) 692 1.17 kefren mpls_add_label(lab); 693 1.1 kefren free(pm); 694 1.1 kefren } else 695 1.5 kefren label_add(so_dest, so_pref, so_gate, 696 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0, 697 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST); 698 1.1 kefren } 699 1.1 kefren } else /* We already know about this prefix */ 700 1.17 kefren fatalp("Binding already there for prefix %s/%d !\n", 701 1.15 kefren satos(&so_dest->sa), prefixlen); 702 1.1 kefren break; 703 1.1 kefren case RTM_DELETE: 704 1.1 kefren /* 705 1.1 kefren * Send withdraw check the binding, delete the route, delete 706 1.1 kefren * the binding 707 1.1 kefren */ 708 1.1 kefren lab = label_get(so_dest, so_pref); 709 1.1 kefren if (!lab) 710 1.1 kefren break; 711 1.10 kefren send_withdraw_tlv_to_all(&so_dest->sa, prefixlen); 712 1.6 kefren /* No readd or delete IP route. Just delete the MPLS route */ 713 1.18 kefren label_reattach_route(lab, REATT_INET_NODEL); 714 1.1 kefren label_del(lab); 715 1.1 kefren break; 716 1.1 kefren } 717 1.1 kefren 718 1.7 kefren if (!debug_f && !warn_f) { 719 1.7 kefren if(so_pref_allocated) 720 1.7 kefren free(so_pref); 721 1.7 kefren return LDP_E_OK; 722 1.7 kefren } 723 1.7 kefren 724 1.1 kefren /* Rest is just for debug */ 725 1.1 kefren 726 1.1 kefren if (so_dest) 727 1.15 kefren strlcpy(dest, satos(&so_dest->sa), sizeof(dest)); 728 1.1 kefren if (so_pref) 729 1.15 kefren snprintf(pref, sizeof(pref), "%d", prefixlen); 730 1.1 kefren if (so_gate) 731 1.15 kefren strlcpy(gate, satos(&so_gate->sa), sizeof(gate)); 732 1.1 kefren 733 1.1 kefren switch (rg->m_rtm.rtm_type) { 734 1.1 kefren case RTM_ADD: 735 1.1 kefren strlcpy(oper, "added", 20); 736 1.1 kefren break; 737 1.1 kefren case RTM_DELETE: 738 1.1 kefren strlcpy(oper, "delete", 20); 739 1.1 kefren break; 740 1.1 kefren case RTM_GET: 741 1.1 kefren strlcpy(oper, "get", 20); 742 1.1 kefren break; 743 1.1 kefren case RTM_CHANGE: 744 1.1 kefren strlcpy(oper, "change", 20); 745 1.1 kefren break; 746 1.1 kefren case RTM_LOSING: 747 1.1 kefren strlcpy(oper, "losing", 20); 748 1.1 kefren break; 749 1.14 kefren case RTM_REDIRECT: 750 1.14 kefren strlcpy(oper, "redirect", 20); 751 1.14 kefren break; 752 1.1 kefren case RTM_NEWADDR: 753 1.1 kefren strlcpy(oper, "new address", 20); 754 1.1 kefren break; 755 1.1 kefren case RTM_DELADDR: 756 1.1 kefren strlcpy(oper, "del address", 20); 757 1.1 kefren break; 758 1.1 kefren default: 759 1.14 kefren snprintf(oper, sizeof(oper), "unknown 0x%X operation", 760 1.1 kefren rg->m_rtm.rtm_type); 761 1.1 kefren } 762 1.1 kefren 763 1.16 kefren debugp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest, 764 1.1 kefren pref, gate, rg->m_rtm.rtm_pid); 765 1.1 kefren 766 1.1 kefren if(so_pref_allocated) 767 1.1 kefren free(so_pref); 768 1.1 kefren return LDP_E_OK; 769 1.1 kefren } 770 1.1 kefren 771 1.13 kefren /* 772 1.13 kefren * Checks NEWADDR and DELADDR messages and sends announcements accordingly 773 1.13 kefren */ 774 1.13 kefren static int 775 1.14 kefren check_if_addr_updown(struct rt_msg * rg, uint rlen) 776 1.13 kefren { 777 1.13 kefren union sockunion *ifa, *netmask; 778 1.13 kefren struct ldp_peer *p; 779 1.13 kefren struct address_list_tlv al_tlv; 780 1.14 kefren struct ifa_msghdr *msghdr = (struct ifa_msghdr *)&rg->m_rtm; 781 1.15 kefren size_t size_cp = sizeof(struct ifa_msghdr); 782 1.13 kefren 783 1.14 kefren if (rlen < sizeof(struct ifa_msghdr) || 784 1.14 kefren (msghdr->ifam_addrs & RTA_NETMASK) == 0 || 785 1.14 kefren (msghdr->ifam_addrs & RTA_IFA) == 0) 786 1.13 kefren return LDP_E_ROUTE_ERROR; 787 1.13 kefren 788 1.15 kefren CHECK_MINSA; 789 1.15 kefren 790 1.14 kefren /* we should have RTA_NETMASK, RTA_IFP, RTA_IFA and RTA_BRD */ 791 1.14 kefren ifa = netmask = (union sockunion *)(msghdr + 1); 792 1.13 kefren if (netmask->sa.sa_family != AF_INET) 793 1.13 kefren return LDP_E_OK; 794 1.15 kefren CHECK_LEN(netmask); 795 1.13 kefren 796 1.14 kefren if (msghdr->ifam_addrs & RTA_IFP) 797 1.15 kefren GETNEXT(ifa, ifa); 798 1.15 kefren 799 1.15 kefren GETNEXT(ifa, ifa); 800 1.13 kefren 801 1.14 kefren if (ifa->sa.sa_family != AF_INET || 802 1.14 kefren ntohl(ifa->sin.sin_addr.s_addr) >> 24 == IN_LOOPBACKNET) 803 1.13 kefren return LDP_E_OK; 804 1.13 kefren 805 1.13 kefren memset(&al_tlv, 0, sizeof(al_tlv)); 806 1.13 kefren al_tlv.type = rg->m_rtm.rtm_type == RTM_NEWADDR ? htons(LDP_ADDRESS) : 807 1.13 kefren htons(LDP_ADDRESS_WITHDRAW); 808 1.13 kefren al_tlv.length = htons(sizeof(al_tlv) - TLV_TYPE_LENGTH); 809 1.13 kefren al_tlv.messageid = htonl(get_message_id()); 810 1.13 kefren al_tlv.a_type = htons(TLV_ADDRESS_LIST); 811 1.13 kefren al_tlv.a_length = htons(sizeof(al_tlv.a_af) + sizeof(al_tlv.a_address)); 812 1.13 kefren al_tlv.a_af = htons(LDP_AF_INET); 813 1.13 kefren memcpy(&al_tlv.a_address, &ifa->sin.sin_addr, sizeof(al_tlv.a_address)); 814 1.13 kefren 815 1.13 kefren SLIST_FOREACH(p, &ldp_peer_head, peers) 816 1.13 kefren if (p->state == LDP_PEER_ESTABLISHED) 817 1.13 kefren send_tlv(p, (struct tlv *)&al_tlv); 818 1.13 kefren 819 1.13 kefren return LDP_E_OK; 820 1.13 kefren } 821 1.13 kefren 822 1.1 kefren int 823 1.1 kefren bind_current_routes() 824 1.1 kefren { 825 1.15 kefren size_t needed, size_cp; 826 1.1 kefren int mib[6]; 827 1.1 kefren char *buf, *next, *lim; 828 1.1 kefren struct rt_msghdr *rtmes; 829 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate; 830 1.15 kefren uint rlen; 831 1.1 kefren 832 1.1 kefren mib[0] = CTL_NET; 833 1.1 kefren mib[1] = PF_ROUTE; 834 1.1 kefren mib[2] = 0; 835 1.1 kefren mib[3] = 0; 836 1.1 kefren mib[4] = NET_RT_DUMP; 837 1.1 kefren mib[5] = 0; 838 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 839 1.1 kefren fatalp("route-sysctl-estimate: %s", 840 1.1 kefren strerror(errno)); 841 1.1 kefren return LDP_E_ROUTE_ERROR; 842 1.1 kefren } 843 1.1 kefren if ((buf = malloc(needed)) == 0) 844 1.1 kefren return LDP_E_ROUTE_ERROR; 845 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 846 1.1 kefren free(buf); 847 1.1 kefren return LDP_E_ROUTE_ERROR; 848 1.1 kefren } 849 1.1 kefren lim = buf + needed; 850 1.1 kefren 851 1.15 kefren for (next = buf; next < lim; next += rlen) { 852 1.1 kefren rtmes = (struct rt_msghdr *) next; 853 1.15 kefren rlen = rtmes->rtm_msglen; 854 1.15 kefren size_cp = sizeof(struct rt_msghdr); 855 1.17 kefren so_gate = so_pref = NULL; 856 1.1 kefren if (!(rtmes->rtm_addrs & RTA_DST)) { 857 1.1 kefren debugp("No dst\n"); 858 1.1 kefren continue; 859 1.1 kefren } 860 1.1 kefren 861 1.15 kefren CHECK_MINSA; 862 1.1 kefren so_dst = (union sockunion *) & rtmes[1]; 863 1.15 kefren CHECK_LEN(so_dst); 864 1.17 kefren 865 1.1 kefren /* 866 1.10 kefren * This function is called only at startup, so use 867 1.25 andvar * this occasion to delete all MPLS routes 868 1.1 kefren */ 869 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) { 870 1.1 kefren delete_route(so_dst, NULL, NO_FREESO); 871 1.1 kefren debugp("MPLS route deleted.\n"); 872 1.1 kefren continue; 873 1.1 kefren } 874 1.1 kefren 875 1.1 kefren if (so_dst->sa.sa_family != AF_INET) { 876 1.10 kefren /*debugp("sa_dst is not AF_INET\n");*/ 877 1.1 kefren continue; 878 1.1 kefren } 879 1.1 kefren 880 1.1 kefren /* Check if it's the default gateway */ 881 1.6 kefren if (so_dst->sin.sin_addr.s_addr == 0 && no_default_route != 0) 882 1.1 kefren continue; 883 1.1 kefren 884 1.15 kefren /* Check if it's loopback */ 885 1.1 kefren if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET) 886 1.1 kefren continue; 887 1.1 kefren 888 1.1 kefren /* Get Gateway */ 889 1.1 kefren if (rtmes->rtm_addrs & RTA_GATEWAY) 890 1.15 kefren GETNEXT(so_gate, so_dst); 891 1.1 kefren 892 1.1 kefren /* Get prefix */ 893 1.3 kefren if (rtmes->rtm_flags & RTF_HOST) { 894 1.3 kefren if ((so_pref = from_cidr_to_union(32)) == NULL) 895 1.3 kefren return LDP_E_MEMORY; 896 1.15 kefren } else if (rtmes->rtm_addrs & RTA_GATEWAY) { 897 1.15 kefren GETNEXT(so_pref, so_gate); 898 1.15 kefren } else 899 1.15 kefren GETNEXT(so_pref, so_dst); 900 1.1 kefren 901 1.1 kefren so_pref->sa.sa_family = AF_INET; 902 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in); 903 1.22 kefren so_pref->sin.sin_port = 0; 904 1.22 kefren memset(&so_pref->sin.sin_zero, 0, 8); 905 1.1 kefren 906 1.1 kefren /* Also deletes when dest is IPv4 and gateway MPLS */ 907 1.1 kefren if ((rtmes->rtm_addrs & RTA_GATEWAY) && 908 1.1 kefren (so_gate->sa.sa_family == AF_MPLS)) { 909 1.1 kefren debugp("MPLS route to %s deleted.\n", 910 1.1 kefren inet_ntoa(so_dst->sin.sin_addr)); 911 1.20 kefren delete_route(so_dst, 912 1.20 kefren rtmes->rtm_flags & RTF_HOST ? NULL : so_pref, 913 1.20 kefren NO_FREESO); 914 1.1 kefren if (rtmes->rtm_flags & RTF_HOST) 915 1.1 kefren free(so_pref); 916 1.1 kefren continue; 917 1.1 kefren } 918 1.17 kefren 919 1.17 kefren if (so_gate != NULL && so_gate->sa.sa_family == AF_LINK) 920 1.17 kefren so_gate = NULL; /* connected route */ 921 1.17 kefren 922 1.16 kefren if (so_gate == NULL || so_gate->sa.sa_family == AF_INET) 923 1.5 kefren label_add(so_dst, so_pref, so_gate, 924 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0, 925 1.20 kefren rtmes->rtm_flags & RTF_HOST); 926 1.1 kefren 927 1.1 kefren if (rtmes->rtm_flags & RTF_HOST) 928 1.1 kefren free(so_pref); 929 1.1 kefren } 930 1.1 kefren free(buf); 931 1.1 kefren return LDP_E_OK; 932 1.1 kefren } 933 1.1 kefren 934 1.1 kefren int 935 1.1 kefren flush_mpls_routes() 936 1.1 kefren { 937 1.15 kefren size_t needed, size_cp; 938 1.15 kefren int mib[6]; 939 1.15 kefren uint rlen; 940 1.15 kefren char *buf, *next, *lim; 941 1.1 kefren struct rt_msghdr *rtm; 942 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate; 943 1.1 kefren 944 1.1 kefren mib[0] = CTL_NET; 945 1.1 kefren mib[1] = PF_ROUTE; 946 1.1 kefren mib[2] = 0; 947 1.1 kefren mib[3] = 0; 948 1.1 kefren mib[4] = NET_RT_DUMP; 949 1.1 kefren mib[5] = 0; 950 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 951 1.1 kefren fatalp("route-sysctl-estimate: %s", strerror(errno)); 952 1.1 kefren return LDP_E_ROUTE_ERROR; 953 1.1 kefren } 954 1.2 christos if ((buf = malloc(needed)) == NULL) { 955 1.2 christos fatalp("route-sysctl-estimate: %s", strerror(errno)); 956 1.2 christos return LDP_E_MEMORY; 957 1.2 christos } 958 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 959 1.1 kefren free(buf); 960 1.1 kefren return LDP_E_ROUTE_ERROR; 961 1.1 kefren } 962 1.1 kefren lim = buf + needed; 963 1.1 kefren 964 1.15 kefren for (next = buf; next < lim; next += rlen) { 965 1.1 kefren rtm = (struct rt_msghdr *) next; 966 1.15 kefren size_cp = sizeof(struct rt_msghdr); 967 1.15 kefren rlen = rtm->rtm_msglen; 968 1.1 kefren so_pref = NULL; 969 1.1 kefren so_gate = NULL; 970 1.1 kefren if (!(rtm->rtm_addrs & RTA_DST)) { 971 1.1 kefren debugp("No dst\n"); 972 1.1 kefren continue; 973 1.1 kefren } 974 1.1 kefren so_dst = (union sockunion *) & rtm[1]; 975 1.1 kefren 976 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) { 977 1.1 kefren delete_route(so_dst, NULL, NO_FREESO); 978 1.1 kefren debugp("MPLS route deleted.\n"); 979 1.1 kefren continue; 980 1.1 kefren } 981 1.1 kefren 982 1.20 kefren if ((rtm->rtm_addrs & RTA_GATEWAY) == 0) 983 1.20 kefren continue; 984 1.20 kefren GETNEXT(so_gate, so_dst); 985 1.20 kefren 986 1.20 kefren if ((rtm->rtm_flags & RTF_HOST) == 0) 987 1.15 kefren GETNEXT(so_pref, so_gate); 988 1.1 kefren 989 1.1 kefren if (so_gate->sa.sa_family == AF_MPLS) { 990 1.7 kefren if (so_dst->sa.sa_family == AF_INET) 991 1.7 kefren debugp("MPLS route to %s deleted.\n", 992 1.7 kefren inet_ntoa(so_dst->sin.sin_addr)); 993 1.1 kefren delete_route(so_dst, so_pref, NO_FREESO); 994 1.1 kefren continue; 995 1.1 kefren } 996 1.1 kefren 997 1.1 kefren } 998 1.1 kefren free(buf); 999 1.1 kefren return LDP_E_OK; 1000 1.1 kefren } 1001