1/* 2 * Kernel routing table updates by routing socket. 3 * Copyright (C) 1997, 98 Kunihiro Ishiguro 4 * 5 * This file is part of GNU Zebra. 6 * 7 * GNU Zebra is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2, or (at your option) any 10 * later version. 11 * 12 * GNU Zebra is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Zebra; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "if.h" 26#include "prefix.h" 27#include "sockunion.h" 28#include "log.h" 29#include "str.h" 30#include "privs.h" 31 32#include "zebra/debug.h" 33#include "zebra/rib.h" 34#include "zebra/rt.h" 35#include "zebra/kernel_socket.h" 36 37extern struct zebra_privs_t zserv_privs; 38 39/* kernel socket export */ 40extern int rtm_write (int message, union sockunion *dest, 41 union sockunion *mask, union sockunion *gate, 42 unsigned int index, int zebra_flags, int metric); 43 44/* Adjust netmask socket length. Return value is a adjusted sin_len 45 value. */ 46static int 47sin_masklen (struct in_addr mask) 48{ 49 char *p, *lim; 50 int len; 51 struct sockaddr_in sin; 52 53 if (mask.s_addr == 0) 54 return sizeof (long); 55 56 sin.sin_addr = mask; 57 len = sizeof (struct sockaddr_in); 58 59 lim = (char *) &sin.sin_addr; 60 p = lim + sizeof (sin.sin_addr); 61 62 while (*--p == 0 && p >= lim) 63 len--; 64 return len; 65} 66 67/* Interface between zebra message and rtm message. */ 68static int 69kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) 70 71{ 72 struct sockaddr_in *mask = NULL; 73 struct sockaddr_in sin_dest, sin_mask, sin_gate; 74 struct nexthop *nexthop, *tnexthop; 75 int recursing; 76 int nexthop_num = 0; 77 unsigned int ifindex = 0; 78 int gate = 0; 79 int error; 80 char prefix_buf[INET_ADDRSTRLEN]; 81 82 if (IS_ZEBRA_DEBUG_RIB) 83 inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); 84 memset (&sin_dest, 0, sizeof (struct sockaddr_in)); 85 sin_dest.sin_family = AF_INET; 86#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 87 sin_dest.sin_len = sizeof (struct sockaddr_in); 88#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 89 sin_dest.sin_addr = p->u.prefix4; 90 91 memset (&sin_mask, 0, sizeof (struct sockaddr_in)); 92 93 memset (&sin_gate, 0, sizeof (struct sockaddr_in)); 94 sin_gate.sin_family = AF_INET; 95#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 96 sin_gate.sin_len = sizeof (struct sockaddr_in); 97#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 98 99 /* Make gateway. */ 100 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) 101 { 102 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) 103 continue; 104 105 gate = 0; 106 char gate_buf[INET_ADDRSTRLEN] = "NULL"; 107 108 /* 109 * XXX We need to refrain from kernel operations in some cases, 110 * but this if statement seems overly cautious - what about 111 * other than ADD and DELETE? 112 */ 113 if ((cmd == RTM_ADD 114 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) 115 || (cmd == RTM_DELETE 116 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) 117 )) 118 { 119 if (nexthop->type == NEXTHOP_TYPE_IPV4 || 120 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) 121 { 122 sin_gate.sin_addr = nexthop->gate.ipv4; 123 gate = 1; 124 } 125 if (nexthop->type == NEXTHOP_TYPE_IFINDEX 126 || nexthop->type == NEXTHOP_TYPE_IFNAME 127 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) 128 ifindex = nexthop->ifindex; 129 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) 130 { 131 struct in_addr loopback; 132 loopback.s_addr = htonl (INADDR_LOOPBACK); 133 sin_gate.sin_addr = loopback; 134 gate = 1; 135 } 136 137 if (gate && p->prefixlen == 32) 138 mask = NULL; 139 else 140 { 141 masklen2ip (p->prefixlen, &sin_mask.sin_addr); 142 sin_mask.sin_family = AF_INET; 143#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 144 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr); 145#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 146 mask = &sin_mask; 147 } 148 149 error = rtm_write (cmd, 150 (union sockunion *)&sin_dest, 151 (union sockunion *)mask, 152 gate ? (union sockunion *)&sin_gate : NULL, 153 ifindex, 154 rib->flags, 155 rib->metric); 156 157 if (IS_ZEBRA_DEBUG_RIB) 158 { 159 if (!gate) 160 { 161 zlog_debug ("%s: %s/%d: attention! gate not found for rib %p", 162 __func__, prefix_buf, p->prefixlen, rib); 163 rib_dump (p, rib); 164 } 165 else 166 inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN); 167 } 168 169 switch (error) 170 { 171 /* We only flag nexthops as being in FIB if rtm_write() did its work. */ 172 case ZEBRA_ERR_NOERROR: 173 nexthop_num++; 174 if (IS_ZEBRA_DEBUG_RIB) 175 zlog_debug ("%s: %s/%d: successfully did NH %s", 176 __func__, prefix_buf, p->prefixlen, gate_buf); 177 if (cmd == RTM_ADD) 178 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); 179 break; 180 181 /* The only valid case for this error is kernel's failure to install 182 * a multipath route, which is common for FreeBSD. This should be 183 * ignored silently, but logged as an error otherwise. 184 */ 185 case ZEBRA_ERR_RTEXIST: 186 if (cmd != RTM_ADD) 187 zlog_err ("%s: rtm_write() returned %d for command %d", 188 __func__, error, cmd); 189 continue; 190 break; 191 192 /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't 193 * normal to get any other messages in ANY case. 194 */ 195 case ZEBRA_ERR_RTNOEXIST: 196 case ZEBRA_ERR_RTUNREACH: 197 default: 198 /* This point is reachable regardless of debugging mode. */ 199 if (!IS_ZEBRA_DEBUG_RIB) 200 inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); 201 zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s", 202 __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd)); 203 break; 204 } 205 } /* if (cmd and flags make sense) */ 206 else 207 if (IS_ZEBRA_DEBUG_RIB) 208 zlog_debug ("%s: odd command %s for flags %d", 209 __func__, lookup (rtm_type_str, cmd), nexthop->flags); 210 } /* for (ALL_NEXTHOPS_RO(...))*/ 211 212 /* If there was no useful nexthop, then complain. */ 213 if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL) 214 zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib); 215 216 return 0; /*XXX*/ 217} 218 219int 220kernel_add_ipv4 (struct prefix *p, struct rib *rib) 221{ 222 int route; 223 224 if (zserv_privs.change(ZPRIVS_RAISE)) 225 zlog (NULL, LOG_ERR, "Can't raise privileges"); 226 route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); 227 if (zserv_privs.change(ZPRIVS_LOWER)) 228 zlog (NULL, LOG_ERR, "Can't lower privileges"); 229 230 return route; 231} 232 233int 234kernel_delete_ipv4 (struct prefix *p, struct rib *rib) 235{ 236 int route; 237 238 if (zserv_privs.change(ZPRIVS_RAISE)) 239 zlog (NULL, LOG_ERR, "Can't raise privileges"); 240 route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); 241 if (zserv_privs.change(ZPRIVS_LOWER)) 242 zlog (NULL, LOG_ERR, "Can't lower privileges"); 243 244 return route; 245} 246 247#ifdef HAVE_IPV6 248 249/* Calculate sin6_len value for netmask socket value. */ 250static int 251sin6_masklen (struct in6_addr mask) 252{ 253 struct sockaddr_in6 sin6; 254 char *p, *lim; 255 int len; 256 257 if (IN6_IS_ADDR_UNSPECIFIED (&mask)) 258 return sizeof (long); 259 260 sin6.sin6_addr = mask; 261 len = sizeof (struct sockaddr_in6); 262 263 lim = (char *) & sin6.sin6_addr; 264 p = lim + sizeof (sin6.sin6_addr); 265 266 while (*--p == 0 && p >= lim) 267 len--; 268 269 return len; 270} 271 272/* Interface between zebra message and rtm message. */ 273static int 274kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, 275 struct in6_addr *gate, int index, int flags) 276{ 277 struct sockaddr_in6 *mask; 278 struct sockaddr_in6 sin_dest, sin_mask, sin_gate; 279 280 memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); 281 sin_dest.sin6_family = AF_INET6; 282#ifdef SIN6_LEN 283 sin_dest.sin6_len = sizeof (struct sockaddr_in6); 284#endif /* SIN6_LEN */ 285 286 memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); 287 288 memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); 289 sin_gate.sin6_family = AF_INET6; 290#ifdef SIN6_LEN 291 sin_gate.sin6_len = sizeof (struct sockaddr_in6); 292#endif /* SIN6_LEN */ 293 294 sin_dest.sin6_addr = dest->prefix; 295 296 if (gate) 297 memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); 298 299 /* Under kame set interface index to link local address. */ 300#ifdef KAME 301 302#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ 303 do { \ 304 (a).s6_addr[2] = ((i) >> 8) & 0xff; \ 305 (a).s6_addr[3] = (i) & 0xff; \ 306 } while (0) 307 308 if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) 309 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); 310#endif /* KAME */ 311 312 if (gate && dest->prefixlen == 128) 313 mask = NULL; 314 else 315 { 316 masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); 317 sin_mask.sin6_family = AF_INET6; 318#ifdef SIN6_LEN 319 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); 320#endif /* SIN6_LEN */ 321 mask = &sin_mask; 322 } 323 324 return rtm_write (message, 325 (union sockunion *) &sin_dest, 326 (union sockunion *) mask, 327 gate ? (union sockunion *)&sin_gate : NULL, 328 index, 329 flags, 330 0); 331} 332 333/* Interface between zebra message and rtm message. */ 334static int 335kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, 336 int family) 337{ 338 struct sockaddr_in6 *mask; 339 struct sockaddr_in6 sin_dest, sin_mask, sin_gate; 340 struct nexthop *nexthop, *tnexthop; 341 int recursing; 342 int nexthop_num = 0; 343 unsigned int ifindex = 0; 344 int gate = 0; 345 int error; 346 347 memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); 348 sin_dest.sin6_family = AF_INET6; 349#ifdef SIN6_LEN 350 sin_dest.sin6_len = sizeof (struct sockaddr_in6); 351#endif /* SIN6_LEN */ 352 sin_dest.sin6_addr = p->u.prefix6; 353 354 memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); 355 356 memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); 357 sin_gate.sin6_family = AF_INET6; 358#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 359 sin_gate.sin6_len = sizeof (struct sockaddr_in6); 360#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 361 362 /* Make gateway. */ 363 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) 364 { 365 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) 366 continue; 367 368 gate = 0; 369 370 if ((cmd == RTM_ADD 371 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) 372 || (cmd == RTM_DELETE 373#if 0 374 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) 375#endif 376 )) 377 { 378 if (nexthop->type == NEXTHOP_TYPE_IPV6 379 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME 380 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) 381 { 382 sin_gate.sin6_addr = nexthop->gate.ipv6; 383 gate = 1; 384 } 385 if (nexthop->type == NEXTHOP_TYPE_IFINDEX 386 || nexthop->type == NEXTHOP_TYPE_IFNAME 387 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME 388 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) 389 ifindex = nexthop->ifindex; 390 391 if (cmd == RTM_ADD) 392 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); 393 } 394 395 /* Under kame set interface index to link local address. */ 396#ifdef KAME 397 398#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ 399 do { \ 400 (a).s6_addr[2] = ((i) >> 8) & 0xff; \ 401 (a).s6_addr[3] = (i) & 0xff; \ 402 } while (0) 403 404 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr)) 405 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex); 406#endif /* KAME */ 407 408 if (gate && p->prefixlen == 128) 409 mask = NULL; 410 else 411 { 412 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr); 413 sin_mask.sin6_family = AF_INET6; 414#ifdef SIN6_LEN 415 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); 416#endif /* SIN6_LEN */ 417 mask = &sin_mask; 418 } 419 420 error = rtm_write (cmd, 421 (union sockunion *) &sin_dest, 422 (union sockunion *) mask, 423 gate ? (union sockunion *)&sin_gate : NULL, 424 ifindex, 425 rib->flags, 426 rib->metric); 427 428#if 0 429 if (error) 430 { 431 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", 432 nexthop_num, error); 433 } 434#endif 435 436 nexthop_num++; 437 } 438 439 /* If there is no useful nexthop then return. */ 440 if (nexthop_num == 0) 441 { 442 if (IS_ZEBRA_DEBUG_KERNEL) 443 zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop."); 444 return 0; 445 } 446 447 return 0; /*XXX*/ 448} 449 450int 451kernel_add_ipv6 (struct prefix *p, struct rib *rib) 452{ 453 int route; 454 455 if (zserv_privs.change(ZPRIVS_RAISE)) 456 zlog (NULL, LOG_ERR, "Can't raise privileges"); 457 route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); 458 if (zserv_privs.change(ZPRIVS_LOWER)) 459 zlog (NULL, LOG_ERR, "Can't lower privileges"); 460 461 return route; 462} 463 464int 465kernel_delete_ipv6 (struct prefix *p, struct rib *rib) 466{ 467 int route; 468 469 if (zserv_privs.change(ZPRIVS_RAISE)) 470 zlog (NULL, LOG_ERR, "Can't raise privileges"); 471 route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); 472 if (zserv_privs.change(ZPRIVS_LOWER)) 473 zlog (NULL, LOG_ERR, "Can't lower privileges"); 474 475 return route; 476} 477#endif /* HAVE_IPV6 */ 478