Beispiel #1
0
void nl_bridge::add_neigh_to_fdb(rtnl_neigh *neigh) {
  assert(sw);
  assert(neigh);

  uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh));
  if (port == 0) {
    VLOG(1) << __FUNCTION__ << ": unknown port for neigh " << OBJ_CAST(neigh);
    return;
  }

  nl_addr *mac = rtnl_neigh_get_lladdr(neigh);
  int vlan = rtnl_neigh_get_vlan(neigh);

  bool permanent = true;

  // for sure this is master (sw bridged)
  if (rtnl_neigh_get_master(neigh) &&
      !(rtnl_neigh_get_flags(neigh) & NTF_MASTER)) {
    rtnl_neigh_set_flags(neigh, NTF_MASTER);
  }

  // check if entry already exists in cache
  if (is_mac_in_l2_cache(neigh)) {
    permanent = false;
  }

  rofl::caddress_ll _mac((uint8_t *)nl_addr_get_binary_addr(mac),
                         nl_addr_get_len(mac));

  LOG(INFO) << __FUNCTION__ << ": add mac=" << _mac << " to bridge "
            << rtnl_link_get_name(bridge) << " on port=" << port
            << " vlan=" << (unsigned)vlan << ", permanent=" << permanent;
  LOG(INFO) << __FUNCTION__ << ": object: " << OBJ_CAST(neigh);
  sw->l2_addr_add(port, vlan, _mac, true, permanent);
}
Beispiel #2
0
/**
 * Create a new kernel bonding device
 * @arg sock		netlink socket
 * @arg name		name of bonding device or NULL
 * @arg opts		bonding options (currently unused)
 *
 * Creates a new bonding device in the kernel. If no name is
 * provided, the kernel will automatically pick a name of the
 * form "type%d" (e.g. bond0, vlan1, etc.)
 *
 * The \a opts argument is currently unused. In the future, it
 * may be used to carry additional bonding options to be set
 * when creating the bonding device.
 *
 * @note When letting the kernel assign a name, it will become
 *       difficult to retrieve the interface afterwards because
 *       you have to guess the name the kernel has chosen. It is
 *       therefore not recommended to not provide a device name.
 *
 * @see rtnl_link_bond_enslave()
 * @see rtnl_link_bond_release()
 *
 * @return 0 on success or a negative error code
 */
int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
		       struct rtnl_link *opts)
{
	struct rtnl_link *link;
	int err;

	if (!(link = rtnl_link_alloc()))
		return -NLE_NOMEM;

	if (!name) {
		if (opts)
			name = rtnl_link_get_name(opts);

		if (!name)
			return -NLE_MISSING_ATTR;
	}

	if ((err = rtnl_link_set_type(link, "bond")) < 0)
		goto errout;
	

		rtnl_link_set_name(link, name);

	err = rtnl_link_add(sock, link, NLM_F_CREATE);
errout:
	rtnl_link_put(link);

	return err;
}
Beispiel #3
0
int sysnet_interface_set_mtu(VPNInterface *i, unsigned int mtu)
{
    int err;

    struct nl_cache *link_cache;
    struct nl_sock *sock;
    struct rtnl_link *link;
    struct rtnl_link *new_link;

    sock = nl_socket_alloc();
    nl_connect(sock, NETLINK_ROUTE);

    rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache);
    link = rtnl_link_get_by_name(link_cache, i->name);
    new_link = rtnl_link_alloc();

    if (!link)
    {
        tox_trace(i->context->tox, "can't find link \"%s\"", i->name);
        return -1;
    }

    rtnl_link_set_mtu(new_link, mtu);

    if ((err = rtnl_link_change(sock, link, new_link, 0)) < 0) {
        tox_trace(i->context->tox, "unable to change link \"%s\" flags: %s", rtnl_link_get_name(link), nl_geterror(err));
    }

    rtnl_link_put(link);
    rtnl_link_put(new_link);
    nl_cache_free(link_cache);
    nl_socket_free(sock);

    return 0;
}
static void dump_stat(struct rtnl_link *link, int id)
{
	uint64_t st = rtnl_link_get_stat(link, id);
	char buf[64];

	printf("%s.%s %" PRIu64 "\n", rtnl_link_get_name(link),
	       rtnl_link_stat2str(id, buf, sizeof(buf)), st);
}
Beispiel #5
0
void nl_bridge::add_interface(rtnl_link *link) {

  assert(rtnl_link_get_family(link) == AF_BRIDGE);

  if (bridge == nullptr) {
    LOG(ERROR) << __FUNCTION__ << ": cannot be done without bridge";
    return;
  }

  if (rtnl_link_get_ifindex(bridge) != rtnl_link_get_master(link)) {
    LOG(INFO) << __FUNCTION__ << ": link " << rtnl_link_get_name(link)
              << " is no slave of " << rtnl_link_get_name(bridge);
    return;
  }

  update_vlans(nullptr, link);
}
Beispiel #6
0
void nl_bridge::update_interface(rtnl_link *old_link, rtnl_link *new_link) {
  assert(rtnl_link_get_family(old_link) == AF_BRIDGE);
  assert(rtnl_link_get_family(new_link) == AF_BRIDGE);

  // sanity checks
  if (bridge == nullptr) {
    LOG(ERROR) << __FUNCTION__ << ": cannot be done without bridge";
    return;
  }

  if (rtnl_link_get_ifindex(bridge) != rtnl_link_get_master(new_link)) {
    LOG(INFO) << __FUNCTION__ << ": link " << rtnl_link_get_name(new_link)
              << " is no slave of " << rtnl_link_get_name(bridge);
    return;
  }

  update_vlans(old_link, new_link);
}
Beispiel #7
0
static void veth_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
	struct rtnl_link *peer = link->l_info;
	char *name;
	name = rtnl_link_get_name(peer);
	nl_dump(p, "      peer ");
	if (name)
		nl_dump_line(p, "%s\n", name);
	else
		nl_dump_line(p, "%u\n", peer->l_index);
}
Beispiel #8
0
Result<string> name(int index)
{
  Result<Netlink<struct rtnl_link> > link = internal::get(index);
  if (link.isError()) {
    return Error(link.error());
  } else if (link.isNone()) {
    return None();
  }

  return rtnl_link_get_name(link.get().get());
}
Beispiel #9
0
TError TNlLink::Load() {
    struct rtnl_link *link;
    int ret;

    ret = rtnl_link_get_kernel(GetSock(), rtnl_link_get_ifindex(Link),
                                       rtnl_link_get_name(Link), &link);
    if (ret)
        return Error(ret, "Cannot load link");
    rtnl_link_put(Link);
    Link = link;
    return TError::Success();
}
Beispiel #10
0
TError TNlLink::AddVeth(const std::string &name,
                        const std::string &hw,
                        int mtu, int nsFd) {
    struct rtnl_link *veth, *peer;
    int ret;

    peer = rtnl_link_veth_alloc();
    if (!peer)
        return TError(EError::Unknown, "Unable to allocate veth");

    rtnl_link_set_name(peer, rtnl_link_get_name(Link));

    veth = rtnl_link_veth_get_peer(peer);
    rtnl_link_set_name(veth, name.c_str());

    if (nsFd >= 0)
        rtnl_link_set_ns_fd(veth, nsFd);

    if (mtu > 0) {
        rtnl_link_set_mtu(peer, mtu);
        rtnl_link_set_mtu(veth, mtu);
    }

    if (!hw.empty()) {
        TNlAddr addr;
        TError error = addr.Parse(AF_LLC, hw.c_str());
        if (error)
            return error;
        rtnl_link_set_addr(veth, addr.Addr);
    }

    rtnl_link_set_flags(peer, IFF_UP);

    Dump("add", veth);
    rtnl_link_put(veth);

    Dump("add", peer);
    ret = rtnl_link_add(GetSock(), peer, NLM_F_CREATE | NLM_F_EXCL);
    if (ret < 0) {
        rtnl_link_put(peer);
        return Error(ret, "Cannot add veth");
    }

    rtnl_link_put(peer);

    return Load();
}
Beispiel #11
0
/* Given an interface's MAC address, return the name (e.g., eth0) in human
 * readable format.  Return NULL for no match
 */
char *iface_mac2device(char *mac) {
    struct nl_handle *handle = NULL;
    struct nl_cache *cache = NULL;
    struct rtnl_link *link = NULL;
    struct nl_addr *mac_as_nl_addr = NULL;
    char *retval = NULL;
    int i, n;

    if (mac == NULL) {
        return NULL;
    }

    if ((mac_as_nl_addr = nl_addr_parse(mac, AF_LLC)) == NULL) {
        return NULL;
    }

    if ((cache = _iface_get_link_cache(&handle)) == NULL) {
        return NULL;
    }

    n = nl_cache_nitems(cache);
    for (i = 0; i <= n; i++) {
        struct nl_addr *addr;

        if ((link = rtnl_link_get(cache, i)) == NULL) {
            continue;
        }

        addr = rtnl_link_get_addr(link);

        if (!nl_addr_cmp(mac_as_nl_addr, addr)) {
            retval = strdup(rtnl_link_get_name(link));
            rtnl_link_put(link);
            break;
        }

        rtnl_link_put(link);
    }

    nl_close(handle);
    nl_handle_destroy(handle);

    return retval;
}
Beispiel #12
0
void TNlLink::LogCache(struct nl_cache *cache) const {
    if (!debug)
        return;

    static std::function<void(struct nl_dump_params *, char *)> handler;

    struct nl_dump_params dp = {};
    dp.dp_cb = [](struct nl_dump_params *params, char *buf) { handler(params, buf); };
    dp.dp_type = NL_DUMP_DETAILS;

    auto &str = L();
    handler = [&](struct nl_dump_params *params, char *buf) { str << buf; };

    if (Link)
        str << "netlink " << rtnl_link_get_name(Link) << " cache: ";
    else
        str << "netlink cache: ";
    nl_cache_dump(cache, &dp);
}
Beispiel #13
0
static void
iface_mon_handler2(struct nl_object *obj, void *arg)
{
    struct rtnl_link *filter;
    struct rtnl_link *link_obj;
    int flags, up;
    char *ifname;
    iface_mon_cb cb = (iface_mon_cb)arg;

    filter = rtnl_link_alloc();
    if (!filter) {
        fprintf(stderr, "error allocating filter\n");
        return;
    }

    if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
        rtnl_link_put(filter);
        return;
    }

    link_obj = (struct rtnl_link *) obj;
    flags = rtnl_link_get_flags (link_obj);
    ifname = rtnl_link_get_name(link_obj);

    /*
     * You can't bind a PF_PACKET socket to an interface that's not
     * up, so an interface going down is an "interface should be
     * removed" indication.
     *
     * XXX - what indication, if any, do we get if the interface
     * *completely goes away*?
     *
     * XXX - can we get events if an interface's link-layer or
     * network addresses change?
     */
    up = (flags & IFF_UP) ? 1 : 0;

    cb(ifname, up);

    rtnl_link_put(filter);

    return;
}
Beispiel #14
0
/*
 * Called by nl_cache_mngr_data_ready if a link object changed.
 *
 * Sends a port status message to the controller.
 */
static void
link_change_cb(struct nl_cache *cache,
               struct nl_object *obj,
               int action,
               void *arg)
{
    struct rtnl_link *link = (struct rtnl_link *) obj;
    const char *ifname = rtnl_link_get_name(link);
    int ifflags = rtnl_link_get_flags(link);

    /*
     * Ignore additions/deletions, already handled by
     * ind_ovs_handle_vport_multicast.
     */
    if (action != NL_ACT_CHANGE) {
        return;
    }

    /* Ignore interfaces not connected to our datapath. */
    struct ind_ovs_port *port = ind_ovs_port_lookup_by_name(ifname);
    if (port == NULL) {
        return;
    }

    /* Log at INFO only if the interface transitioned between up/down */
    if ((ifflags & IFF_UP) && !(port->ifflags & IFF_UP)) {
        LOG_INFO("Interface %s state changed to up", ifname);
    } else if (!(ifflags & IFF_UP) && (port->ifflags & IFF_UP)) {
        LOG_INFO("Interface %s state changed to down", ifname);
    }

    LOG_VERBOSE("Sending port status change notification for interface %s", ifname);

    port->ifflags = ifflags;
    port_status_notify(port->dp_port_no, OF_PORT_CHANGE_REASON_MODIFY);
}
Beispiel #15
0
void nl_bridge::update_vlans(rtnl_link *old_link, rtnl_link *new_link) {
  assert(sw);
  assert(bridge); // already checked

  rtnl_link_bridge_vlan *old_br_vlan, *new_br_vlan;
  rtnl_link *_link;

  if (old_link == nullptr) {
    // link added
    old_br_vlan = &empty_br_vlan;
    new_br_vlan = rtnl_link_bridge_get_port_vlan(new_link);
    _link = nl->get_link(rtnl_link_get_ifindex(new_link), AF_UNSPEC);
  } else if (new_link == nullptr) {
    // link deleted
    old_br_vlan = rtnl_link_bridge_get_port_vlan(old_link);
    new_br_vlan = &empty_br_vlan;
    _link = nl->get_link(rtnl_link_get_ifindex(old_link), AF_UNSPEC);
  } else {
    // link updated
    old_br_vlan = rtnl_link_bridge_get_port_vlan(old_link);
    new_br_vlan = rtnl_link_bridge_get_port_vlan(new_link);
    _link = nl->get_link(rtnl_link_get_ifindex(new_link), AF_UNSPEC);
  }

  if (old_br_vlan == nullptr) {
    old_br_vlan = &empty_br_vlan;
  }

  if (new_br_vlan == nullptr) {
    new_br_vlan = &empty_br_vlan;
  }

  if (_link == nullptr) {
    // XXX FIXME in case a vxlan has been deleted the vxlan_domain and
    // vxlan_dom_bitmap need an update, maybe this can be handled already from
    // the link_deleted of the vxlan itself?
    LOG(WARNING) << __FUNCTION__
                 << ": could not get parent link of bridge interface. This "
                    "case needs further checks if everything got already "
                    "deleted.";
    return;
  }

  // check for vid changes
  if (br_vlan_equal(old_br_vlan, new_br_vlan)) {
    VLOG(2) << __FUNCTION__ << ": vlans did not change";
    return;
  }

  link_type lt = get_link_type(_link);
  uint32_t pport_no = 0;
  uint32_t tunnel_id = -1;
  std::deque<rtnl_link *> bridge_ports;

  if (lt == LT_VXLAN) {
    assert(nl);
    nl->get_bridge_ports(rtnl_link_get_master(_link), &bridge_ports);

    if (vxlan->get_tunnel_id(_link, nullptr, &tunnel_id) != 0) {
      LOG(ERROR) << __FUNCTION__ << ": failed to get vni of link "
                 << OBJ_CAST(_link);
    }

  } else {
    pport_no = nl->get_port_id(rtnl_link_get_ifindex(_link));
    if (pport_no == 0) {
      LOG(ERROR) << __FUNCTION__
                 << ": invalid pport_no=0 of link: " << OBJ_CAST(_link);
      return;
    }
  }

  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = old_br_vlan->vlan_bitmap[k];
    uint32_t b = new_br_vlan->vlan_bitmap[k];
    uint32_t vlan_diff = a ^ b;

#if 0  // untagged change not yet implemented
    uint32_t c = old_br_vlan->untagged_bitmap[k];
    uint32_t d = new_br_vlan->untagged_bitmap[k];
    uint32_t untagged_diff = c ^ d;
#endif // 0

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, vlan_diff);
      if (j > 0) {
        // vlan added or removed
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;

#if 0  // untagged change not yet implemented
       // clear untagged_diff bit
          untagged_diff &= ~((uint32_t)1 << (j - 1));
#endif // 0
        }

        if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) {
          // vlan added
          if (lt == LT_VXLAN) {
            // update vxlan domain
            if (!is_vid_set(vid, vxlan_dom_bitmap)) {
              VLOG(1) << __FUNCTION__ << ": new vxlan domain vid=" << vid
                      << ", tunnel_id=" << tunnel_id;

              vxlan_domain.emplace(vid, tunnel_id);
              set_vid(vid, vxlan_dom_bitmap);
            } else {
              // XXX TODO check the map
            }

            // update all bridge ports to be access ports
            update_access_ports(_link, new_link ? new_link : old_link, vid,
                                tunnel_id, bridge_ports, true);
          } else {
            assert(pport_no);
            if (is_vid_set(vid, vxlan_dom_bitmap)) {
              // configure as access port
              std::string port_name = std::string(rtnl_link_get_name(_link));
              auto vxd_it = vxlan_domain.find(vid);

              if (vxd_it != vxlan_domain.end()) {
                vxlan->create_access_port((new_link) ? new_link : old_link,
                                          vxd_it->second, port_name, pport_no,
                                          vid, egress_untagged, nullptr);
              } else {
                LOG(FATAL) << __FUNCTION__
                           << ": should not happen, something is broken";
              }
            } else {
              // normal vlan port
              VLOG(3) << __FUNCTION__ << ": add vid=" << vid
                      << " on pport_no=" << pport_no
                      << " link: " << OBJ_CAST(_link);
              sw->egress_bridge_port_vlan_add(pport_no, vid, egress_untagged);
              sw->ingress_port_vlan_add(pport_no, vid,
                                        new_br_vlan->pvid == vid);
            }
          }
        } else {
          // vlan removed
          if (lt == LT_VXLAN) {
            unset_vid(vid, vxlan_dom_bitmap);
            vxlan_domain.erase(vid);

            // update all bridge ports to be normal bridge ports
            update_access_ports(_link, new_link ? new_link : old_link, vid,
                                tunnel_id, bridge_ports, false);
          } else {
            VLOG(3) << __FUNCTION__ << ": remove vid=" << vid
                    << " on pport_no=" << pport_no
                    << " link: " << OBJ_CAST(_link);
            sw->ingress_port_vlan_remove(pport_no, vid,
                                         old_br_vlan->pvid == vid);

            // delete all FM pointing to this group first
            sw->l2_addr_remove_all_in_vlan(pport_no, vid);

            std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> filter(
                rtnl_neigh_alloc(), rtnl_neigh_put);

            rtnl_neigh_set_ifindex(filter.get(), rtnl_link_get_ifindex(bridge));
            rtnl_neigh_set_master(filter.get(), rtnl_link_get_master(bridge));
            rtnl_neigh_set_family(filter.get(), AF_BRIDGE);
            rtnl_neigh_set_vlan(filter.get(), vid);
            rtnl_neigh_set_flags(filter.get(), NTF_MASTER | NTF_EXT_LEARNED);
            rtnl_neigh_set_state(filter.get(), NUD_REACHABLE);

            nl_cache_foreach_filter(l2_cache.get(), OBJ_CAST(filter.get()),
                                    [](struct nl_object *o, void *arg) {
                                      VLOG(3) << "l2_cache remove object " << o;
                                      nl_cache_remove(o);
                                    },
                                    nullptr);

            sw->egress_bridge_port_vlan_remove(pport_no, vid);
          }
        }

        i = j;
      } else {
        done = 1;
      }
    }

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// XXX implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);


				i = j;
			} else {
				done = 1;
			}
		}
#endif
  }
}
Beispiel #16
0
void nl_bridge::update_access_ports(rtnl_link *vxlan_link, rtnl_link *br_link,
                                    const uint16_t vid,
                                    const uint32_t tunnel_id,
                                    const std::deque<rtnl_link *> &bridge_ports,
                                    bool add) {
  // XXX pvid is currently not taken into account
  for (auto _br_port : bridge_ports) {
    auto br_port_vlans = rtnl_link_bridge_get_port_vlan(_br_port);

    if (rtnl_link_get_ifindex(vxlan_link) == rtnl_link_get_ifindex(_br_port))
      continue;

    if (br_port_vlans == nullptr)
      continue;

    if (!is_vid_set(vid, br_port_vlans->vlan_bitmap))
      continue;

    bool untagged = is_vid_set(vid, br_port_vlans->untagged_bitmap);
    int ifindex = rtnl_link_get_ifindex(_br_port);
    uint32_t pport_no = nl->get_port_id(ifindex);

    if (pport_no == 0) {
      LOG(WARNING) << __FUNCTION__ << ": ignoring unknown port "
                   << OBJ_CAST(_br_port);
      continue;
    }

    rtnl_link *link = nl->get_link(rtnl_link_get_ifindex(_br_port), AF_UNSPEC);

    VLOG(2) << __FUNCTION__ << ": vid=" << vid << ", untagged=" << untagged
            << ", tunnel_id=" << tunnel_id << ", add=" << add
            << ", ifindex=" << ifindex << ", pport_no=" << pport_no
            << ", port: " << OBJ_CAST(_br_port);

    if (add) {
      std::string port_name = std::string(rtnl_link_get_name(_br_port));

      // this is no longer a normal bridge interface thus we delete all the
      // bridging entries
      sw->l2_addr_remove_all_in_vlan(pport_no, vid);
      vxlan->create_access_port(_br_port, tunnel_id, port_name, pport_no, vid,
                                untagged, nullptr);

      auto neighs = get_fdb_entries_of_port(_br_port, vid);
      for (auto n : neighs) {
        // ignore ll addr of bridge on slave
        if (nl_addr_cmp(rtnl_link_get_addr(bridge), rtnl_neigh_get_lladdr(n)) ==
            0) {
          continue;
        }
        VLOG(3) << ": needs to be updated " << OBJ_CAST(n);
        vxlan->add_l2_neigh(n, link, br_link);
      }

    } else {
      // delete access port and all bridging entries
      vxlan->delete_access_port(_br_port, pport_no, vid, true);
      // XXX FIXME check if we have to add the VLANs again (ingress/egress)
    }
  }
}
Beispiel #17
0
static void __interface_statistics_get(struct nl_object *obj, void *arg)
{
    struct rtnl_link *link = (struct rtnl_link *)obj;
    Dabba__InterfaceStatisticsList *statistics_list = arg;
    Dabba__InterfaceStatistics *statisticsp, **listpp;
    size_t lsize =
        sizeof(*statistics_list->list) * (statistics_list->n_list + 1);

    listpp = realloc(statistics_list->list, lsize);

    if (!listpp)
        return;

    statistics_list->list = listpp;
    statistics_list->list[statistics_list->n_list] =
        malloc(sizeof(*statistics_list->list[statistics_list->n_list]));
    statisticsp = statistics_list->list[statistics_list->n_list];

    if (!statisticsp)
        return;

    dabba__interface_statistics__init(statisticsp);

    statisticsp->id = malloc(sizeof(*statisticsp->id));
    statisticsp->status = malloc(sizeof(*statisticsp->status));

    if (!statisticsp->id || !statisticsp->status) {
        free(statisticsp->status);
        free(statisticsp->id);
        free(statisticsp);
        return;
    }

    dabba__interface_id__init(statisticsp->id);
    dabba__error_code__init(statisticsp->status);

    statisticsp->id->name = rtnl_link_get_name(link);
    statisticsp->rx_byte = rtnl_link_get_stat(link, RTNL_LINK_RX_BYTES);
    statisticsp->rx_packet = rtnl_link_get_stat(link, RTNL_LINK_RX_PACKETS);
    statisticsp->rx_error = rtnl_link_get_stat(link, RTNL_LINK_RX_ERRORS);
    statisticsp->rx_dropped =
        rtnl_link_get_stat(link, RTNL_LINK_RX_DROPPED);
    statisticsp->rx_compressed =
        rtnl_link_get_stat(link, RTNL_LINK_RX_COMPRESSED);
    statisticsp->rx_error_fifo =
        rtnl_link_get_stat(link, RTNL_LINK_RX_FIFO_ERR);
    statisticsp->rx_error_frame =
        rtnl_link_get_stat(link, RTNL_LINK_RX_FRAME_ERR);
    statisticsp->rx_error_crc =
        rtnl_link_get_stat(link, RTNL_LINK_RX_CRC_ERR);
    statisticsp->rx_error_length =
        rtnl_link_get_stat(link, RTNL_LINK_RX_LEN_ERR);
    statisticsp->rx_error_missed =
        rtnl_link_get_stat(link, RTNL_LINK_RX_MISSED_ERR);
    statisticsp->rx_error_over =
        rtnl_link_get_stat(link, RTNL_LINK_RX_OVER_ERR);

    statisticsp->tx_byte = rtnl_link_get_stat(link, RTNL_LINK_TX_BYTES);
    statisticsp->tx_packet = rtnl_link_get_stat(link, RTNL_LINK_TX_PACKETS);
    statisticsp->tx_error = rtnl_link_get_stat(link, RTNL_LINK_TX_ERRORS);
    statisticsp->tx_dropped =
        rtnl_link_get_stat(link, RTNL_LINK_TX_DROPPED);
    statisticsp->tx_compressed =
        rtnl_link_get_stat(link, RTNL_LINK_TX_COMPRESSED);
    statisticsp->tx_error_fifo =
        rtnl_link_get_stat(link, RTNL_LINK_TX_FIFO_ERR);
    statisticsp->tx_error_carrier =
        rtnl_link_get_stat(link, RTNL_LINK_TX_CARRIER_ERR);
    statisticsp->tx_error_heartbeat =
        rtnl_link_get_stat(link, RTNL_LINK_TX_HBEAT_ERR);
    statisticsp->tx_error_window =
        rtnl_link_get_stat(link, RTNL_LINK_TX_WIN_ERR);
    statisticsp->tx_error_aborted =
        rtnl_link_get_stat(link, RTNL_LINK_TX_ABORT_ERR);

    statistics_list->n_list++;
}
Beispiel #18
0
static void handle_class(struct nl_object *obj, void *arg)
{
	struct rtnl_tc *tc = (struct rtnl_tc *) obj;
	struct element *e;
	struct rdata *rdata = arg;
	struct rdata ndata = {
		.level = rdata->level + 1,
	};

	if (!(e = handle_tc_obj(tc, "class", rdata)))
		return;

	ndata.parent = e;

	if (!strcmp(rtnl_tc_get_kind(tc), "htb"))
		element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc));

	find_classes(rtnl_tc_get_handle(tc), &ndata);
	find_qdiscs(rtnl_tc_get_handle(tc), &ndata);
}

static void find_qdiscs(uint32_t parent, struct rdata *rdata)
{
	struct rtnl_qdisc *filter;

	if (!(filter = rtnl_qdisc_alloc()))
		return;

	rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);

	nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
				handle_qdisc, rdata);

	rtnl_qdisc_put(filter);
}

static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata)
{
	struct nl_cache *cls_cache;

	if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
		return;

	nl_cache_foreach(cls_cache, handle_cls, rdata);

	nl_cache_free(cls_cache);
}

static void find_classes(uint32_t parent, struct rdata *rdata)
{
	struct rtnl_class *filter;

	if (!(filter = rtnl_class_alloc()))
		return;

	rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);

	nl_cache_foreach_filter(class_cache, OBJ_CAST(filter),
				handle_class, rdata);

	rtnl_class_put(filter);
}

static void handle_qdisc(struct nl_object *obj, void *arg)
{
	struct rtnl_tc *tc = (struct rtnl_tc *) obj;
	struct element *e;
	struct rdata *rdata = arg;
	struct rdata ndata = {
		.level = rdata->level + 1,
	};

	if (!(e = handle_tc_obj(tc, "qdisc", rdata)))
		return;

	ndata.parent = e;

	find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);

	if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
		find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata);
		find_classes(TC_H_ROOT, &ndata);
	}

	find_classes(rtnl_tc_get_handle(tc), &ndata);
}

static void handle_tc(struct element *e, struct rtnl_link *link)
{
	struct rtnl_qdisc *qdisc;
	int ifindex = rtnl_link_get_ifindex(link);
	struct rdata rdata = {
		.level = 1,
		.parent = e,
	};

	if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
		return;

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
	if (qdisc) {
		handle_qdisc(OBJ_CAST(qdisc), &rdata);
		rtnl_qdisc_put(qdisc);
	}

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
	if (qdisc) {
		handle_qdisc(OBJ_CAST(qdisc), &rdata);
		rtnl_qdisc_put(qdisc);
	}

	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
	if (qdisc) {
		handle_qdisc(OBJ_CAST(qdisc), &rdata);
		rtnl_qdisc_put(qdisc);
	}

	nl_cache_free(class_cache);
}

static void update_link_infos(struct element *e, struct rtnl_link *link)
{
	char buf[64];

	snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link));
	element_update_info(e, "MTU", buf);

	rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf));
	element_update_info(e, "Flags", buf);

	rtnl_link_operstate2str(rtnl_link_get_operstate(link),
				buf, sizeof(buf));
	element_update_info(e, "Operstate", buf);

	snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link));
	element_update_info(e, "IfIndex", buf);

	nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf));
	element_update_info(e, "Address", buf);

	nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf));
	element_update_info(e, "Broadcast", buf);

	rtnl_link_mode2str(rtnl_link_get_linkmode(link),
			   buf, sizeof(buf));
	element_update_info(e, "Mode", buf);

	snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link));
	element_update_info(e, "TXQlen", buf);

	nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf));
	element_update_info(e, "Family", buf);

	element_update_info(e, "Alias",
		rtnl_link_get_ifalias(link) ? : "");

	element_update_info(e, "Qdisc",
		rtnl_link_get_qdisc(link) ? : "");

	if (rtnl_link_get_link(link)) {
		snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link));
		element_update_info(e, "SlaveOfIndex", buf);
	}
}

static void do_link(struct nl_object *obj, void *arg)
{
	struct rtnl_link *link = (struct rtnl_link *) obj;
	struct element *e, *e_parent = NULL;
	int i, master_ifindex;

	if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) {
		/* FIXME: delete element */
		return;
	}

	/* Check if the interface is a slave of another interface */
	if ((master_ifindex = rtnl_link_get_link(link))) {
		char parent[IFNAMSIZ+1];

		rtnl_link_i2name(link_cache, master_ifindex,
				 parent, sizeof(parent));

		e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0);
	}

	if (!(e = element_lookup(grp, rtnl_link_get_name(link),
				 rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT)))
		return;

	if (e->e_flags & ELEMENT_FLAG_CREATED) {
		if (e->e_parent)
			e->e_level = e->e_parent->e_level + 1;

		if (element_set_key_attr(e, "bytes", "packets") ||
		    element_set_usage_attr(e, "bytes"))
			BUG();

		/* FIXME: Update link infos every 1s or so */
		update_link_infos(e, link);

		e->e_flags &= ~ELEMENT_FLAG_CREATED;
	}

	for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
		struct attr_map *m = &link_attrs[i];
		uint64_t c_rx = 0, c_tx = 0;
		int flags = 0;

		if (m->rxid >= 0) {
			c_rx = rtnl_link_get_stat(link, m->rxid);
			flags |= UPDATE_FLAG_RX;
		}

		if (m->txid >= 0) {
			c_tx = rtnl_link_get_stat(link, m->txid);
			flags |= UPDATE_FLAG_TX;
		}

		attr_update(e, m->attrid, c_rx, c_tx, flags);
	}

	if (!c_notc)
		handle_tc(e, link);

	element_notify_update(e, NULL);
	element_lifesign(e, 1);
}

static void netlink_read(void)
{
	int err;

	if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) {
		fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err));
		goto disable;
	}

	if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
		fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err));
		goto disable;
	}

	nl_cache_foreach(link_cache, do_link, NULL);

	return;

disable:
	netlink_ops.m_flags &= ~BMON_MODULE_ENABLED;
}

static void netlink_shutdown(void)
{
	nl_cache_free(link_cache);
	nl_cache_free(qdisc_cache);
	nl_socket_free(sock);
}
Beispiel #19
0
int sysnet_interface_set_addr(VPNInterface *i)
{
    int err;

    struct nl_cache *link_cache;
    struct nl_sock *sock;
    struct rtnl_addr *addr;
    struct rtnl_link *link;
    struct nl_addr *local_addr;

    sock = nl_socket_alloc();
    nl_connect(sock, NETLINK_ROUTE);

    rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache);

    addr = rtnl_addr_alloc();
    link = rtnl_link_get_by_name(link_cache, i->name);
    local_addr = nl_addr_build(i->address.ip.family, &i->address.ip.ip4, sizeof(i->address.ip.ip4));

    rtnl_addr_set_local(addr, local_addr);
    rtnl_addr_set_family(addr, i->address.ip.family);
    rtnl_addr_set_prefixlen(addr, i->address.prefix);
    rtnl_addr_set_link(addr, link);

    if ((err = rtnl_addr_add(sock, addr, 0)) < 0) {
        tox_trace(i->context->tox, "Unable to add address %s on %s: %s", ip_ntoa(&i->address.ip), rtnl_link_get_name(link), nl_geterror(err));
    }
    else {
        tox_trace(i->context->tox, "Added address %s on \"%s\"", ip_ntoa(&i->address.ip), i->name);
    }

    rtnl_link_put(link);
    rtnl_addr_put(addr);
    nl_cache_free(link_cache);
    nl_addr_put(local_addr);
    nl_socket_free(sock);

    return err;
}
Beispiel #20
0
static void nl_obj_input(struct nl_object *obj, void *arg)
{
	struct _obj
	{
		NLHDR_COMMON
	};

	struct _obj *o = (struct _obj *)obj;

	if( o->ce_msgtype == RTM_NEWLINK  || o->ce_msgtype == RTM_DELLINK ) 
	{
		struct rtnl_link *link = (struct rtnl_link *)obj;
		struct nl_addr *a = rtnl_link_get_addr(link);
		char buf[123];
		nl_addr2str(a, buf, sizeof(buf));
		int ifindex = rtnl_link_get_ifindex(link);
		bool active = rtnl_link_get_flags(link) & IFF_UP;
		char *iface = rtnl_link_get_name(link);
		if( o->ce_msgtype == RTM_NEWLINK ) 
		{
			struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex);
			if( nla == NULL )
			{
				g_critical("LINK NEW %s %i", iface, ifindex);
				struct link_addr *nla = link_addr_new(iface, ifindex, active);
				g_hash_table_insert(nl_runtime.link_addr_cache, &nla->ifindex, nla);
			}else
			{
				g_critical("LINK CHANGE %s %i", iface, ifindex);
				GHashTableIter iter;
				gpointer key, value;
				g_hash_table_iter_init(&iter, nla->addrs);
				if( active != nla->active )
				{
					while( g_hash_table_iter_next(&iter, &key, &value) )
					{
						struct incident *i;
						if( active )
						{
							g_critical("LINK UP");
							i = incident_new("dionaea.module.nl.addr.new");
						}else
						{
							g_critical("LINK DOWN");
							i = incident_new("dionaea.module.nl.addr.del");
						}
						incident_value_string_set(i, "addr", g_string_new(key));
						incident_value_string_set(i, "iface", g_string_new(nla->iface));
						incident_value_int_set(i, "scope", nla->ifindex);
						incident_report(i);
						incident_free(i);
					}
					nla->active = active;
				}
			}
		}else
		if( o->ce_msgtype == RTM_DELLINK ) 
		{
			g_critical("LINK DEL %s %i", iface, ifindex);
			struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex);
			g_hash_table_remove(nl_runtime.link_addr_cache, &ifindex);
			link_addr_free(nla);
		}
	}else
	if( o->ce_msgtype == RTM_NEWADDR  || o->ce_msgtype == RTM_DELADDR ) 
	{
		char buf[128];
		struct rtnl_addr *addr = (struct rtnl_addr *)obj;
		struct nl_addr *a = rtnl_addr_get_local(addr);
		int ifindex = rtnl_addr_get_ifindex(addr);
		nl_addr2str(a, buf, 128);
		char *slash; 
		if( (slash = strstr(buf, "/")) != NULL)
			*slash = '\0';
		char *saddr = NULL;

		struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex);
		if( !nla )
			return;

		if( o->ce_msgtype == RTM_NEWADDR ) 
		{
			if( g_hash_table_lookup(nla->addrs, buf) == NULL )
			{
				g_warning("NEW ADDR %s!", buf);
				saddr = g_strdup(buf);
				g_hash_table_insert(nla->addrs, saddr, saddr);

				if( nla->active )
				{
					struct incident *i = incident_new("dionaea.module.nl.addr.new");
					incident_value_string_set(i, "addr", g_string_new(saddr));
					incident_value_string_set(i, "iface", g_string_new(nla->iface));
					incident_value_int_set(i, "scope", nla->ifindex);
					incident_report(i);
					incident_free(i);
				}
			}
		}else
		if( o->ce_msgtype == RTM_DELADDR )
		{
			if( ( saddr = g_hash_table_lookup(nla->addrs, buf) ) != NULL )
			{
				g_warning("DEL ADDR! %s", buf);
				if( nla->active )
				{
					struct incident *i = incident_new("dionaea.module.nl.addr.del");
					incident_value_string_set(i, "addr", g_string_new(saddr));
					incident_value_string_set(i, "iface", g_string_new(nla->iface));
					incident_value_int_set(i, "scope", nla->ifindex);
					incident_report(i);
					incident_free(i);
				}
				g_hash_table_remove(nla->addrs, buf);
				g_free(saddr);
			}
		}
	}
/*
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nl_object_dump(obj, &dp);

	struct nl_dump_params params = {
		.dp_type = NL_DUMP_LINE,
		.dp_fd = stdout,
		.dp_prefix = 1,
	};
	g_debug("addr cache");
	nl_cache_dump(nl_runtime.addr_cache, &params);
	g_debug("arp cache");
	nl_cache_dump(nl_runtime.neigh_cache, &params);
	g_debug("link cache");
	nl_cache_dump(nl_runtime.link_cache, &params);
*/
}
Beispiel #21
0
static void __interface_coalesce_get(struct nl_object *obj, void *arg)
{
	struct rtnl_link *link = (struct rtnl_link *)obj;
	Dabba__InterfaceCoalesceList *coalesce_list = arg;
	Dabba__InterfaceCoalesce *coalescep, **listpp;
	size_t lsize =
	    sizeof(*coalesce_list->list) * (coalesce_list->n_list + 1);
	struct ethtool_coalesce coalesce;

	listpp = realloc(coalesce_list->list, lsize);

	if (!listpp)
		return;

	coalesce_list->list = listpp;
	coalesce_list->list[coalesce_list->n_list] =
	    malloc(sizeof(*coalesce_list->list[coalesce_list->n_list]));
	coalescep = coalesce_list->list[coalesce_list->n_list];

	if (!coalescep)
		return;

	dabba__interface_coalesce__init(coalescep);

	coalescep->id = malloc(sizeof(*coalescep->id));
	coalescep->status = malloc(sizeof(*coalescep->status));

	if (!coalescep->id || !coalescep->status) {
		free(coalescep->status);
		free(coalescep->id);
		free(coalescep);
		return;
	}

	dabba__interface_id__init(coalescep->id);
	dabba__error_code__init(coalescep->status);

	coalescep->id->name = rtnl_link_get_name(link);
	coalescep->status->code =
	    ldab_dev_coalesce_get(coalescep->id->name, &coalesce);

	coalescep->has_pkt_rate_high = coalescep->has_pkt_rate_low =
	    coalescep->has_rate_sample_interval =
	    coalescep->has_stats_block_coalesce_usecs =
	    coalescep->has_use_adaptive_rx_coalesce =
	    coalescep->has_rx_coalesce_usecs =
	    coalescep->has_rx_coalesce_usecs_irq =
	    coalescep->has_rx_coalesce_usecs_high =
	    coalescep->has_rx_coalesce_usecs_low =
	    coalescep->has_rx_max_coalesced_frames =
	    coalescep->has_rx_max_coalesced_frames_irq =
	    coalescep->has_rx_max_coalesced_frames_high =
	    coalescep->has_rx_max_coalesced_frames_low =
	    coalescep->has_use_adaptive_tx_coalesce =
	    coalescep->has_tx_coalesce_usecs =
	    coalescep->has_tx_coalesce_usecs_irq =
	    coalescep->has_tx_coalesce_usecs_high =
	    coalescep->has_tx_coalesce_usecs_low =
	    coalescep->has_tx_max_coalesced_frames =
	    coalescep->has_tx_max_coalesced_frames_irq =
	    coalescep->has_tx_max_coalesced_frames_high =
	    coalescep->has_tx_max_coalesced_frames_low = 1;

	coalescep->pkt_rate_high = coalesce.pkt_rate_high;
	coalescep->pkt_rate_low = coalesce.pkt_rate_low;
	coalescep->rate_sample_interval = coalesce.rate_sample_interval;
	coalescep->stats_block_coalesce_usecs =
	    coalesce.stats_block_coalesce_usecs;
	coalescep->use_adaptive_rx_coalesce = coalesce.use_adaptive_rx_coalesce;
	coalescep->rx_coalesce_usecs = coalesce.rx_coalesce_usecs;
	coalescep->rx_coalesce_usecs_irq = coalesce.rx_coalesce_usecs_irq;
	coalescep->rx_coalesce_usecs_high = coalesce.rx_coalesce_usecs_high;
	coalescep->rx_coalesce_usecs_low = coalesce.rx_coalesce_usecs_low;
	coalescep->rx_max_coalesced_frames = coalesce.rx_max_coalesced_frames;
	coalescep->rx_max_coalesced_frames_irq =
	    coalesce.rx_max_coalesced_frames_irq;
	coalescep->rx_max_coalesced_frames_high =
	    coalesce.rx_max_coalesced_frames_high;
	coalescep->rx_max_coalesced_frames_low =
	    coalesce.rx_max_coalesced_frames_low;
	coalescep->use_adaptive_tx_coalesce = coalesce.use_adaptive_tx_coalesce;
	coalescep->tx_coalesce_usecs = coalesce.tx_coalesce_usecs;
	coalescep->tx_coalesce_usecs_irq = coalesce.tx_coalesce_usecs_irq;
	coalescep->tx_coalesce_usecs_high = coalesce.tx_coalesce_usecs_high;
	coalescep->tx_coalesce_usecs_low = coalesce.tx_coalesce_usecs_low;
	coalescep->tx_max_coalesced_frames = coalesce.tx_max_coalesced_frames;
	coalescep->tx_max_coalesced_frames_irq =
	    coalesce.tx_max_coalesced_frames_irq;
	coalescep->tx_max_coalesced_frames_high =
	    coalesce.tx_max_coalesced_frames_high;
	coalescep->tx_max_coalesced_frames_low =
	    coalesce.tx_max_coalesced_frames_low;

	coalesce_list->n_list++;
}