Annotation of embedaddon/quagga/zebra/rt_socket.c, revision 1.1
1.1 ! misho 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:
! 37: extern struct zebra_privs_t zserv_privs;
! 38:
! 39: /* kernel socket export */
! 40: extern 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. */
! 46: static int
! 47: sin_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. */
! 68: static int
! 69: kernel_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;
! 75: int nexthop_num = 0;
! 76: unsigned int ifindex = 0;
! 77: int gate = 0;
! 78: int error;
! 79: char prefix_buf[INET_ADDRSTRLEN];
! 80:
! 81: if (IS_ZEBRA_DEBUG_RIB)
! 82: inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
! 83: memset (&sin_dest, 0, sizeof (struct sockaddr_in));
! 84: sin_dest.sin_family = AF_INET;
! 85: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 86: sin_dest.sin_len = sizeof (struct sockaddr_in);
! 87: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 88: sin_dest.sin_addr = p->u.prefix4;
! 89:
! 90: memset (&sin_mask, 0, sizeof (struct sockaddr_in));
! 91:
! 92: memset (&sin_gate, 0, sizeof (struct sockaddr_in));
! 93: sin_gate.sin_family = AF_INET;
! 94: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 95: sin_gate.sin_len = sizeof (struct sockaddr_in);
! 96: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 97:
! 98: /* Make gateway. */
! 99: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 100: {
! 101: gate = 0;
! 102: char gate_buf[INET_ADDRSTRLEN] = "NULL";
! 103:
! 104: /*
! 105: * XXX We need to refrain from kernel operations in some cases,
! 106: * but this if statement seems overly cautious - what about
! 107: * other than ADD and DELETE?
! 108: */
! 109: if ((cmd == RTM_ADD
! 110: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 111: || (cmd == RTM_DELETE
! 112: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
! 113: ))
! 114: {
! 115: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 116: {
! 117: if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
! 118: nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
! 119: {
! 120: sin_gate.sin_addr = nexthop->rgate.ipv4;
! 121: gate = 1;
! 122: }
! 123: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 124: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
! 125: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
! 126: ifindex = nexthop->rifindex;
! 127: }
! 128: else
! 129: {
! 130: if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
! 131: nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 132: {
! 133: sin_gate.sin_addr = nexthop->gate.ipv4;
! 134: gate = 1;
! 135: }
! 136: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 137: || nexthop->type == NEXTHOP_TYPE_IFNAME
! 138: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 139: ifindex = nexthop->ifindex;
! 140: if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
! 141: {
! 142: struct in_addr loopback;
! 143: loopback.s_addr = htonl (INADDR_LOOPBACK);
! 144: sin_gate.sin_addr = loopback;
! 145: gate = 1;
! 146: }
! 147: }
! 148:
! 149: if (gate && p->prefixlen == 32)
! 150: mask = NULL;
! 151: else
! 152: {
! 153: masklen2ip (p->prefixlen, &sin_mask.sin_addr);
! 154: sin_mask.sin_family = AF_INET;
! 155: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 156: sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
! 157: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 158: mask = &sin_mask;
! 159: }
! 160:
! 161: error = rtm_write (cmd,
! 162: (union sockunion *)&sin_dest,
! 163: (union sockunion *)mask,
! 164: gate ? (union sockunion *)&sin_gate : NULL,
! 165: ifindex,
! 166: rib->flags,
! 167: rib->metric);
! 168:
! 169: if (IS_ZEBRA_DEBUG_RIB)
! 170: {
! 171: if (!gate)
! 172: {
! 173: zlog_debug ("%s: %s/%d: attention! gate not found for rib %p",
! 174: __func__, prefix_buf, p->prefixlen, rib);
! 175: rib_dump (__func__, (struct prefix_ipv4 *)p, rib);
! 176: }
! 177: else
! 178: inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
! 179: }
! 180:
! 181: switch (error)
! 182: {
! 183: /* We only flag nexthops as being in FIB if rtm_write() did its work. */
! 184: case ZEBRA_ERR_NOERROR:
! 185: nexthop_num++;
! 186: if (IS_ZEBRA_DEBUG_RIB)
! 187: zlog_debug ("%s: %s/%d: successfully did NH %s",
! 188: __func__, prefix_buf, p->prefixlen, gate_buf);
! 189: if (cmd == RTM_ADD)
! 190: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 191: break;
! 192:
! 193: /* The only valid case for this error is kernel's failure to install
! 194: * a multipath route, which is common for FreeBSD. This should be
! 195: * ignored silently, but logged as an error otherwise.
! 196: */
! 197: case ZEBRA_ERR_RTEXIST:
! 198: if (cmd != RTM_ADD)
! 199: zlog_err ("%s: rtm_write() returned %d for command %d",
! 200: __func__, error, cmd);
! 201: continue;
! 202: break;
! 203:
! 204: /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
! 205: * normal to get any other messages in ANY case.
! 206: */
! 207: case ZEBRA_ERR_RTNOEXIST:
! 208: case ZEBRA_ERR_RTUNREACH:
! 209: default:
! 210: /* This point is reachable regardless of debugging mode. */
! 211: if (!IS_ZEBRA_DEBUG_RIB)
! 212: inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
! 213: zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
! 214: __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd));
! 215: break;
! 216: }
! 217: } /* if (cmd and flags make sense) */
! 218: else
! 219: if (IS_ZEBRA_DEBUG_RIB)
! 220: zlog_debug ("%s: odd command %s for flags %d",
! 221: __func__, lookup (rtm_type_str, cmd), nexthop->flags);
! 222: } /* for (nexthop = ... */
! 223:
! 224: /* If there was no useful nexthop, then complain. */
! 225: if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
! 226: zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib);
! 227:
! 228: return 0; /*XXX*/
! 229: }
! 230:
! 231: int
! 232: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
! 233: {
! 234: int route;
! 235:
! 236: if (zserv_privs.change(ZPRIVS_RAISE))
! 237: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 238: route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
! 239: if (zserv_privs.change(ZPRIVS_LOWER))
! 240: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 241:
! 242: return route;
! 243: }
! 244:
! 245: int
! 246: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
! 247: {
! 248: int route;
! 249:
! 250: if (zserv_privs.change(ZPRIVS_RAISE))
! 251: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 252: route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
! 253: if (zserv_privs.change(ZPRIVS_LOWER))
! 254: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 255:
! 256: return route;
! 257: }
! 258:
! 259: #ifdef HAVE_IPV6
! 260:
! 261: /* Calculate sin6_len value for netmask socket value. */
! 262: static int
! 263: sin6_masklen (struct in6_addr mask)
! 264: {
! 265: struct sockaddr_in6 sin6;
! 266: char *p, *lim;
! 267: int len;
! 268:
! 269: #if defined (INRIA)
! 270: if (IN_ANYADDR6 (mask))
! 271: return sizeof (long);
! 272: #else /* ! INRIA */
! 273: if (IN6_IS_ADDR_UNSPECIFIED (&mask))
! 274: return sizeof (long);
! 275: #endif /* ! INRIA */
! 276:
! 277: sin6.sin6_addr = mask;
! 278: len = sizeof (struct sockaddr_in6);
! 279:
! 280: lim = (char *) & sin6.sin6_addr;
! 281: p = lim + sizeof (sin6.sin6_addr);
! 282:
! 283: while (*--p == 0 && p >= lim)
! 284: len--;
! 285:
! 286: return len;
! 287: }
! 288:
! 289: /* Interface between zebra message and rtm message. */
! 290: static int
! 291: kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
! 292: struct in6_addr *gate, int index, int flags)
! 293: {
! 294: struct sockaddr_in6 *mask;
! 295: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
! 296:
! 297: memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
! 298: sin_dest.sin6_family = AF_INET6;
! 299: #ifdef SIN6_LEN
! 300: sin_dest.sin6_len = sizeof (struct sockaddr_in6);
! 301: #endif /* SIN6_LEN */
! 302:
! 303: memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
! 304:
! 305: memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
! 306: sin_gate.sin6_family = AF_INET6;
! 307: #ifdef SIN6_LEN
! 308: sin_gate.sin6_len = sizeof (struct sockaddr_in6);
! 309: #endif /* SIN6_LEN */
! 310:
! 311: sin_dest.sin6_addr = dest->prefix;
! 312:
! 313: if (gate)
! 314: memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
! 315:
! 316: /* Under kame set interface index to link local address. */
! 317: #ifdef KAME
! 318:
! 319: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
! 320: do { \
! 321: (a).s6_addr[2] = ((i) >> 8) & 0xff; \
! 322: (a).s6_addr[3] = (i) & 0xff; \
! 323: } while (0)
! 324:
! 325: if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
! 326: SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
! 327: #endif /* KAME */
! 328:
! 329: if (gate && dest->prefixlen == 128)
! 330: mask = NULL;
! 331: else
! 332: {
! 333: masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
! 334: sin_mask.sin6_family = AF_INET6;
! 335: #ifdef SIN6_LEN
! 336: sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
! 337: #endif /* SIN6_LEN */
! 338: mask = &sin_mask;
! 339: }
! 340:
! 341: return rtm_write (message,
! 342: (union sockunion *) &sin_dest,
! 343: (union sockunion *) mask,
! 344: gate ? (union sockunion *)&sin_gate : NULL,
! 345: index,
! 346: flags,
! 347: 0);
! 348: }
! 349:
! 350: /* Interface between zebra message and rtm message. */
! 351: static int
! 352: kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
! 353: int family)
! 354: {
! 355: struct sockaddr_in6 *mask;
! 356: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
! 357: struct nexthop *nexthop;
! 358: int nexthop_num = 0;
! 359: unsigned int ifindex = 0;
! 360: int gate = 0;
! 361: int error;
! 362:
! 363: memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
! 364: sin_dest.sin6_family = AF_INET6;
! 365: #ifdef SIN6_LEN
! 366: sin_dest.sin6_len = sizeof (struct sockaddr_in6);
! 367: #endif /* SIN6_LEN */
! 368: sin_dest.sin6_addr = p->u.prefix6;
! 369:
! 370: memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
! 371:
! 372: memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
! 373: sin_gate.sin6_family = AF_INET6;
! 374: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 375: sin_gate.sin6_len = sizeof (struct sockaddr_in6);
! 376: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 377:
! 378: /* Make gateway. */
! 379: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 380: {
! 381: gate = 0;
! 382:
! 383: if ((cmd == RTM_ADD
! 384: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 385: || (cmd == RTM_DELETE
! 386: #if 0
! 387: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
! 388: #endif
! 389: ))
! 390: {
! 391: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 392: {
! 393: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
! 394: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
! 395: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
! 396: {
! 397: sin_gate.sin6_addr = nexthop->rgate.ipv6;
! 398: gate = 1;
! 399: }
! 400: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 401: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
! 402: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
! 403: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
! 404: ifindex = nexthop->rifindex;
! 405: }
! 406: else
! 407: {
! 408: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 409: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 410: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 411: {
! 412: sin_gate.sin6_addr = nexthop->gate.ipv6;
! 413: gate = 1;
! 414: }
! 415: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 416: || nexthop->type == NEXTHOP_TYPE_IFNAME
! 417: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 418: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 419: ifindex = nexthop->ifindex;
! 420: }
! 421:
! 422: if (cmd == RTM_ADD)
! 423: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 424: }
! 425:
! 426: /* Under kame set interface index to link local address. */
! 427: #ifdef KAME
! 428:
! 429: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
! 430: do { \
! 431: (a).s6_addr[2] = ((i) >> 8) & 0xff; \
! 432: (a).s6_addr[3] = (i) & 0xff; \
! 433: } while (0)
! 434:
! 435: if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
! 436: SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
! 437: #endif /* KAME */
! 438:
! 439: if (gate && p->prefixlen == 128)
! 440: mask = NULL;
! 441: else
! 442: {
! 443: masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
! 444: sin_mask.sin6_family = AF_INET6;
! 445: #ifdef SIN6_LEN
! 446: sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
! 447: #endif /* SIN6_LEN */
! 448: mask = &sin_mask;
! 449: }
! 450:
! 451: error = rtm_write (cmd,
! 452: (union sockunion *) &sin_dest,
! 453: (union sockunion *) mask,
! 454: gate ? (union sockunion *)&sin_gate : NULL,
! 455: ifindex,
! 456: rib->flags,
! 457: rib->metric);
! 458:
! 459: #if 0
! 460: if (error)
! 461: {
! 462: zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
! 463: nexthop_num, error);
! 464: }
! 465: #endif
! 466:
! 467: nexthop_num++;
! 468: }
! 469:
! 470: /* If there is no useful nexthop then return. */
! 471: if (nexthop_num == 0)
! 472: {
! 473: if (IS_ZEBRA_DEBUG_KERNEL)
! 474: zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
! 475: return 0;
! 476: }
! 477:
! 478: return 0; /*XXX*/
! 479: }
! 480:
! 481: int
! 482: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
! 483: {
! 484: int route;
! 485:
! 486: if (zserv_privs.change(ZPRIVS_RAISE))
! 487: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 488: route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
! 489: if (zserv_privs.change(ZPRIVS_LOWER))
! 490: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 491:
! 492: return route;
! 493: }
! 494:
! 495: int
! 496: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
! 497: {
! 498: int route;
! 499:
! 500: if (zserv_privs.change(ZPRIVS_RAISE))
! 501: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 502: route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
! 503: if (zserv_privs.change(ZPRIVS_LOWER))
! 504: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 505:
! 506: return route;
! 507: }
! 508:
! 509: /* Delete IPv6 route from the kernel. */
! 510: int
! 511: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
! 512: unsigned int index, int flags, int table)
! 513: {
! 514: int route;
! 515:
! 516: if (zserv_privs.change(ZPRIVS_RAISE))
! 517: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 518: route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
! 519: if (zserv_privs.change(ZPRIVS_LOWER))
! 520: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 521:
! 522: return route;
! 523: }
! 524: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>