Annotation of embedaddon/quagga/zebra/kernel_socket.c, revision 1.1
1.1 ! misho 1: /* Kernel communication using routing socket.
! 2: * Copyright (C) 1999 Kunihiro Ishiguro
! 3: *
! 4: * This file is part of GNU Zebra.
! 5: *
! 6: * GNU Zebra is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2, or (at your option) any
! 9: * later version.
! 10: *
! 11: * GNU Zebra is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: * General Public License for more details.
! 15: *
! 16: * You should have received a copy of the GNU General Public License
! 17: * along with GNU Zebra; see the file COPYING. If not, write to the Free
! 18: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 19: * 02111-1307, USA.
! 20: */
! 21:
! 22: #include <zebra.h>
! 23:
! 24: #include "if.h"
! 25: #include "prefix.h"
! 26: #include "sockunion.h"
! 27: #include "connected.h"
! 28: #include "memory.h"
! 29: #include "ioctl.h"
! 30: #include "log.h"
! 31: #include "str.h"
! 32: #include "table.h"
! 33: #include "rib.h"
! 34: #include "privs.h"
! 35:
! 36: #include "zebra/interface.h"
! 37: #include "zebra/zserv.h"
! 38: #include "zebra/debug.h"
! 39: #include "zebra/kernel_socket.h"
! 40:
! 41: extern struct zebra_privs_t zserv_privs;
! 42: extern struct zebra_t zebrad;
! 43:
! 44: /*
! 45: * Given a sockaddr length, round it up to include pad bytes following
! 46: * it. Assumes the kernel pads to sizeof(long).
! 47: *
! 48: * XXX: why is ROUNDUP(0) sizeof(long)? 0 is an illegal sockaddr
! 49: * length anyway (< sizeof (struct sockaddr)), so this shouldn't
! 50: * matter.
! 51: */
! 52: #define ROUNDUP(a) \
! 53: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
! 54:
! 55: /*
! 56: * Given a pointer (sockaddr or void *), return the number of bytes
! 57: * taken up by the sockaddr and any padding needed for alignment.
! 58: */
! 59: #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
! 60: #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
! 61: #elif defined(HAVE_IPV6)
! 62: /*
! 63: * One would hope all fixed-size structure definitions are aligned,
! 64: * but round them up nonetheless.
! 65: */
! 66: #define SAROUNDUP(X) \
! 67: (((struct sockaddr *)(X))->sa_family == AF_INET ? \
! 68: ROUNDUP(sizeof(struct sockaddr_in)):\
! 69: (((struct sockaddr *)(X))->sa_family == AF_INET6 ? \
! 70: ROUNDUP(sizeof(struct sockaddr_in6)) : \
! 71: (((struct sockaddr *)(X))->sa_family == AF_LINK ? \
! 72: ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))))
! 73: #else /* HAVE_IPV6 */
! 74: #define SAROUNDUP(X) \
! 75: (((struct sockaddr *)(X))->sa_family == AF_INET ? \
! 76: ROUNDUP(sizeof(struct sockaddr_in)):\
! 77: (((struct sockaddr *)(X))->sa_family == AF_LINK ? \
! 78: ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))
! 79: #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
! 80:
! 81: /* We use an additional pointer in following, pdest, rather than (DEST)
! 82: * directly, because gcc will warn if the macro is expanded and DEST is NULL,
! 83: * complaining that memcpy is being passed a NULL value, despite the fact
! 84: * the if (NULL) makes it impossible.
! 85: */
! 86: #define RTA_ADDR_GET(DEST, RTA, RTMADDRS, PNT) \
! 87: if ((RTMADDRS) & (RTA)) \
! 88: { \
! 89: void *pdest = (DEST); \
! 90: int len = SAROUNDUP ((PNT)); \
! 91: if ( ((DEST) != NULL) && \
! 92: af_check (((struct sockaddr *)(PNT))->sa_family)) \
! 93: memcpy (pdest, (PNT), len); \
! 94: (PNT) += len; \
! 95: }
! 96: #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \
! 97: if ((RTMADDRS) & (RTA)) \
! 98: { \
! 99: void *pdest = (DEST); \
! 100: int len = SAROUNDUP ((PNT)); \
! 101: if ((DEST) != NULL) \
! 102: memcpy (pdest, (PNT), len); \
! 103: (PNT) += len; \
! 104: }
! 105:
! 106: #define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \
! 107: if ((RTMADDRS) & (RTA)) \
! 108: { \
! 109: u_char *pdest = (u_char *) (DEST); \
! 110: int len = SAROUNDUP ((PNT)); \
! 111: struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \
! 112: if (IS_ZEBRA_DEBUG_KERNEL) \
! 113: zlog_debug ("%s: RTA_SDL_GET nlen %d, alen %d", \
! 114: __func__, sdl->sdl_nlen, sdl->sdl_alen); \
! 115: if ( ((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \
! 116: && (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len) ) \
! 117: { \
! 118: memcpy (pdest, sdl->sdl_data, sdl->sdl_nlen); \
! 119: pdest[sdl->sdl_nlen] = '\0'; \
! 120: (LEN) = sdl->sdl_nlen; \
! 121: } \
! 122: (PNT) += len; \
! 123: } \
! 124: else \
! 125: { \
! 126: (LEN) = 0; \
! 127: }
! 128: /* Routing socket message types. */
! 129: const struct message rtm_type_str[] =
! 130: {
! 131: {RTM_ADD, "RTM_ADD"},
! 132: {RTM_DELETE, "RTM_DELETE"},
! 133: {RTM_CHANGE, "RTM_CHANGE"},
! 134: {RTM_GET, "RTM_GET"},
! 135: {RTM_LOSING, "RTM_LOSING"},
! 136: {RTM_REDIRECT, "RTM_REDIRECT"},
! 137: {RTM_MISS, "RTM_MISS"},
! 138: {RTM_LOCK, "RTM_LOCK"},
! 139: #ifdef OLDADD
! 140: {RTM_OLDADD, "RTM_OLDADD"},
! 141: #endif /* RTM_OLDADD */
! 142: #ifdef RTM_OLDDEL
! 143: {RTM_OLDDEL, "RTM_OLDDEL"},
! 144: #endif /* RTM_OLDDEL */
! 145: {RTM_RESOLVE, "RTM_RESOLVE"},
! 146: {RTM_NEWADDR, "RTM_NEWADDR"},
! 147: {RTM_DELADDR, "RTM_DELADDR"},
! 148: {RTM_IFINFO, "RTM_IFINFO"},
! 149: #ifdef RTM_OIFINFO
! 150: {RTM_OIFINFO, "RTM_OIFINFO"},
! 151: #endif /* RTM_OIFINFO */
! 152: #ifdef RTM_NEWMADDR
! 153: {RTM_NEWMADDR, "RTM_NEWMADDR"},
! 154: #endif /* RTM_NEWMADDR */
! 155: #ifdef RTM_DELMADDR
! 156: {RTM_DELMADDR, "RTM_DELMADDR"},
! 157: #endif /* RTM_DELMADDR */
! 158: #ifdef RTM_IFANNOUNCE
! 159: {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
! 160: #endif /* RTM_IFANNOUNCE */
! 161: {0, NULL}
! 162: };
! 163:
! 164: static const struct message rtm_flag_str[] =
! 165: {
! 166: {RTF_UP, "UP"},
! 167: {RTF_GATEWAY, "GATEWAY"},
! 168: {RTF_HOST, "HOST"},
! 169: {RTF_REJECT, "REJECT"},
! 170: {RTF_DYNAMIC, "DYNAMIC"},
! 171: {RTF_MODIFIED, "MODIFIED"},
! 172: {RTF_DONE, "DONE"},
! 173: #ifdef RTF_MASK
! 174: {RTF_MASK, "MASK"},
! 175: #endif /* RTF_MASK */
! 176: #ifdef RTF_CLONING
! 177: {RTF_CLONING, "CLONING"},
! 178: #endif /* RTF_CLONING */
! 179: {RTF_XRESOLVE, "XRESOLVE"},
! 180: {RTF_LLINFO, "LLINFO"},
! 181: {RTF_STATIC, "STATIC"},
! 182: {RTF_BLACKHOLE, "BLACKHOLE"},
! 183: #ifdef RTF_PRIVATE
! 184: {RTF_PRIVATE, "PRIVATE"},
! 185: #endif /* RTF_PRIVATE */
! 186: {RTF_PROTO1, "PROTO1"},
! 187: {RTF_PROTO2, "PROTO2"},
! 188: #ifdef RTF_PRCLONING
! 189: {RTF_PRCLONING, "PRCLONING"},
! 190: #endif /* RTF_PRCLONING */
! 191: #ifdef RTF_WASCLONED
! 192: {RTF_WASCLONED, "WASCLONED"},
! 193: #endif /* RTF_WASCLONED */
! 194: #ifdef RTF_PROTO3
! 195: {RTF_PROTO3, "PROTO3"},
! 196: #endif /* RTF_PROTO3 */
! 197: #ifdef RTF_PINNED
! 198: {RTF_PINNED, "PINNED"},
! 199: #endif /* RTF_PINNED */
! 200: #ifdef RTF_LOCAL
! 201: {RTF_LOCAL, "LOCAL"},
! 202: #endif /* RTF_LOCAL */
! 203: #ifdef RTF_BROADCAST
! 204: {RTF_BROADCAST, "BROADCAST"},
! 205: #endif /* RTF_BROADCAST */
! 206: #ifdef RTF_MULTICAST
! 207: {RTF_MULTICAST, "MULTICAST"},
! 208: #endif /* RTF_MULTICAST */
! 209: #ifdef RTF_MULTIRT
! 210: {RTF_MULTIRT, "MULTIRT"},
! 211: #endif /* RTF_MULTIRT */
! 212: #ifdef RTF_SETSRC
! 213: {RTF_SETSRC, "SETSRC"},
! 214: #endif /* RTF_SETSRC */
! 215: {0, NULL}
! 216: };
! 217:
! 218: /* Kernel routing update socket. */
! 219: int routing_sock = -1;
! 220:
! 221: /* Yes I'm checking ugly routing socket behavior. */
! 222: /* #define DEBUG */
! 223:
! 224: /* Supported address family check. */
! 225: static int inline
! 226: af_check (int family)
! 227: {
! 228: if (family == AF_INET)
! 229: return 1;
! 230: #ifdef HAVE_IPV6
! 231: if (family == AF_INET6)
! 232: return 1;
! 233: #endif /* HAVE_IPV6 */
! 234: return 0;
! 235: }
! 236:
! 237: /* Dump routing table flag for debug purpose. */
! 238: static void
! 239: rtm_flag_dump (int flag)
! 240: {
! 241: const struct message *mes;
! 242: static char buf[BUFSIZ];
! 243:
! 244: buf[0] = '\0';
! 245: for (mes = rtm_flag_str; mes->key != 0; mes++)
! 246: {
! 247: if (mes->key & flag)
! 248: {
! 249: strlcat (buf, mes->str, BUFSIZ);
! 250: strlcat (buf, " ", BUFSIZ);
! 251: }
! 252: }
! 253: zlog_debug ("Kernel: %s", buf);
! 254: }
! 255:
! 256: #ifdef RTM_IFANNOUNCE
! 257: /* Interface adding function */
! 258: static int
! 259: ifan_read (struct if_announcemsghdr *ifan)
! 260: {
! 261: struct interface *ifp;
! 262:
! 263: ifp = if_lookup_by_index (ifan->ifan_index);
! 264:
! 265: if (ifp)
! 266: assert ( (ifp->ifindex == ifan->ifan_index)
! 267: || (ifp->ifindex == IFINDEX_INTERNAL) );
! 268:
! 269: if ( (ifp == NULL)
! 270: || ((ifp->ifindex == IFINDEX_INTERNAL)
! 271: && (ifan->ifan_what == IFAN_ARRIVAL)) )
! 272: {
! 273: if (IS_ZEBRA_DEBUG_KERNEL)
! 274: zlog_debug ("%s: creating interface for ifindex %d, name %s",
! 275: __func__, ifan->ifan_index, ifan->ifan_name);
! 276:
! 277: /* Create Interface */
! 278: ifp = if_get_by_name_len(ifan->ifan_name,
! 279: strnlen(ifan->ifan_name,
! 280: sizeof(ifan->ifan_name)));
! 281: ifp->ifindex = ifan->ifan_index;
! 282:
! 283: if_add_update (ifp);
! 284: }
! 285: else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
! 286: if_delete_update (ifp);
! 287:
! 288: if_get_flags (ifp);
! 289: if_get_mtu (ifp);
! 290: if_get_metric (ifp);
! 291:
! 292: if (IS_ZEBRA_DEBUG_KERNEL)
! 293: zlog_debug ("%s: interface %s index %d",
! 294: __func__, ifan->ifan_name, ifan->ifan_index);
! 295:
! 296: return 0;
! 297: }
! 298: #endif /* RTM_IFANNOUNCE */
! 299:
! 300: #ifdef HAVE_BSD_LINK_DETECT
! 301: /* BSD link detect translation */
! 302: static void
! 303: bsd_linkdetect_translate (struct if_msghdr *ifm)
! 304: {
! 305: if ((ifm->ifm_data.ifi_link_state >= LINK_STATE_UP) ||
! 306: (ifm->ifm_data.ifi_link_state == LINK_STATE_UNKNOWN))
! 307: SET_FLAG(ifm->ifm_flags, IFF_RUNNING);
! 308: else
! 309: UNSET_FLAG(ifm->ifm_flags, IFF_RUNNING);
! 310: }
! 311: #endif /* HAVE_BSD_LINK_DETECT */
! 312:
! 313: /*
! 314: * Handle struct if_msghdr obtained from reading routing socket or
! 315: * sysctl (from interface_list). There may or may not be sockaddrs
! 316: * present after the header.
! 317: */
! 318: int
! 319: ifm_read (struct if_msghdr *ifm)
! 320: {
! 321: struct interface *ifp = NULL;
! 322: char ifname[IFNAMSIZ];
! 323: short ifnlen = 0;
! 324: caddr_t *cp;
! 325:
! 326: /* terminate ifname at head (for strnlen) and tail (for safety) */
! 327: ifname[IFNAMSIZ - 1] = '\0';
! 328:
! 329: /* paranoia: sanity check structure */
! 330: if (ifm->ifm_msglen < sizeof(struct if_msghdr))
! 331: {
! 332: zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n",
! 333: ifm->ifm_msglen);
! 334: return -1;
! 335: }
! 336:
! 337: /*
! 338: * Check for a sockaddr_dl following the message. First, point to
! 339: * where a socakddr might be if one follows the message.
! 340: */
! 341: cp = (void *)(ifm + 1);
! 342:
! 343: #ifdef SUNOS_5
! 344: /*
! 345: * XXX This behavior should be narrowed to only the kernel versions
! 346: * for which the structures returned do not match the headers.
! 347: *
! 348: * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions
! 349: * is 12 bytes larger than the 32 bit version.
! 350: */
! 351: if (((struct sockaddr *) cp)->sa_family == AF_UNSPEC)
! 352: cp = cp + 12;
! 353: #endif
! 354:
! 355: RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp);
! 356: RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
! 357: RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
! 358: RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
! 359: RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
! 360: RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
! 361: RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
! 362: RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp);
! 363:
! 364: if (IS_ZEBRA_DEBUG_KERNEL)
! 365: zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)"));
! 366:
! 367: /*
! 368: * Look up on ifindex first, because ifindices are the primary handle for
! 369: * interfaces across the user/kernel boundary, for most systems. (Some
! 370: * messages, such as up/down status changes on NetBSD, do not include a
! 371: * sockaddr_dl).
! 372: */
! 373: if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL )
! 374: {
! 375: /* we have an ifp, verify that the name matches as some systems,
! 376: * eg Solaris, have a 1:many association of ifindex:ifname
! 377: * if they dont match, we dont have the correct ifp and should
! 378: * set it back to NULL to let next check do lookup by name
! 379: */
! 380: if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) )
! 381: {
! 382: if (IS_ZEBRA_DEBUG_KERNEL)
! 383: zlog_debug ("%s: ifp name %s doesnt match sdl name %s",
! 384: __func__, ifp->name, ifname);
! 385: ifp = NULL;
! 386: }
! 387: }
! 388:
! 389: /*
! 390: * If we dont have an ifp, try looking up by name. Particularly as some
! 391: * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname
! 392: * is therefore our unique handle to that interface.
! 393: *
! 394: * Interfaces specified in the configuration file for which the ifindex
! 395: * has not been determined will have ifindex == IFINDEX_INTERNAL, and such
! 396: * interfaces are found by this search, and then their ifindex values can
! 397: * be filled in.
! 398: */
! 399: if ( (ifp == NULL) && ifnlen)
! 400: ifp = if_lookup_by_name (ifname);
! 401:
! 402: /*
! 403: * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL),
! 404: * create or fill in an interface.
! 405: */
! 406: if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL))
! 407: {
! 408: /*
! 409: * To create or fill in an interface, a sockaddr_dl (via
! 410: * RTA_IFP) is required.
! 411: */
! 412: if (!ifnlen)
! 413: {
! 414: zlog_warn ("Interface index %d (new) missing ifname\n",
! 415: ifm->ifm_index);
! 416: return -1;
! 417: }
! 418:
! 419: #ifndef RTM_IFANNOUNCE
! 420: /* Down->Down interface should be ignored here.
! 421: * See further comment below.
! 422: */
! 423: if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP))
! 424: return 0;
! 425: #endif /* !RTM_IFANNOUNCE */
! 426:
! 427: if (ifp == NULL)
! 428: {
! 429: /* Interface that zebra was not previously aware of, so create. */
! 430: ifp = if_create (ifname, ifnlen);
! 431: if (IS_ZEBRA_DEBUG_KERNEL)
! 432: zlog_debug ("%s: creating ifp for ifindex %d",
! 433: __func__, ifm->ifm_index);
! 434: }
! 435:
! 436: if (IS_ZEBRA_DEBUG_KERNEL)
! 437: zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d",
! 438: __func__, ifp->name, ifp->ifindex);
! 439: /*
! 440: * Fill in newly created interface structure, or larval
! 441: * structure with ifindex IFINDEX_INTERNAL.
! 442: */
! 443: ifp->ifindex = ifm->ifm_index;
! 444:
! 445: #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */
! 446: bsd_linkdetect_translate(ifm);
! 447: #endif /* HAVE_BSD_LINK_DETECT */
! 448:
! 449: if_flags_update (ifp, ifm->ifm_flags);
! 450: #if defined(__bsdi__)
! 451: if_kvm_get_mtu (ifp);
! 452: #else
! 453: if_get_mtu (ifp);
! 454: #endif /* __bsdi__ */
! 455: if_get_metric (ifp);
! 456:
! 457: if_add_update (ifp);
! 458: }
! 459: else
! 460: /*
! 461: * Interface structure exists. Adjust stored flags from
! 462: * notification. If interface has up->down or down->up
! 463: * transition, call state change routines (to adjust routes,
! 464: * notify routing daemons, etc.). (Other flag changes are stored
! 465: * but apparently do not trigger action.)
! 466: */
! 467: {
! 468: if (ifp->ifindex != ifm->ifm_index)
! 469: {
! 470: zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, "
! 471: "ifm index %d",
! 472: __func__, ifp->name, ifp->ifindex, ifm->ifm_index);
! 473: return -1;
! 474: }
! 475:
! 476: #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */
! 477: bsd_linkdetect_translate(ifm);
! 478: #endif /* HAVE_BSD_LINK_DETECT */
! 479:
! 480: /* update flags and handle operative->inoperative transition, if any */
! 481: if_flags_update (ifp, ifm->ifm_flags);
! 482:
! 483: #ifndef RTM_IFANNOUNCE
! 484: if (!if_is_up (ifp))
! 485: {
! 486: /* No RTM_IFANNOUNCE on this platform, so we can never
! 487: * distinguish between ~IFF_UP and delete. We must presume
! 488: * it has been deleted.
! 489: * Eg, Solaris will not notify us of unplumb.
! 490: *
! 491: * XXX: Fixme - this should be runtime detected
! 492: * So that a binary compiled on a system with IFANNOUNCE
! 493: * will still behave correctly if run on a platform without
! 494: */
! 495: if_delete_update (ifp);
! 496: }
! 497: #endif /* RTM_IFANNOUNCE */
! 498: if (if_is_up (ifp))
! 499: {
! 500: #if defined(__bsdi__)
! 501: if_kvm_get_mtu (ifp);
! 502: #else
! 503: if_get_mtu (ifp);
! 504: #endif /* __bsdi__ */
! 505: if_get_metric (ifp);
! 506: }
! 507: }
! 508:
! 509: #ifdef HAVE_NET_RT_IFLIST
! 510: ifp->stats = ifm->ifm_data;
! 511: #endif /* HAVE_NET_RT_IFLIST */
! 512:
! 513: if (IS_ZEBRA_DEBUG_KERNEL)
! 514: zlog_debug ("%s: interface %s index %d",
! 515: __func__, ifp->name, ifp->ifindex);
! 516:
! 517: return 0;
! 518: }
! 519:
! 520: /* Address read from struct ifa_msghdr. */
! 521: static void
! 522: ifam_read_mesg (struct ifa_msghdr *ifm,
! 523: union sockunion *addr,
! 524: union sockunion *mask,
! 525: union sockunion *brd,
! 526: char *ifname,
! 527: short *ifnlen)
! 528: {
! 529: caddr_t pnt, end;
! 530: union sockunion dst;
! 531: union sockunion gateway;
! 532:
! 533: pnt = (caddr_t)(ifm + 1);
! 534: end = ((caddr_t)ifm) + ifm->ifam_msglen;
! 535:
! 536: /* Be sure structure is cleared */
! 537: memset (mask, 0, sizeof (union sockunion));
! 538: memset (addr, 0, sizeof (union sockunion));
! 539: memset (brd, 0, sizeof (union sockunion));
! 540: memset (&dst, 0, sizeof (union sockunion));
! 541: memset (&gateway, 0, sizeof (union sockunion));
! 542:
! 543: /* We fetch each socket variable into sockunion. */
! 544: RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt);
! 545: RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt);
! 546: RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
! 547: RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
! 548: RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
! 549: RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt);
! 550: RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
! 551: RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt);
! 552:
! 553: if (IS_ZEBRA_DEBUG_KERNEL)
! 554: {
! 555: switch (sockunion_family(addr))
! 556: {
! 557: case AF_INET:
! 558: {
! 559: char buf[4][INET_ADDRSTRLEN];
! 560: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
! 561: "ifam_flags 0x%x, addr %s/%d broad %s dst %s "
! 562: "gateway %s",
! 563: __func__, ifm->ifam_index,
! 564: (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
! 565: ifm->ifam_flags,
! 566: inet_ntop(AF_INET,&addr->sin.sin_addr,
! 567: buf[0],sizeof(buf[0])),
! 568: ip_masklen(mask->sin.sin_addr),
! 569: inet_ntop(AF_INET,&brd->sin.sin_addr,
! 570: buf[1],sizeof(buf[1])),
! 571: inet_ntop(AF_INET,&dst.sin.sin_addr,
! 572: buf[2],sizeof(buf[2])),
! 573: inet_ntop(AF_INET,&gateway.sin.sin_addr,
! 574: buf[3],sizeof(buf[3])));
! 575: }
! 576: break;
! 577: #ifdef HAVE_IPV6
! 578: case AF_INET6:
! 579: {
! 580: char buf[4][INET6_ADDRSTRLEN];
! 581: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
! 582: "ifam_flags 0x%x, addr %s/%d broad %s dst %s "
! 583: "gateway %s",
! 584: __func__, ifm->ifam_index,
! 585: (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
! 586: ifm->ifam_flags,
! 587: inet_ntop(AF_INET6,&addr->sin6.sin6_addr,
! 588: buf[0],sizeof(buf[0])),
! 589: ip6_masklen(mask->sin6.sin6_addr),
! 590: inet_ntop(AF_INET6,&brd->sin6.sin6_addr,
! 591: buf[1],sizeof(buf[1])),
! 592: inet_ntop(AF_INET6,&dst.sin6.sin6_addr,
! 593: buf[2],sizeof(buf[2])),
! 594: inet_ntop(AF_INET6,&gateway.sin6.sin6_addr,
! 595: buf[3],sizeof(buf[3])));
! 596: }
! 597: break;
! 598: #endif /* HAVE_IPV6 */
! 599: default:
! 600: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x",
! 601: __func__, ifm->ifam_index,
! 602: (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs);
! 603: break;
! 604: }
! 605: }
! 606:
! 607: /* Assert read up end point matches to end point */
! 608: if (pnt != end)
! 609: zlog_warn ("ifam_read() does't read all socket data");
! 610: }
! 611:
! 612: /* Interface's address information get. */
! 613: int
! 614: ifam_read (struct ifa_msghdr *ifam)
! 615: {
! 616: struct interface *ifp = NULL;
! 617: union sockunion addr, mask, brd;
! 618: char ifname[INTERFACE_NAMSIZ];
! 619: short ifnlen = 0;
! 620: char isalias = 0;
! 621: int flags = 0;
! 622:
! 623: ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0';
! 624:
! 625: /* Allocate and read address information. */
! 626: ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen);
! 627:
! 628: if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL)
! 629: {
! 630: zlog_warn ("%s: no interface for ifname %s, index %d",
! 631: __func__, ifname, ifam->ifam_index);
! 632: return -1;
! 633: }
! 634:
! 635: if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ))
! 636: isalias = 1;
! 637:
! 638: /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD
! 639: field contains a broadcast address or a peer address, so we are forced to
! 640: rely upon the interface type. */
! 641: if (if_is_pointopoint(ifp))
! 642: SET_FLAG(flags, ZEBRA_IFA_PEER);
! 643:
! 644: #if 0
! 645: /* it might seem cute to grab the interface metric here, however
! 646: * we're processing an address update message, and so some systems
! 647: * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left
! 648: * in deliberately, as comment.
! 649: */
! 650: ifp->metric = ifam->ifam_metric;
! 651: #endif
! 652:
! 653: /* Add connected address. */
! 654: switch (sockunion_family (&addr))
! 655: {
! 656: case AF_INET:
! 657: if (ifam->ifam_type == RTM_NEWADDR)
! 658: connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr,
! 659: ip_masklen (mask.sin.sin_addr),
! 660: &brd.sin.sin_addr,
! 661: (isalias ? ifname : NULL));
! 662: else
! 663: connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr,
! 664: ip_masklen (mask.sin.sin_addr),
! 665: &brd.sin.sin_addr);
! 666: break;
! 667: #ifdef HAVE_IPV6
! 668: case AF_INET6:
! 669: /* Unset interface index from link-local address when IPv6 stack
! 670: is KAME. */
! 671: if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr))
! 672: SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
! 673:
! 674: if (ifam->ifam_type == RTM_NEWADDR)
! 675: connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr,
! 676: ip6_masklen (mask.sin6.sin6_addr),
! 677: &brd.sin6.sin6_addr,
! 678: (isalias ? ifname : NULL));
! 679: else
! 680: connected_delete_ipv6 (ifp,
! 681: &addr.sin6.sin6_addr,
! 682: ip6_masklen (mask.sin6.sin6_addr),
! 683: &brd.sin6.sin6_addr);
! 684: break;
! 685: #endif /* HAVE_IPV6 */
! 686: default:
! 687: /* Unsupported family silently ignore... */
! 688: break;
! 689: }
! 690:
! 691: /* Check interface flag for implicit up of the interface. */
! 692: if_refresh (ifp);
! 693:
! 694: #ifdef SUNOS_5
! 695: /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange.
! 696: * See comments for SUNOS_5 in interface.c::if_flags_mangle.
! 697: *
! 698: * Here we take care of case where the real IFF_UP was previously
! 699: * unset (as kept in struct zebra_if.primary_state) and the mangled
! 700: * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned
! 701: * to unset due to the lost non-primary address having DELADDR'd.
! 702: *
! 703: * we must delete the interface, because in between here and next
! 704: * event for this interface-name the administrator could unplumb
! 705: * and replumb the interface.
! 706: */
! 707: if (!if_is_up (ifp))
! 708: if_delete_update (ifp);
! 709: #endif /* SUNOS_5 */
! 710:
! 711: return 0;
! 712: }
! 713:
! 714: /* Interface function for reading kernel routing table information. */
! 715: static int
! 716: rtm_read_mesg (struct rt_msghdr *rtm,
! 717: union sockunion *dest,
! 718: union sockunion *mask,
! 719: union sockunion *gate,
! 720: char *ifname,
! 721: short *ifnlen)
! 722: {
! 723: caddr_t pnt, end;
! 724:
! 725: /* Pnt points out socket data start point. */
! 726: pnt = (caddr_t)(rtm + 1);
! 727: end = ((caddr_t)rtm) + rtm->rtm_msglen;
! 728:
! 729: /* rt_msghdr version check. */
! 730: if (rtm->rtm_version != RTM_VERSION)
! 731: zlog (NULL, LOG_WARNING,
! 732: "Routing message version different %d should be %d."
! 733: "This may cause problem\n", rtm->rtm_version, RTM_VERSION);
! 734:
! 735: /* Be sure structure is cleared */
! 736: memset (dest, 0, sizeof (union sockunion));
! 737: memset (gate, 0, sizeof (union sockunion));
! 738: memset (mask, 0, sizeof (union sockunion));
! 739:
! 740: /* We fetch each socket variable into sockunion. */
! 741: RTA_ADDR_GET (dest, RTA_DST, rtm->rtm_addrs, pnt);
! 742: RTA_ADDR_GET (gate, RTA_GATEWAY, rtm->rtm_addrs, pnt);
! 743: RTA_ATTR_GET (mask, RTA_NETMASK, rtm->rtm_addrs, pnt);
! 744: RTA_ADDR_GET (NULL, RTA_GENMASK, rtm->rtm_addrs, pnt);
! 745: RTA_NAME_GET (ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen);
! 746: RTA_ADDR_GET (NULL, RTA_IFA, rtm->rtm_addrs, pnt);
! 747: RTA_ADDR_GET (NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt);
! 748: RTA_ADDR_GET (NULL, RTA_BRD, rtm->rtm_addrs, pnt);
! 749:
! 750: /* If there is netmask information set it's family same as
! 751: destination family*/
! 752: if (rtm->rtm_addrs & RTA_NETMASK)
! 753: mask->sa.sa_family = dest->sa.sa_family;
! 754:
! 755: /* Assert read up to the end of pointer. */
! 756: if (pnt != end)
! 757: zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
! 758:
! 759: return rtm->rtm_flags;
! 760: }
! 761:
! 762: void
! 763: rtm_read (struct rt_msghdr *rtm)
! 764: {
! 765: int flags;
! 766: u_char zebra_flags;
! 767: union sockunion dest, mask, gate;
! 768: char ifname[INTERFACE_NAMSIZ + 1];
! 769: short ifnlen = 0;
! 770:
! 771: zebra_flags = 0;
! 772:
! 773: /* Read destination and netmask and gateway from rtm message
! 774: structure. */
! 775: flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
! 776: if (!(flags & RTF_DONE))
! 777: return;
! 778: if (IS_ZEBRA_DEBUG_KERNEL)
! 779: zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type,
! 780: lookup (rtm_type_str, rtm->rtm_type));
! 781:
! 782: #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
! 783: if (flags & RTF_CLONED)
! 784: return;
! 785: #endif
! 786: #ifdef RTF_WASCLONED /*freebsd*/
! 787: if (flags & RTF_WASCLONED)
! 788: return;
! 789: #endif
! 790:
! 791: if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
! 792: return;
! 793:
! 794: /* This is connected route. */
! 795: if (! (flags & RTF_GATEWAY))
! 796: return;
! 797:
! 798: if (flags & RTF_PROTO1)
! 799: SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);
! 800:
! 801: /* This is persistent route. */
! 802: if (flags & RTF_STATIC)
! 803: SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);
! 804:
! 805: /* This is a reject or blackhole route */
! 806: if (flags & RTF_REJECT)
! 807: SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT);
! 808: if (flags & RTF_BLACKHOLE)
! 809: SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE);
! 810:
! 811: if (dest.sa.sa_family == AF_INET)
! 812: {
! 813: struct prefix_ipv4 p;
! 814:
! 815: p.family = AF_INET;
! 816: p.prefix = dest.sin.sin_addr;
! 817: if (flags & RTF_HOST)
! 818: p.prefixlen = IPV4_MAX_PREFIXLEN;
! 819: else
! 820: p.prefixlen = ip_masklen (mask.sin.sin_addr);
! 821:
! 822: /* Catch self originated messages and match them against our current RIB.
! 823: * At the same time, ignore unconfirmed messages, they should be tracked
! 824: * by rtm_write() and kernel_rtm_ipv4().
! 825: */
! 826: if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
! 827: {
! 828: char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN];
! 829: int ret;
! 830: if (! IS_ZEBRA_DEBUG_RIB)
! 831: return;
! 832: ret = rib_lookup_ipv4_route (&p, &gate);
! 833: inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN);
! 834: switch (rtm->rtm_type)
! 835: {
! 836: case RTM_ADD:
! 837: case RTM_GET:
! 838: case RTM_CHANGE:
! 839: /* The kernel notifies us about a new route in FIB created by us.
! 840: Do we have a correspondent entry in our RIB? */
! 841: switch (ret)
! 842: {
! 843: case ZEBRA_RIB_NOTFOUND:
! 844: zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB",
! 845: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
! 846: break;
! 847: case ZEBRA_RIB_FOUND_CONNECTED:
! 848: case ZEBRA_RIB_FOUND_NOGATE:
! 849: inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN);
! 850: zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)",
! 851: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf);
! 852: break;
! 853: case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */
! 854: zlog_debug ("%s: %s %s/%d: done Ok",
! 855: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
! 856: rib_lookup_and_dump (&p);
! 857: return;
! 858: break;
! 859: }
! 860: break;
! 861: case RTM_DELETE:
! 862: /* The kernel notifies us about a route deleted by us. Do we still
! 863: have it in the RIB? Do we have anything instead? */
! 864: switch (ret)
! 865: {
! 866: case ZEBRA_RIB_FOUND_EXACT:
! 867: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB",
! 868: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
! 869: rib_lookup_and_dump (&p);
! 870: break;
! 871: case ZEBRA_RIB_FOUND_CONNECTED:
! 872: case ZEBRA_RIB_FOUND_NOGATE:
! 873: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs",
! 874: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
! 875: rib_lookup_and_dump (&p);
! 876: break;
! 877: case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */
! 878: zlog_debug ("%s: %s %s/%d: done Ok",
! 879: __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
! 880: rib_lookup_and_dump (&p);
! 881: return;
! 882: break;
! 883: }
! 884: break;
! 885: default:
! 886: zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received",
! 887: __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type));
! 888: }
! 889: return;
! 890: }
! 891:
! 892: /* Change, delete the old prefix, we have no further information
! 893: * to specify the route really
! 894: */
! 895: if (rtm->rtm_type == RTM_CHANGE)
! 896: rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
! 897: NULL, 0, 0);
! 898:
! 899: if (rtm->rtm_type == RTM_GET
! 900: || rtm->rtm_type == RTM_ADD
! 901: || rtm->rtm_type == RTM_CHANGE)
! 902: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
! 903: &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0);
! 904: else
! 905: rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
! 906: &p, &gate.sin.sin_addr, 0, 0);
! 907: }
! 908: #ifdef HAVE_IPV6
! 909: if (dest.sa.sa_family == AF_INET6)
! 910: {
! 911: /* One day we might have a debug section here like one in the
! 912: * IPv4 case above. Just ignore own messages at the moment.
! 913: */
! 914: if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
! 915: return;
! 916: struct prefix_ipv6 p;
! 917: unsigned int ifindex = 0;
! 918:
! 919: p.family = AF_INET6;
! 920: p.prefix = dest.sin6.sin6_addr;
! 921: if (flags & RTF_HOST)
! 922: p.prefixlen = IPV6_MAX_PREFIXLEN;
! 923: else
! 924: p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);
! 925:
! 926: #ifdef KAME
! 927: if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
! 928: {
! 929: ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
! 930: SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
! 931: }
! 932: #endif /* KAME */
! 933:
! 934: /* CHANGE: delete the old prefix, we have no further information
! 935: * to specify the route really
! 936: */
! 937: if (rtm->rtm_type == RTM_CHANGE)
! 938: rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
! 939: NULL, 0, 0);
! 940:
! 941: if (rtm->rtm_type == RTM_GET
! 942: || rtm->rtm_type == RTM_ADD
! 943: || rtm->rtm_type == RTM_CHANGE)
! 944: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
! 945: &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0);
! 946: else
! 947: rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
! 948: &p, &gate.sin6.sin6_addr, ifindex, 0);
! 949: }
! 950: #endif /* HAVE_IPV6 */
! 951: }
! 952:
! 953: /* Interface function for the kernel routing table updates. Support
! 954: * for RTM_CHANGE will be needed.
! 955: * Exported only for rt_socket.c
! 956: */
! 957: int
! 958: rtm_write (int message,
! 959: union sockunion *dest,
! 960: union sockunion *mask,
! 961: union sockunion *gate,
! 962: unsigned int index,
! 963: int zebra_flags,
! 964: int metric)
! 965: {
! 966: int ret;
! 967: caddr_t pnt;
! 968: struct interface *ifp;
! 969:
! 970: /* Sequencial number of routing message. */
! 971: static int msg_seq = 0;
! 972:
! 973: /* Struct of rt_msghdr and buffer for storing socket's data. */
! 974: struct
! 975: {
! 976: struct rt_msghdr rtm;
! 977: char buf[512];
! 978: } msg;
! 979:
! 980: if (routing_sock < 0)
! 981: return ZEBRA_ERR_EPERM;
! 982:
! 983: /* Clear and set rt_msghdr values */
! 984: memset (&msg, 0, sizeof (struct rt_msghdr));
! 985: msg.rtm.rtm_version = RTM_VERSION;
! 986: msg.rtm.rtm_type = message;
! 987: msg.rtm.rtm_seq = msg_seq++;
! 988: msg.rtm.rtm_addrs = RTA_DST;
! 989: msg.rtm.rtm_addrs |= RTA_GATEWAY;
! 990: msg.rtm.rtm_flags = RTF_UP;
! 991: msg.rtm.rtm_index = index;
! 992:
! 993: if (metric != 0)
! 994: {
! 995: msg.rtm.rtm_rmx.rmx_hopcount = metric;
! 996: msg.rtm.rtm_inits |= RTV_HOPCOUNT;
! 997: }
! 998:
! 999: ifp = if_lookup_by_index (index);
! 1000:
! 1001: if (gate && message == RTM_ADD)
! 1002: msg.rtm.rtm_flags |= RTF_GATEWAY;
! 1003:
! 1004: /* When RTF_CLONING is unavailable on BSD, should we set some
! 1005: * other flag instead?
! 1006: */
! 1007: #ifdef RTF_CLONING
! 1008: if (! gate && message == RTM_ADD && ifp &&
! 1009: (ifp->flags & IFF_POINTOPOINT) == 0)
! 1010: msg.rtm.rtm_flags |= RTF_CLONING;
! 1011: #endif /* RTF_CLONING */
! 1012:
! 1013: /* If no protocol specific gateway is specified, use link
! 1014: address for gateway. */
! 1015: if (! gate)
! 1016: {
! 1017: if (!ifp)
! 1018: {
! 1019: char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255";
! 1020: if (dest)
! 1021: inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN);
! 1022: if (mask)
! 1023: inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN);
! 1024: zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d",
! 1025: __func__, dest_buf, mask_buf, index);
! 1026: return -1;
! 1027: }
! 1028: gate = (union sockunion *) & ifp->sdl;
! 1029: }
! 1030:
! 1031: if (mask)
! 1032: msg.rtm.rtm_addrs |= RTA_NETMASK;
! 1033: else if (message == RTM_ADD)
! 1034: msg.rtm.rtm_flags |= RTF_HOST;
! 1035:
! 1036: /* Tagging route with flags */
! 1037: msg.rtm.rtm_flags |= (RTF_PROTO1);
! 1038:
! 1039: /* Additional flags. */
! 1040: if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
! 1041: msg.rtm.rtm_flags |= RTF_BLACKHOLE;
! 1042: if (zebra_flags & ZEBRA_FLAG_REJECT)
! 1043: msg.rtm.rtm_flags |= RTF_REJECT;
! 1044:
! 1045:
! 1046: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 1047: #define SOCKADDRSET(X,R) \
! 1048: if (msg.rtm.rtm_addrs & (R)) \
! 1049: { \
! 1050: int len = ROUNDUP ((X)->sa.sa_len); \
! 1051: memcpy (pnt, (caddr_t)(X), len); \
! 1052: pnt += len; \
! 1053: }
! 1054: #else
! 1055: #define SOCKADDRSET(X,R) \
! 1056: if (msg.rtm.rtm_addrs & (R)) \
! 1057: { \
! 1058: int len = SAROUNDUP (X); \
! 1059: memcpy (pnt, (caddr_t)(X), len); \
! 1060: pnt += len; \
! 1061: }
! 1062: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 1063:
! 1064: pnt = (caddr_t) msg.buf;
! 1065:
! 1066: /* Write each socket data into rtm message buffer */
! 1067: SOCKADDRSET (dest, RTA_DST);
! 1068: SOCKADDRSET (gate, RTA_GATEWAY);
! 1069: SOCKADDRSET (mask, RTA_NETMASK);
! 1070:
! 1071: msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
! 1072:
! 1073: ret = write (routing_sock, &msg, msg.rtm.rtm_msglen);
! 1074:
! 1075: if (ret != msg.rtm.rtm_msglen)
! 1076: {
! 1077: if (errno == EEXIST)
! 1078: return ZEBRA_ERR_RTEXIST;
! 1079: if (errno == ENETUNREACH)
! 1080: return ZEBRA_ERR_RTUNREACH;
! 1081: if (errno == ESRCH)
! 1082: return ZEBRA_ERR_RTNOEXIST;
! 1083:
! 1084: zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno);
! 1085: return ZEBRA_ERR_KERNEL;
! 1086: }
! 1087: return ZEBRA_ERR_NOERROR;
! 1088: }
! 1089:
! 1090:
! 1091: #include "thread.h"
! 1092: #include "zebra/zserv.h"
! 1093:
! 1094: /* For debug purpose. */
! 1095: static void
! 1096: rtmsg_debug (struct rt_msghdr *rtm)
! 1097: {
! 1098: zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup (rtm_type_str, rtm->rtm_type));
! 1099: rtm_flag_dump (rtm->rtm_flags);
! 1100: zlog_debug ("Kernel: message seq %d", rtm->rtm_seq);
! 1101: zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs);
! 1102: }
! 1103:
! 1104: /* This is pretty gross, better suggestions welcome -- mhandler */
! 1105: #ifndef RTAX_MAX
! 1106: #ifdef RTA_NUMBITS
! 1107: #define RTAX_MAX RTA_NUMBITS
! 1108: #else
! 1109: #define RTAX_MAX 8
! 1110: #endif /* RTA_NUMBITS */
! 1111: #endif /* RTAX_MAX */
! 1112:
! 1113: /* Kernel routing table and interface updates via routing socket. */
! 1114: static int
! 1115: kernel_read (struct thread *thread)
! 1116: {
! 1117: int sock;
! 1118: int nbytes;
! 1119: struct rt_msghdr *rtm;
! 1120:
! 1121: /*
! 1122: * This must be big enough for any message the kernel might send.
! 1123: * Rather than determining how many sockaddrs of what size might be
! 1124: * in each particular message, just use RTAX_MAX of sockaddr_storage
! 1125: * for each. Note that the sockaddrs must be after each message
! 1126: * definition, or rather after whichever happens to be the largest,
! 1127: * since the buffer needs to be big enough for a message and the
! 1128: * sockaddrs together.
! 1129: */
! 1130: union
! 1131: {
! 1132: /* Routing information. */
! 1133: struct
! 1134: {
! 1135: struct rt_msghdr rtm;
! 1136: struct sockaddr_storage addr[RTAX_MAX];
! 1137: } r;
! 1138:
! 1139: /* Interface information. */
! 1140: struct
! 1141: {
! 1142: struct if_msghdr ifm;
! 1143: struct sockaddr_storage addr[RTAX_MAX];
! 1144: } im;
! 1145:
! 1146: /* Interface address information. */
! 1147: struct
! 1148: {
! 1149: struct ifa_msghdr ifa;
! 1150: struct sockaddr_storage addr[RTAX_MAX];
! 1151: } ia;
! 1152:
! 1153: #ifdef RTM_IFANNOUNCE
! 1154: /* Interface arrival/departure */
! 1155: struct
! 1156: {
! 1157: struct if_announcemsghdr ifan;
! 1158: struct sockaddr_storage addr[RTAX_MAX];
! 1159: } ian;
! 1160: #endif /* RTM_IFANNOUNCE */
! 1161:
! 1162: } buf;
! 1163:
! 1164: /* Fetch routing socket. */
! 1165: sock = THREAD_FD (thread);
! 1166:
! 1167: nbytes= read (sock, &buf, sizeof buf);
! 1168:
! 1169: if (nbytes <= 0)
! 1170: {
! 1171: if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
! 1172: zlog_warn ("routing socket error: %s", safe_strerror (errno));
! 1173: return 0;
! 1174: }
! 1175:
! 1176: thread_add_read (zebrad.master, kernel_read, NULL, sock);
! 1177:
! 1178: if (IS_ZEBRA_DEBUG_KERNEL)
! 1179: rtmsg_debug (&buf.r.rtm);
! 1180:
! 1181: rtm = &buf.r.rtm;
! 1182:
! 1183: /*
! 1184: * Ensure that we didn't drop any data, so that processing routines
! 1185: * can assume they have the whole message.
! 1186: */
! 1187: if (rtm->rtm_msglen != nbytes)
! 1188: {
! 1189: zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n",
! 1190: rtm->rtm_msglen, nbytes, rtm->rtm_type);
! 1191: return -1;
! 1192: }
! 1193:
! 1194: switch (rtm->rtm_type)
! 1195: {
! 1196: case RTM_ADD:
! 1197: case RTM_DELETE:
! 1198: case RTM_CHANGE:
! 1199: rtm_read (rtm);
! 1200: break;
! 1201: case RTM_IFINFO:
! 1202: ifm_read (&buf.im.ifm);
! 1203: break;
! 1204: case RTM_NEWADDR:
! 1205: case RTM_DELADDR:
! 1206: ifam_read (&buf.ia.ifa);
! 1207: break;
! 1208: #ifdef RTM_IFANNOUNCE
! 1209: case RTM_IFANNOUNCE:
! 1210: ifan_read (&buf.ian.ifan);
! 1211: break;
! 1212: #endif /* RTM_IFANNOUNCE */
! 1213: default:
! 1214: if (IS_ZEBRA_DEBUG_KERNEL)
! 1215: zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type);
! 1216: break;
! 1217: }
! 1218: return 0;
! 1219: }
! 1220:
! 1221: /* Make routing socket. */
! 1222: static void
! 1223: routing_socket (void)
! 1224: {
! 1225: if ( zserv_privs.change (ZPRIVS_RAISE) )
! 1226: zlog_err ("routing_socket: Can't raise privileges");
! 1227:
! 1228: routing_sock = socket (AF_ROUTE, SOCK_RAW, 0);
! 1229:
! 1230: if (routing_sock < 0)
! 1231: {
! 1232: if ( zserv_privs.change (ZPRIVS_LOWER) )
! 1233: zlog_err ("routing_socket: Can't lower privileges");
! 1234: zlog_warn ("Can't init kernel routing socket");
! 1235: return;
! 1236: }
! 1237:
! 1238: /* XXX: Socket should be NONBLOCK, however as we currently
! 1239: * discard failed writes, this will lead to inconsistencies.
! 1240: * For now, socket must be blocking.
! 1241: */
! 1242: /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
! 1243: zlog_warn ("Can't set O_NONBLOCK to routing socket");*/
! 1244:
! 1245: if ( zserv_privs.change (ZPRIVS_LOWER) )
! 1246: zlog_err ("routing_socket: Can't lower privileges");
! 1247:
! 1248: /* kernel_read needs rewrite. */
! 1249: thread_add_read (zebrad.master, kernel_read, NULL, routing_sock);
! 1250: }
! 1251:
! 1252: /* Exported interface function. This function simply calls
! 1253: routing_socket (). */
! 1254: void
! 1255: kernel_init (void)
! 1256: {
! 1257: routing_socket ();
! 1258: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>