diff options
Diffstat (limited to 'zebra/kernel_socket.c')
| -rw-r--r-- | zebra/kernel_socket.c | 187 |
1 files changed, 136 insertions, 51 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 7cdd6ef84e..8fd0c96bd9 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -80,12 +80,6 @@ extern struct zebra_privs_t zserv_privs; #define ROUNDUP(a) RT_ROUNDUP(a) #endif /* defined(RT_ROUNDUP) */ -#if defined(SUNOS_5) -/* Solaris has struct sockaddr_in[6] definitions at 16 / 32 bytes size, - * so the whole concept doesn't really apply. */ -#define ROUNDUP(a) (a) -#endif - /* * If ROUNDUP has not yet been defined in terms of platform-provided * defines, attempt to cope with heuristics. @@ -547,18 +541,6 @@ int ifm_read(struct if_msghdr *ifm) */ cp = (void *)(ifm + 1); -#ifdef SUNOS_5 - /* - * XXX This behavior should be narrowed to only the kernel versions - * for which the structures returned do not match the headers. - * - * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions - * is 12 bytes larger than the 32 bit version. - */ - if (((struct sockaddr *)cp)->sa_family == AF_UNSPEC) - cp += 12; -#endif - /* Look up for RTA_IFP and skip others. */ for (maskbit = 1; maskbit; maskbit <<= 1) { if ((maskbit & ifm->ifm_addrs) == 0) @@ -712,8 +694,7 @@ int ifm_read(struct if_msghdr *ifm) { if (ifp->ifindex != ifm->ifm_index) { zlog_debug( - "%s: index mismatch, ifname %s, ifp index %d, " - "ifm index %d", + "%s: index mismatch, ifname %s, ifp index %d, ifm index %d", __func__, ifp->name, ifp->ifindex, ifm->ifm_index); return -1; @@ -833,9 +814,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, ? ip_masklen(mask->sin.sin_addr) : ip6_masklen(mask->sin6.sin6_addr); zlog_debug( - "%s: ifindex %d, ifname %s, ifam_addrs {%s}, " - "ifam_flags 0x%x, addr %s/%d broad %s dst %s " - "gateway %s", + "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %s/%d broad %s dst %s gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)), @@ -868,6 +847,7 @@ int ifam_read(struct ifa_msghdr *ifam) { struct interface *ifp = NULL; union sockunion addr, mask, brd; + bool dest_same = false; char ifname[INTERFACE_NAMSIZ]; short ifnlen = 0; char isalias = 0; @@ -894,6 +874,10 @@ int ifam_read(struct ifa_msghdr *ifam) rely upon the interface type. */ if (if_is_pointopoint(ifp)) SET_FLAG(flags, ZEBRA_IFA_PEER); + else { + if (memcmp(&addr, &brd, sizeof(addr)) == 0) + dest_same = true; + } #if 0 /* it might seem cute to grab the interface metric here, however @@ -910,13 +894,14 @@ int ifam_read(struct ifa_msghdr *ifam) if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), - &brd.sin.sin_addr, + dest_same ? NULL : &brd.sin.sin_addr, (isalias ? ifname : NULL), METRIC_MAX); else connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), - &brd.sin.sin_addr); + dest_same ? NULL + : &brd.sin.sin_addr); break; case AF_INET6: /* Unset interface index from link-local address when IPv6 stack @@ -943,23 +928,6 @@ int ifam_read(struct ifa_msghdr *ifam) /* Check interface flag for implicit up of the interface. */ if_refresh(ifp); -#ifdef SUNOS_5 - /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. - * See comments for SUNOS_5 in interface.c::if_flags_mangle. - * - * Here we take care of case where the real IFF_UP was previously - * unset (as kept in struct zebra_if.primary_state) and the mangled - * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned - * to unset due to the lost non-primary address having DELADDR'd. - * - * we must delete the interface, because in between here and next - * event for this interface-name the administrator could unplumb - * and replumb the interface. - */ - if (!if_is_up(ifp)) - if_delete_update(ifp); -#endif /* SUNOS_5 */ - return 0; } @@ -978,8 +946,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest, /* rt_msghdr version check. */ if (rtm->rtm_version != RTM_VERSION) flog_warn(EC_ZEBRA_RTM_VERSION_MISMATCH, - "Routing message version different %d should be %d." - "This may cause problem\n", + "Routing message version different %d should be %d.This may cause problem\n", rtm->rtm_version, RTM_VERSION); /* Be sure structure is cleared */ @@ -1140,7 +1107,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0, - 0, true); + 0, true, false); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, @@ -1149,7 +1116,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, - 0, true); + 0, true, false); } /* Interface function for the kernel routing table updates. Support @@ -1371,15 +1338,29 @@ static int kernel_read(struct thread *thread) /* Fetch routing socket. */ sock = THREAD_FD(thread); - nbytes = read(sock, &buf, sizeof buf); - - if (nbytes <= 0) { - if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) + nbytes = read(sock, &buf, sizeof(buf)); + + if (nbytes < 0) { + if (errno == ENOBUFS) { + flog_err(EC_ZEBRA_RECVMSG_OVERRUN, + "routing socket overrun: %s", + safe_strerror(errno)); + /* + * In this case we are screwed. + * There is no good way to + * recover zebra at this point. + */ + exit(-1); + } + if (errno != EAGAIN && errno != EWOULDBLOCK) flog_err_sys(EC_LIB_SOCKET, "routing socket error: %s", safe_strerror(errno)); return 0; } + if (nbytes == 0) + return 0; + thread_add_read(zrouter.master, kernel_read, NULL, sock, NULL); if (IS_ZEBRA_DEBUG_KERNEL) @@ -1393,7 +1374,7 @@ static int kernel_read(struct thread *thread) */ if (rtm->rtm_msglen != nbytes) { zlog_debug( - "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n", + "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d", rtm->rtm_msglen, nbytes, rtm->rtm_type); return -1; } @@ -1445,6 +1426,15 @@ static void routing_socket(struct zebra_ns *zns) return; } +#ifdef SO_RERROR + /* Allow reporting of route(4) buffer overflow errors */ + int n = 1; + + if (setsockopt(routing_sock, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) < 0) + flog_err_sys(EC_LIB_SOCKET, + "Can't set SO_RERROR on routing socket"); +#endif + /* XXX: Socket should be NONBLOCK, however as we currently * discard failed writes, this will lead to inconsistencies. * For now, socket must be blocking. @@ -1468,4 +1458,99 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) return; } +void kernel_update_multi(struct dplane_ctx_q *ctx_list) +{ + struct zebra_dplane_ctx *ctx; + struct dplane_ctx_q handled_list; + enum zebra_dplane_result res; + + TAILQ_INIT(&handled_list); + + while (true) { + ctx = dplane_ctx_dequeue(ctx_list); + if (ctx == NULL) + break; + + /* + * A previous provider plugin may have asked to skip the + * kernel update. + */ + if (dplane_ctx_is_skip_kernel(ctx)) { + res = ZEBRA_DPLANE_REQUEST_SUCCESS; + goto skip_one; + } + + switch (dplane_ctx_get_op(ctx)) { + + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + res = kernel_route_update(ctx); + break; + + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: + res = kernel_nexthop_update(ctx); + break; + + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + res = kernel_lsp_update(ctx); + break; + + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + res = kernel_pw_update(ctx); + break; + + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + res = kernel_address_update_ctx(ctx); + break; + + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + res = kernel_mac_update_ctx(ctx); + break; + + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: + case DPLANE_OP_NEIGH_DISCOVER: + res = kernel_neigh_update_ctx(ctx); + break; + + case DPLANE_OP_RULE_ADD: + case DPLANE_OP_RULE_DELETE: + case DPLANE_OP_RULE_UPDATE: + res = kernel_pbr_rule_update(ctx); + break; + + /* Ignore 'notifications' - no-op */ + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_NOTIFY: + res = ZEBRA_DPLANE_REQUEST_SUCCESS; + break; + + default: + res = ZEBRA_DPLANE_REQUEST_FAILURE; + break; + } + + skip_one: + dplane_ctx_set_status(ctx, res); + + dplane_ctx_enqueue_tail(&handled_list, ctx); + } + + TAILQ_INIT(ctx_list); + dplane_ctx_list_append(ctx_list, &handled_list); +} + #endif /* !HAVE_NETLINK */ |
