Пример #1
0
static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
				     struct rdata *rdata)
{
	char buf[IFNAME_MAX], name[IFNAME_MAX];
	uint32_t id = rtnl_tc_get_handle(tc);
	struct element *e;

	rtnl_tc_handle2str(id, buf, sizeof(buf));
	snprintf(name, sizeof(name), "%s %s (%s)",
		 prefix, buf, rtnl_tc_get_kind(tc));

	if (!(e = element_lookup(grp, name, id, rdata ? rdata->parent : NULL, ELEMENT_CREAT)))
		return NULL;

	if (e->e_flags & ELEMENT_FLAG_CREATED) {
		e->e_level = rdata ? rdata->level : 0;

		if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
		    element_set_usage_attr(e, "tc_bytes"))
			BUG();

		update_tc_infos(e, tc);

		e->e_flags &= ~ELEMENT_FLAG_CREATED;
	}

	update_tc_attrs(e, tc);

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

	return e;
}
Пример #2
0
bool TNlHtb::Valid(const TNlLink &link, uint32_t defaultClass) {
    int ret;
    struct nl_cache *qdiscCache;
    bool valid = true;

    ret = rtnl_qdisc_alloc_cache(link.GetSock(), &qdiscCache);
    if (ret < 0) {
        L_ERR() << "can't alloc qdisc cache" << std::endl;
        return false;
    }

    struct rtnl_qdisc *qdisc = rtnl_qdisc_get(qdiscCache, link.GetIndex(), Handle);
    if (qdisc) {
        link.Dump("found", qdisc);
        if (rtnl_tc_get_ifindex(TC_CAST(qdisc)) != link.GetIndex())
            valid = false;
        else if (rtnl_tc_get_parent(TC_CAST(qdisc)) != Parent)
            valid = false;
        else if (rtnl_tc_get_handle(TC_CAST(qdisc)) != Handle)
            valid = false;
        else if (rtnl_tc_get_kind(TC_CAST(qdisc)) != std::string("htb"))
            valid = false;
        else if (rtnl_htb_get_defcls(qdisc) != TC_H_MIN(defaultClass))
            valid = false;
    } else {
        valid = false;
    }

    rtnl_qdisc_put(qdisc);
    nl_cache_free(qdiscCache);

    return valid;
}
Пример #3
0
TError TNlClass::Load(const TNl &nl) {
    struct nl_cache *cache;
    struct rtnl_class *tclass;

    int ret = rtnl_class_alloc_cache(nl.GetSock(), Index, &cache);
    if (ret < 0)
            return nl.Error(ret, "Cannot allocate class cache");

    tclass = rtnl_class_get(cache, Index, Handle);
    if (!tclass) {
        nl_cache_free(cache);
        return TError(EError::Unknown, "Can't find tc class");
    }

    Kind = rtnl_tc_get_kind(TC_CAST(tclass));

    if (Kind == "htb") {
        Prio = rtnl_htb_get_prio(tclass);
        Rate = rtnl_htb_get_rate(tclass);
        Ceil = rtnl_htb_get_ceil(tclass);
    }

    if (Kind == "hfsc") {
        struct tc_service_curve sc;
        if (!rtnl_class_hfsc_get_fsc(tclass, &sc))
            Rate = sc.m2;
        if (!rtnl_class_hfsc_get_usc(tclass, &sc))
            Ceil = sc.m2;
    }

    rtnl_class_put(tclass);
    nl_cache_free(cache);

    return TError::Success();
}
Пример #4
0
Result<htb::Config> decode<htb::Config>(
    const Netlink<struct rtnl_qdisc>& qdisc)
{
  if (rtnl_tc_get_kind(TC_CAST(qdisc.get())) != htb::KIND) {
    return None();
  }

  return htb::Config();
}
Пример #5
0
Result<basic::Classifier> decode<basic::Classifier>(
    const Netlink<struct rtnl_cls>& cls)
{
  if (rtnl_tc_get_kind(TC_CAST(cls.get())) != string("basic")) {
    return None();
  }

  return basic::Classifier(rtnl_cls_get_protocol(cls.get()));
}
Пример #6
0
Result<ingress::Discipline> decode<ingress::Discipline>(
    const Netlink<struct rtnl_qdisc>& qdisc)
{
  if (rtnl_tc_get_kind(TC_CAST(qdisc.get())) != string("ingress") ||
      rtnl_tc_get_parent(TC_CAST(qdisc.get())) != INGRESS_ROOT.get() ||
      rtnl_tc_get_handle(TC_CAST(qdisc.get())) != ingress::HANDLE.get()) {
    return None();
  }

  return ingress::Discipline();
}
Пример #7
0
bool TNlQdisc::Check(const TNl &nl) {
    struct nl_cache *qdiscCache;
    bool result = false;
    int ret;

    ret = rtnl_qdisc_alloc_cache(nl.GetSock(), &qdiscCache);
    if (ret < 0) {
        L_ERR() <<  nl.Error(ret, "cannot alloc qdisc cache") << std::endl;
        return false;
    }

    struct rtnl_qdisc *qdisc = rtnl_qdisc_get(qdiscCache, Index, Handle);
    if (!qdisc) {
        result = Kind == "";
        goto out;
    }

    nl.Dump("found", qdisc);
    if (rtnl_tc_get_ifindex(TC_CAST(qdisc)) != Index)
        goto out;

    if (rtnl_tc_get_parent(TC_CAST(qdisc)) != Parent)
        goto out;

    if (rtnl_tc_get_handle(TC_CAST(qdisc)) != Handle)
        goto out;

    if (rtnl_tc_get_kind(TC_CAST(qdisc)) != Kind)
        goto out;

    if (Kind == "htb") {
        if (rtnl_htb_get_defcls(qdisc) != Default)
            goto out;
    }

    result = true;

out:
    rtnl_qdisc_put(qdisc);
    nl_cache_free(qdiscCache);
    return result;
}
Пример #8
0
static int init_qdisc(libxl__checkpoint_devices_state *cds,
                      libxl__remus_device_nic *remus_nic)
{
    int rc, ret, ifindex;
    struct rtnl_link *ifb = NULL;
    struct rtnl_qdisc *qdisc = NULL;
    libxl__remus_state *rs = cds->concrete_data;

    STATE_AO_GC(cds->ao);

    /* Now that we have brought up REMUS_IFB device with plug qdisc for
     * this vif, so we need to refill the qdisc cache.
     */
    ret = nl_cache_refill(rs->nlsock, rs->qdisc_cache);
    if (ret) {
        LOGD(ERROR, cds->domid,
             "cannot refill qdisc cache: %s", nl_geterror(ret));
        rc = ERROR_FAIL;
        goto out;
    }

    /* get a handle to the REMUS_IFB interface */
    ret = rtnl_link_get_kernel(rs->nlsock, 0, remus_nic->ifb, &ifb);
    if (ret) {
        LOGD(ERROR, cds->domid,
             "cannot obtain handle for %s: %s", remus_nic->ifb,
            nl_geterror(ret));
        rc = ERROR_FAIL;
        goto out;
    }

    ifindex = rtnl_link_get_ifindex(ifb);
    if (!ifindex) {
        LOGD(ERROR, cds->domid,
             "interface %s has no index", remus_nic->ifb);
        rc = ERROR_FAIL;
        goto out;
    }

    /* Get a reference to the root qdisc installed on the REMUS_IFB, by
     * querying the qdisc list we obtained earlier. The netbufscript
     * sets up the plug qdisc as the root qdisc, so we don't have to
     * search the entire qdisc tree on the REMUS_IFB dev.

     * There is no need to explicitly free this qdisc as its just a
     * reference from the qdisc cache we allocated earlier.
     */
    qdisc = rtnl_qdisc_get_by_parent(rs->qdisc_cache, ifindex, TC_H_ROOT);
    if (qdisc) {
        const char *tc_kind = rtnl_tc_get_kind(TC_CAST(qdisc));
        /* Sanity check: Ensure that the root qdisc is a plug qdisc. */
        if (!tc_kind || strcmp(tc_kind, "plug")) {
            LOGD(ERROR, cds->domid,
                 "plug qdisc is not installed on %s", remus_nic->ifb);
            rc = ERROR_FAIL;
            goto out;
        }
        remus_nic->qdisc = qdisc;
    } else {
        LOGD(ERROR, cds->domid,
             "Cannot get qdisc handle from ifb %s", remus_nic->ifb);
        rc = ERROR_FAIL;
        goto out;
    }

    rc = 0;

out:
    if (ifb)
        rtnl_link_put(ifb);

    if (rc && qdisc)
        nl_object_put((struct nl_object *)qdisc);

    return rc;
}
Пример #9
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);
}
Пример #10
0
Result<icmp::Classifier> decode<icmp::Classifier>(
    const Netlink<struct rtnl_cls>& cls)
{
  if (rtnl_cls_get_protocol(cls.get()) != ETH_P_IP ||
      rtnl_tc_get_kind(TC_CAST(cls.get())) != string("u32")) {
    return None();
  }

  // Raw values.
  Option<uint32_t> protocol;
  Option<net::IP> destinationIP;

  // There are at most 0xff keys.
  for (uint8_t i = 0; i <= 0xff; i++) {
    uint32_t value;
    uint32_t mask;
    int offset;
    int offsetmask;

    // Decode a selector from the libnl filter 'cls'.
    int error = rtnl_u32_get_key(
        cls.get(),
        i,
        &value,
        &mask,
        &offset,
        &offsetmask);

    if (error != 0) {
      if (error == -NLE_INVAL) {
        // This is the case where cls does not have a u32 selector. In
        // that case, we just return None.
        return None();
      } else if (error == -NLE_RANGE) {
        break;
      } else {
        return Error(
            "Failed to decode a u32 selector: " +
            string(nl_geterror(error)));
      }
    }

    // The function "rtnl_u32_get_key" sets value and mask in network
    // order. Convert them back to host order.
    value = ntohl(value);
    mask = ntohl(mask);

    // IP protocol field.
    if (offset == 8 && value == 0x00010000 && mask == 0x00ff0000) {
      protocol = value;
    }

    // Destination IP address.
    if (offset == 16 && mask == 0xffffffff) {
      destinationIP = net::IP(value);
    }
  }

  if (protocol.isSome()) {
    return icmp::Classifier(destinationIP);
  }

  return None();
}