Beispiel #1
0
/* Interface adding function */
int
ifan_read (struct if_announcemsghdr *ifan)
{
  struct interface *ifp;

  ifp = if_lookup_by_index (ifan->ifan_index);
  if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
    {
      /* Create Interface */
      ifp = if_get_by_name (ifan->ifan_name);
      ifp->ifindex = ifan->ifan_index;

      if_add_update (ifp);
    }
  else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
    {
      if_delete_update (ifp);
      if_delete (ifp);
    }

  if_get_flags (ifp);
  if_get_mtu (ifp);
  if_get_metric (ifp);

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

  return 0;
}
Beispiel #2
0
/* Interface structure allocation by proc filesystem. */
int
interface_list_proc ()
{
  FILE *fp;
  char buf[PROCBUFSIZ];
  struct interface *ifp;
  char *name;

  /* Open /proc/net/dev. */
  fp = fopen (_PATH_PROC_NET_DEV, "r");
  if (fp == NULL)
    {
      zlog_warn ("Can't open proc file %s: %s",
		 _PATH_PROC_NET_DEV, strerror (errno));
      return -1;
    }

  /* Drop header lines. */
  fgets (buf, PROCBUFSIZ, fp);
  fgets (buf, PROCBUFSIZ, fp);

  /* Only allocate interface structure.  Other jobs will be done in
     if_ioctl.c. */
  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
    {
      interface_name_cut (buf, &name);
      ifp = if_get_by_name (name);
      if_add_update (ifp);
    }
  return 0;
}
Beispiel #3
0
/* Called from interface_lookup_netlink().  This function is only used
   during bootstrap. */
static int
netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
  int len;
  struct ifinfomsg *ifi;
  struct rtattr *tb[IFLA_MAX + 1];
  struct interface *ifp;
  char *name;

  ifi = NLMSG_DATA (h);

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

  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
  if (len < 0)
    return -1;

  /* Looking up interface name. */
  memset (tb, 0, sizeof tb);
  netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
  
#ifdef IFLA_WIRELESS
  /* check for wireless messages to ignore */
  if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
    {
      if (IS_DEBUG_HA(kroute, KROUTE))
        zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
      return 0;
    }
#endif /* IFLA_WIRELESS */

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

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

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

  if_add_update (ifp);

  return 0;
}
Beispiel #4
0
/* Update interface's statistics. */
int
ifstat_update_proc ()
{
  FILE *fp;
  char buf[PROCBUFSIZ];
  int version;
  struct interface *ifp;
  char *stat;
  char *name;
  char *retval;

  /* Open /proc/net/dev. */
  fp = fopen (_PATH_PROC_NET_DEV, "r");
  if (fp == NULL)
    {
      zlog_warn ("Can't open proc file %s: %s",
		 _PATH_PROC_NET_DEV, strerror (errno));
      return -1;
    }

  /* Drop header lines. */
  retval = fgets (buf, PROCBUFSIZ, fp);
  retval = fgets (buf, PROCBUFSIZ, fp);

  /* To detect proc format veresion, parse second line. */
  if (strstr (buf, "compressed"))
    version = 3;
  else if (strstr (buf, "bytes"))
    version = 2;
  else
    version = 1;

  /* Update each interface's statistics. */
  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
    {
      stat = interface_name_cut (buf, &name);
      ifp = if_get_by_name (name);
      ifstat_dev_fields (version, stat, ifp);
    }
  fclose(fp);
  return 0;
}
Beispiel #5
0
void sibling_ctrl_add_ctrl_client(unsigned int hostnum, char * ifname, char * area)
{
  struct ctrl_client * ctrl_client;
  struct interface * ifp;
  struct ospf6_interface * oi;
  struct ospf6_area * oa;

  u_int32_t area_id;

  ctrl_client = ctrl_client_new();
  ctrl_client->hostnum = hostnum;
  ctrl_client->inter_con = NULL;

  list_push_back(&ctrl_clients, &ctrl_client->node);

  /* find/create ospf6 interface */
  ifp = if_get_by_name(ctrl_client->if_list, ifname);
  oi = (struct ospf6_interface *) ifp->info;
  if(oi == NULL)
  {
    oi = ospf6_interface_create(ifp);
  }

  /* parse Area-ID */
  if (inet_pton (AF_INET, area, &area_id) != 1)  
  {
    printf("Invalid Area-ID: %s\n", area);
  }
  
  /* find/create ospf6 area */
  oa = ospf6_area_lookup (area_id, ospf6); 
  if(oa == NULL)
    oa = ospf6_area_create(area_id, ospf6); 
 
  /* attach interface to area */
  list_push_back(&oa->if_list, &oi->node);
  oi->area = oa;

  /* start up */
  thread_add_event(master, interface_up, oi, 0); 
}
Beispiel #6
0
int recv_features_reply(struct ctrl_client * ctrl_client, struct rfpbuf * buffer)
{
  struct rfp_router_features * rrf = buffer->data;
  struct interface * ifp;
  int i;
  unsigned int ifindex;
  unsigned int mtu;
  int offset = offsetof(struct rfp_router_features, ports);
  size_t n_ports = ((ntohs(rrf->header.length)
                                     - offset)
                        / sizeof(*rrf->ports));
  if(IS_OSPF6_SIBLING_DEBUG_MSG)
  {
    zlog_notice("number of ports: %d", n_ports);
  }
  for(i = 0; i < n_ports; i++)
  {  
    const struct rfp_phy_port * rpp = &rrf->ports[i];
    ifindex = ntohs(rpp->port_no);
    mtu = ntohl(rpp->mtu);
    if(IS_OSPF6_SIBLING_DEBUG_MSG)
    {
      zlog_notice("port #: %d, name: %s, mtu: %d", ifindex, rpp->name, mtu);
    }
    /* create new interface if not created */
    ifp = if_get_by_name(ctrl_client->if_list, rpp->name);

    // fill up the interface info
    ifp->ifindex = ifindex;

    // fill up the mtu
    ifp->mtu = mtu;
    // copy over the flags
    ifp->state = ntohl(rpp->state);
    ospf6_interface_if_add(ifp, ctrl_client);
  }

  return 0;
}
Beispiel #7
0
// helper function
void schedule_hellos_on_interfaces()
{
  struct interface * ifp;
  struct ospf6_interface * oi;
  struct ctrl_client * ctrl_client;

  // if we already scheduled hellos, dont need to do it again
  if(scheduled_hellos)
  {
    return;
  }

  LIST_FOR_EACH(ctrl_client, struct ctrl_client, node, &ctrl_clients)
  {
    ifp = if_get_by_name(ctrl_client->if_list, ctrl_client->interface_name);
    oi = (struct ospf6_interface *)ifp->info;

    thread_add_event(master, ospf6_hello_send, oi, 0);
  }

  scheduled_hellos = true;
}
Beispiel #8
0
int
ifaddr_proc_ipv6 ()
{
  FILE *fp;
  char buf[PROCBUFSIZ];
  int n;
  char addr[33];
  char ifname[20];
  int ifindex, plen, scope, status;
  struct interface *ifp;
  struct prefix_ipv6 p;

  /* Open proc file system. */
  fp = fopen (_PATH_PROC_NET_IF_INET6, "r");
  if (fp == NULL)
    {
      zlog_warn ("Can't open proc file %s: %s",
		 _PATH_PROC_NET_IF_INET6, strerror (errno));
      return -1;
    }
  
  /* Get interface's IPv6 address. */
  while (fgets (buf, PROCBUFSIZ, fp) != NULL)
    {
      n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", 
		  addr, &ifindex, &plen, &scope, &status, ifname);
      if (n != 6)
	continue;

      ifp = if_get_by_name (ifname);

      /* Fetch interface's IPv6 address. */
      str2in6_addr (addr, &p.prefix);
      p.prefixlen = plen;

      connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL);
    }
  return 0;
}
Beispiel #9
0
static int
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
  int len;
  struct ifinfomsg *ifi;
  struct rtattr *tb[IFLA_MAX + 1];
  struct interface *ifp;
  char *name;

  ifi = NLMSG_DATA (h);

  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\n",
                 h->nlmsg_type);
      return 0;
    }

  len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
  if (len < 0)
    return -1;

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

#ifdef IFLA_WIRELESS
  /* check for wireless messages to ignore */
  if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
    {
      if (IS_DEBUG_HA(kroute, KROUTE))
        zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
      return 0;
    }
#endif /* IFLA_WIRELESS */
  
  if (tb[IFLA_IFNAME] == NULL)
    return -1;
  name = (char *) RTA_DATA (tb[IFLA_IFNAME]);

  /* Add interface. */
  if (h->nlmsg_type == RTM_NEWLINK)
    {
      ifp = if_lookup_by_name (name);

      if (ifp == NULL || !CHECK_FLAG (ifp->status, KROUTE_INTERFACE_ACTIVE))
        {
          if (ifp == NULL)
            ifp = if_get_by_name (name);

          set_ifindex(ifp, ifi->ifi_index);
          ifp->flags = ifi->ifi_flags & 0x0000fffff;
          ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
          ifp->metric = 1;

          netlink_interface_update_hw_addr (tb, ifp);

          /* If new link is added. */
          if_add_update (ifp);
        }
      else
        {
          /* Interface status change. */
          set_ifindex(ifp, ifi->ifi_index);
          ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
          ifp->metric = 1;

          netlink_interface_update_hw_addr (tb, ifp);

          if (if_is_operative (ifp))
            {
              ifp->flags = ifi->ifi_flags & 0x0000fffff;
              if (!if_is_operative (ifp))
                if_down (ifp);
	      else
		/* Must notify client daemons of new interface status. */
	        kroute_interface_up_update (ifp);
            }
          else
            {
              ifp->flags = ifi->ifi_flags & 0x0000fffff;
              if (if_is_operative (ifp))
                if_up (ifp);
            }
        }
    }
  else
    {
      /* RTM_DELLINK. */
      ifp = if_lookup_by_name (name);

      if (ifp == NULL)
        {
          zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
                name);
          return 0;
        }

      if_delete_update (ifp);
    }

  return 0;
}
Beispiel #10
0
int
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
    int len;
    struct ifinfomsg *ifi;
    struct rtattr *tb [IFLA_MAX + 1];
    struct interface *ifp;
    char *name;

    ifi = NLMSG_DATA (h);

    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\n",
                   h->nlmsg_type);
        return 0;
    }

    len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
    if (len < 0)
        return -1;

    /* Looking up interface name. */
    memset (tb, 0, sizeof tb);
    netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
    if (tb[IFLA_IFNAME] == NULL)
        return -1;
    name = (char *)RTA_DATA(tb[IFLA_IFNAME]);

    /* Add interface. */
    if (h->nlmsg_type == RTM_NEWLINK)
    {
        ifp = if_lookup_by_name (name);

        if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
        {
            if (ifp == NULL)
                ifp = if_get_by_name (name);

            ifp->ifindex = ifi->ifi_index;
            ifp->flags = ifi->ifi_flags & 0x0000fffff;
            ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
            ifp->metric = 1;

            /* If new link is added. */
            if_add_update(ifp);
        }
        else
        {
            /* Interface status change. */
            ifp->ifindex = ifi->ifi_index;
            ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
            ifp->metric = 1;

            if (if_is_up (ifp))
            {
                ifp->flags = ifi->ifi_flags & 0x0000fffff;
                if (! if_is_up (ifp))
                    if_down (ifp);
            }
            else
            {
                ifp->flags = ifi->ifi_flags & 0x0000fffff;
                if (if_is_up (ifp))
                    if_up (ifp);
            }
        }
    }
    else
    {
        /* RTM_DELLINK. */
        ifp = if_lookup_by_name (name);

        if (ifp == NULL)
        {
            zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
                  ifp->name);
            return 0;
        }

        if_delete_update (ifp);
    }

    return 0;
}
Beispiel #11
0
/* Called from interface_lookup_netlink().  This function is only used
   during bootstrap. */
int
netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
    int len;
    struct ifinfomsg *ifi;
    struct rtattr *tb[IFLA_MAX + 1];
    struct interface *ifp;
    char *name;
    int i;

    ifi = NLMSG_DATA (h);

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

    len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
    if (len < 0)
        return -1;

    /* Looking up interface name. */
    memset (tb, 0, sizeof tb);
    netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
    if (tb[IFLA_IFNAME] == NULL)
        return -1;
    name = (char *)RTA_DATA(tb[IFLA_IFNAME]);

    /* Add interface. */
    ifp = if_get_by_name (name);

    ifp->ifindex = ifi->ifi_index;
    ifp->flags = ifi->ifi_flags & 0x0000fffff;
    ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
    ifp->metric = 1;

    /* Hardware type and address. */
    ifp->hw_type = ifi->ifi_type;

    if (tb[IFLA_ADDRESS])
    {
        int hw_addr_len;

        hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);

        if (hw_addr_len > INTERFACE_HWADDR_MAX)
            zlog_warn ("Hardware address is too large: %d", hw_addr_len);
        else
        {
            ifp->hw_addr_len = hw_addr_len;
            memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);

            for (i = 0; i < hw_addr_len; i++)
                if (ifp->hw_addr[i] != 0)
                    break;

            if (i == hw_addr_len)
                ifp->hw_addr_len = 0;
            else
                ifp->hw_addr_len = hw_addr_len;
        }
    }

    if_add_update (ifp);

    return 0;
}
Beispiel #12
0
/* Interface looking up using infamous SIOCGIFCONF. */
int
interface_list_ioctl ()
{
  int ret;
  int sock;
#define IFNUM_BASE 32
  int ifnum;
  struct ifreq *ifreq;
  struct ifconf ifconf;
  struct interface_FOO *ifp;
  int n;
  int lastlen;

  /* Normally SIOCGIFCONF works with AF_INET socket. */
  sock = socket (AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) 
    {
      zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
      return -1;
    }

  /* Set initial ifreq count.  This will be double when SIOCGIFCONF
     fail.  Solaris has SIOCGIFNUM. */
#ifdef SIOCGIFNUM
  ret = ioctl (sock, SIOCGIFNUM, &ifnum);
  if (ret < 0)
    ifnum = IFNUM_BASE;
  else
    ifnum++;
#else
  ifnum = IFNUM_BASE;
#endif /* SIOCGIFNUM */

  ifconf.ifc_buf = NULL;

  lastlen = 0;
  /* Loop until SIOCGIFCONF success. */
  for (;;) 
    {
      ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
      ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);

      ret = ioctl(sock, SIOCGIFCONF, &ifconf);

      if (ret < 0) 
	{
	  zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
	  goto end;
	}
      /* Repeatedly get info til buffer fails to grow. */
      if (ifconf.ifc_len > lastlen)
	{
          lastlen = ifconf.ifc_len;
	  ifnum += 10;
	  continue;
	}
      /* Success. */
      break;
    }

  /* Allocate interface. */
  ifreq = ifconf.ifc_req;

#ifdef OPEN_BSD
  for (n = 0; n < ifconf.ifc_len; )
    {
      int size;

      ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
      ifp = if_get_by_name (ifreq->ifr_name);
      if_add_update (ifp);
      size = ifreq->ifr_addr.sa_len;
      if (size < sizeof (ifreq->ifr_addr))
	size = sizeof (ifreq->ifr_addr);
      size += sizeof (ifreq->ifr_name);
      n += size;
    }
#else
  for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
    {
      ifp = if_get_by_name (ifreq->ifr_name);
      if_add_update (ifp);
      ifreq++;
    }
#endif /* OPEN_BSD */

 end:
  close (sock);
  XFREE (MTYPE_TMP, ifconf.ifc_buf);

  return ret;
}
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
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;
}