Example #1
0
/* Interface between zebra message and rtm message. */
static int
kernel_rtm_ipv6_multipath(int cmd, struct prefix *p, struct rib *rib,
			  int family)
{
	struct sockaddr_in6 *mask;
	struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
	struct nexthop *nexthop, *tnexthop;
	int recursing;
	int nexthop_num = 0;
	unsigned int ifindex = 0;
	int gate = 0;
	int error;

	memset(&sin_dest, 0, sizeof(struct sockaddr_in6));
	sin_dest.sin6_family = AF_INET6;
#ifdef SIN6_LEN
	sin_dest.sin6_len = sizeof(struct sockaddr_in6);
#endif /* SIN6_LEN */
	sin_dest.sin6_addr = p->u.prefix6;

	memset(&sin_mask, 0, sizeof(struct sockaddr_in6));

	memset(&sin_gate, 0, sizeof(struct sockaddr_in6));
	sin_gate.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
	sin_gate.sin6_len = sizeof(struct sockaddr_in6);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */

	/* Make gateway. */
	for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) {
		if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
			continue;

		gate = 0;

		if ((cmd == RTM_ADD
		     && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
		    || (cmd == RTM_DELETE
#if 0
			&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
#endif
		    )) {
			if (nexthop->type == NEXTHOP_TYPE_IPV6
			    || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
			    || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
				sin_gate.sin6_addr = nexthop->gate.ipv6;
				gate = 1;
			}
			if (nexthop->type == NEXTHOP_TYPE_IFINDEX
			    || nexthop->type == NEXTHOP_TYPE_IFNAME
			    || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
			    || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
				ifindex = nexthop->ifindex;

			if (cmd == RTM_ADD)
				SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
		}

		/* Under kame set interface index to link local address. */
#ifdef KAME

#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
      do { \
	(a).s6_addr[2] = ((i) >> 8) & 0xff; \
	(a).s6_addr[3] = (i) & 0xff; \
      } while (0)

		if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
			SET_IN6_LINKLOCAL_IFINDEX(sin_gate.sin6_addr, ifindex);
#endif /* KAME */

		if (gate && p->prefixlen == 128)
			mask = NULL;
		else {
			masklen2ip6(p->prefixlen, &sin_mask.sin6_addr);
			sin_mask.sin6_family = AF_INET6;
#ifdef SIN6_LEN
			sin_mask.sin6_len = sin6_masklen(sin_mask.sin6_addr);
#endif /* SIN6_LEN */
			mask = &sin_mask;
		}

		error = rtm_write(cmd,
				  (union sockunion *)&sin_dest,
				  (union sockunion *)mask,
				  gate ? (union sockunion *)&sin_gate : NULL,
				  ifindex, rib->flags, rib->metric);

#if 0
		if (error) {
			zlog_info
			    ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
			     nexthop_num, error);
		}
#endif

		nexthop_num++;
	}

	/* If there is no useful nexthop then return. */
	if (nexthop_num == 0) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug
			    ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
		return 0;
	}

	return 0;
 /*XXX*/}
Example #2
0
/* Interface between zebra message and rtm message. */
static int
kernel_rtm_ipv4(int cmd, struct prefix *p, struct rib *rib, int family)
{
	struct sockaddr_in *mask = NULL;
	struct sockaddr_in sin_dest, sin_mask, sin_gate;
	struct nexthop *nexthop, *tnexthop;
	int recursing;
	int nexthop_num = 0;
	unsigned int ifindex = 0;
	int gate = 0;
	int error;
	char prefix_buf[INET_ADDRSTRLEN];

	if (IS_ZEBRA_DEBUG_RIB)
		inet_ntop(AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
	memset(&sin_dest, 0, sizeof(struct sockaddr_in));
	sin_dest.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
	sin_dest.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
	sin_dest.sin_addr = p->u.prefix4;

	memset(&sin_mask, 0, sizeof(struct sockaddr_in));

	memset(&sin_gate, 0, sizeof(struct sockaddr_in));
	sin_gate.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
	sin_gate.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */

	/* Make gateway. */
	for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) {
		if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
			continue;

		gate = 0;
		char gate_buf[INET_ADDRSTRLEN] = "NULL";

		/*
		 * XXX We need to refrain from kernel operations in some cases,
		 * but this if statement seems overly cautious - what about
		 * other than ADD and DELETE?
		 */
		if ((cmd == RTM_ADD
		     && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
		    || (cmd == RTM_DELETE
			&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
		    )) {
			if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
			    nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
				sin_gate.sin_addr = nexthop->gate.ipv4;
				gate = 1;
			}
			if (nexthop->type == NEXTHOP_TYPE_IFINDEX
			    || nexthop->type == NEXTHOP_TYPE_IFNAME
			    || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
				ifindex = nexthop->ifindex;
			if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
				struct in_addr loopback;
				loopback.s_addr = htonl(INADDR_LOOPBACK);
				sin_gate.sin_addr = loopback;
				gate = 1;
			}

			if (gate && p->prefixlen == 32)
				mask = NULL;
			else {
				masklen2ip(p->prefixlen, &sin_mask.sin_addr);
				sin_mask.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
				sin_mask.sin_len =
				    sin_masklen(sin_mask.sin_addr);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
				mask = &sin_mask;
			}

			error = rtm_write(cmd,
					  (union sockunion *)&sin_dest,
					  (union sockunion *)mask,
					  gate ? (union sockunion *)&sin_gate :
					  NULL, ifindex, rib->flags,
					  rib->metric);

			if (IS_ZEBRA_DEBUG_RIB) {
				if (!gate) {
					zlog_debug
					    ("%s: %s/%d: attention! gate not found for rib %p",
					     __func__, prefix_buf, p->prefixlen,
					     rib);
					rib_dump(p, rib);
				} else
					inet_ntop(AF_INET, &sin_gate.sin_addr,
						  gate_buf, INET_ADDRSTRLEN);
			}

			switch (error) {
				/* We only flag nexthops as being in FIB if rtm_write() did its work. */
			case ZEBRA_ERR_NOERROR:
				nexthop_num++;
				if (IS_ZEBRA_DEBUG_RIB)
					zlog_debug
					    ("%s: %s/%d: successfully did NH %s",
					     __func__, prefix_buf, p->prefixlen,
					     gate_buf);
				if (cmd == RTM_ADD)
					SET_FLAG(nexthop->flags,
						 NEXTHOP_FLAG_FIB);
				break;

				/* The only valid case for this error is kernel's failure to install
				 * a multipath route, which is common for FreeBSD. This should be
				 * ignored silently, but logged as an error otherwise.
				 */
			case ZEBRA_ERR_RTEXIST:
				if (cmd != RTM_ADD)
					zlog_err
					    ("%s: rtm_write() returned %d for command %d",
					     __func__, error, cmd);
				continue;
				break;

				/* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
				 * normal to get any other messages in ANY case.
				 */
			case ZEBRA_ERR_RTNOEXIST:
			case ZEBRA_ERR_RTUNREACH:
			default:
				/* This point is reachable regardless of debugging mode. */
				if (!IS_ZEBRA_DEBUG_RIB)
					inet_ntop(AF_INET, &p->u.prefix,
						  prefix_buf, INET_ADDRSTRLEN);
				zlog_err
				    ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
				     __func__, prefix_buf, p->prefixlen, error,
				     lookup(rtm_type_str, cmd));
				break;
			}
		} /* if (cmd and flags make sense) */
		else if (IS_ZEBRA_DEBUG_RIB)
			zlog_debug("%s: odd command %s for flags %d",
				   __func__, lookup(rtm_type_str, cmd),
				   nexthop->flags);
	}			/* for (ALL_NEXTHOPS_RO(...)) */

	/* If there was no useful nexthop, then complain. */
	if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
		zlog_debug("%s: No useful nexthops were found in RIB entry %p",
			   __func__, rib);

	return 0;
 /*XXX*/}
/*
 * create_add_route_message
 */
static Fpm__AddRoute *
create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest,
			  struct rib *rib)
{
  Fpm__AddRoute *msg;
  int discard;
  struct nexthop *nexthop, *tnexthop;
  int recursing;
  uint num_nhs, u;
  struct nexthop *nexthops[MAX (MULTIPATH_NUM, 64)];

  msg = QPB_ALLOC(allocator, typeof(*msg));
  if (!msg) {
    assert(0);
    return NULL;
  }

  fpm__add_route__init(msg);

  msg->vrf_id = rib_dest_vrf(dest)->vrf_id;

  qpb_address_family_set (&msg->address_family, rib_dest_af(dest));

  /*
   * XXX Hardcode subaddress family for now.
   */
  msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
  msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest));
  qpb_protocol_set (&msg->protocol, rib->type);

  if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
    discard = 1;
  else
    discard = 0;

  if (discard)
    {
      if (rib->flags & ZEBRA_FLAG_BLACKHOLE) {
	msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE;
      } else if (rib->flags & ZEBRA_FLAG_REJECT) {
	msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE;
      } else {
	assert (0);
      }
      return msg;
    }
  else {
    msg->route_type = FPM__ROUTE_TYPE__NORMAL;
  }

  msg->metric = rib->metric;

  /*
   * Figure out the set of nexthops to be added to the message.
   */
  num_nhs = 0;
  for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing))
    {
      if (MULTIPATH_NUM != 0 && num_nhs >= MULTIPATH_NUM)
        break;

      if (num_nhs >= ZEBRA_NUM_OF(nexthops))
	break;

      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
        continue;

      if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
	continue;

      nexthops[num_nhs] = nexthop;
      num_nhs++;
    }

  if (!num_nhs) {
    zfpm_debug ("netlink_encode_route(): No useful nexthop.");
    assert(0);
    return NULL;
  }

  /*
   * And add them to the message.
   */
  if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) {
    assert(0);
    return NULL;
  }

  msg->n_nexthops = 0;
  for (u = 0; u < num_nhs; u++) {
    if (!add_nexthop(allocator, msg, dest, nexthops[u])) {
      assert(0);
      return NULL;
    }
  }

  assert(msg->n_nexthops == num_nhs);

  return msg;
}