Annotation of embedaddon/quagga/zebra/rt_netlink.c, revision 1.1
1.1 ! misho 1: /* Kernel routing table updates using netlink over GNU/Linux system.
! 2: * Copyright (C) 1997, 98, 99 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: /* Hack for GNU libc version 2. */
! 25: #ifndef MSG_TRUNC
! 26: #define MSG_TRUNC 0x20
! 27: #endif /* MSG_TRUNC */
! 28:
! 29: #include "linklist.h"
! 30: #include "if.h"
! 31: #include "log.h"
! 32: #include "prefix.h"
! 33: #include "connected.h"
! 34: #include "table.h"
! 35: #include "rib.h"
! 36: #include "thread.h"
! 37: #include "privs.h"
! 38:
! 39: #include "zebra/zserv.h"
! 40: #include "zebra/rt.h"
! 41: #include "zebra/redistribute.h"
! 42: #include "zebra/interface.h"
! 43: #include "zebra/debug.h"
! 44:
! 45: /* Socket interface to kernel */
! 46: struct nlsock
! 47: {
! 48: int sock;
! 49: int seq;
! 50: struct sockaddr_nl snl;
! 51: const char *name;
! 52: } netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
! 53: netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
! 54:
! 55: static const struct message nlmsg_str[] = {
! 56: {RTM_NEWROUTE, "RTM_NEWROUTE"},
! 57: {RTM_DELROUTE, "RTM_DELROUTE"},
! 58: {RTM_GETROUTE, "RTM_GETROUTE"},
! 59: {RTM_NEWLINK, "RTM_NEWLINK"},
! 60: {RTM_DELLINK, "RTM_DELLINK"},
! 61: {RTM_GETLINK, "RTM_GETLINK"},
! 62: {RTM_NEWADDR, "RTM_NEWADDR"},
! 63: {RTM_DELADDR, "RTM_DELADDR"},
! 64: {RTM_GETADDR, "RTM_GETADDR"},
! 65: {0, NULL}
! 66: };
! 67:
! 68: static const char *nexthop_types_desc[] =
! 69: {
! 70: "none",
! 71: "Directly connected",
! 72: "Interface route",
! 73: "IPv4 nexthop",
! 74: "IPv4 nexthop with ifindex",
! 75: "IPv4 nexthop with ifname",
! 76: "IPv6 nexthop",
! 77: "IPv6 nexthop with ifindex",
! 78: "IPv6 nexthop with ifname",
! 79: "Null0 nexthop",
! 80: };
! 81:
! 82: extern struct zebra_t zebrad;
! 83:
! 84: extern struct zebra_privs_t zserv_privs;
! 85:
! 86: extern u_int32_t nl_rcvbufsize;
! 87:
! 88: /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
! 89: names and ifindex values. */
! 90: static void
! 91: set_ifindex(struct interface *ifp, unsigned int ifi_index)
! 92: {
! 93: struct interface *oifp;
! 94:
! 95: if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
! 96: {
! 97: if (ifi_index == IFINDEX_INTERNAL)
! 98: zlog_err("Netlink is setting interface %s ifindex to reserved "
! 99: "internal value %u", ifp->name, ifi_index);
! 100: else
! 101: {
! 102: if (IS_ZEBRA_DEBUG_KERNEL)
! 103: zlog_debug("interface index %d was renamed from %s to %s",
! 104: ifi_index, oifp->name, ifp->name);
! 105: if (if_is_up(oifp))
! 106: zlog_err("interface rename detected on up interface: index %d "
! 107: "was renamed from %s to %s, results are uncertain!",
! 108: ifi_index, oifp->name, ifp->name);
! 109: if_delete_update(oifp);
! 110: }
! 111: }
! 112: ifp->ifindex = ifi_index;
! 113: }
! 114:
! 115: static int
! 116: netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
! 117: {
! 118: u_int32_t oldsize;
! 119: socklen_t newlen = sizeof(newsize);
! 120: socklen_t oldlen = sizeof(oldsize);
! 121: int ret;
! 122:
! 123: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
! 124: if (ret < 0)
! 125: {
! 126: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
! 127: safe_strerror (errno));
! 128: return -1;
! 129: }
! 130:
! 131: ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
! 132: sizeof(nl_rcvbufsize));
! 133: if (ret < 0)
! 134: {
! 135: zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
! 136: safe_strerror (errno));
! 137: return -1;
! 138: }
! 139:
! 140: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
! 141: if (ret < 0)
! 142: {
! 143: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
! 144: safe_strerror (errno));
! 145: return -1;
! 146: }
! 147:
! 148: zlog (NULL, LOG_INFO,
! 149: "Setting netlink socket receive buffer size: %u -> %u",
! 150: oldsize, newsize);
! 151: return 0;
! 152: }
! 153:
! 154: /* Make socket for Linux netlink interface. */
! 155: static int
! 156: netlink_socket (struct nlsock *nl, unsigned long groups)
! 157: {
! 158: int ret;
! 159: struct sockaddr_nl snl;
! 160: int sock;
! 161: int namelen;
! 162: int save_errno;
! 163:
! 164: sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
! 165: if (sock < 0)
! 166: {
! 167: zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
! 168: safe_strerror (errno));
! 169: return -1;
! 170: }
! 171:
! 172: memset (&snl, 0, sizeof snl);
! 173: snl.nl_family = AF_NETLINK;
! 174: snl.nl_groups = groups;
! 175:
! 176: /* Bind the socket to the netlink structure for anything. */
! 177: if (zserv_privs.change (ZPRIVS_RAISE))
! 178: {
! 179: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 180: return -1;
! 181: }
! 182:
! 183: ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
! 184: save_errno = errno;
! 185: if (zserv_privs.change (ZPRIVS_LOWER))
! 186: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 187:
! 188: if (ret < 0)
! 189: {
! 190: zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
! 191: nl->name, snl.nl_groups, safe_strerror (save_errno));
! 192: close (sock);
! 193: return -1;
! 194: }
! 195:
! 196: /* multiple netlink sockets will have different nl_pid */
! 197: namelen = sizeof snl;
! 198: ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
! 199: if (ret < 0 || namelen != sizeof snl)
! 200: {
! 201: zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
! 202: safe_strerror (errno));
! 203: close (sock);
! 204: return -1;
! 205: }
! 206:
! 207: nl->snl = snl;
! 208: nl->sock = sock;
! 209: return ret;
! 210: }
! 211:
! 212: /* Get type specified information from netlink. */
! 213: static int
! 214: netlink_request (int family, int type, struct nlsock *nl)
! 215: {
! 216: int ret;
! 217: struct sockaddr_nl snl;
! 218: int save_errno;
! 219:
! 220: struct
! 221: {
! 222: struct nlmsghdr nlh;
! 223: struct rtgenmsg g;
! 224: } req;
! 225:
! 226:
! 227: /* Check netlink socket. */
! 228: if (nl->sock < 0)
! 229: {
! 230: zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
! 231: return -1;
! 232: }
! 233:
! 234: memset (&snl, 0, sizeof snl);
! 235: snl.nl_family = AF_NETLINK;
! 236:
! 237: memset (&req, 0, sizeof req);
! 238: req.nlh.nlmsg_len = sizeof req;
! 239: req.nlh.nlmsg_type = type;
! 240: req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
! 241: req.nlh.nlmsg_pid = nl->snl.nl_pid;
! 242: req.nlh.nlmsg_seq = ++nl->seq;
! 243: req.g.rtgen_family = family;
! 244:
! 245: /* linux appears to check capabilities on every message
! 246: * have to raise caps for every message sent
! 247: */
! 248: if (zserv_privs.change (ZPRIVS_RAISE))
! 249: {
! 250: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 251: return -1;
! 252: }
! 253:
! 254: ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
! 255: (struct sockaddr *) &snl, sizeof snl);
! 256: save_errno = errno;
! 257:
! 258: if (zserv_privs.change (ZPRIVS_LOWER))
! 259: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 260:
! 261: if (ret < 0)
! 262: {
! 263: zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
! 264: safe_strerror (save_errno));
! 265: return -1;
! 266: }
! 267:
! 268: return 0;
! 269: }
! 270:
! 271: /* Receive message from netlink interface and pass those information
! 272: to the given function. */
! 273: static int
! 274: netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
! 275: struct nlsock *nl)
! 276: {
! 277: int status;
! 278: int ret = 0;
! 279: int error;
! 280:
! 281: while (1)
! 282: {
! 283: char buf[4096];
! 284: struct iovec iov = { buf, sizeof buf };
! 285: struct sockaddr_nl snl;
! 286: struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
! 287: struct nlmsghdr *h;
! 288:
! 289: status = recvmsg (nl->sock, &msg, 0);
! 290: if (status < 0)
! 291: {
! 292: if (errno == EINTR)
! 293: continue;
! 294: if (errno == EWOULDBLOCK || errno == EAGAIN)
! 295: break;
! 296: zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
! 297: nl->name, safe_strerror(errno));
! 298: continue;
! 299: }
! 300:
! 301: if (status == 0)
! 302: {
! 303: zlog (NULL, LOG_ERR, "%s EOF", nl->name);
! 304: return -1;
! 305: }
! 306:
! 307: if (msg.msg_namelen != sizeof snl)
! 308: {
! 309: zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
! 310: nl->name, msg.msg_namelen);
! 311: return -1;
! 312: }
! 313:
! 314: for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
! 315: h = NLMSG_NEXT (h, status))
! 316: {
! 317: /* Finish of reading. */
! 318: if (h->nlmsg_type == NLMSG_DONE)
! 319: return ret;
! 320:
! 321: /* Error handling. */
! 322: if (h->nlmsg_type == NLMSG_ERROR)
! 323: {
! 324: struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
! 325: int errnum = err->error;
! 326: int msg_type = err->msg.nlmsg_type;
! 327:
! 328: /* If the error field is zero, then this is an ACK */
! 329: if (err->error == 0)
! 330: {
! 331: if (IS_ZEBRA_DEBUG_KERNEL)
! 332: {
! 333: zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
! 334: __FUNCTION__, nl->name,
! 335: lookup (nlmsg_str, err->msg.nlmsg_type),
! 336: err->msg.nlmsg_type, err->msg.nlmsg_seq,
! 337: err->msg.nlmsg_pid);
! 338: }
! 339:
! 340: /* return if not a multipart message, otherwise continue */
! 341: if (!(h->nlmsg_flags & NLM_F_MULTI))
! 342: {
! 343: return 0;
! 344: }
! 345: continue;
! 346: }
! 347:
! 348: if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
! 349: {
! 350: zlog (NULL, LOG_ERR, "%s error: message truncated",
! 351: nl->name);
! 352: return -1;
! 353: }
! 354:
! 355: /* Deal with errors that occur because of races in link handling */
! 356: if (nl == &netlink_cmd
! 357: && ((msg_type == RTM_DELROUTE &&
! 358: (-errnum == ENODEV || -errnum == ESRCH))
! 359: || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
! 360: {
! 361: if (IS_ZEBRA_DEBUG_KERNEL)
! 362: zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
! 363: nl->name, safe_strerror (-errnum),
! 364: lookup (nlmsg_str, msg_type),
! 365: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
! 366: return 0;
! 367: }
! 368:
! 369: zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
! 370: nl->name, safe_strerror (-errnum),
! 371: lookup (nlmsg_str, msg_type),
! 372: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
! 373: return -1;
! 374: }
! 375:
! 376: /* OK we got netlink message. */
! 377: if (IS_ZEBRA_DEBUG_KERNEL)
! 378: zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
! 379: nl->name,
! 380: lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
! 381: h->nlmsg_seq, h->nlmsg_pid);
! 382:
! 383: /* skip unsolicited messages originating from command socket */
! 384: if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
! 385: {
! 386: if (IS_ZEBRA_DEBUG_KERNEL)
! 387: zlog_debug ("netlink_parse_info: %s packet comes from %s",
! 388: netlink_cmd.name, nl->name);
! 389: continue;
! 390: }
! 391:
! 392: error = (*filter) (&snl, h);
! 393: if (error < 0)
! 394: {
! 395: zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
! 396: ret = error;
! 397: }
! 398: }
! 399:
! 400: /* After error care. */
! 401: if (msg.msg_flags & MSG_TRUNC)
! 402: {
! 403: zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
! 404: continue;
! 405: }
! 406: if (status)
! 407: {
! 408: zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
! 409: status);
! 410: return -1;
! 411: }
! 412: }
! 413: return ret;
! 414: }
! 415:
! 416: /* Utility function for parse rtattr. */
! 417: static void
! 418: netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
! 419: int len)
! 420: {
! 421: while (RTA_OK (rta, len))
! 422: {
! 423: if (rta->rta_type <= max)
! 424: tb[rta->rta_type] = rta;
! 425: rta = RTA_NEXT (rta, len);
! 426: }
! 427: }
! 428:
! 429: /* Called from interface_lookup_netlink(). This function is only used
! 430: during bootstrap. */
! 431: static int
! 432: netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 433: {
! 434: int len;
! 435: struct ifinfomsg *ifi;
! 436: struct rtattr *tb[IFLA_MAX + 1];
! 437: struct interface *ifp;
! 438: char *name;
! 439: int i;
! 440:
! 441: ifi = NLMSG_DATA (h);
! 442:
! 443: if (h->nlmsg_type != RTM_NEWLINK)
! 444: return 0;
! 445:
! 446: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
! 447: if (len < 0)
! 448: return -1;
! 449:
! 450: /* Looking up interface name. */
! 451: memset (tb, 0, sizeof tb);
! 452: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
! 453:
! 454: #ifdef IFLA_WIRELESS
! 455: /* check for wireless messages to ignore */
! 456: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
! 457: {
! 458: if (IS_ZEBRA_DEBUG_KERNEL)
! 459: zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
! 460: return 0;
! 461: }
! 462: #endif /* IFLA_WIRELESS */
! 463:
! 464: if (tb[IFLA_IFNAME] == NULL)
! 465: return -1;
! 466: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
! 467:
! 468: /* Add interface. */
! 469: ifp = if_get_by_name (name);
! 470: set_ifindex(ifp, ifi->ifi_index);
! 471: ifp->flags = ifi->ifi_flags & 0x0000fffff;
! 472: ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
! 473: ifp->metric = 1;
! 474:
! 475: /* Hardware type and address. */
! 476: ifp->hw_type = ifi->ifi_type;
! 477:
! 478: if (tb[IFLA_ADDRESS])
! 479: {
! 480: int hw_addr_len;
! 481:
! 482: hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
! 483:
! 484: if (hw_addr_len > INTERFACE_HWADDR_MAX)
! 485: zlog_warn ("Hardware address is too large: %d", hw_addr_len);
! 486: else
! 487: {
! 488: ifp->hw_addr_len = hw_addr_len;
! 489: memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
! 490:
! 491: for (i = 0; i < hw_addr_len; i++)
! 492: if (ifp->hw_addr[i] != 0)
! 493: break;
! 494:
! 495: if (i == hw_addr_len)
! 496: ifp->hw_addr_len = 0;
! 497: else
! 498: ifp->hw_addr_len = hw_addr_len;
! 499: }
! 500: }
! 501:
! 502: if_add_update (ifp);
! 503:
! 504: return 0;
! 505: }
! 506:
! 507: /* Lookup interface IPv4/IPv6 address. */
! 508: static int
! 509: netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 510: {
! 511: int len;
! 512: struct ifaddrmsg *ifa;
! 513: struct rtattr *tb[IFA_MAX + 1];
! 514: struct interface *ifp;
! 515: void *addr;
! 516: void *broad;
! 517: u_char flags = 0;
! 518: char *label = NULL;
! 519:
! 520: ifa = NLMSG_DATA (h);
! 521:
! 522: if (ifa->ifa_family != AF_INET
! 523: #ifdef HAVE_IPV6
! 524: && ifa->ifa_family != AF_INET6
! 525: #endif /* HAVE_IPV6 */
! 526: )
! 527: return 0;
! 528:
! 529: if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
! 530: return 0;
! 531:
! 532: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
! 533: if (len < 0)
! 534: return -1;
! 535:
! 536: memset (tb, 0, sizeof tb);
! 537: netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
! 538:
! 539: ifp = if_lookup_by_index (ifa->ifa_index);
! 540: if (ifp == NULL)
! 541: {
! 542: zlog_err ("netlink_interface_addr can't find interface by index %d",
! 543: ifa->ifa_index);
! 544: return -1;
! 545: }
! 546:
! 547: if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
! 548: {
! 549: char buf[BUFSIZ];
! 550: zlog_debug ("netlink_interface_addr %s %s:",
! 551: lookup (nlmsg_str, h->nlmsg_type), ifp->name);
! 552: if (tb[IFA_LOCAL])
! 553: zlog_debug (" IFA_LOCAL %s/%d",
! 554: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
! 555: buf, BUFSIZ), ifa->ifa_prefixlen);
! 556: if (tb[IFA_ADDRESS])
! 557: zlog_debug (" IFA_ADDRESS %s/%d",
! 558: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
! 559: buf, BUFSIZ), ifa->ifa_prefixlen);
! 560: if (tb[IFA_BROADCAST])
! 561: zlog_debug (" IFA_BROADCAST %s/%d",
! 562: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
! 563: buf, BUFSIZ), ifa->ifa_prefixlen);
! 564: if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
! 565: zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
! 566:
! 567: if (tb[IFA_CACHEINFO])
! 568: {
! 569: struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
! 570: zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
! 571: ci->ifa_prefered, ci->ifa_valid);
! 572: }
! 573: }
! 574:
! 575: /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
! 576: if (tb[IFA_LOCAL] == NULL)
! 577: tb[IFA_LOCAL] = tb[IFA_ADDRESS];
! 578: if (tb[IFA_ADDRESS] == NULL)
! 579: tb[IFA_ADDRESS] = tb[IFA_LOCAL];
! 580:
! 581: /* local interface address */
! 582: addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
! 583:
! 584: /* is there a peer address? */
! 585: if (tb[IFA_ADDRESS] &&
! 586: memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
! 587: {
! 588: broad = RTA_DATA(tb[IFA_ADDRESS]);
! 589: SET_FLAG (flags, ZEBRA_IFA_PEER);
! 590: }
! 591: else
! 592: /* seeking a broadcast address */
! 593: broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
! 594:
! 595: /* addr is primary key, SOL if we don't have one */
! 596: if (addr == NULL)
! 597: {
! 598: zlog_debug ("%s: NULL address", __func__);
! 599: return -1;
! 600: }
! 601:
! 602: /* Flags. */
! 603: if (ifa->ifa_flags & IFA_F_SECONDARY)
! 604: SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
! 605:
! 606: /* Label */
! 607: if (tb[IFA_LABEL])
! 608: label = (char *) RTA_DATA (tb[IFA_LABEL]);
! 609:
! 610: if (ifp && label && strcmp (ifp->name, label) == 0)
! 611: label = NULL;
! 612:
! 613: /* Register interface address to the interface. */
! 614: if (ifa->ifa_family == AF_INET)
! 615: {
! 616: if (h->nlmsg_type == RTM_NEWADDR)
! 617: connected_add_ipv4 (ifp, flags,
! 618: (struct in_addr *) addr, ifa->ifa_prefixlen,
! 619: (struct in_addr *) broad, label);
! 620: else
! 621: connected_delete_ipv4 (ifp, flags,
! 622: (struct in_addr *) addr, ifa->ifa_prefixlen,
! 623: (struct in_addr *) broad);
! 624: }
! 625: #ifdef HAVE_IPV6
! 626: if (ifa->ifa_family == AF_INET6)
! 627: {
! 628: if (h->nlmsg_type == RTM_NEWADDR)
! 629: connected_add_ipv6 (ifp, flags,
! 630: (struct in6_addr *) addr, ifa->ifa_prefixlen,
! 631: (struct in6_addr *) broad, label);
! 632: else
! 633: connected_delete_ipv6 (ifp,
! 634: (struct in6_addr *) addr, ifa->ifa_prefixlen,
! 635: (struct in6_addr *) broad);
! 636: }
! 637: #endif /* HAVE_IPV6 */
! 638:
! 639: return 0;
! 640: }
! 641:
! 642: /* Looking up routing table by netlink interface. */
! 643: static int
! 644: netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 645: {
! 646: int len;
! 647: struct rtmsg *rtm;
! 648: struct rtattr *tb[RTA_MAX + 1];
! 649: u_char flags = 0;
! 650:
! 651: char anyaddr[16] = { 0 };
! 652:
! 653: int index;
! 654: int table;
! 655: int metric;
! 656:
! 657: void *dest;
! 658: void *gate;
! 659: void *src;
! 660:
! 661: rtm = NLMSG_DATA (h);
! 662:
! 663: if (h->nlmsg_type != RTM_NEWROUTE)
! 664: return 0;
! 665: if (rtm->rtm_type != RTN_UNICAST)
! 666: return 0;
! 667:
! 668: table = rtm->rtm_table;
! 669: #if 0 /* we weed them out later in rib_weed_tables () */
! 670: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
! 671: return 0;
! 672: #endif
! 673:
! 674: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
! 675: if (len < 0)
! 676: return -1;
! 677:
! 678: memset (tb, 0, sizeof tb);
! 679: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
! 680:
! 681: if (rtm->rtm_flags & RTM_F_CLONED)
! 682: return 0;
! 683: if (rtm->rtm_protocol == RTPROT_REDIRECT)
! 684: return 0;
! 685: if (rtm->rtm_protocol == RTPROT_KERNEL)
! 686: return 0;
! 687:
! 688: if (rtm->rtm_src_len != 0)
! 689: return 0;
! 690:
! 691: /* Route which inserted by Zebra. */
! 692: if (rtm->rtm_protocol == RTPROT_ZEBRA)
! 693: flags |= ZEBRA_FLAG_SELFROUTE;
! 694:
! 695: index = 0;
! 696: metric = 0;
! 697: dest = NULL;
! 698: gate = NULL;
! 699: src = NULL;
! 700:
! 701: if (tb[RTA_OIF])
! 702: index = *(int *) RTA_DATA (tb[RTA_OIF]);
! 703:
! 704: if (tb[RTA_DST])
! 705: dest = RTA_DATA (tb[RTA_DST]);
! 706: else
! 707: dest = anyaddr;
! 708:
! 709: if (tb[RTA_PREFSRC])
! 710: src = RTA_DATA (tb[RTA_PREFSRC]);
! 711:
! 712: /* Multipath treatment is needed. */
! 713: if (tb[RTA_GATEWAY])
! 714: gate = RTA_DATA (tb[RTA_GATEWAY]);
! 715:
! 716: if (tb[RTA_PRIORITY])
! 717: metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
! 718:
! 719: if (rtm->rtm_family == AF_INET)
! 720: {
! 721: struct prefix_ipv4 p;
! 722: p.family = AF_INET;
! 723: memcpy (&p.prefix, dest, 4);
! 724: p.prefixlen = rtm->rtm_dst_len;
! 725:
! 726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
! 727: }
! 728: #ifdef HAVE_IPV6
! 729: if (rtm->rtm_family == AF_INET6)
! 730: {
! 731: struct prefix_ipv6 p;
! 732: p.family = AF_INET6;
! 733: memcpy (&p.prefix, dest, 16);
! 734: p.prefixlen = rtm->rtm_dst_len;
! 735:
! 736: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
! 737: metric, 0);
! 738: }
! 739: #endif /* HAVE_IPV6 */
! 740:
! 741: return 0;
! 742: }
! 743:
! 744: static const struct message rtproto_str[] = {
! 745: {RTPROT_REDIRECT, "redirect"},
! 746: {RTPROT_KERNEL, "kernel"},
! 747: {RTPROT_BOOT, "boot"},
! 748: {RTPROT_STATIC, "static"},
! 749: {RTPROT_GATED, "GateD"},
! 750: {RTPROT_RA, "router advertisement"},
! 751: {RTPROT_MRT, "MRT"},
! 752: {RTPROT_ZEBRA, "Zebra"},
! 753: #ifdef RTPROT_BIRD
! 754: {RTPROT_BIRD, "BIRD"},
! 755: #endif /* RTPROT_BIRD */
! 756: {0, NULL}
! 757: };
! 758:
! 759: /* Routing information change from the kernel. */
! 760: static int
! 761: netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 762: {
! 763: int len;
! 764: struct rtmsg *rtm;
! 765: struct rtattr *tb[RTA_MAX + 1];
! 766:
! 767: char anyaddr[16] = { 0 };
! 768:
! 769: int index;
! 770: int table;
! 771: int metric;
! 772:
! 773: void *dest;
! 774: void *gate;
! 775: void *src;
! 776:
! 777: rtm = NLMSG_DATA (h);
! 778:
! 779: if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
! 780: {
! 781: /* If this is not route add/delete message print warning. */
! 782: zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
! 783: return 0;
! 784: }
! 785:
! 786: /* Connected route. */
! 787: if (IS_ZEBRA_DEBUG_KERNEL)
! 788: zlog_debug ("%s %s %s proto %s",
! 789: h->nlmsg_type ==
! 790: RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
! 791: rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
! 792: rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
! 793: lookup (rtproto_str, rtm->rtm_protocol));
! 794:
! 795: if (rtm->rtm_type != RTN_UNICAST)
! 796: {
! 797: return 0;
! 798: }
! 799:
! 800: table = rtm->rtm_table;
! 801: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
! 802: {
! 803: return 0;
! 804: }
! 805:
! 806: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
! 807: if (len < 0)
! 808: return -1;
! 809:
! 810: memset (tb, 0, sizeof tb);
! 811: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
! 812:
! 813: if (rtm->rtm_flags & RTM_F_CLONED)
! 814: return 0;
! 815: if (rtm->rtm_protocol == RTPROT_REDIRECT)
! 816: return 0;
! 817: if (rtm->rtm_protocol == RTPROT_KERNEL)
! 818: return 0;
! 819:
! 820: if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
! 821: return 0;
! 822:
! 823: if (rtm->rtm_src_len != 0)
! 824: {
! 825: zlog_warn ("netlink_route_change(): no src len");
! 826: return 0;
! 827: }
! 828:
! 829: index = 0;
! 830: metric = 0;
! 831: dest = NULL;
! 832: gate = NULL;
! 833: src = NULL;
! 834:
! 835: if (tb[RTA_OIF])
! 836: index = *(int *) RTA_DATA (tb[RTA_OIF]);
! 837:
! 838: if (tb[RTA_DST])
! 839: dest = RTA_DATA (tb[RTA_DST]);
! 840: else
! 841: dest = anyaddr;
! 842:
! 843: if (tb[RTA_GATEWAY])
! 844: gate = RTA_DATA (tb[RTA_GATEWAY]);
! 845:
! 846: if (tb[RTA_PREFSRC])
! 847: src = RTA_DATA (tb[RTA_PREFSRC]);
! 848:
! 849: if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
! 850: metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
! 851:
! 852: if (rtm->rtm_family == AF_INET)
! 853: {
! 854: struct prefix_ipv4 p;
! 855: p.family = AF_INET;
! 856: memcpy (&p.prefix, dest, 4);
! 857: p.prefixlen = rtm->rtm_dst_len;
! 858:
! 859: if (IS_ZEBRA_DEBUG_KERNEL)
! 860: {
! 861: if (h->nlmsg_type == RTM_NEWROUTE)
! 862: zlog_debug ("RTM_NEWROUTE %s/%d",
! 863: inet_ntoa (p.prefix), p.prefixlen);
! 864: else
! 865: zlog_debug ("RTM_DELROUTE %s/%d",
! 866: inet_ntoa (p.prefix), p.prefixlen);
! 867: }
! 868:
! 869: if (h->nlmsg_type == RTM_NEWROUTE)
! 870: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0);
! 871: else
! 872: rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
! 873: }
! 874:
! 875: #ifdef HAVE_IPV6
! 876: if (rtm->rtm_family == AF_INET6)
! 877: {
! 878: struct prefix_ipv6 p;
! 879: char buf[BUFSIZ];
! 880:
! 881: p.family = AF_INET6;
! 882: memcpy (&p.prefix, dest, 16);
! 883: p.prefixlen = rtm->rtm_dst_len;
! 884:
! 885: if (IS_ZEBRA_DEBUG_KERNEL)
! 886: {
! 887: if (h->nlmsg_type == RTM_NEWROUTE)
! 888: zlog_debug ("RTM_NEWROUTE %s/%d",
! 889: inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
! 890: p.prefixlen);
! 891: else
! 892: zlog_debug ("RTM_DELROUTE %s/%d",
! 893: inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
! 894: p.prefixlen);
! 895: }
! 896:
! 897: if (h->nlmsg_type == RTM_NEWROUTE)
! 898: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0);
! 899: else
! 900: rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
! 901: }
! 902: #endif /* HAVE_IPV6 */
! 903:
! 904: return 0;
! 905: }
! 906:
! 907: static int
! 908: netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 909: {
! 910: int len;
! 911: struct ifinfomsg *ifi;
! 912: struct rtattr *tb[IFLA_MAX + 1];
! 913: struct interface *ifp;
! 914: char *name;
! 915:
! 916: ifi = NLMSG_DATA (h);
! 917:
! 918: if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
! 919: {
! 920: /* If this is not link add/delete message so print warning. */
! 921: zlog_warn ("netlink_link_change: wrong kernel message %d\n",
! 922: h->nlmsg_type);
! 923: return 0;
! 924: }
! 925:
! 926: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
! 927: if (len < 0)
! 928: return -1;
! 929:
! 930: /* Looking up interface name. */
! 931: memset (tb, 0, sizeof tb);
! 932: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
! 933:
! 934: #ifdef IFLA_WIRELESS
! 935: /* check for wireless messages to ignore */
! 936: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
! 937: {
! 938: if (IS_ZEBRA_DEBUG_KERNEL)
! 939: zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
! 940: return 0;
! 941: }
! 942: #endif /* IFLA_WIRELESS */
! 943:
! 944: if (tb[IFLA_IFNAME] == NULL)
! 945: return -1;
! 946: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
! 947:
! 948: /* Add interface. */
! 949: if (h->nlmsg_type == RTM_NEWLINK)
! 950: {
! 951: ifp = if_lookup_by_name (name);
! 952:
! 953: if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
! 954: {
! 955: if (ifp == NULL)
! 956: ifp = if_get_by_name (name);
! 957:
! 958: set_ifindex(ifp, ifi->ifi_index);
! 959: ifp->flags = ifi->ifi_flags & 0x0000fffff;
! 960: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
! 961: ifp->metric = 1;
! 962:
! 963: /* If new link is added. */
! 964: if_add_update (ifp);
! 965: }
! 966: else
! 967: {
! 968: /* Interface status change. */
! 969: set_ifindex(ifp, ifi->ifi_index);
! 970: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
! 971: ifp->metric = 1;
! 972:
! 973: if (if_is_operative (ifp))
! 974: {
! 975: ifp->flags = ifi->ifi_flags & 0x0000fffff;
! 976: if (!if_is_operative (ifp))
! 977: if_down (ifp);
! 978: else
! 979: /* Must notify client daemons of new interface status. */
! 980: zebra_interface_up_update (ifp);
! 981: }
! 982: else
! 983: {
! 984: ifp->flags = ifi->ifi_flags & 0x0000fffff;
! 985: if (if_is_operative (ifp))
! 986: if_up (ifp);
! 987: }
! 988: }
! 989: }
! 990: else
! 991: {
! 992: /* RTM_DELLINK. */
! 993: ifp = if_lookup_by_name (name);
! 994:
! 995: if (ifp == NULL)
! 996: {
! 997: zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
! 998: name);
! 999: return 0;
! 1000: }
! 1001:
! 1002: if_delete_update (ifp);
! 1003: }
! 1004:
! 1005: return 0;
! 1006: }
! 1007:
! 1008: static int
! 1009: netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 1010: {
! 1011: /* JF: Ignore messages that aren't from the kernel */
! 1012: if ( snl->nl_pid != 0 )
! 1013: {
! 1014: zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
! 1015: return 0;
! 1016: }
! 1017:
! 1018: switch (h->nlmsg_type)
! 1019: {
! 1020: case RTM_NEWROUTE:
! 1021: return netlink_route_change (snl, h);
! 1022: break;
! 1023: case RTM_DELROUTE:
! 1024: return netlink_route_change (snl, h);
! 1025: break;
! 1026: case RTM_NEWLINK:
! 1027: return netlink_link_change (snl, h);
! 1028: break;
! 1029: case RTM_DELLINK:
! 1030: return netlink_link_change (snl, h);
! 1031: break;
! 1032: case RTM_NEWADDR:
! 1033: return netlink_interface_addr (snl, h);
! 1034: break;
! 1035: case RTM_DELADDR:
! 1036: return netlink_interface_addr (snl, h);
! 1037: break;
! 1038: default:
! 1039: zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
! 1040: break;
! 1041: }
! 1042: return 0;
! 1043: }
! 1044:
! 1045: /* Interface lookup by netlink socket. */
! 1046: int
! 1047: interface_lookup_netlink (void)
! 1048: {
! 1049: int ret;
! 1050:
! 1051: /* Get interface information. */
! 1052: ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
! 1053: if (ret < 0)
! 1054: return ret;
! 1055: ret = netlink_parse_info (netlink_interface, &netlink_cmd);
! 1056: if (ret < 0)
! 1057: return ret;
! 1058:
! 1059: /* Get IPv4 address of the interfaces. */
! 1060: ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
! 1061: if (ret < 0)
! 1062: return ret;
! 1063: ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
! 1064: if (ret < 0)
! 1065: return ret;
! 1066:
! 1067: #ifdef HAVE_IPV6
! 1068: /* Get IPv6 address of the interfaces. */
! 1069: ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
! 1070: if (ret < 0)
! 1071: return ret;
! 1072: ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
! 1073: if (ret < 0)
! 1074: return ret;
! 1075: #endif /* HAVE_IPV6 */
! 1076:
! 1077: return 0;
! 1078: }
! 1079:
! 1080: /* Routing table read function using netlink interface. Only called
! 1081: bootstrap time. */
! 1082: int
! 1083: netlink_route_read (void)
! 1084: {
! 1085: int ret;
! 1086:
! 1087: /* Get IPv4 routing table. */
! 1088: ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
! 1089: if (ret < 0)
! 1090: return ret;
! 1091: ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
! 1092: if (ret < 0)
! 1093: return ret;
! 1094:
! 1095: #ifdef HAVE_IPV6
! 1096: /* Get IPv6 routing table. */
! 1097: ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
! 1098: if (ret < 0)
! 1099: return ret;
! 1100: ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
! 1101: if (ret < 0)
! 1102: return ret;
! 1103: #endif /* HAVE_IPV6 */
! 1104:
! 1105: return 0;
! 1106: }
! 1107:
! 1108: /* Utility function comes from iproute2.
! 1109: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
! 1110: static int
! 1111: addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
! 1112: {
! 1113: int len;
! 1114: struct rtattr *rta;
! 1115:
! 1116: len = RTA_LENGTH (alen);
! 1117:
! 1118: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
! 1119: return -1;
! 1120:
! 1121: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
! 1122: rta->rta_type = type;
! 1123: rta->rta_len = len;
! 1124: memcpy (RTA_DATA (rta), data, alen);
! 1125: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
! 1126:
! 1127: return 0;
! 1128: }
! 1129:
! 1130: static int
! 1131: rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
! 1132: {
! 1133: int len;
! 1134: struct rtattr *subrta;
! 1135:
! 1136: len = RTA_LENGTH (alen);
! 1137:
! 1138: if (RTA_ALIGN (rta->rta_len) + len > maxlen)
! 1139: return -1;
! 1140:
! 1141: subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
! 1142: subrta->rta_type = type;
! 1143: subrta->rta_len = len;
! 1144: memcpy (RTA_DATA (subrta), data, alen);
! 1145: rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
! 1146:
! 1147: return 0;
! 1148: }
! 1149:
! 1150: /* Utility function comes from iproute2.
! 1151: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
! 1152: static int
! 1153: addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
! 1154: {
! 1155: int len;
! 1156: struct rtattr *rta;
! 1157:
! 1158: len = RTA_LENGTH (4);
! 1159:
! 1160: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
! 1161: return -1;
! 1162:
! 1163: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
! 1164: rta->rta_type = type;
! 1165: rta->rta_len = len;
! 1166: memcpy (RTA_DATA (rta), &data, 4);
! 1167: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
! 1168:
! 1169: return 0;
! 1170: }
! 1171:
! 1172: static int
! 1173: netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
! 1174: {
! 1175: zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
! 1176: return 0;
! 1177: }
! 1178:
! 1179: /* sendmsg() to netlink socket then recvmsg(). */
! 1180: static int
! 1181: netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
! 1182: {
! 1183: int status;
! 1184: struct sockaddr_nl snl;
! 1185: struct iovec iov = { (void *) n, n->nlmsg_len };
! 1186: struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
! 1187: int save_errno;
! 1188:
! 1189: memset (&snl, 0, sizeof snl);
! 1190: snl.nl_family = AF_NETLINK;
! 1191:
! 1192: n->nlmsg_seq = ++nl->seq;
! 1193:
! 1194: /* Request an acknowledgement by setting NLM_F_ACK */
! 1195: n->nlmsg_flags |= NLM_F_ACK;
! 1196:
! 1197: if (IS_ZEBRA_DEBUG_KERNEL)
! 1198: zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
! 1199: lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
! 1200: n->nlmsg_seq);
! 1201:
! 1202: /* Send message to netlink interface. */
! 1203: if (zserv_privs.change (ZPRIVS_RAISE))
! 1204: zlog (NULL, LOG_ERR, "Can't raise privileges");
! 1205: status = sendmsg (nl->sock, &msg, 0);
! 1206: save_errno = errno;
! 1207: if (zserv_privs.change (ZPRIVS_LOWER))
! 1208: zlog (NULL, LOG_ERR, "Can't lower privileges");
! 1209:
! 1210: if (status < 0)
! 1211: {
! 1212: zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
! 1213: safe_strerror (save_errno));
! 1214: return -1;
! 1215: }
! 1216:
! 1217:
! 1218: /*
! 1219: * Get reply from netlink socket.
! 1220: * The reply should either be an acknowlegement or an error.
! 1221: */
! 1222: return netlink_parse_info (netlink_talk_filter, nl);
! 1223: }
! 1224:
! 1225: /* Routing table change via netlink interface. */
! 1226: static int
! 1227: netlink_route (int cmd, int family, void *dest, int length, void *gate,
! 1228: int index, int zebra_flags, int table)
! 1229: {
! 1230: int ret;
! 1231: int bytelen;
! 1232: struct sockaddr_nl snl;
! 1233: int discard;
! 1234:
! 1235: struct
! 1236: {
! 1237: struct nlmsghdr n;
! 1238: struct rtmsg r;
! 1239: char buf[1024];
! 1240: } req;
! 1241:
! 1242: memset (&req, 0, sizeof req);
! 1243:
! 1244: bytelen = (family == AF_INET ? 4 : 16);
! 1245:
! 1246: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
! 1247: req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
! 1248: req.n.nlmsg_type = cmd;
! 1249: req.r.rtm_family = family;
! 1250: req.r.rtm_table = table;
! 1251: req.r.rtm_dst_len = length;
! 1252: req.r.rtm_protocol = RTPROT_ZEBRA;
! 1253: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
! 1254:
! 1255: if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
! 1256: || (zebra_flags & ZEBRA_FLAG_REJECT))
! 1257: discard = 1;
! 1258: else
! 1259: discard = 0;
! 1260:
! 1261: if (cmd == RTM_NEWROUTE)
! 1262: {
! 1263: if (discard)
! 1264: {
! 1265: if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
! 1266: req.r.rtm_type = RTN_BLACKHOLE;
! 1267: else if (zebra_flags & ZEBRA_FLAG_REJECT)
! 1268: req.r.rtm_type = RTN_UNREACHABLE;
! 1269: else
! 1270: assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
! 1271: }
! 1272: else
! 1273: req.r.rtm_type = RTN_UNICAST;
! 1274: }
! 1275:
! 1276: if (dest)
! 1277: addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
! 1278:
! 1279: if (!discard)
! 1280: {
! 1281: if (gate)
! 1282: addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
! 1283: if (index > 0)
! 1284: addattr32 (&req.n, sizeof req, RTA_OIF, index);
! 1285: }
! 1286:
! 1287: /* Destination netlink address. */
! 1288: memset (&snl, 0, sizeof snl);
! 1289: snl.nl_family = AF_NETLINK;
! 1290:
! 1291: /* Talk to netlink socket. */
! 1292: ret = netlink_talk (&req.n, &netlink_cmd);
! 1293: if (ret < 0)
! 1294: return -1;
! 1295:
! 1296: return 0;
! 1297: }
! 1298:
! 1299: /* Routing table change via netlink interface. */
! 1300: static int
! 1301: netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
! 1302: int family)
! 1303: {
! 1304: int bytelen;
! 1305: struct sockaddr_nl snl;
! 1306: struct nexthop *nexthop = NULL;
! 1307: int nexthop_num = 0;
! 1308: int discard;
! 1309:
! 1310: struct
! 1311: {
! 1312: struct nlmsghdr n;
! 1313: struct rtmsg r;
! 1314: char buf[1024];
! 1315: } req;
! 1316:
! 1317: memset (&req, 0, sizeof req);
! 1318:
! 1319: bytelen = (family == AF_INET ? 4 : 16);
! 1320:
! 1321: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
! 1322: req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
! 1323: req.n.nlmsg_type = cmd;
! 1324: req.r.rtm_family = family;
! 1325: req.r.rtm_table = rib->table;
! 1326: req.r.rtm_dst_len = p->prefixlen;
! 1327: req.r.rtm_protocol = RTPROT_ZEBRA;
! 1328: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
! 1329:
! 1330: if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
! 1331: discard = 1;
! 1332: else
! 1333: discard = 0;
! 1334:
! 1335: if (cmd == RTM_NEWROUTE)
! 1336: {
! 1337: if (discard)
! 1338: {
! 1339: if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
! 1340: req.r.rtm_type = RTN_BLACKHOLE;
! 1341: else if (rib->flags & ZEBRA_FLAG_REJECT)
! 1342: req.r.rtm_type = RTN_UNREACHABLE;
! 1343: else
! 1344: assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
! 1345: }
! 1346: else
! 1347: req.r.rtm_type = RTN_UNICAST;
! 1348: }
! 1349:
! 1350: addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
! 1351:
! 1352: /* Metric. */
! 1353: addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
! 1354:
! 1355: if (discard)
! 1356: {
! 1357: if (cmd == RTM_NEWROUTE)
! 1358: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 1359: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 1360: goto skip;
! 1361: }
! 1362:
! 1363: /* Multipath case. */
! 1364: if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
! 1365: {
! 1366: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 1367: {
! 1368:
! 1369: if ((cmd == RTM_NEWROUTE
! 1370: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 1371: || (cmd == RTM_DELROUTE
! 1372: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
! 1373: {
! 1374:
! 1375: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1376: {
! 1377: if (IS_ZEBRA_DEBUG_KERNEL)
! 1378: {
! 1379: zlog_debug
! 1380: ("netlink_route_multipath() (recursive, 1 hop): "
! 1381: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
! 1382: #ifdef HAVE_IPV6
! 1383: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
! 1384: inet6_ntoa (p->u.prefix6),
! 1385: #else
! 1386: inet_ntoa (p->u.prefix4),
! 1387: #endif /* HAVE_IPV6 */
! 1388:
! 1389: p->prefixlen, nexthop_types_desc[nexthop->rtype]);
! 1390: }
! 1391:
! 1392: if (nexthop->rtype == NEXTHOP_TYPE_IPV4
! 1393: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1394: {
! 1395: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
! 1396: &nexthop->rgate.ipv4, bytelen);
! 1397: if (nexthop->src.ipv4.s_addr)
! 1398: addattr_l(&req.n, sizeof req, RTA_PREFSRC,
! 1399: &nexthop->src.ipv4, bytelen);
! 1400: if (IS_ZEBRA_DEBUG_KERNEL)
! 1401: zlog_debug("netlink_route_multipath() (recursive, "
! 1402: "1 hop): nexthop via %s if %u",
! 1403: inet_ntoa (nexthop->rgate.ipv4),
! 1404: nexthop->rifindex);
! 1405: }
! 1406: #ifdef HAVE_IPV6
! 1407: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
! 1408: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
! 1409: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
! 1410: {
! 1411: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
! 1412: &nexthop->rgate.ipv6, bytelen);
! 1413:
! 1414: if (IS_ZEBRA_DEBUG_KERNEL)
! 1415: zlog_debug("netlink_route_multipath() (recursive, "
! 1416: "1 hop): nexthop via %s if %u",
! 1417: inet6_ntoa (nexthop->rgate.ipv6),
! 1418: nexthop->rifindex);
! 1419: }
! 1420: #endif /* HAVE_IPV6 */
! 1421: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 1422: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
! 1423: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
! 1424: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
! 1425: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
! 1426: {
! 1427: addattr32 (&req.n, sizeof req, RTA_OIF,
! 1428: nexthop->rifindex);
! 1429: if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
! 1430: || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
! 1431: && nexthop->src.ipv4.s_addr)
! 1432: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
! 1433: &nexthop->src.ipv4, bytelen);
! 1434:
! 1435: if (IS_ZEBRA_DEBUG_KERNEL)
! 1436: zlog_debug("netlink_route_multipath() (recursive, "
! 1437: "1 hop): nexthop via if %u",
! 1438: nexthop->rifindex);
! 1439: }
! 1440: }
! 1441: else
! 1442: {
! 1443: if (IS_ZEBRA_DEBUG_KERNEL)
! 1444: {
! 1445: zlog_debug
! 1446: ("netlink_route_multipath() (single hop): "
! 1447: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
! 1448: #ifdef HAVE_IPV6
! 1449: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
! 1450: inet6_ntoa (p->u.prefix6),
! 1451: #else
! 1452: inet_ntoa (p->u.prefix4),
! 1453: #endif /* HAVE_IPV6 */
! 1454: p->prefixlen, nexthop_types_desc[nexthop->type]);
! 1455: }
! 1456:
! 1457: if (nexthop->type == NEXTHOP_TYPE_IPV4
! 1458: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1459: {
! 1460: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
! 1461: &nexthop->gate.ipv4, bytelen);
! 1462: if (nexthop->src.ipv4.s_addr)
! 1463: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
! 1464: &nexthop->src.ipv4, bytelen);
! 1465:
! 1466: if (IS_ZEBRA_DEBUG_KERNEL)
! 1467: zlog_debug("netlink_route_multipath() (single hop): "
! 1468: "nexthop via %s if %u",
! 1469: inet_ntoa (nexthop->gate.ipv4),
! 1470: nexthop->ifindex);
! 1471: }
! 1472: #ifdef HAVE_IPV6
! 1473: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 1474: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1475: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1476: {
! 1477: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
! 1478: &nexthop->gate.ipv6, bytelen);
! 1479:
! 1480: if (IS_ZEBRA_DEBUG_KERNEL)
! 1481: zlog_debug("netlink_route_multipath() (single hop): "
! 1482: "nexthop via %s if %u",
! 1483: inet6_ntoa (nexthop->gate.ipv6),
! 1484: nexthop->ifindex);
! 1485: }
! 1486: #endif /* HAVE_IPV6 */
! 1487: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 1488: || nexthop->type == NEXTHOP_TYPE_IFNAME
! 1489: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1490: {
! 1491: addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
! 1492:
! 1493: if (nexthop->src.ipv4.s_addr)
! 1494: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
! 1495: &nexthop->src.ipv4, bytelen);
! 1496:
! 1497: if (IS_ZEBRA_DEBUG_KERNEL)
! 1498: zlog_debug("netlink_route_multipath() (single hop): "
! 1499: "nexthop via if %u", nexthop->ifindex);
! 1500: }
! 1501: else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
! 1502: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
! 1503: {
! 1504: addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
! 1505:
! 1506: if (IS_ZEBRA_DEBUG_KERNEL)
! 1507: zlog_debug("netlink_route_multipath() (single hop): "
! 1508: "nexthop via if %u", nexthop->ifindex);
! 1509: }
! 1510: }
! 1511:
! 1512: if (cmd == RTM_NEWROUTE)
! 1513: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 1514:
! 1515: nexthop_num++;
! 1516: break;
! 1517: }
! 1518: }
! 1519: }
! 1520: else
! 1521: {
! 1522: char buf[1024];
! 1523: struct rtattr *rta = (void *) buf;
! 1524: struct rtnexthop *rtnh;
! 1525: union g_addr *src = NULL;
! 1526:
! 1527: rta->rta_type = RTA_MULTIPATH;
! 1528: rta->rta_len = RTA_LENGTH (0);
! 1529: rtnh = RTA_DATA (rta);
! 1530:
! 1531: nexthop_num = 0;
! 1532: for (nexthop = rib->nexthop;
! 1533: nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
! 1534: nexthop = nexthop->next)
! 1535: {
! 1536: if ((cmd == RTM_NEWROUTE
! 1537: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 1538: || (cmd == RTM_DELROUTE
! 1539: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
! 1540: {
! 1541: nexthop_num++;
! 1542:
! 1543: rtnh->rtnh_len = sizeof (*rtnh);
! 1544: rtnh->rtnh_flags = 0;
! 1545: rtnh->rtnh_hops = 0;
! 1546: rta->rta_len += rtnh->rtnh_len;
! 1547:
! 1548: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 1549: {
! 1550: if (IS_ZEBRA_DEBUG_KERNEL)
! 1551: {
! 1552: zlog_debug ("netlink_route_multipath() "
! 1553: "(recursive, multihop): %s %s/%d type %s",
! 1554: lookup (nlmsg_str, cmd),
! 1555: #ifdef HAVE_IPV6
! 1556: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
! 1557: inet6_ntoa (p->u.prefix6),
! 1558: #else
! 1559: inet_ntoa (p->u.prefix4),
! 1560: #endif /* HAVE_IPV6 */
! 1561: p->prefixlen, nexthop_types_desc[nexthop->rtype]);
! 1562: }
! 1563: if (nexthop->rtype == NEXTHOP_TYPE_IPV4
! 1564: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1565: {
! 1566: rta_addattr_l (rta, 4096, RTA_GATEWAY,
! 1567: &nexthop->rgate.ipv4, bytelen);
! 1568: rtnh->rtnh_len += sizeof (struct rtattr) + 4;
! 1569:
! 1570: if (nexthop->src.ipv4.s_addr)
! 1571: src = &nexthop->src;
! 1572:
! 1573: if (IS_ZEBRA_DEBUG_KERNEL)
! 1574: zlog_debug("netlink_route_multipath() (recursive, "
! 1575: "multihop): nexthop via %s if %u",
! 1576: inet_ntoa (nexthop->rgate.ipv4),
! 1577: nexthop->rifindex);
! 1578: }
! 1579: #ifdef HAVE_IPV6
! 1580: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
! 1581: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
! 1582: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1583: {
! 1584: rta_addattr_l (rta, 4096, RTA_GATEWAY,
! 1585: &nexthop->rgate.ipv6, bytelen);
! 1586:
! 1587: if (IS_ZEBRA_DEBUG_KERNEL)
! 1588: zlog_debug("netlink_route_multipath() (recursive, "
! 1589: "multihop): nexthop via %s if %u",
! 1590: inet6_ntoa (nexthop->rgate.ipv6),
! 1591: nexthop->rifindex);
! 1592: }
! 1593: #endif /* HAVE_IPV6 */
! 1594: /* ifindex */
! 1595: if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
! 1596: || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 1597: || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
! 1598: {
! 1599: rtnh->rtnh_ifindex = nexthop->rifindex;
! 1600: if (nexthop->src.ipv4.s_addr)
! 1601: src = &nexthop->src;
! 1602:
! 1603: if (IS_ZEBRA_DEBUG_KERNEL)
! 1604: zlog_debug("netlink_route_multipath() (recursive, "
! 1605: "multihop): nexthop via if %u",
! 1606: nexthop->rifindex);
! 1607: }
! 1608: else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
! 1609: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
! 1610: {
! 1611: rtnh->rtnh_ifindex = nexthop->rifindex;
! 1612:
! 1613: if (IS_ZEBRA_DEBUG_KERNEL)
! 1614: zlog_debug("netlink_route_multipath() (recursive, "
! 1615: "multihop): nexthop via if %u",
! 1616: nexthop->rifindex);
! 1617: }
! 1618: else
! 1619: {
! 1620: rtnh->rtnh_ifindex = 0;
! 1621: }
! 1622: }
! 1623: else
! 1624: {
! 1625: if (IS_ZEBRA_DEBUG_KERNEL)
! 1626: {
! 1627: zlog_debug ("netlink_route_multipath() (multihop): "
! 1628: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
! 1629: #ifdef HAVE_IPV6
! 1630: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
! 1631: inet6_ntoa (p->u.prefix6),
! 1632: #else
! 1633: inet_ntoa (p->u.prefix4),
! 1634: #endif /* HAVE_IPV6 */
! 1635: p->prefixlen, nexthop_types_desc[nexthop->type]);
! 1636: }
! 1637: if (nexthop->type == NEXTHOP_TYPE_IPV4
! 1638: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 1639: {
! 1640: rta_addattr_l (rta, 4096, RTA_GATEWAY,
! 1641: &nexthop->gate.ipv4, bytelen);
! 1642: rtnh->rtnh_len += sizeof (struct rtattr) + 4;
! 1643:
! 1644: if (nexthop->src.ipv4.s_addr)
! 1645: src = &nexthop->src;
! 1646:
! 1647: if (IS_ZEBRA_DEBUG_KERNEL)
! 1648: zlog_debug("netlink_route_multipath() (multihop): "
! 1649: "nexthop via %s if %u",
! 1650: inet_ntoa (nexthop->gate.ipv4),
! 1651: nexthop->ifindex);
! 1652: }
! 1653: #ifdef HAVE_IPV6
! 1654: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 1655: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1656: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1657: {
! 1658: rta_addattr_l (rta, 4096, RTA_GATEWAY,
! 1659: &nexthop->gate.ipv6, bytelen);
! 1660:
! 1661: if (IS_ZEBRA_DEBUG_KERNEL)
! 1662: zlog_debug("netlink_route_multipath() (multihop): "
! 1663: "nexthop via %s if %u",
! 1664: inet6_ntoa (nexthop->gate.ipv6),
! 1665: nexthop->ifindex);
! 1666: }
! 1667: #endif /* HAVE_IPV6 */
! 1668: /* ifindex */
! 1669: if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
! 1670: || nexthop->type == NEXTHOP_TYPE_IFINDEX
! 1671: || nexthop->type == NEXTHOP_TYPE_IFNAME)
! 1672: {
! 1673: rtnh->rtnh_ifindex = nexthop->ifindex;
! 1674: if (nexthop->src.ipv4.s_addr)
! 1675: src = &nexthop->src;
! 1676: if (IS_ZEBRA_DEBUG_KERNEL)
! 1677: zlog_debug("netlink_route_multipath() (multihop): "
! 1678: "nexthop via if %u", nexthop->ifindex);
! 1679: }
! 1680: else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 1681: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 1682: {
! 1683: rtnh->rtnh_ifindex = nexthop->ifindex;
! 1684:
! 1685: if (IS_ZEBRA_DEBUG_KERNEL)
! 1686: zlog_debug("netlink_route_multipath() (multihop): "
! 1687: "nexthop via if %u", nexthop->ifindex);
! 1688: }
! 1689: else
! 1690: {
! 1691: rtnh->rtnh_ifindex = 0;
! 1692: }
! 1693: }
! 1694: rtnh = RTNH_NEXT (rtnh);
! 1695:
! 1696: if (cmd == RTM_NEWROUTE)
! 1697: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 1698: }
! 1699: }
! 1700: if (src)
! 1701: addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
! 1702:
! 1703: if (rta->rta_len > RTA_LENGTH (0))
! 1704: addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
! 1705: RTA_PAYLOAD (rta));
! 1706: }
! 1707:
! 1708: /* If there is no useful nexthop then return. */
! 1709: if (nexthop_num == 0)
! 1710: {
! 1711: if (IS_ZEBRA_DEBUG_KERNEL)
! 1712: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
! 1713: return 0;
! 1714: }
! 1715:
! 1716: skip:
! 1717:
! 1718: /* Destination netlink address. */
! 1719: memset (&snl, 0, sizeof snl);
! 1720: snl.nl_family = AF_NETLINK;
! 1721:
! 1722: /* Talk to netlink socket. */
! 1723: return netlink_talk (&req.n, &netlink_cmd);
! 1724: }
! 1725:
! 1726: int
! 1727: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
! 1728: {
! 1729: return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
! 1730: }
! 1731:
! 1732: int
! 1733: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
! 1734: {
! 1735: return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
! 1736: }
! 1737:
! 1738: #ifdef HAVE_IPV6
! 1739: int
! 1740: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
! 1741: {
! 1742: return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
! 1743: }
! 1744:
! 1745: int
! 1746: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
! 1747: {
! 1748: return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
! 1749: }
! 1750:
! 1751: /* Delete IPv6 route from the kernel. */
! 1752: int
! 1753: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
! 1754: unsigned int index, int flags, int table)
! 1755: {
! 1756: return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
! 1757: dest->prefixlen, gate, index, flags, table);
! 1758: }
! 1759: #endif /* HAVE_IPV6 */
! 1760:
! 1761: /* Interface address modification. */
! 1762: static int
! 1763: netlink_address (int cmd, int family, struct interface *ifp,
! 1764: struct connected *ifc)
! 1765: {
! 1766: int bytelen;
! 1767: struct prefix *p;
! 1768:
! 1769: struct
! 1770: {
! 1771: struct nlmsghdr n;
! 1772: struct ifaddrmsg ifa;
! 1773: char buf[1024];
! 1774: } req;
! 1775:
! 1776: p = ifc->address;
! 1777: memset (&req, 0, sizeof req);
! 1778:
! 1779: bytelen = (family == AF_INET ? 4 : 16);
! 1780:
! 1781: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
! 1782: req.n.nlmsg_flags = NLM_F_REQUEST;
! 1783: req.n.nlmsg_type = cmd;
! 1784: req.ifa.ifa_family = family;
! 1785:
! 1786: req.ifa.ifa_index = ifp->ifindex;
! 1787: req.ifa.ifa_prefixlen = p->prefixlen;
! 1788:
! 1789: addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
! 1790:
! 1791: if (family == AF_INET && cmd == RTM_NEWADDR)
! 1792: {
! 1793: if (!CONNECTED_PEER(ifc) && ifc->destination)
! 1794: {
! 1795: p = ifc->destination;
! 1796: addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
! 1797: bytelen);
! 1798: }
! 1799: }
! 1800:
! 1801: if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
! 1802: SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
! 1803:
! 1804: if (ifc->label)
! 1805: addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
! 1806: strlen (ifc->label) + 1);
! 1807:
! 1808: return netlink_talk (&req.n, &netlink_cmd);
! 1809: }
! 1810:
! 1811: int
! 1812: kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
! 1813: {
! 1814: return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
! 1815: }
! 1816:
! 1817: int
! 1818: kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
! 1819: {
! 1820: return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
! 1821: }
! 1822:
! 1823:
! 1824: extern struct thread_master *master;
! 1825:
! 1826: /* Kernel route reflection. */
! 1827: static int
! 1828: kernel_read (struct thread *thread)
! 1829: {
! 1830: int ret;
! 1831: int sock;
! 1832:
! 1833: sock = THREAD_FD (thread);
! 1834: ret = netlink_parse_info (netlink_information_fetch, &netlink);
! 1835: thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
! 1836:
! 1837: return 0;
! 1838: }
! 1839:
! 1840: /* Filter out messages from self that occur on listener socket,
! 1841: caused by our actions on the command socket
! 1842: */
! 1843: static void netlink_install_filter (int sock, __u32 pid)
! 1844: {
! 1845: struct sock_filter filter[] = {
! 1846: /* 0: ldh [4] */
! 1847: BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
! 1848: /* 1: jeq 0x18 jt 3 jf 6 */
! 1849: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
! 1850: /* 2: jeq 0x19 jt 3 jf 6 */
! 1851: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
! 1852: /* 3: ldw [12] */
! 1853: BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
! 1854: /* 4: jeq XX jt 5 jf 6 */
! 1855: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
! 1856: /* 5: ret 0 (skip) */
! 1857: BPF_STMT(BPF_RET|BPF_K, 0),
! 1858: /* 6: ret 0xffff (keep) */
! 1859: BPF_STMT(BPF_RET|BPF_K, 0xffff),
! 1860: };
! 1861:
! 1862: struct sock_fprog prog = {
! 1863: .len = sizeof(filter) / sizeof(filter[0]),
! 1864: .filter = filter,
! 1865: };
! 1866:
! 1867: if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
! 1868: zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
! 1869: }
! 1870:
! 1871: /* Exported interface function. This function simply calls
! 1872: netlink_socket (). */
! 1873: void
! 1874: kernel_init (void)
! 1875: {
! 1876: unsigned long groups;
! 1877:
! 1878: groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
! 1879: #ifdef HAVE_IPV6
! 1880: groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
! 1881: #endif /* HAVE_IPV6 */
! 1882: netlink_socket (&netlink, groups);
! 1883: netlink_socket (&netlink_cmd, 0);
! 1884:
! 1885: /* Register kernel socket. */
! 1886: if (netlink.sock > 0)
! 1887: {
! 1888: /* Only want non-blocking on the netlink event socket */
! 1889: if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
! 1890: zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
! 1891: safe_strerror (errno));
! 1892:
! 1893: /* Set receive buffer size if it's set from command line */
! 1894: if (nl_rcvbufsize)
! 1895: netlink_recvbuf (&netlink, nl_rcvbufsize);
! 1896:
! 1897: netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
! 1898: thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
! 1899: }
! 1900: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>