summaryrefslogtreecommitdiff
path: root/zebra/kernel_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/kernel_socket.c')
-rw-r--r--zebra/kernel_socket.c187
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 */