Beispiel #1
0
int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
	int len;
	struct ifinfomsg *ifi;
	struct rtattr *tb[IFLA_MAX + 1];
	struct rtattr *linkinfo[IFLA_MAX + 1];
	struct interface *ifp;
	char *name = NULL;
	char *kind = NULL;
	char *desc = NULL;
	char *slave_kind = NULL;
	struct zebra_ns *zns;
	vrf_id_t vrf_id = VRF_DEFAULT;
	zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
	zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
	ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
	ifindex_t link_ifindex = IFINDEX_INTERNAL;


	zns = zebra_ns_lookup(ns_id);
	ifi = NLMSG_DATA(h);

	/* assume if not default zns, then new VRF */
	if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) {
		/* If this is not link add/delete message so print warning. */
		zlog_warn("netlink_link_change: wrong kernel message %d",
			  h->nlmsg_type);
		return 0;
	}

	if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE
	      || ifi->ifi_family == AF_INET6)) {
		zlog_warn(
			"Invalid address family: %u received from kernel link change: %u",
			ifi->ifi_family, h->nlmsg_type);
		return 0;
	}

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
	if (len < 0) {
		zlog_err("%s: Message received from netlink is of a broken size %d %zu",
			 __PRETTY_FUNCTION__, h->nlmsg_len,
			 (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
		return -1;
	}

	/* We are interested in some AF_BRIDGE notifications. */
	if (ifi->ifi_family == AF_BRIDGE)
		return netlink_bridge_interface(h, len, ns_id, startup);

	/* Looking up interface name. */
	memset(tb, 0, sizeof tb);
	memset(linkinfo, 0, sizeof linkinfo);
	netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);

	/* check for wireless messages to ignore */
	if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("%s: ignoring IFLA_WIRELESS message",
				   __func__);
		return 0;
	}

	if (tb[IFLA_IFNAME] == NULL)
		return -1;
	name = (char *)RTA_DATA(tb[IFLA_IFNAME]);

	if (tb[IFLA_LINKINFO]) {
		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (linkinfo[IFLA_INFO_KIND])
			kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);

		if (linkinfo[IFLA_INFO_SLAVE_KIND])
			slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);

		netlink_determine_zebra_iftype(kind, &zif_type);
	}

	/* If linking to another interface, note it. */
	if (tb[IFLA_LINK])
		link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);

	if (tb[IFLA_IFALIAS]) {
		desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]);
	}

	/* If VRF, create or update the VRF structure itself. */
	if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) {
		netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
		vrf_id = (vrf_id_t)ifi->ifi_index;
	}

	/* See if interface is present. */
	ifp = if_lookup_by_name_per_ns(zns, name);

	if (ifp) {
		if (ifp->desc)
			XFREE(MTYPE_TMP, ifp->desc);
		if (desc)
			ifp->desc = XSTRDUP(MTYPE_TMP, desc);
	}

	if (h->nlmsg_type == RTM_NEWLINK) {
		if (tb[IFLA_MASTER]) {
			if (slave_kind && (strcmp(slave_kind, "vrf") == 0)
			    && !vrf_is_backend_netns()) {
				zif_slave_type = ZEBRA_IF_SLAVE_VRF;
				vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]);
			} else if (slave_kind
				   && (strcmp(slave_kind, "bridge") == 0)) {
				zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
				bridge_ifindex =
					*(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
			} else
				zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
		}
		if (vrf_is_backend_netns())
			vrf_id = (vrf_id_t)ns_id;
		if (ifp == NULL
		    || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
			/* Add interface notification from kernel */
			if (IS_ZEBRA_DEBUG_KERNEL)
				zlog_debug(
					"RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d "
					"sl_type %d master %u flags 0x%x",
					name, ifi->ifi_index, vrf_id, zif_type,
					zif_slave_type, bridge_ifindex,
					ifi->ifi_flags);

			if (ifp == NULL) {
				/* unknown interface */
				ifp = if_get_by_name(name, vrf_id, 0);
			} else {
				/* pre-configured interface, learnt now */
				if (ifp->vrf_id != vrf_id)
					if_update_to_new_vrf(ifp, vrf_id);
			}

			/* Update interface information. */
			set_ifindex(ifp, ifi->ifi_index, zns);
			ifp->flags = ifi->ifi_flags & 0x0000fffff;
			if (!tb[IFLA_MTU]) {
				zlog_warn(
					"RTM_NEWLINK for interface %s(%u) without MTU set",
					name, ifi->ifi_index);
				return 0;
			}
			ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
			ifp->metric = 0;
			ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;

			/* Set interface type */
			zebra_if_set_ziftype(ifp, zif_type, zif_slave_type);
			if (IS_ZEBRA_IF_VRF(ifp))
				SET_FLAG(ifp->status,
					 ZEBRA_INTERFACE_VRF_LOOPBACK);

			/* Update link. */
			zebra_if_update_link(ifp, link_ifindex);

			netlink_interface_update_hw_addr(tb, ifp);

			/* Inform clients, install any configured addresses. */
			if_add_update(ifp);

			/* Extract and save L2 interface information, take
			 * additional actions. */
			netlink_interface_update_l2info(
				ifp, linkinfo[IFLA_INFO_DATA], 1);
			if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
				zebra_l2if_update_bridge_slave(ifp,
							       bridge_ifindex);
			if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
								  ifp, ns_id);
		} else if (ifp->vrf_id != vrf_id) {
			/* VRF change for an interface. */
			if (IS_ZEBRA_DEBUG_KERNEL)
				zlog_debug(
					"RTM_NEWLINK vrf-change for %s(%u) "
					"vrf_id %u -> %u flags 0x%x",
					name, ifp->ifindex, ifp->vrf_id, vrf_id,
					ifi->ifi_flags);

			if_handle_vrf_change(ifp, vrf_id);
		} else {
			int was_bridge_slave;

			/* Interface update. */
			if (IS_ZEBRA_DEBUG_KERNEL)
				zlog_debug(
					"RTM_NEWLINK update for %s(%u) "
					"sl_type %d master %u flags 0x%x",
					name, ifp->ifindex, zif_slave_type,
					bridge_ifindex, ifi->ifi_flags);

			set_ifindex(ifp, ifi->ifi_index, zns);
			if (!tb[IFLA_MTU]) {
				zlog_warn(
					"RTM_NEWLINK for interface %s(%u) without MTU set",
					name, ifi->ifi_index);
				return 0;
			}
			ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
			ifp->metric = 0;

			/* Update interface type - NOTE: Only slave_type can
			 * change. */
			was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp);
			zebra_if_set_ziftype(ifp, zif_type, zif_slave_type);

			netlink_interface_update_hw_addr(tb, ifp);

			if (if_is_no_ptm_operative(ifp)) {
				ifp->flags = ifi->ifi_flags & 0x0000fffff;
				if (!if_is_no_ptm_operative(ifp)) {
					if (IS_ZEBRA_DEBUG_KERNEL)
						zlog_debug(
							"Intf %s(%u) has gone DOWN",
							name, ifp->ifindex);
					if_down(ifp);
				} else if (if_is_operative(ifp)) {
					/* Must notify client daemons of new
					 * interface status. */
					if (IS_ZEBRA_DEBUG_KERNEL)
						zlog_debug(
							"Intf %s(%u) PTM up, notifying clients",
							name, ifp->ifindex);
					zebra_interface_up_update(ifp);
				}
			} else {
				ifp->flags = ifi->ifi_flags & 0x0000fffff;
				if (if_is_operative(ifp)) {
					if (IS_ZEBRA_DEBUG_KERNEL)
						zlog_debug(
							"Intf %s(%u) has come UP",
							name, ifp->ifindex);
					if_up(ifp);
				}
			}

			/* Extract and save L2 interface information, take
			 * additional actions. */
			netlink_interface_update_l2info(
				ifp, linkinfo[IFLA_INFO_DATA], 0);
			if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
				zebra_l2if_update_bridge_slave(ifp,
							       bridge_ifindex);
			if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
								  ifp, ns_id);
		}
	} else {
		/* Delete interface notification from kernel */
		if (ifp == NULL) {
			zlog_warn("RTM_DELLINK for unknown interface %s(%u)",
				  name, ifi->ifi_index);
			return 0;
		}

		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("RTM_DELLINK for %s(%u)", name,
				   ifp->ifindex);

		UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);

		/* Special handling for bridge or VxLAN interfaces. */
		if (IS_ZEBRA_IF_BRIDGE(ifp))
			zebra_l2_bridge_del(ifp);
		else if (IS_ZEBRA_IF_VXLAN(ifp))
			zebra_l2_vxlanif_del(ifp);

		if (!IS_ZEBRA_IF_VRF(ifp))
			if_delete_update(ifp);
		if_netlink_check_ifp_instance_consistency(RTM_DELLINK,
							  ifp, ns_id);
	}

	return 0;
}
Beispiel #2
0
static int
ospf6_spf_calculation_thread (struct thread *t)
{
  struct ospf6_area *oa;
  struct ospf6 *ospf6;
  struct timeval start, end, runtime;
  struct listnode *node;
  struct ospf6_route *route;
  int areas_processed = 0;
  char rbuf[32];

  ospf6 = (struct ospf6 *)THREAD_ARG (t);
  ospf6->t_spf_calc = NULL;

  /* execute SPF calculation */
  quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);

  for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
    {

      if (oa == ospf6->backbone)
	continue;

      if (IS_OSPF6_DEBUG_SPF (PROCESS))
	zlog_debug ("SPF calculation for Area %s", oa->name);
      if (IS_OSPF6_DEBUG_SPF (DATABASE))
	ospf6_spf_log_database (oa);

      ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
      ospf6_intra_route_calculation (oa);
      ospf6_intra_brouter_calculation (oa);

      areas_processed++;
    }

  if (ospf6->backbone)
    {
      if (IS_OSPF6_DEBUG_SPF (PROCESS))
	zlog_debug ("SPF calculation for Backbone area %s",
		    ospf6->backbone->name);
      if (IS_OSPF6_DEBUG_SPF (DATABASE))
	ospf6_spf_log_database(ospf6->backbone);

      ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
			    ospf6->backbone);
      ospf6_intra_route_calculation(ospf6->backbone);
      ospf6_intra_brouter_calculation(ospf6->backbone);
      areas_processed++;
    }

  /* Redo summaries if required */
  for (route = ospf6_route_head (ospf6->route_table); route;
       route = ospf6_route_next (route))
    ospf6_abr_originate_summary(route);

  quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
  timersub (&end, &start, &runtime);

  ospf6->ts_spf_duration = runtime;

  ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));

  if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
    zlog_debug ("SPF runtime: %lld sec %lld usec",
		(long long)runtime.tv_sec, (long long)runtime.tv_usec);

  zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
	    "Reason: %s\n", areas_processed,
	    (long long)runtime.tv_sec, (long long)runtime.tv_usec,
	    rbuf);
  ospf6->last_spf_reason = ospf6->spf_reason;
  ospf6_reset_spf_reason(ospf6);
  return 0;
}
Beispiel #3
0
struct isis_circuit *
isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
{
  int old_state;

  old_state = circuit ? circuit->state : C_STATE_NA;
  if (isis->debugs & DEBUG_EVENTS)
    zlog_debug ("CSM_EVENT: %s", EVENT2STR (event));

  switch (old_state)
    {
    case C_STATE_NA:
      if (circuit)
	zlog_warn ("Non-null circuit while state C_STATE_NA");
      switch (event)
	{
	case ISIS_ENABLE:
	  circuit = isis_circuit_new ();
	  isis_circuit_configure (circuit, (struct isis_area *) arg);
	  circuit->state = C_STATE_CONF;
	  break;
	case IF_UP_FROM_Z:
	  circuit = isis_circuit_new ();
	  isis_circuit_if_add (circuit, (struct interface *) arg);
	  listnode_add (isis->init_circ_list, circuit);
	  circuit->state = C_STATE_INIT;
	  break;
	case ISIS_DISABLE:
	  zlog_warn ("circuit already disabled");
	case IF_DOWN_FROM_Z:
	  zlog_warn ("circuit already disconnected");
	  break;
	}
      break;
    case C_STATE_INIT:
      switch (event)
	{
	case ISIS_ENABLE:
	  isis_circuit_configure (circuit, (struct isis_area *) arg);
	  isis_circuit_up (circuit);
	  circuit->state = C_STATE_UP;
	  isis_event_circuit_state_change (circuit, 1);
	  listnode_delete (isis->init_circ_list, circuit);
	  break;
	case IF_UP_FROM_Z:
	  zlog_warn ("circuit already connected");
	  break;
	case ISIS_DISABLE:
	  zlog_warn ("circuit already disabled");
	  break;
	case IF_DOWN_FROM_Z:
	  isis_circuit_if_del (circuit);
	  listnode_delete (isis->init_circ_list, circuit);
	  isis_circuit_del (circuit);
	  circuit = NULL;
	  break;
	}
      break;
    case C_STATE_CONF:
      switch (event)
	{
	case ISIS_ENABLE:
	  zlog_warn ("circuit already enabled");
	  break;
	case IF_UP_FROM_Z:
	  isis_circuit_if_add (circuit, (struct interface *) arg);
	  isis_circuit_up (circuit);
	  circuit->state = C_STATE_UP;
	  isis_event_circuit_state_change (circuit, 1);
	  break;
	case ISIS_DISABLE:
	  isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
	  isis_circuit_del (circuit);
	  circuit = NULL;
	  break;
	case IF_DOWN_FROM_Z:
	  zlog_warn ("circuit already disconnected");
	  break;
	}
      break;
    case C_STATE_UP:
      switch (event)
	{
	case ISIS_ENABLE:
	  zlog_warn ("circuit already configured");
	  break;
	case IF_UP_FROM_Z:
	  zlog_warn ("circuit already connected");
	  break;
	case ISIS_DISABLE:
	  isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
	  listnode_add (isis->init_circ_list, circuit);
	  circuit->state = C_STATE_INIT;
	  isis_event_circuit_state_change (circuit, 0);
	  break;
	case IF_DOWN_FROM_Z:
	  isis_circuit_if_del (circuit);
	  circuit->state = C_STATE_CONF;
	  isis_event_circuit_state_change (circuit, 0);
	  break;
	}
      break;

    default:
      zlog_warn ("Invalid circuit state %d", old_state);
    }

  if (isis->debugs & DEBUG_EVENTS)
    zlog_debug ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state),
		circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA));

  return circuit;
}
Beispiel #4
0
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
{
  struct ip *ip_hdr;
  size_t ip_hlen; /* ip header length in bytes */
  char src_str[100];
  char dst_str[100];
  uint8_t *pim_msg;
  int pim_msg_len;
  uint8_t pim_version;
  uint8_t pim_type;
  uint16_t pim_checksum; /* received checksum */
  uint16_t checksum;     /* computed checksum */
  struct pim_neighbor *neigh;

  if (!ifp->info) {
    zlog_warn("%s: PIM not enabled on interface %s",
	      __PRETTY_FUNCTION__, ifp->name);
    return -1;
  }
    
  if (len < sizeof(*ip_hdr)) {
    zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
	      len, sizeof(*ip_hdr));
    return -1;
  }

  ip_hdr = (struct ip *) buf;

  pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
  pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));

  ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */

  if (PIM_DEBUG_PIM_PACKETS) {
    zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
	       src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
  }

  if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
    zlog_warn("IP packet protocol=%d is not PIM=%d",
	      ip_hdr->ip_p, PIM_IP_PROTO_PIM);
    return -1;
  }

  if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
    zlog_warn("IP packet header size=%zu shorter than minimum=%d",
	      ip_hlen, PIM_IP_HEADER_MIN_LEN);
    return -1;
  }
  if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
    zlog_warn("IP packet header size=%zu greater than maximum=%d",
	      ip_hlen, PIM_IP_HEADER_MAX_LEN);
    return -1;
  }

  pim_msg = buf + ip_hlen;
  pim_msg_len = len - ip_hlen;

  if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
    pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
  }

  if (pim_msg_len < PIM_PIM_MIN_LEN) {
    zlog_warn("PIM message size=%d shorter than minimum=%d",
	      pim_msg_len, PIM_PIM_MIN_LEN);
    return -1;
  }

  pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
  pim_type    = PIM_MSG_HDR_GET_TYPE(pim_msg);

  if (pim_version != PIM_PROTO_VERSION) {
    zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
	      ifp->name, pim_version);
    return -1;
  }

  /* save received checksum */
  pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);

  /* for computing checksum */
  *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;

  checksum = in_cksum(pim_msg, pim_msg_len);
  if (checksum != pim_checksum) {
    zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
	      ifp->name, pim_checksum, checksum);
    return -1;
  }

  if (PIM_DEBUG_PIM_PACKETS) {
    zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x",
	       src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
	       pim_version, pim_type, pim_msg_len, checksum);
  }

  if (pim_type == PIM_MSG_TYPE_REGISTER  ||
      pim_type == PIM_MSG_TYPE_REG_STOP  ||
      pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
      pim_type == PIM_MSG_TYPE_GRAFT     ||
      pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
      pim_type == PIM_MSG_TYPE_CANDIDATE)
    {
      if (PIM_DEBUG_PIM_PACKETS) {
	zlog_debug("Recv PIM packet type %d which is not currently understood",
		   pim_type);
      }
      return -1;
    }

  if (pim_type == PIM_MSG_TYPE_HELLO) {
    int result = pim_hello_recv(ifp,
                 ip_hdr->ip_src,
                 pim_msg + PIM_MSG_HEADER_LEN,
                 pim_msg_len - PIM_MSG_HEADER_LEN);
    return result;
  }

  neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
  if (!neigh) {
    zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
	      __FILE__, __PRETTY_FUNCTION__,
	      pim_type, src_str, ifp->name);
    return -1;
  }

  switch (pim_type) {
  case PIM_MSG_TYPE_JOIN_PRUNE:
    return pim_joinprune_recv(ifp, neigh,
			      ip_hdr->ip_src,
			      pim_msg + PIM_MSG_HEADER_LEN,
			      pim_msg_len - PIM_MSG_HEADER_LEN);
  case PIM_MSG_TYPE_ASSERT:
    return pim_assert_recv(ifp, neigh,
			   ip_hdr->ip_src,
			   pim_msg + PIM_MSG_HEADER_LEN,
			   pim_msg_len - PIM_MSG_HEADER_LEN);
  default:
    zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
	      __FILE__, __PRETTY_FUNCTION__,
	      pim_type, src_str, ifp->name);
  }

  return -1;
}
Beispiel #5
0
static int
ospf6_spf_install (struct ospf6_vertex *v,
                   struct ospf6_route_table *result_table)
{
  struct ospf6_route *route;
  int i, j;
  struct ospf6_vertex *prev;

  if (IS_OSPF6_DEBUG_SPF (PROCESS))
    zlog_debug ("SPF install %s hops %d cost %d",
		v->name, v->hops, v->cost);

  route = ospf6_route_lookup (&v->vertex_id, result_table);
  if (route && route->path.cost < v->cost)
    {
      if (IS_OSPF6_DEBUG_SPF (PROCESS))
        zlog_debug ("  already installed with lower cost (%d), ignore",
		    route->path.cost);
      ospf6_vertex_delete (v);
      return -1;
    }
  else if (route && route->path.cost == v->cost)
    {
      if (IS_OSPF6_DEBUG_SPF (PROCESS))
        zlog_debug ("  another path found, merge");

      for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
           i < OSPF6_MULTI_PATH_LIMIT; i++)
        {
          for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
            {
              if (ospf6_nexthop_is_set (&route->nexthop[j]))
                {
                  if (ospf6_nexthop_is_same (&route->nexthop[j],
                                             &v->nexthop[i]))
                    break;
                  else
                    continue;
                }
              ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
              break;
            }
        }

      prev = (struct ospf6_vertex *) route->route_option;
      assert (prev->hops <= v->hops);
      ospf6_vertex_delete (v);

      return -1;
    }

  /* There should be no case where candidate being installed (variable
     "v") is closer than the one in the SPF tree (variable "route").
     In the case something has gone wrong with the behavior of
     Priority-Queue. */

  /* the case where the route exists already is handled and returned
     up to here. */
  assert (route == NULL);

  route = ospf6_route_create ();
  memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
  route->type = OSPF6_DEST_TYPE_LINKSTATE;
  route->path.type = OSPF6_PATH_TYPE_INTRA;
  route->path.origin.type = v->lsa->header->type;
  route->path.origin.id = v->lsa->header->id;
  route->path.origin.adv_router = v->lsa->header->adv_router;
  route->path.metric_type = 1;
  route->path.cost = v->cost;
  route->path.cost_e2 = v->hops;
  route->path.router_bits = v->capability;
  route->path.options[0] = v->options[0];
  route->path.options[1] = v->options[1];
  route->path.options[2] = v->options[2];

  for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
       i < OSPF6_MULTI_PATH_LIMIT; i++)
    ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);

  if (v->parent)
    listnode_add_sort (v->parent->child_list, v);
  route->route_option = v;

  ospf6_route_add (route, result_table);
  return 0;
}
Beispiel #6
0
/*
 * Handle struct if_msghdr obtained from reading routing socket or
 * sysctl (from interface_list).  There may or may not be sockaddrs
 * present after the header.
 */
int
ifm_read (struct if_msghdr *ifm)
{
  struct interface *ifp = NULL;
  struct sockaddr_dl *sdl;
  char ifname[IFNAMSIZ];
  short ifnlen = 0;
  caddr_t cp;
  
  /* terminate ifname at head (for strnlen) and tail (for safety) */
  ifname[IFNAMSIZ - 1] = '\0';
  
  /* paranoia: sanity check structure */
  if (ifm->ifm_msglen < sizeof(struct if_msghdr))
    {
      zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n",
		ifm->ifm_msglen);
      return -1;
    }

  /*
   * Check for a sockaddr_dl following the message.  First, point to
   * where a socakddr might be if one follows the message.
   */
  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 = cp + 12;
#endif

  RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp);
  RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
  RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
  RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
  sdl = (struct sockaddr_dl *)cp;
  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
  RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
  RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
  RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp);
  
  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)"));
  
  /* 
   * Look up on ifindex first, because ifindices are the primary handle for
   * interfaces across the user/kernel boundary, for most systems.  (Some
   * messages, such as up/down status changes on NetBSD, do not include a
   * sockaddr_dl).
   */
  if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL )
    {
      /* we have an ifp, verify that the name matches as some systems,
       * eg Solaris, have a 1:many association of ifindex:ifname
       * if they dont match, we dont have the correct ifp and should
       * set it back to NULL to let next check do lookup by name
       */
      if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) )
        {
          if (IS_ZEBRA_DEBUG_KERNEL)
            zlog_debug ("%s: ifp name %s doesnt match sdl name %s",
                        __func__, ifp->name, ifname);
          ifp = NULL;
        }
    }
  
  /* 
   * If we dont have an ifp, try looking up by name.  Particularly as some
   * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname
   * is therefore our unique handle to that interface.
   *
   * Interfaces specified in the configuration file for which the ifindex
   * has not been determined will have ifindex == IFINDEX_INTERNAL, and such
   * interfaces are found by this search, and then their ifindex values can
   * be filled in.
   */
  if ( (ifp == NULL) && ifnlen)
    ifp = if_lookup_by_name (ifname);

  /*
   * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL),
   * create or fill in an interface.
   */
  if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL))
    {
      /*
       * To create or fill in an interface, a sockaddr_dl (via
       * RTA_IFP) is required.
       */
      if (!ifnlen)
	{
	  zlog_warn ("Interface index %d (new) missing ifname\n",
		     ifm->ifm_index);
	  return -1;
	}

#ifndef RTM_IFANNOUNCE
      /* Down->Down interface should be ignored here.
       * See further comment below.
       */
      if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP))
        return 0;
#endif /* !RTM_IFANNOUNCE */
      
      if (ifp == NULL)
        {
	  /* Interface that zebra was not previously aware of, so create. */ 
	  ifp = if_create (ifname, ifnlen);
	  if (IS_ZEBRA_DEBUG_KERNEL)
	    zlog_debug ("%s: creating ifp for ifindex %d", 
	                __func__, ifm->ifm_index);
        }

      if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d",
                    __func__, ifp->name, ifp->ifindex);
      /* 
       * Fill in newly created interface structure, or larval
       * structure with ifindex IFINDEX_INTERNAL.
       */
      ifp->ifindex = ifm->ifm_index;
      
#ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */
      bsd_linkdetect_translate(ifm);
#endif /* HAVE_BSD_IFI_LINK_STATE */

      if_flags_update (ifp, ifm->ifm_flags);
#if defined(__bsdi__)
      if_kvm_get_mtu (ifp);
#else
      if_get_mtu (ifp);
#endif /* __bsdi__ */
      if_get_metric (ifp);

      /*
       * XXX sockaddr_dl contents can be larger than the structure
       * definition, so the user of the stored structure must be
       * careful not to read off the end.
       *
       * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid
       */
      if (ifnlen)
	memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));

      if_add_update (ifp);
    }
  else
    /*
     * Interface structure exists.  Adjust stored flags from
     * notification.  If interface has up->down or down->up
     * transition, call state change routines (to adjust routes,
     * notify routing daemons, etc.).  (Other flag changes are stored
     * but apparently do not trigger action.)
     */
    {
      if (ifp->ifindex != ifm->ifm_index)
        {
          zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, "
                     "ifm index %d", 
                     __func__, ifp->name, ifp->ifindex, ifm->ifm_index);
          return -1;
        }
      
#ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */
      bsd_linkdetect_translate(ifm);
#endif /* HAVE_BSD_IFI_LINK_STATE */

      /* update flags and handle operative->inoperative transition, if any */
      if_flags_update (ifp, ifm->ifm_flags);
      
#ifndef RTM_IFANNOUNCE
      if (!if_is_up (ifp))
          {
            /* No RTM_IFANNOUNCE on this platform, so we can never
             * distinguish between ~IFF_UP and delete. We must presume
             * it has been deleted.
             * Eg, Solaris will not notify us of unplumb.
             *
             * XXX: Fixme - this should be runtime detected
             * So that a binary compiled on a system with IFANNOUNCE
             * will still behave correctly if run on a platform without
             */
            if_delete_update (ifp);
          }
#endif /* RTM_IFANNOUNCE */
      if (if_is_up (ifp))
      {
#if defined(__bsdi__)
        if_kvm_get_mtu (ifp);
#else
        if_get_mtu (ifp);
#endif /* __bsdi__ */
        if_get_metric (ifp);
      }
    }

#ifdef HAVE_NET_RT_IFLIST
  ifp->stats = ifm->ifm_data;
#endif /* HAVE_NET_RT_IFLIST */

  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("%s: interface %s index %d", 
                __func__, ifp->name, ifp->ifindex);

  return 0;
}
Beispiel #7
0
void
rtm_read (struct rt_msghdr *rtm)
{
  int flags;
  u_char zebra_flags;
  union sockunion dest, mask, gate;
  char ifname[INTERFACE_NAMSIZ + 1];
  short ifnlen = 0;

  zebra_flags = 0;

  /* Read destination and netmask and gateway from rtm message
     structure. */
  flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
  if (!(flags & RTF_DONE))
    return;
  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type,
      lookup (rtm_type_str, rtm->rtm_type));

#ifdef RTF_CLONED	/*bsdi, netbsd 1.6*/
  if (flags & RTF_CLONED)
    return;
#endif
#ifdef RTF_WASCLONED	/*freebsd*/
  if (flags & RTF_WASCLONED)
    return;
#endif

  if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
    return;

  /* This is connected route. */
  if (! (flags & RTF_GATEWAY))
      return;

  if (flags & RTF_PROTO1)
    SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);

  /* This is persistent route. */
  if (flags & RTF_STATIC)
    SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);

  /* This is a reject or blackhole route */
  if (flags & RTF_REJECT)
    SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT);
  if (flags & RTF_BLACKHOLE)
    SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE);

  if (dest.sa.sa_family == AF_INET)
    {
      struct prefix_ipv4 p;

      p.family = AF_INET;
      p.prefix = dest.sin.sin_addr;
      if (flags & RTF_HOST)
	p.prefixlen = IPV4_MAX_PREFIXLEN;
      else
	p.prefixlen = ip_masklen (mask.sin.sin_addr);
      
      /* Catch self originated messages and match them against our current RIB.
       * At the same time, ignore unconfirmed messages, they should be tracked
       * by rtm_write() and kernel_rtm_ipv4().
       */
      if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
      {
        char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN];
        int ret;
        if (! IS_ZEBRA_DEBUG_RIB)
          return;
        ret = rib_lookup_ipv4_route (&p, &gate); 
        inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN);
        switch (rtm->rtm_type)
        {
          case RTM_ADD:
          case RTM_GET:
          case RTM_CHANGE:
            /* The kernel notifies us about a new route in FIB created by us.
               Do we have a correspondent entry in our RIB? */
            switch (ret)
            {
              case ZEBRA_RIB_NOTFOUND:
                zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
                break;
              case ZEBRA_RIB_FOUND_CONNECTED:
              case ZEBRA_RIB_FOUND_NOGATE:
                inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN);
                zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf);
                break;
              case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */
                zlog_debug ("%s: %s %s/%d: done Ok",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
                rib_lookup_and_dump (&p);
                return;
                break;
            }
            break;
          case RTM_DELETE:
            /* The kernel notifies us about a route deleted by us. Do we still
               have it in the RIB? Do we have anything instead? */
            switch (ret)
            {
              case ZEBRA_RIB_FOUND_EXACT:
                zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
                rib_lookup_and_dump (&p);
                break;
              case ZEBRA_RIB_FOUND_CONNECTED:
              case ZEBRA_RIB_FOUND_NOGATE:
                zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
                rib_lookup_and_dump (&p);
                break;
              case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */
                zlog_debug ("%s: %s %s/%d: done Ok",
                  __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
                rib_lookup_and_dump (&p);
                return;
                break;
            }
            break;
          default:
            zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received",
              __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type));
        }
        return;
      }

      /* Change, delete the old prefix, we have no further information
       * to specify the route really
       */
      if (rtm->rtm_type == RTM_CHANGE)
        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
                         NULL, 0, 0, SAFI_UNICAST);
      
      if (rtm->rtm_type == RTM_GET 
          || rtm->rtm_type == RTM_ADD
          || rtm->rtm_type == RTM_CHANGE)
	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
		      &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, SAFI_UNICAST);
      else
	rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
		      &p, &gate.sin.sin_addr, 0, 0, SAFI_UNICAST);
    }
#ifdef HAVE_IPV6
  if (dest.sa.sa_family == AF_INET6)
    {
      /* One day we might have a debug section here like one in the
       * IPv4 case above. Just ignore own messages at the moment.
       */
      if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
        return;
      struct prefix_ipv6 p;
      unsigned int ifindex = 0;

      p.family = AF_INET6;
      p.prefix = dest.sin6.sin6_addr;
      if (flags & RTF_HOST)
	p.prefixlen = IPV6_MAX_PREFIXLEN;
      else
	p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);

#ifdef KAME
      if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
	{
	  ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
	  SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
	}
#endif /* KAME */

      /* CHANGE: delete the old prefix, we have no further information
       * to specify the route really
       */
      if (rtm->rtm_type == RTM_CHANGE)
        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
                         NULL, 0, 0, SAFI_UNICAST);
      
      if (rtm->rtm_type == RTM_GET 
          || rtm->rtm_type == RTM_ADD
          || rtm->rtm_type == RTM_CHANGE)
	rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
		      &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0, SAFI_UNICAST);
      else
	rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
			 &p, &gate.sin6.sin6_addr, ifindex, 0, SAFI_UNICAST);
    }
#endif /* HAVE_IPV6 */
}
Beispiel #8
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*/
}
Beispiel #9
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*/
}
Beispiel #10
0
int atlas_mgmt_parse(char* cbuff, int bufsz) {
	char cc;				// current char
	char lc = 0;			// last char
	int acx = 0;			// current arg char index
	int esc_active = 0;		// used for quoted strings
	int argcnt = 0;			// arg counter (0 = command name, 1 = arglist[0])
	int xrec = 0;			// recording

	int cmatch = -1;		// cmd index from match
	int cflags = 0;			// cmd flags from command LUT

	int (*cmd_cback)(char*,int);	// pointer to command callback function
	int exec_rv;			// return val from callback func

	char escaper = 0;

	char arglist[ATLS_MGMT_MAX_ARGS][ATLS_MGMT_ARG_STRSZ];
	char cmdname[ATLS_MGMT_CMD_STRSZ];

	ATLS_FENTER();
	ATLS_ASSERT_NULLPTR(cbuff,-1);
	ATLS_ASSERT_NONPOS(bufsz,-1);

	// clear arglist memory
	memset(arglist,0,ATLS_MGMT_MAX_ARGS * ATLS_MGMT_ARG_STRSZ);

	// iterate through and parse the command name and argument strings
	// if the command does not exist, no further processing is done and atlas_mgmt_parse() returns (-2).
	// General or other fatal errors return (-1). On success, return value of callback function is returned.
	for(int i = 0; i <= bufsz; i++) {
		cc = cbuff[i];
		if(i > 0) lc = cbuff[i - 1];

		if(cc == '\'' || cc == '\"' || cc == '\n' || cc == '\t') {
			// check to see if we have two quotes together (to represent an actual quote mark instead of delimeter)
			// an empty quoted string doesn't count and is skipped
			if(cc == lc && acx > 0) {
				esc_active = 1;
				// ensure escape is active, then copy the quote to output string
			} else {
				if(esc_active) {
					esc_active = 0;
					continue;
				} else {
					esc_active = 1;
					continue;
				}
			}
		} else if((cc == ' ' || cc == '\t' || cc == '\n') && !esc_active && xrec && lc != escaper) {

			// ensure this arg wasn't somehow empty, if so, keep trying
			if(acx == 0) continue;

			// increment arg counter
			argcnt++;

			if(argcnt >= ATLS_MGMT_MAX_ARGS) {
				zlog_error("atlas_mgmt_parse(): Max number of arguments reached! [argcnt = %i] [ATLS_MGMT_MAX_ARGS = %i]\n",argcnt,ATLS_MGMT_MAX_ARGS);
				return -1;
			}

			// perform command-related stuff
			if(argcnt == 1) {
				if((cmatch = atlas_mgmt_cmdluk(cmdname)) == -1) {
					zlog_error("atlas_mgmt_parse(): Command \"%s\" not found!\n",cmdname);
					return -2;
				} else {
					cflags = mgmt_cmddex[cmatch].flags;
					cmd_cback = mgmt_cmddex[cmatch].ccback;

					if(cflags & MGMTC_NOARGS) {
						// Don't bother collecting args (ignore them if they exist)
						exec_rv = cmd_cback(NULL,0);
						return exec_rv;
					} else if(cflags & MGMTC_NOSPLIT) {
						// If MGMTC_NOSPLIT defined, pass whole arg string as one chunk via cbuff pointer
						exec_rv = cmd_cback((char*)(cbuff + acx), 0);
						return exec_rv;
					}

					if(cflags & MGMTC_UCESCAPE) {
						// Use caret for escaping chars
						escaper = '^';
					}
					if(cflags & MGMTC_SLESCAPE) {
						// Use backslash for esacping chars
						escaper = '\\';
					}
				}
			}

			acx = 0;	// reset char index

		} else if((cc == ' ' || cc == '\t') && !xrec && !escaper) {
			// skip whitespace
			continue;
		} else if(escaper && cc == escaper) {
			if(!esc_active) {
				esc_active = 2;
				continue;
			} else {
				esc_active = 0;
			}
		} else if(cc > 32 && cc < 127) {
			xrec = 1;
		}

		// copy valid char to arglist/cmdname
		if(!argcnt) {
			cmdname[acx] = cc;
			cmdname[acx+1] = 0; // append null terminator
		} else {
			arglist[argcnt - 1][acx] = cc;
			arglist[argcnt - 1][acx+1] = 0; // null terminator
		}


		// if parsing the command, convert to lowercase
		if(!argcnt && cc > 64 && cc < 91) cc += 32;

		acx++;		// increment index for current arg

		// ensure we haven't exceeded max limits
		if(!argcnt && acx > ATLS_MGMT_CMD_STRSZ) {
			zlog_error("atlas_mgmt_parse(): command string exceeded max size of 32 bytes!\n");
			return -1;
		} else if(argcnt && acx > ATLS_MGMT_ARG_STRSZ) {
			zlog_error("atlas_mgmt_parse(): argument %i exceeded max size of 256 bytes!\n",argcnt);
			return -1;
		}
	}

	// run command using callback function
	zlog_debug("");
	exec_rv = cmd_cback(arglist, argcnt);

	ATLS_FLEAVE();
	return exec_rv;
}
Beispiel #11
0
int atlas_mgmt_fifo_init(char* pipe_path) {
	struct stat atr_in;
	struct stat atr_out;
	int srv_in, srv_out;

	ATLS_FENTER();

	mgmt_fifo_in.status = STATUS_NOTREADY;
	mgmt_fifo_out.status = STATUS_NOTREADY;
	ATLS_ASSERT_NULLPTR(pipe_path,-1);

	// copy pipe path
	strcpy(mgmt_fifo_in.fifo_path, pipe_path);
	strcpy(mgmt_fifo_out.fifo_path, pipe_path);
	strcat(mgmt_fifo_in.fifo_path,"_in");
	strcat(mgmt_fifo_out.fifo_path,"_out");

	zlog_debug("atlas_mgmt_init(): Initializing Management FIFOs [in=%s/out=%s] ...\n ",mgmt_fifo_in.fifo_path,mgmt_fifo_out.fifo_path);

	// check to see if fifos already exist...
	// In
	if((srv_in = stat(mgmt_fifo_in.fifo_path, &atr_in)) != 0) {
		zlog_error("atlas_mgmt_fifo_init(): FIFO-IN file does not exist. Creating.\n");
		if(mkfifo(mgmt_fifo_in.fifo_path, 0666)) {
			zlog_error("mkfifo() failed to create FIFO-IN file (errno = %i) [%s].\n",errno, mgmt_fifo_in.fifo_path);
			return -1;
		} else {
			zlog_debug("FIFO-IN created OK!\n");
		}
	} else {
		if(!S_ISFIFO(atr_in.st_mode)) {
			zlog_error("FIFO-IN file already exists as a non-FIFO file type! [%s]\n",mgmt_fifo_in.fifo_path);
			return -1;
		}
	}
	// Out
	if((srv_out = stat(mgmt_fifo_out.fifo_path, &atr_out)) != 0) {
		zlog_error("atlas_mgmt_fifo_init(): FIFO-OUT file does not exist. Creating.\n");
		if(mkfifo(mgmt_fifo_out.fifo_path, 0666)) {
			zlog_error("mkfifo() failed to create FIFO-OUT file (errno = %i) [%s].\n",errno, mgmt_fifo_in.fifo_path);
			return -1;
		} else {
			zlog_debug("FIFO-OUT created OK!\n");
		}
	} else {
		if(!S_ISFIFO(atr_out.st_mode)) {
			zlog_error("FIFO-OUT file already exists as a non-FIFO file type! [%s]\n",mgmt_fifo_out.fifo_path);
			return -1;
		}
	}

	// get handle/open the FIFOs
	// In (Rx)
	if((mgmt_fifo_in.fifoHandle = open(mgmt_fifo_in.fifo_path, O_RDONLY | O_NONBLOCK)) == 0) {
		zlog_error("atlas_mgmt_init(): open() failed for mgmt_fifo_in!\n");
		mgmt_fifo_in.status = STATUS_INITFAIL;
		return -1;
	}
	// Out (Tx)
	if((mgmt_fifo_out.fifoHandle = open(mgmt_fifo_out.fifo_path, O_WRONLY | O_NONBLOCK)) == 0) {
		zlog_error("atlas_mgmt_init(): open() failed for mgmt_fifo_out!\n");
		mgmt_fifo_out.status = STATUS_INITFAIL;
		return -1;
	}

	// FIFO setup & ready!
	mgmt_fifo_in.status = STATUS_READY;
	mgmt_fifo_out.status = STATUS_READY;

	zlog_debug("Mgmt FIFOs created successfully!\n");

	ATLS_FLEAVE();
	return 0;
}
Beispiel #12
0
int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
	int len;
	struct ifaddrmsg *ifa;
	struct rtattr *tb[IFA_MAX + 1];
	struct interface *ifp;
	void *addr;
	void *broad;
	uint8_t flags = 0;
	char *label = NULL;
	struct zebra_ns *zns;

	zns = zebra_ns_lookup(ns_id);
	ifa = NLMSG_DATA(h);

	if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
		zlog_warn(
			"Invalid address family: %u received from kernel interface addr change: %u",
			ifa->ifa_family, h->nlmsg_type);
		return 0;
	}

	if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	if (len < 0) {
		zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
			 __PRETTY_FUNCTION__,
			 h->nlmsg_len,
			 (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg)));
		return -1;
	}

	memset(tb, 0, sizeof tb);
	netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);

	ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index);
	if (ifp == NULL) {
		flog_err(
			LIB_ERR_INTERFACE,
			"netlink_interface_addr can't find interface by index %d",
			ifa->ifa_index);
		return -1;
	}

	if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
	{
		char buf[BUFSIZ];
		zlog_debug("netlink_interface_addr %s %s flags 0x%x:",
			   nl_msg_type_to_str(h->nlmsg_type), ifp->name,
			   ifa->ifa_flags);
		if (tb[IFA_LOCAL])
			zlog_debug("  IFA_LOCAL     %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_LOCAL]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_ADDRESS])
			zlog_debug("  IFA_ADDRESS   %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_ADDRESS]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_BROADCAST])
			zlog_debug("  IFA_BROADCAST %s/%d",
				   inet_ntop(ifa->ifa_family,
					     RTA_DATA(tb[IFA_BROADCAST]), buf,
					     BUFSIZ),
				   ifa->ifa_prefixlen);
		if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL])))
			zlog_debug("  IFA_LABEL     %s",
				   (char *)RTA_DATA(tb[IFA_LABEL]));

		if (tb[IFA_CACHEINFO]) {
			struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);
			zlog_debug("  IFA_CACHEINFO pref %d, valid %d",
				   ci->ifa_prefered, ci->ifa_valid);
		}
	}

	/* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
	if (tb[IFA_LOCAL] == NULL)
		tb[IFA_LOCAL] = tb[IFA_ADDRESS];
	if (tb[IFA_ADDRESS] == NULL)
		tb[IFA_ADDRESS] = tb[IFA_LOCAL];

	/* local interface address */
	addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);

	/* is there a peer address? */
	if (tb[IFA_ADDRESS]
	    && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]),
		      RTA_PAYLOAD(tb[IFA_ADDRESS]))) {
		broad = RTA_DATA(tb[IFA_ADDRESS]);
		SET_FLAG(flags, ZEBRA_IFA_PEER);
	} else
		/* seeking a broadcast address */
		broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST])
					   : NULL);

	/* addr is primary key, SOL if we don't have one */
	if (addr == NULL) {
		zlog_debug("%s: NULL address", __func__);
		return -1;
	}

	/* Flags. */
	if (ifa->ifa_flags & IFA_F_SECONDARY)
		SET_FLAG(flags, ZEBRA_IFA_SECONDARY);

	/* Label */
	if (tb[IFA_LABEL])
		label = (char *)RTA_DATA(tb[IFA_LABEL]);

	if (label && strcmp(ifp->name, label) == 0)
		label = NULL;

	/* Register interface address to the interface. */
	if (ifa->ifa_family == AF_INET) {
		if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
			zlog_err(
				"Invalid prefix length: %u received from kernel interface addr change: %u",
				ifa->ifa_prefixlen, h->nlmsg_type);
			return -1;
		}
		if (h->nlmsg_type == RTM_NEWADDR)
			connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
					   ifa->ifa_prefixlen,
					   (struct in_addr *)broad, label);
		else
			connected_delete_ipv4(
				ifp, flags, (struct in_addr *)addr,
				ifa->ifa_prefixlen, (struct in_addr *)broad);
	}
	if (ifa->ifa_family == AF_INET6) {
		if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
			zlog_err(
				"Invalid prefix length: %u received from kernel interface addr change: %u",
				ifa->ifa_prefixlen, h->nlmsg_type);
			return -1;
		}
		if (h->nlmsg_type == RTM_NEWADDR) {
			/* Only consider valid addresses; we'll not get a
			 * notification from
			 * the kernel till IPv6 DAD has completed, but at init
			 * time, Quagga
			 * does query for and will receive all addresses.
			 */
			if (!(ifa->ifa_flags
			      & (IFA_F_DADFAILED | IFA_F_TENTATIVE)))
				connected_add_ipv6(ifp, flags,
						   (struct in6_addr *)addr,
						   (struct in6_addr *)broad,
						   ifa->ifa_prefixlen, label);
		} else
			connected_delete_ipv6(ifp, (struct in6_addr *)addr,
					      (struct in6_addr *)broad,
					      ifa->ifa_prefixlen);
	}

	return 0;
}
Beispiel #13
0
/*
 * Called from interface_lookup_netlink().  This function is only used
 * during bootstrap.
 */
static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
	int len;
	struct ifinfomsg *ifi;
	struct rtattr *tb[IFLA_MAX + 1];
	struct rtattr *linkinfo[IFLA_MAX + 1];
	struct interface *ifp;
	char *name = NULL;
	char *kind = NULL;
	char *desc = NULL;
	char *slave_kind = NULL;
	struct zebra_ns *zns;
	vrf_id_t vrf_id = VRF_DEFAULT;
	zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
	zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
	ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
	ifindex_t link_ifindex = IFINDEX_INTERNAL;

	zns = zebra_ns_lookup(ns_id);
	ifi = NLMSG_DATA(h);

	if (h->nlmsg_type != RTM_NEWLINK)
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
	if (len < 0) {
		zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
			 __PRETTY_FUNCTION__,
			 h->nlmsg_len,
			 (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
		return -1;
	}

	/* We are interested in some AF_BRIDGE notifications. */
	if (ifi->ifi_family == AF_BRIDGE)
		return netlink_bridge_interface(h, len, ns_id, startup);

	/* Looking up interface name. */
	memset(tb, 0, sizeof tb);
	memset(linkinfo, 0, sizeof linkinfo);
	netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);

	/* check for wireless messages to ignore */
	if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("%s: ignoring IFLA_WIRELESS message",
				   __func__);
		return 0;
	}

	if (tb[IFLA_IFNAME] == NULL)
		return -1;
	name = (char *)RTA_DATA(tb[IFLA_IFNAME]);

	if (tb[IFLA_IFALIAS])
		desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]);

	if (tb[IFLA_LINKINFO]) {
		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (linkinfo[IFLA_INFO_KIND])
			kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);

		if (linkinfo[IFLA_INFO_SLAVE_KIND])
			slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);

		netlink_determine_zebra_iftype(kind, &zif_type);
	}

	/* If VRF, create the VRF structure itself. */
	if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) {
		netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
		vrf_id = (vrf_id_t)ifi->ifi_index;
	}

	if (tb[IFLA_MASTER]) {
		if (slave_kind && (strcmp(slave_kind, "vrf") == 0)
		    && !vrf_is_backend_netns()) {
			zif_slave_type = ZEBRA_IF_SLAVE_VRF;
			vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]);
		} else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) {
			zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
			bridge_ifindex =
				*(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
		} else
			zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
	}
	if (vrf_is_backend_netns())
		vrf_id = (vrf_id_t)ns_id;

	/* If linking to another interface, note it. */
	if (tb[IFLA_LINK])
		link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);

	/* Add interface. */
	ifp = if_get_by_name(name, vrf_id, 0);
	set_ifindex(ifp, ifi->ifi_index, zns);
	ifp->flags = ifi->ifi_flags & 0x0000fffff;
	ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
	ifp->metric = 0;
	ifp->speed = get_iflink_speed(ifp);
	ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;

	if (desc)
		ifp->desc = XSTRDUP(MTYPE_TMP, desc);

	/* Set zebra interface type */
	zebra_if_set_ziftype(ifp, zif_type, zif_slave_type);
	if (IS_ZEBRA_IF_VRF(ifp))
		SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);

	/* Update link. */
	zebra_if_update_link(ifp, link_ifindex);

	/* Hardware type and address. */
	ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type);
	netlink_interface_update_hw_addr(tb, ifp);

	if_add_update(ifp);

	/* Extract and save L2 interface information, take additional actions.
	 */
	netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], 1);
	if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
		zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);

	return 0;
}
Beispiel #14
0
static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
			       const char *name)
{
	struct ifinfomsg *ifi;
	struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
	struct rtattr *attr[IFLA_VRF_MAX + 1];
	struct vrf *vrf;
	struct zebra_vrf *zvrf;
	uint32_t nl_table_id;

	ifi = NLMSG_DATA(h);

	memset(linkinfo, 0, sizeof linkinfo);
	parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);

	if (!linkinfo[IFLA_INFO_DATA]) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug(
				"%s: IFLA_INFO_DATA missing from VRF message: %s",
				__func__, name);
		return;
	}

	memset(attr, 0, sizeof attr);
	parse_rtattr_nested(attr, IFLA_VRF_MAX, linkinfo[IFLA_INFO_DATA]);
	if (!attr[IFLA_VRF_TABLE]) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug(
				"%s: IFLA_VRF_TABLE missing from VRF message: %s",
				__func__, name);
		return;
	}

	nl_table_id = *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]);

	if (h->nlmsg_type == RTM_NEWLINK) {
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("RTM_NEWLINK for VRF %s(%u) table %u", name,
				   ifi->ifi_index, nl_table_id);

		/*
		 * vrf_get is implied creation if it does not exist
		 */
		vrf = vrf_get((vrf_id_t)ifi->ifi_index,
			      name); // It would create vrf
		if (!vrf) {
			flog_err(LIB_ERR_INTERFACE, "VRF %s id %u not created",
				  name, ifi->ifi_index);
			return;
		}

		/*
		 * This is the only place that we get the actual kernel table_id
		 * being used.  We need it to set the table_id of the routes
		 * we are passing to the kernel.... And to throw some totally
		 * awesome parties. that too.
		 *
		 * At this point we *must* have a zvrf because the vrf_create
		 * callback creates one.  We *must* set the table id
		 * before the vrf_enable because of( at the very least )
		 * static routes being delayed for installation until
		 * during the vrf_enable callbacks.
		 */
		zvrf = (struct zebra_vrf *)vrf->info;
		zvrf->table_id = nl_table_id;

		/* Enable the created VRF. */
		if (!vrf_enable(vrf)) {
			flog_err(LIB_ERR_INTERFACE,
				  "Failed to enable VRF %s id %u", name,
				  ifi->ifi_index);
			return;
		}

	} else // h->nlmsg_type == RTM_DELLINK
	{
		if (IS_ZEBRA_DEBUG_KERNEL)
			zlog_debug("RTM_DELLINK for VRF %s(%u)", name,
				   ifi->ifi_index);

		vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index);

		if (!vrf) {
			zlog_warn("%s: vrf not found", __func__);
			return;
		}

		vrf_delete(vrf);
	}
}
Beispiel #15
0
/* Status goes to Established.  Send keepalive packet then make first
   update information. */
static int
bgp_establish (struct peer *peer)
{
  struct bgp_notify *notify;
  afi_t afi;
  safi_t safi;
  int nsf_af_count = 0;

  /* Reset capability open status flag. */
  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
    SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);

  /* Clear last notification data. */
  notify = &peer->notify;
  if (notify->data)
    XFREE (MTYPE_TMP, notify->data);
  memset (notify, 0, sizeof (struct bgp_notify));

  /* Clear start timer value to default. */
  peer->v_start = BGP_INIT_START_TIMER;

  /* Increment established count. */
  peer->established++;
  bgp_fsm_change_status (peer, Established);

  /* bgp log-neighbor-changes of neighbor Up */
  if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
    zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);

  /* graceful restart */
  UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
      {
	if (peer->afc_nego[afi][safi]
	    && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
	    && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
	  {
	    if (peer->nsf[afi][safi]
		&& ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
	      bgp_clear_stale_route (peer, afi, safi);

	    peer->nsf[afi][safi] = 1;
	    nsf_af_count++;
	  }
	else
	  {
	    if (peer->nsf[afi][safi])
	      bgp_clear_stale_route (peer, afi, safi);
	    peer->nsf[afi][safi] = 0;
	  }
      }

  if (nsf_af_count)
    SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
  else
    {
      UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
      if (peer->t_gr_stale)
	{
	  BGP_TIMER_OFF (peer->t_gr_stale);
	  if (BGP_DEBUG (events, EVENTS))
	    zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
	}
    }

  if (peer->t_gr_restart)
    {
      BGP_TIMER_OFF (peer->t_gr_restart);
      if (BGP_DEBUG (events, EVENTS))
	zlog_debug ("%s graceful restart timer stopped", peer->host);
    }

#ifdef HAVE_SNMP
  bgpTrapEstablished (peer);
#endif /* HAVE_SNMP */

  /* Reset uptime, send keepalive, send current table. */
  peer->uptime = bgp_clock ();

  /* Send route-refresh when ORF is enabled */
  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
	{
	  if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
	    bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
				    REFRESH_IMMEDIATE, 0);
	  else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
	    bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
				    REFRESH_IMMEDIATE, 0);
	}

  if (peer->v_keepalive)
    bgp_keepalive_send (peer);

  /* First update is deferred until ORF or ROUTE-REFRESH is received */
  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
	if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
	    || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
	  SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);

  bgp_announce_route_all (peer);

  BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);

  return 0;
}
Beispiel #16
0
static int
ospf_interface_state_up (int command, struct zclient *zclient,
                         zebra_size_t length)
{
  struct interface *ifp;
  struct ospf_interface *oi;
  struct route_node *rn;

  ifp = zebra_interface_if_lookup (zclient->ibuf);

  if (ifp == NULL)
    return 0;

  /* Interface is already up. */
  if (if_is_operative (ifp))
    {
      /* Temporarily keep ifp values. */
      struct interface if_tmp;
      memcpy (&if_tmp, ifp, sizeof (struct interface));

      zebra_interface_if_set_value (zclient->ibuf, ifp);

      if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
        zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);

      if (if_tmp.bandwidth != ifp->bandwidth)
        {
          if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
            zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
                       ifp->name, if_tmp.bandwidth, ifp->bandwidth);

          ospf_if_recalculate_output_cost (ifp);
        }

      if (if_tmp.mtu != ifp->mtu)
        {
          if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
            zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.",
                       ifp->name, if_tmp.mtu, ifp->mtu);

	  /* Must reset the interface (simulate down/up) when MTU changes. */
          ospf_if_reset(ifp);
	}
      return 0;
    }

  zebra_interface_if_set_value (zclient->ibuf, ifp);

  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
    zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name);

  for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
    {
      if ((oi = rn->info) == NULL)
        continue;

      ospf_if_up (oi);
    }

  return 0;
}
Beispiel #17
0
/* Kernel routing table and interface updates via routing socket. */
static int
kernel_read (struct thread *thread)
{
  int sock;
  int nbytes;
  struct rt_msghdr *rtm;

  /*
   * This must be big enough for any message the kernel might send.
   * Rather than determining how many sockaddrs of what size might be
   * in each particular message, just use RTAX_MAX of sockaddr_storage
   * for each.  Note that the sockaddrs must be after each message
   * definition, or rather after whichever happens to be the largest,
   * since the buffer needs to be big enough for a message and the
   * sockaddrs together.
   */
  union 
  {
    /* Routing information. */
    struct 
    {
      struct rt_msghdr rtm;
      struct sockaddr_storage addr[RTAX_MAX];
    } r;

    /* Interface information. */
    struct
    {
      struct if_msghdr ifm;
      struct sockaddr_storage addr[RTAX_MAX];
    } im;

    /* Interface address information. */
    struct
    {
      struct ifa_msghdr ifa;
      struct sockaddr_storage addr[RTAX_MAX];
    } ia;

#ifdef RTM_IFANNOUNCE
    /* Interface arrival/departure */
    struct
    {
      struct if_announcemsghdr ifan;
      struct sockaddr_storage addr[RTAX_MAX];
    } ian;
#endif /* RTM_IFANNOUNCE */

  } buf;

  /* Fetch routing socket. */
  sock = THREAD_FD (thread);

  nbytes= read (sock, &buf, sizeof buf);

  if (nbytes <= 0)
    {
      if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
	zlog_warn ("routing socket error: %s", safe_strerror (errno));
      return 0;
    }

  thread_add_read (zebrad.master, kernel_read, NULL, sock);

  if (IS_ZEBRA_DEBUG_KERNEL)
    rtmsg_debug (&buf.r.rtm);

  rtm = &buf.r.rtm;

  /*
   * Ensure that we didn't drop any data, so that processing routines
   * can assume they have the whole message.
   */
  if (rtm->rtm_msglen != nbytes)
    {
      zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n",
		 rtm->rtm_msglen, nbytes, rtm->rtm_type);
      return -1;
    }

  switch (rtm->rtm_type)
    {
    case RTM_ADD:
    case RTM_DELETE:
    case RTM_CHANGE:
      rtm_read (rtm);
      break;
    case RTM_IFINFO:
      ifm_read (&buf.im.ifm);
      break;
    case RTM_NEWADDR:
    case RTM_DELADDR:
      ifam_read (&buf.ia.ifa);
      break;
#ifdef RTM_IFANNOUNCE
    case RTM_IFANNOUNCE:
      ifan_read (&buf.ian.ifan);
      break;
#endif /* RTM_IFANNOUNCE */
    default:
      if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type);
      break;
    }
  return 0;
}
Beispiel #18
0
void
ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
{
  u_char message;
  u_char distance;
  u_char flags;
  int psize;
  struct stream *s;
  struct ospf_path *path;
  struct listnode *node;

  if (zclient->redist[ZEBRA_ROUTE_OSPF])
    {
      message = 0;
      flags = 0;

      /* OSPF pass nexthop and metric */
      SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
      SET_FLAG (message, ZAPI_MESSAGE_METRIC);

      /* Distance value. */
      distance = ospf_distance_apply (p, or);
      if (distance)
        SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);

      /* Make packet. */
      s = zclient->obuf;
      stream_reset (s);

      /* Put command, type, flags, message. */
      zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD);
      stream_putc (s, ZEBRA_ROUTE_OSPF);
      stream_putc (s, flags);
      stream_putc (s, message);
      stream_putw (s, SAFI_UNICAST);

      /* Put prefix information. */
      psize = PSIZE (p->prefixlen);
      stream_putc (s, p->prefixlen);
      stream_write (s, (u_char *) & p->prefix, psize);

      /* Nexthop count. */
      stream_putc (s, or->paths->count);

      /* Nexthop, ifindex, distance and metric information. */
      for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
        {
          if (path->nexthop.s_addr != INADDR_ANY &&
	      path->ifindex != 0)
            {
              stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX);
              stream_put_in_addr (s, &path->nexthop);
	      stream_putl (s, path->ifindex);
            }
          else if (path->nexthop.s_addr != INADDR_ANY)
            {
              stream_putc (s, ZEBRA_NEXTHOP_IPV4);
              stream_put_in_addr (s, &path->nexthop);
            }
          else
            {
              stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
              if (path->ifindex)
                stream_putl (s, path->ifindex);
              else
                stream_putl (s, 0);
            }

          if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
            {
	      char buf[2][INET_ADDRSTRLEN];
	      zlog_debug("Zebra: Route add %s/%d nexthop %s",
			 inet_ntop(AF_INET, &p->prefix,
				   buf[0], sizeof(buf[0])),
			 p->prefixlen,
			 inet_ntop(AF_INET, &path->nexthop,
				   buf[1], sizeof(buf[1])));
            }
        }

      if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
        stream_putc (s, distance);
      if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
        {
          if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
            stream_putl (s, or->cost + or->u.ext.type2_cost);
          else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
            stream_putl (s, or->u.ext.type2_cost);
          else
            stream_putl (s, or->cost);
        }

      stream_putw_at (s, 0, stream_get_endp (s));

      zclient_send_message(zclient);
    }
Beispiel #19
0
/* Address read from struct ifa_msghdr. */
static void
ifam_read_mesg (struct ifa_msghdr *ifm,
		union sockunion *addr,
		union sockunion *mask,
		union sockunion *brd,
		char *ifname,
		short *ifnlen)
{
  caddr_t pnt, end;
  union sockunion dst;
  union sockunion gateway;

  pnt = (caddr_t)(ifm + 1);
  end = ((caddr_t)ifm) + ifm->ifam_msglen;

  /* Be sure structure is cleared */
  memset (mask, 0, sizeof (union sockunion));
  memset (addr, 0, sizeof (union sockunion));
  memset (brd, 0, sizeof (union sockunion));
  memset (&dst, 0, sizeof (union sockunion));
  memset (&gateway, 0, sizeof (union sockunion));

  /* We fetch each socket variable into sockunion. */
  RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt);
  RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt);
  RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
  RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
  RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt);
  RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
  RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt);

  if (IS_ZEBRA_DEBUG_KERNEL)
    {
      switch (sockunion_family(addr))
        {
	case AF_INET:
	  {
	    char buf[4][INET_ADDRSTRLEN];
	    zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
			"ifam_flags 0x%x, addr %s/%d broad %s dst %s "
			"gateway %s",
			__func__, ifm->ifam_index,
			(ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
			ifm->ifam_flags,
			inet_ntop(AF_INET,&addr->sin.sin_addr,
			          buf[0],sizeof(buf[0])),
			ip_masklen(mask->sin.sin_addr),
			inet_ntop(AF_INET,&brd->sin.sin_addr,
			          buf[1],sizeof(buf[1])),
			inet_ntop(AF_INET,&dst.sin.sin_addr,
			          buf[2],sizeof(buf[2])),
			inet_ntop(AF_INET,&gateway.sin.sin_addr,
			          buf[3],sizeof(buf[3])));
	  }
	  break;
#ifdef HAVE_IPV6
	case AF_INET6:
	  {
	    char buf[4][INET6_ADDRSTRLEN];
	    zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
			"ifam_flags 0x%x, addr %s/%d broad %s dst %s "
			"gateway %s",
			__func__, ifm->ifam_index, 
			(ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
			ifm->ifam_flags,
			inet_ntop(AF_INET6,&addr->sin6.sin6_addr,
			          buf[0],sizeof(buf[0])),
			ip6_masklen(mask->sin6.sin6_addr),
			inet_ntop(AF_INET6,&brd->sin6.sin6_addr,
			          buf[1],sizeof(buf[1])),
			inet_ntop(AF_INET6,&dst.sin6.sin6_addr,
			          buf[2],sizeof(buf[2])),
			inet_ntop(AF_INET6,&gateway.sin6.sin6_addr,
			          buf[3],sizeof(buf[3])));
	  }
	  break;
#endif /* HAVE_IPV6 */
        default:
	  zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x",
		      __func__, ifm->ifam_index, 
		      (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs);
	  break;
        }
    }

  /* Assert read up end point matches to end point */
  if (pnt != end)
    zlog_warn ("ifam_read() doesn't read all socket data");
}
Beispiel #20
0
static void parse_irdp_packet(char *p, int len, struct interface *ifp)
{
	struct ip *ip = (struct ip *)p;
	struct icmphdr *icmp;
	struct in_addr src;
	int ip_hlen, iplen, datalen;
	struct zebra_if *zi;
	struct irdp_interface *irdp;

	zi = ifp->info;
	if (!zi)
		return;

	irdp = &zi->irdp;
	if (!irdp)
		return;

	ip_hlen = ip->ip_hl << 2;

	sockopt_iphdrincl_swab_systoh(ip);

	iplen = ip->ip_len;
	datalen = len - ip_hlen;
	src = ip->ip_src;

	if (len != iplen) {
		zlog_err("IRDP: RX length doesnt match IP length");
		return;
	}

	if (iplen < ICMP_MINLEN) {
		zlog_err("IRDP: RX ICMP packet too short from %s\n",
			 inet_ntoa(src));
		return;
	}

	/* XXX: RAW doesnt receive link-layer, surely? ??? */
	/* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
	   len of IP-header) 14+20 */
	if (iplen > IRDP_RX_BUF - 34) {
		zlog_err("IRDP: RX ICMP packet too long from %s\n",
			 inet_ntoa(src));
		return;
	}

	icmp = (struct icmphdr *)(p + ip_hlen);

	/* check icmp checksum */
	if (in_cksum(icmp, datalen) != icmp->checksum) {
		zlog_warn
		    ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
		     inet_ntoa(src));
		return;
	}

	/* Handle just only IRDP */
	if (!(icmp->type == ICMP_ROUTERADVERT
	      || icmp->type == ICMP_ROUTERSOLICIT))
		return;

	if (icmp->code != 0) {
		zlog_warn("IRDP: RX packet type %d from %s. Bad ICMP type code,"
			  " silently ignored", icmp->type, inet_ntoa(src));
		return;
	}

	if (!((ntohl(ip->ip_dst.s_addr) == INADDR_BROADCAST)
	      && (irdp->flags & IF_BROADCAST))
	    ||
	    (ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
	     && !(irdp->flags & IF_BROADCAST))) {
		zlog_warn
		    ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
		     inet_ntoa(src),
		     ntohl(ip->ip_dst.s_addr) ==
		     INADDR_ALLRTRS_GROUP ? "multicast" : inet_ntoa(ip->ip_dst),
		     ifp->name,
		     irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");

		zlog_warn("IRDP: Please correct settings\n");
		return;
	}

	switch (icmp->type) {
	case ICMP_ROUTERADVERT:
		break;

	case ICMP_ROUTERSOLICIT:

		if (irdp->flags & IF_DEBUG_MESSAGES)
			zlog_debug("IRDP: RX Solicit on %s from %s\n",
				   ifp->name, inet_ntoa(src));

		process_solicit(ifp);
		break;

	default:
		zlog_warn
		    ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
		     icmp->type, inet_ntoa(src));
	}
}
Beispiel #21
0
/* Accept bgp connection. */
static int
bgp_accept (struct thread *thread)
{
    int bgp_sock;
    int accept_sock;
    union sockunion su;
    struct bgp_listener *listener = THREAD_ARG(thread);
    struct peer *peer;
    struct peer *peer1;
    char buf[SU_ADDRSTRLEN];

    /* Register accept thread. */
    accept_sock = THREAD_FD (thread);
    if (accept_sock < 0)
    {
        zlog_err ("accept_sock is nevative value %d", accept_sock);
        return -1;
    }
    listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock);

    /* Accept client connection. */
    bgp_sock = sockunion_accept (accept_sock, &su);
    if (bgp_sock < 0)
    {
        zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno));
        return -1;
    }
    set_nonblocking (bgp_sock);

    if (BGP_DEBUG (events, EVENTS))
        zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf));

    /* Check remote IP address */
    peer1 = peer_lookup (NULL, &su);
    if (! peer1 || peer1->status == Idle)
    {
        if (BGP_DEBUG (events, EVENTS))
        {
            if (! peer1)
                zlog_debug ("[Event] BGP connection IP address %s is not configured",
                            inet_sutop (&su, buf));
            else
                zlog_debug ("[Event] BGP connection IP address %s is Idle state",
                            inet_sutop (&su, buf));
        }
        close (bgp_sock);
        return -1;
    }

    /* In case of peer is EBGP, we should set TTL for this connection.  */
    if (peer1->sort == BGP_PEER_EBGP) {
        sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl);
        if (peer1->gtsm_hops)
            sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops);
    }

    /* Make dummy peer until read Open packet. */
    if (BGP_DEBUG (events, EVENTS))
        zlog_debug ("[Event] Make dummy peer structure until read Open packet");

    {
        char buf[SU_ADDRSTRLEN];

        peer = peer_create_accept (peer1->bgp);
        SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
        peer->su = su;
        peer->fd = bgp_sock;
        peer->status = Active;
        peer->local_id = peer1->local_id;
        peer->v_holdtime = BGP_LARGE_HOLDTIME;

        /* Make peer's address string. */
        sockunion2str (&su, buf, SU_ADDRSTRLEN);
        peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
    }

    BGP_EVENT_ADD (peer, TCP_connection_open);

    return 0;
}
Beispiel #22
0
static int
bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
{
  struct stream *s = BGP_INPUT (peer);
  struct capability_orf_entry entry;
  afi_t afi;
  safi_t safi;
  u_char type;
  u_char mode;
  u_int16_t sm_cap = 0; /* capability send-mode receive */
  u_int16_t rm_cap = 0; /* capability receive-mode receive */ 
  int i;

  /* ORF Entry header */
  bgp_capability_mp_data (s, &entry.mpc);
  entry.num = stream_getc (s);
  afi = entry.mpc.afi;
  safi = entry.mpc.safi;
  
  if (BGP_DEBUG (normal, NORMAL))
    zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
	        peer->host, entry.mpc.afi, entry.mpc.safi);

  /* Check AFI and SAFI. */
  if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
    {
      zlog_info ("%s Addr-family %d/%d not supported."
                 " Ignoring the ORF capability",
                 peer->host, entry.mpc.afi, entry.mpc.safi);
      return 0;
    }
  
  /* validate number field */
  if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
    {
      zlog_info ("%s ORF Capability entry length error,"
                 " Cap length %u, num %u",
                 peer->host, hdr->length, entry.num);
      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
      return -1;
    }

  for (i = 0 ; i < entry.num ; i++)
    {
      type = stream_getc(s);
      mode = stream_getc(s);
      
      /* ORF Mode error check */
      switch (mode)
        {
          case ORF_MODE_BOTH:
          case ORF_MODE_SEND:
          case ORF_MODE_RECEIVE:
            break;
          default:
	    bgp_capability_orf_not_support (peer, afi, safi, type, mode);
	    continue;
	}
      /* ORF Type and afi/safi error checks */
      /* capcode versus type */
      switch (hdr->code)
        {
          case CAPABILITY_CODE_ORF:
            switch (type)
              {
                case ORF_TYPE_PREFIX:
                  break;
                default:
                  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
                  continue;
              }
            break;
          case CAPABILITY_CODE_ORF_OLD:
            switch (type)
              {
                case ORF_TYPE_PREFIX_OLD:
                  break;
                default:
                  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
                  continue;
              }
            break;
          default:
            bgp_capability_orf_not_support (peer, afi, safi, type, mode);
            continue;
        }
                
      /* AFI vs SAFI */
      if (!((afi == AFI_IP && safi == SAFI_UNICAST)
            || (afi == AFI_IP && safi == SAFI_MULTICAST)
            || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
        {
          bgp_capability_orf_not_support (peer, afi, safi, type, mode);
          continue;
        }
      
      if (BGP_DEBUG (normal, NORMAL))
        zlog_debug ("%s OPEN has %s ORF capability"
                    " as %s for afi/safi: %d/%d",
                    peer->host, LOOKUP (orf_type_str, type),
                    LOOKUP (orf_mode_str, mode),
                    entry.mpc.afi, safi);

      if (hdr->code == CAPABILITY_CODE_ORF)
	{
          sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
          rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
	}
      else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
	{
          sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
          rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
	}
      else
	{
	  bgp_capability_orf_not_support (peer, afi, safi, type, mode);
	  continue;
	}

      switch (mode)
	{
	  case ORF_MODE_BOTH:
	    SET_FLAG (peer->af_cap[afi][safi], sm_cap);
	    SET_FLAG (peer->af_cap[afi][safi], rm_cap);
	    break;
	  case ORF_MODE_SEND:
	    SET_FLAG (peer->af_cap[afi][safi], sm_cap);
	    break;
	  case ORF_MODE_RECEIVE:
	    SET_FLAG (peer->af_cap[afi][safi], rm_cap);
	    break;
	}
    }
  return 0;
}
Beispiel #23
0
static int pim_sock_read(struct thread *t)
{
  struct interface *ifp;
  struct pim_interface *pim_ifp;
  int fd;
  struct sockaddr_in from;
  struct sockaddr_in to;
  socklen_t fromlen = sizeof(from);
  socklen_t tolen = sizeof(to);
  uint8_t buf[PIM_PIM_BUFSIZE_READ];
  int len;
  ifindex_t ifindex = -1;
  int result = -1; /* defaults to bad */

  zassert(t);

  ifp = THREAD_ARG(t);
  zassert(ifp);

  fd = THREAD_FD(t);

  pim_ifp = ifp->info;
  zassert(pim_ifp);

  zassert(fd == pim_ifp->pim_sock_fd);

  len = pim_socket_recvfromto(fd, buf, sizeof(buf),
			      &from, &fromlen,
			      &to, &tolen,
			      &ifindex);
  if (len < 0) {
    zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
	      fd, errno, safe_strerror(errno));
    goto done;
  }

  if (PIM_DEBUG_PIM_PACKETS) {
    char from_str[100];
    char to_str[100];
    
    if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
      sprintf(from_str, "<from?>");
    if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
      sprintf(to_str, "<to?>");
    
    zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
	       len, from_str, to_str, fd, ifindex, ifp->ifindex);
  }

  if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
    pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
  }

#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
  /* ifindex sanity check */
  if (ifindex != (int) ifp->ifindex) {
    char from_str[100];
    char to_str[100];
    struct interface *recv_ifp;

    if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
      sprintf(from_str, "<from?>");
    if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
      sprintf(to_str, "<to?>");

    recv_ifp = if_lookup_by_index(ifindex);
    if (recv_ifp) {
      zassert(ifindex == (int) recv_ifp->ifindex);
    }

#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
    zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
	      from_str, to_str, fd,
	      ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
	      ifp->ifindex, ifp->name);
#endif
    goto done;
  }
#endif

  int fail = pim_pim_packet(ifp, buf, len);
  if (fail) {
    zlog_warn("%s: pim_pim_packet() return=%d",
              __PRETTY_FUNCTION__, fail);
    goto done;
  }

  result = 0; /* good */

 done:
  pim_sock_read_on(ifp);

  if (result) {
    ++pim_ifp->pim_ifstat_hello_recvfail;
  }

  return result;
}
Beispiel #24
0
/* Parse given capability.
 * XXX: This is reading into a stream, but not using stream API
 */
static int
bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
{
  int ret;
  struct stream *s = BGP_INPUT (peer);
  size_t end = stream_get_getp (s) + length;
  
  assert (STREAM_READABLE (s) >= length);
  
  while (stream_get_getp (s) < end)
    {
      size_t start;
      u_char *sp = stream_pnt (s);
      struct capability_header caphdr;
      
      /* We need at least capability code and capability length. */
      if (stream_get_getp(s) + 2 > end)
	{
	  zlog_info ("%s Capability length error (< header)", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}
      
      caphdr.code = stream_getc (s);
      caphdr.length = stream_getc (s);
      start = stream_get_getp (s);
      
      /* Capability length check sanity check. */
      if (start + caphdr.length > end)
	{
	  zlog_info ("%s Capability length error (< length)", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}
      
      if (BGP_DEBUG (normal, NORMAL))
	zlog_debug ("%s OPEN has %s capability (%u), length %u",
		   peer->host,
		   LOOKUP (capcode_str, caphdr.code),
		   caphdr.code, caphdr.length);
      
      /* Length sanity check, type-specific, for known capabilities */
      switch (caphdr.code)
        {
          case CAPABILITY_CODE_MP:
          case CAPABILITY_CODE_REFRESH:
          case CAPABILITY_CODE_REFRESH_OLD:
          case CAPABILITY_CODE_ORF:
          case CAPABILITY_CODE_ORF_OLD:
          case CAPABILITY_CODE_RESTART:
          case CAPABILITY_CODE_AS4:
          case CAPABILITY_CODE_DYNAMIC:
              /* Check length. */
              if (caphdr.length < cap_minsizes[caphdr.code])
                {
                  zlog_info ("%s %s Capability length error: got %u,"
                             " expected at least %u",
                             peer->host, 
                             LOOKUP (capcode_str, caphdr.code),
                             caphdr.length, 
			     (unsigned) cap_minsizes[caphdr.code]);
                  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
                  return -1;
                }
          /* we deliberately ignore unknown codes, see below */
          default:
            break;
        }
      
      switch (caphdr.code)
        {
          case CAPABILITY_CODE_MP:
            {
              /* Ignore capability when override-capability is set. */
              if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
                {
                  /* Set negotiated value. */
                  ret = bgp_capability_mp (peer, &caphdr);

                  /* Unsupported Capability. */
                  if (ret < 0)
                    {
                      /* Store return data. */
                      memcpy (*error, sp, caphdr.length + 2);
                      *error += caphdr.length + 2;
                    }
                }
            }
            break;
          case CAPABILITY_CODE_REFRESH:
          case CAPABILITY_CODE_REFRESH_OLD:
            {
              /* BGP refresh capability */
              if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
                SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
              else
                SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
            }
            break;
          case CAPABILITY_CODE_ORF:
          case CAPABILITY_CODE_ORF_OLD:
            if (bgp_capability_orf (peer, &caphdr))
              return -1;
            break;
          case CAPABILITY_CODE_RESTART:
            if (bgp_capability_restart (peer, &caphdr))
              return -1;
            break;
          case CAPABILITY_CODE_DYNAMIC:
            SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
            break;
          case CAPABILITY_CODE_AS4:
              /* Already handled as a special-case parsing of the capabilities
               * at the beginning of OPEN processing. So we care not a jot
               * for the value really, only error case.
               */
              if (!bgp_capability_as4 (peer, &caphdr))
                return -1;
              break;            
          default:
            if (caphdr.code > 128)
              {
                /* We don't send Notification for unknown vendor specific
                   capabilities.  It seems reasonable for now...  */
                zlog_warn ("%s Vendor specific capability %d",
                           peer->host, caphdr.code);
              }
            else
              {
                zlog_warn ("%s unrecognized capability code: %d - ignored",
                           peer->host, caphdr.code);
                memcpy (*error, sp, caphdr.length + 2);
                *error += caphdr.length + 2;
              }
          }
      if (stream_get_getp(s) != (start + caphdr.length))
        {
          if (stream_get_getp(s) > (start + caphdr.length))
            zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
                       peer->host, LOOKUP (capcode_str, caphdr.code),
                       caphdr.length);
          stream_set_getp (s, start + caphdr.length);
        }
    }
  return 0;
}
Beispiel #25
0
/* RFC2740 3.8.1.  Calculating the shortest path tree for an area */
void
ospf6_spf_calculation (u_int32_t router_id,
                       struct ospf6_route_table *result_table,
                       struct ospf6_area *oa)
{
  struct pqueue *candidate_list;
  struct ospf6_vertex *root, *v, *w;
  int i;
  int size;
  caddr_t lsdesc;
  struct ospf6_lsa *lsa;

  ospf6_spf_table_finish (result_table);

  /* Install the calculating router itself as the root of the SPF tree */
  /* construct root vertex */
  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
                           router_id, oa->lsdb);
  if (lsa == NULL)
    return;

  /* initialize */
  candidate_list = pqueue_create ();
  candidate_list->cmp = ospf6_vertex_cmp;

  root = ospf6_vertex_create (lsa);
  root->area = oa;
  root->cost = 0;
  root->hops = 0;
  root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
  inet_pton (AF_INET6, "::1", &root->nexthop[0].address);

  /* Actually insert root to the candidate-list as the only candidate */
  pqueue_enqueue (root, candidate_list);

  /* Iterate until candidate-list becomes empty */
  while (candidate_list->size)
    {
      /* get closest candidate from priority queue */
      v = pqueue_dequeue (candidate_list);

      /* installing may result in merging or rejecting of the vertex */
      if (ospf6_spf_install (v, result_table) < 0)
        continue;

      /* Skip overloaded routers */
      if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
	   ospf6_router_is_stub_router (v->lsa)))
	continue;

      /* For each LS description in the just-added vertex V's LSA */
      size = (VERTEX_IS_TYPE (ROUTER, v) ?
              sizeof (struct ospf6_router_lsdesc) :
              sizeof (struct ospf6_network_lsdesc));
      for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
           lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
        {
          lsa = ospf6_lsdesc_lsa (lsdesc, v);
          if (lsa == NULL)
            continue;

          if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
            continue;

          w = ospf6_vertex_create (lsa);
          w->area = oa;
          w->parent = v;
          if (VERTEX_IS_TYPE (ROUTER, v))
            {
              w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
              w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
            }
          else /* NETWORK */
            {
              w->cost = v->cost;
              w->hops = v->hops + 1;
            }

          /* nexthop calculation */
          if (w->hops == 0)
            w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
          else if (w->hops == 1 && v->hops == 0)
            ospf6_nexthop_calc (w, v, lsdesc);
          else
            {
              for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
                   i < OSPF6_MULTI_PATH_LIMIT; i++)
                ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
            }

          /* add new candidate to the candidate_list */
          if (IS_OSPF6_DEBUG_SPF (PROCESS))
            zlog_debug ("  New candidate: %s hops %d cost %d",
			w->name, w->hops, w->cost);
          pqueue_enqueue (w, candidate_list);
        }
    }

  pqueue_delete (candidate_list);

  oa->spf_calculation++;
}
Beispiel #26
0
/* Parse open option */
int
bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
{
  int ret;
  u_char *error;
  u_char error_data[BGP_MAX_PACKET_SIZE];
  struct stream *s = BGP_INPUT(peer);
  size_t end = stream_get_getp (s) + length;

  ret = 0;
  error = error_data;

  if (BGP_DEBUG (normal, NORMAL))
    zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
	       peer->host, length);
  
  while (stream_get_getp(s) < end)
    {
      u_char opt_type;
      u_char opt_length;
      
      /* Must have at least an OPEN option header */
      if (STREAM_READABLE(s) < 2)
	{
	  zlog_info ("%s Option length error", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}

      /* Fetch option type and length. */
      opt_type = stream_getc (s);
      opt_length = stream_getc (s);
      
      /* Option length check. */
      if (STREAM_READABLE (s) < opt_length)
	{
	  zlog_info ("%s Option length error", peer->host);
	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
	  return -1;
	}

      if (BGP_DEBUG (normal, NORMAL))
	zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
		   peer->host, opt_type,
		   opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
		   opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
		   opt_length);
  
      switch (opt_type)
	{
	case BGP_OPEN_OPT_AUTH:
	  ret = bgp_auth_parse (peer, opt_length);
	  break;
	case BGP_OPEN_OPT_CAP:
	  ret = bgp_capability_parse (peer, opt_length, &error);
	  *capability = 1;
	  break;
	default:
	  bgp_notify_send (peer, 
			   BGP_NOTIFY_OPEN_ERR, 
			   BGP_NOTIFY_OPEN_UNSUP_PARAM); 
	  ret = -1;
	  break;
	}

      /* Parse error.  To accumulate all unsupported capability codes,
         bgp_capability_parse does not return -1 when encounter
         unsupported capability code.  To detect that, please check
         error and erro_data pointer, like below.  */
      if (ret < 0)
	return -1;
    }

  /* All OPEN option is parsed.  Check capability when strict compare
     flag is enabled.*/
  if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
    {
      /* If Unsupported Capability exists. */
      if (error != error_data)
	{
	  bgp_notify_send_with_data (peer, 
				     BGP_NOTIFY_OPEN_ERR, 
				     BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
				     error_data, error - error_data);
	  return -1;
	}

      /* Check local capability does not negotiated with remote
         peer. */
      if (! strict_capability_same (peer))
	{
	  bgp_notify_send (peer, 
			   BGP_NOTIFY_OPEN_ERR, 
			   BGP_NOTIFY_OPEN_UNSUP_CAPBL);
	  return -1;
	}
    }

  /* Check there is no common capability send Unsupported Capability
     error. */
  if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
    {
      if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] 
	  && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
	  && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
	  && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
	  && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
	{
	  plog_err (peer->log, "%s [Error] No common capability", peer->host);

	  if (error != error_data)

	    bgp_notify_send_with_data (peer, 
				       BGP_NOTIFY_OPEN_ERR, 
				       BGP_NOTIFY_OPEN_UNSUP_CAPBL, 
				       error_data, error - error_data);
	  else
	    bgp_notify_send (peer, 
			     BGP_NOTIFY_OPEN_ERR, 
			     BGP_NOTIFY_OPEN_UNSUP_CAPBL);
	  return -1;
	}
    }
  return 0;
}
Beispiel #27
0
/* Add schedule for SPF calculation.  To avoid frequenst SPF calc, we
   set timer for SPF calc. */
void
ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
{
  unsigned long delay, elapsed, ht;
  struct timeval now, result;

  ospf6_set_spf_reason(ospf6, reason);

  if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
    {
      char rbuf[32];
      ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
      zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
    }

  /* OSPF instance does not exist. */
  if (ospf6 == NULL)
    return;

  /* SPF calculation timer is already scheduled. */
  if (ospf6->t_spf_calc)
    {
      if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
        zlog_debug ("SPF: calculation timer is already scheduled: %p",
                    (void *)ospf6->t_spf_calc);
      return;
    }

  /* XXX Monotic timers: we only care about relative time here. */
  now = recent_relative_time ();
  timersub (&now, &ospf6->ts_spf, &result);

  elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
  ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;

  if (ht > ospf6->spf_max_holdtime)
    ht = ospf6->spf_max_holdtime;

  /* Get SPF calculation delay time. */
  if (elapsed < ht)
    {
      /* Got an event within the hold time of last SPF. We need to
       * increase the hold_multiplier, if it's not already at/past
       * maximum value, and wasn't already increased..
       */
      if (ht < ospf6->spf_max_holdtime)
        ospf6->spf_hold_multiplier++;

      /* always honour the SPF initial delay */
      if ( (ht - elapsed) < ospf6->spf_delay)
        delay = ospf6->spf_delay;
      else
        delay = ht - elapsed;
    }
  else
    {
      /* Event is past required hold-time of last SPF */
      delay = ospf6->spf_delay;
      ospf6->spf_hold_multiplier = 1;
    }

  if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
    zlog_debug ("SPF: calculation timer delay = %ld", delay);

  zlog_info ("SPF: Scheduled in %ld msec", delay);

  ospf6->t_spf_calc =
    thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
}
Beispiel #28
0
/* May be called multiple times for the same peer */
int
bgp_stop (struct peer *peer)
{
  afi_t afi;
  safi_t safi;
  char orf_name[BUFSIZ];

  /* Can't do this in Clearing; events are used for state transitions */
  if (peer->status != Clearing)
    {
      /* Delete all existing events of the peer */
      BGP_EVENT_FLUSH (peer);
    }

  /* Increment Dropped count. */
  if (peer->status == Established)
    {
      peer->dropped++;

      /* bgp log-neighbor-changes of neighbor Down */
      if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
	zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
                   peer_down_str [(int) peer->last_reset]);

      /* graceful restart */
      if (peer->t_gr_stale)
	{
	  BGP_TIMER_OFF (peer->t_gr_stale);
	  if (BGP_DEBUG (events, EVENTS))
	    zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
	}
      if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
	{
	  if (BGP_DEBUG (events, EVENTS))
	    {
	      zlog_debug ("%s graceful restart timer started for %d sec",
			  peer->host, peer->v_gr_restart);
	      zlog_debug ("%s graceful restart stalepath timer started for %d sec",
			  peer->host, peer->bgp->stalepath_time);
	    }
	  BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
			peer->v_gr_restart);
	  BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
			peer->bgp->stalepath_time);
	}
      else
	{
	  UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);

	  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
	    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
	      peer->nsf[afi][safi] = 0;
	}

      /* set last reset time */
      peer->resettime = peer->uptime = bgp_clock ();

#ifdef HAVE_SNMP
      bgpTrapBackwardTransition (peer);
#endif /* HAVE_SNMP */

      /* Reset peer synctime */
      peer->synctime = 0;
    }

  /* Stop read and write threads when exists. */
  BGP_READ_OFF (peer->t_read);
  BGP_WRITE_OFF (peer->t_write);

  /* Stop all timers. */
  BGP_TIMER_OFF (peer->t_start);
  BGP_TIMER_OFF (peer->t_connect);
  BGP_TIMER_OFF (peer->t_holdtime);
  BGP_TIMER_OFF (peer->t_keepalive);
  BGP_TIMER_OFF (peer->t_asorig);
  BGP_TIMER_OFF (peer->t_routeadv);

  /* Stream reset. */
  peer->packet_size = 0;

  /* Clear input and output buffer.  */
  if (peer->ibuf)
    stream_reset (peer->ibuf);
  if (peer->work)
    stream_reset (peer->work);
  if (peer->obuf)
    stream_fifo_clean (peer->obuf);

  /* Close of file descriptor. */
  if (peer->fd >= 0)
    {
      close (peer->fd);
      peer->fd = -1;
    }

  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
      {
        /* Reset all negotiated variables */
        peer->afc_nego[afi][safi] = 0;
        peer->afc_adv[afi][safi] = 0;
        peer->afc_recv[afi][safi] = 0;

	/* peer address family capability flags*/
	peer->af_cap[afi][safi] = 0;

	/* peer address family status flags*/
	peer->af_sflags[afi][safi] = 0;

	/* Received ORF prefix-filter */
	peer->orf_plist[afi][safi] = NULL;

        /* ORF received prefix-filter pnt */
        sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
        prefix_bgp_orf_remove_all (afi, orf_name);
      }

  /* Reset keepalive and holdtime */
  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
    {
      peer->v_keepalive = peer->keepalive;
      peer->v_holdtime = peer->holdtime;
    }
  else
    {
      peer->v_keepalive = peer->bgp->default_keepalive;
      peer->v_holdtime = peer->bgp->default_holdtime;
    }

  peer->update_time = 0;

  /* Until we are sure that there is no problem about prefix count
     this should be commented out.*/
#if 0
  /* Reset prefix count */
  peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
  peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
  peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
  peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
  peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
#endif /* 0 */

  return 0;
}
Beispiel #29
0
int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{
   struct listnode *node = 0;
   struct listnode *nextnode = 0;
   struct static_route *s_route = 0;
   struct pim_interface *pim_iif = iif ? iif->info : 0;
   struct pim_interface *pim_oif = oif ? oif->info : 0;
   unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
   unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;

   if (!iif_index || !oif_index) {
      zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
               __FILE__, __PRETTY_FUNCTION__,
               iif_index,
               oif_index);
      return -2;
   }

   for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) {
      if (s_route->iif == iif_index &&
          s_route->group.s_addr == group.s_addr &&
          s_route->source.s_addr == source.s_addr &&
          s_route->oif_ttls[oif_index]) {
         s_route->oif_ttls[oif_index] = 0;
         s_route->mc.mfcc_ttls[oif_index] = 0;
         --s_route->oif_count;

         /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
         if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) {
            char gifaddr_str[100];
            char sifaddr_str[100];
            pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
            pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
            zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
                     __FILE__, __PRETTY_FUNCTION__,
                     iif_index,
                     oif_index,
                     gifaddr_str,
                     sifaddr_str);

            s_route->oif_ttls[oif_index] = 1;
            s_route->mc.mfcc_ttls[oif_index] = 1;
            ++s_route->oif_count;

            return -1;
         }

         s_route->creation[oif_index] = 0;

         if (s_route->oif_count <= 0) {
            listnode_delete(qpim_static_route_list, s_route);
            pim_static_route_free(s_route);
         }

         if (PIM_DEBUG_STATIC) {
           char gifaddr_str[100];
           char sifaddr_str[100];
           pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
           pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
           zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
                 __PRETTY_FUNCTION__,
                 iif_index,
                 oif_index,
                 gifaddr_str,
                 sifaddr_str);
         }

         break;
      }
   }

   if (!node) {
      char gifaddr_str[100];
      char sifaddr_str[100];
      pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
      pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
      zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
               __FILE__, __PRETTY_FUNCTION__,
               iif_index,
               oif_index,
               gifaddr_str,
               sifaddr_str);
      return -3;
   }

   return 0;
}
Beispiel #30
0
static u_char *
ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length,
                     int exact, size_t *var_len, WriteMethod **write_method)
{
  struct ospf6_lsa *lsa = NULL;
  struct in_addr area_id;
  u_int16_t type;
  struct in_addr id;
  struct in_addr adv_router;
  int len;
  oid *offset;
  int offsetlen;
  char a[16], b[16], c[16];
  struct ospf6_area *oa;
  struct listnode *node;

  memset (&area_id, 0, sizeof (struct in_addr));
  type = 0;
  memset (&id, 0, sizeof (struct in_addr));
  memset (&adv_router, 0, sizeof (struct in_addr));

  /* Check OSPFv3 instance. */
  if (ospf6 == NULL)
    return NULL;

  /* Get variable length. */
  offset = name + v->namelen;
  offsetlen = *length - v->namelen;

#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET \
  (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE)

  if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET)
    return NULL;

  /* Parse area-id */
  len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE);
  if (len)
    oid2in_addr (offset, len, &area_id);
  offset += len;
  offsetlen -= len;

  /* Parse type */
  len = (offsetlen < 1 ? offsetlen : 1);
  if (len)
    type = htons (*offset);
  offset += len;
  offsetlen -= len;

  /* Parse Router-ID */
  len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE);
  if (len)
    oid2in_addr (offset, len, &adv_router);
  offset += len;
  offsetlen -= len;

  /* Parse LS-ID */
  len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE);
  if (len)
    oid2in_addr (offset, len, &id);
  offset += len;
  offsetlen -= len;

  inet_ntop (AF_INET, &area_id, a, sizeof (a));
  inet_ntop (AF_INET, &adv_router, b, sizeof (b));
  inet_ntop (AF_INET, &id, c, sizeof (c));
  zlog_debug ("SNMP access by lsdb: area=%s exact=%d length=%lu magic=%d"
	      " type=%#x adv_router=%s id=%s",
	      a, exact, (u_long)*length, v->magic, ntohs (type), b, c);

  if (exact)
    {
      oa = ospf6_area_lookup (area_id.s_addr, ospf6);
      lsa = ospf6_lsdb_lookup (type, id.s_addr, adv_router.s_addr, oa->lsdb);
    }
  else
    {
      for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
        {
          if (lsa)
            continue;
          if (ntohl (oa->area_id) < ntohl (area_id.s_addr))
            continue;

          lsa = ospf6_lsdb_lookup_next (type, id.s_addr, adv_router.s_addr,
                                        oa->lsdb);
          if (! lsa)
            {
              type = 0;
              memset (&id, 0, sizeof (struct in_addr));
              memset (&adv_router, 0, sizeof (struct in_addr));
            }
        }
    }

  if (! lsa)
    {
      zlog_debug ("SNMP respond: No LSA to return");
      return NULL;
    }
  oa = OSPF6_AREA (lsa->lsdb->data);

  zlog_debug ("SNMP respond: area: %s lsa: %s", oa->name, lsa->name);

  /* Add Index (AreaId, Type, RouterId, Lsid) */
  *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET;
  offset = name + v->namelen;
  oid_copy_addr (offset, (struct in_addr *) &oa->area_id, IN_ADDR_SIZE);
  offset += IN_ADDR_SIZE;
  *offset = ntohs (lsa->header->type);
  offset++;
  oid_copy_addr (offset, (struct in_addr *) &lsa->header->adv_router,
                 IN_ADDR_SIZE);
  offset += IN_ADDR_SIZE;
  oid_copy_addr (offset, (struct in_addr *) &lsa->header->id, IN_ADDR_SIZE);
  offset += IN_ADDR_SIZE;

  /* Return the current value of the variable */
  switch (v->magic)
    {
    case OSPFv3AREALSDBAREAID:        /* 1 */
      area_id.s_addr = OSPF6_AREA (lsa->lsdb->data)->area_id;
      return SNMP_IPADDRESS (area_id);
      break;
    case OSPFv3AREALSDBTYPE:          /* 2 */
      return SNMP_INTEGER (ntohs (lsa->header->type));
      break;
    case OSPFv3AREALSDBROUTERID:      /* 3 */
      adv_router.s_addr = lsa->header->adv_router;
      return SNMP_IPADDRESS (adv_router);
      break;
    case OSPFv3AREALSDBLSID:          /* 4 */
      id.s_addr = lsa->header->id;
      return SNMP_IPADDRESS (id);
      break;
    case OSPFv3AREALSDBSEQUENCE:      /* 5 */
      return SNMP_INTEGER (lsa->header->seqnum);
      break;
    case OSPFv3AREALSDBAGE:           /* 6 */
      ospf6_lsa_age_current (lsa);
      return SNMP_INTEGER (lsa->header->age);
      break;
    case OSPFv3AREALSDBCHECKSUM:      /* 7 */
      return SNMP_INTEGER (lsa->header->checksum);
      break;
    case OSPFv3AREALSDBADVERTISEMENT: /* 8 */
      *var_len = ntohs (lsa->header->length);
      return (u_char *) lsa->header;
      break;
    case OSPFv3AREALSDBTYPEKNOWN:     /* 9 */
      return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ?
                           SNMP_TRUE : SNMP_FALSE);
      break;
    default:
      return NULL;
      break;
    }
  return NULL;
}