Example #1
0
TError TNlCgFilter::Remove(const TNlLink &link) {
    TError error = TError::Success();
    struct rtnl_cls *cls;
    int ret;

    cls = rtnl_cls_alloc();
    if (!cls)
        return TError(EError::Unknown, std::string("Unable to allocate filter object"));

    rtnl_tc_set_ifindex(TC_CAST(cls), link.GetIndex());

    ret = rtnl_tc_set_kind(TC_CAST(cls), FilterType);
    if (ret < 0) {
        error = TError(EError::Unknown, std::string("Unable to set filter type: ") + nl_geterror(ret));
        goto free_cls;
    }

    rtnl_cls_set_prio(cls, FilterPrio);
    rtnl_cls_set_protocol(cls, 0);
    rtnl_tc_set_parent(TC_CAST(cls), Parent);

    link.Dump("remove", cls);

    ret = rtnl_cls_delete(link.GetSock(), cls, 0);
    if (ret < 0)
        error = TError(EError::Unknown, std::string("Unable to remove filter: ") + nl_geterror(ret));

free_cls:
    rtnl_cls_put(cls);

    return error;
}
Example #2
0
TError TNlHtb::Create(const TNlLink &link, uint32_t defaultClass) {
    TError error = TError::Success();
    int ret;
    struct rtnl_qdisc *qdisc;

    qdisc = rtnl_qdisc_alloc();
    if (!qdisc)
        return TError(EError::Unknown, std::string("Unable to allocate qdisc object"));

    rtnl_tc_set_ifindex(TC_CAST(qdisc), link.GetIndex());
    rtnl_tc_set_parent(TC_CAST(qdisc), Parent);
    rtnl_tc_set_handle(TC_CAST(qdisc), Handle);

    ret = rtnl_tc_set_kind(TC_CAST(qdisc), "htb");
    if (ret < 0) {
        error = TError(EError::Unknown, std::string("Unable to set qdisc type: ") + nl_geterror(ret));
        goto free_qdisc;
    }

    rtnl_htb_set_defcls(qdisc, TC_H_MIN(defaultClass));
    rtnl_htb_set_rate2quantum(qdisc, 10);

    link.Dump("add", qdisc);

    ret = rtnl_qdisc_add(link.GetSock(), qdisc, NLM_F_CREATE);
    if (ret < 0)
        error = TError(EError::Unknown, std::string("Unable to add qdisc: ") + nl_geterror(ret));

free_qdisc:
    rtnl_qdisc_put(qdisc);

    return error;
}
Example #3
0
int netem_set_params(const char *iface, struct netem_params *params)
{
	struct rtnl_link *link;
	struct rtnl_qdisc *qdisc;
	int err;

	pthread_mutex_lock(&nl_sock_mutex);

	/* filter link by name */
	if ((link = rtnl_link_get_by_name(link_cache, iface)) == NULL) {
		fprintf(stderr, "unknown interface/link name.\n");
		pthread_mutex_unlock(&nl_sock_mutex);
		return -1;
	}

	if (!(qdisc = rtnl_qdisc_alloc())) {
		/* OOM error */
		fprintf(stderr, "couldn't alloc qdisc\n");
		pthread_mutex_unlock(&nl_sock_mutex);
		return -1;
	}

	rtnl_tc_set_link(TC_CAST(qdisc), link);
	rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT);
	rtnl_tc_set_kind(TC_CAST(qdisc), "netem");

	rtnl_netem_set_delay(qdisc,
	                     params->delay * 1000); /* expects microseconds */
	rtnl_netem_set_jitter(qdisc, params->jitter * 1000);
	/* params->loss is given in 10ths of a percent */
	rtnl_netem_set_loss(qdisc, (params->loss * (UINT_MAX / 1000)));

	/* Submit request to kernel and wait for response */
	err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE | NLM_F_REPLACE);

	/* Return the qdisc object to free memory resources */
	rtnl_qdisc_put(qdisc);

	if (err < 0) {
		fprintf(stderr, "Unable to add qdisc: %s\n", nl_geterror(err));
		pthread_mutex_unlock(&nl_sock_mutex);
		return err;
	}

	if ((err = nl_cache_refill(sock, link_cache)) < 0) {
		fprintf(stderr, "Unable to resync link cache: %s\n",
		        nl_geterror(err));
		pthread_mutex_unlock(&nl_sock_mutex);
		return -1;
	}

	pthread_mutex_unlock(&nl_sock_mutex);
	return 0;
}
Example #4
0
Try<Nothing> encode<basic::Classifier>(
    const Netlink<struct rtnl_cls>& cls,
    const basic::Classifier& classifier)
{
  rtnl_cls_set_protocol(cls.get(), classifier.protocol());

  int error = rtnl_tc_set_kind(TC_CAST(cls.get()), "basic");
  if (error != 0) {
    return Error(
        "Failed to set the kind of the classifier: " +
        string(nl_geterror(error)));
  }

  return Nothing();
}
/* 
 * Function that adds a new filter and attach it to a hash table 
 * and set next hash table link with hash mask
 *
 */
static
int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, 
	    uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
	    uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset, struct rtnl_act *act, struct rtnl_act *act2)
{
    struct rtnl_cls *cls;
    int err;

    cls=rtnl_cls_alloc();
    if (!(cls)) {
        printf("Can not allocate classifier\n");
        nl_socket_free(sock);
        exit(1);
    }
    
    rtnl_tc_set_link(TC_CAST(cls), rtnlLink);

    if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
        printf("Can not set classifier as u32\n");
        return 1;
    }

    rtnl_cls_set_prio(cls, prio);
    rtnl_cls_set_protocol(cls, ETH_P_IP);

    rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(0xffff, 0));
    
    if (htid)
	rtnl_u32_set_hashtable(cls, htid);

    rtnl_u32_add_key_uint32(cls, keyval, keymask, keyoff, keyoffmask);

    rtnl_u32_set_hashmask(cls, hmask, hoffset);

    rtnl_u32_set_link(cls, htlink);

    rtnl_u32_add_action(cls, act);

    rtnl_u32_add_action(cls, act2);


    if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
        printf("Can not add classifier: %s\n", nl_geterror(err));
        return -1;
    }
    rtnl_cls_put(cls);
    return 0;
}
Example #6
0
Try<Nothing> encode<ingress::Discipline>(
    const Netlink<struct rtnl_qdisc>& qdisc,
    const ingress::Discipline& discipline)
{
  int error = rtnl_tc_set_kind(TC_CAST(qdisc.get()), "ingress");
  if (error != 0) {
    return Error(
        "Failed to set the kind of the queueing discipline: " +
        string(nl_geterror(error)));
  }

  rtnl_tc_set_parent(TC_CAST(qdisc.get()), INGRESS_ROOT.get());
  rtnl_tc_set_handle(TC_CAST(qdisc.get()), ingress::HANDLE.get());

  return Nothing();
}
Example #7
0
TError TNlClass::Create(const TNl &nl) {
    struct rtnl_class *cls;
    TError error;
    int ret;

    cls = rtnl_class_alloc();
    if (!cls)
        return TError(EError::Unknown, "Cannot allocate rtnl_class object");

    rtnl_tc_set_ifindex(TC_CAST(cls), Index);
    rtnl_tc_set_parent(TC_CAST(cls), Parent);
    rtnl_tc_set_handle(TC_CAST(cls), Handle);

    ret = rtnl_tc_set_kind(TC_CAST(cls), Kind.c_str());
    if (ret < 0) {
        error = nl.Error(ret, "Cannot set class kind");
        goto free_class;
    }

    if (Kind == "htb") {
        /* must be <= INT32_MAX to prevent overflows in libnl */
        uint64_t maxRate = INT32_MAX;

        /*
         * HTB doesn't allow 0 rate
         * FIXME add support for 64-bit rates
         */
        rtnl_htb_set_rate(cls, std::min(Rate ?: 1, maxRate));
        rtnl_htb_set_ceil(cls, std::min(Ceil ?: maxRate, maxRate));
        rtnl_htb_set_prio(cls, Prio);

        if (MTU)
            rtnl_tc_set_mtu(TC_CAST(cls), MTU);

        if (Quantum)
            rtnl_htb_set_quantum(cls, Quantum);

        if (RateBurst)
            rtnl_htb_set_rbuffer(cls, RateBurst);

        if (CeilBurst)
            rtnl_htb_set_cbuffer(cls, CeilBurst);
    }
/*
 * function that adds a new ingress qdisc and set the default class for unclassified traffic
 */
static
int qdisc_add_ingress(struct nl_sock *sock, struct rtnl_link *rtnlLink)
{
    
    struct rtnl_qdisc *qdisc;
    int err;
    
    /* Allocation of a qdisc object */
    if (!(qdisc = rtnl_qdisc_alloc())) {
        printf("Can not allocate Qdisc\n");
	return -1;
    }

    //rtnl_tc_set_ifindex(TC_CAST(qdisc), master_index);
    rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink);
    rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT);

    //printf("Delete current qdisc\n");
    rtnl_qdisc_delete(sock, qdisc);
    //rtnl_qdisc_put(qdisc);

    rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(0xffff, 0));

    if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "ingress"))) {
        printf("Can not allocate ingress\n");
	return -1;
    }

    /* Submit request to kernel and wait for response */
    if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) {
        printf("Can not allocate ingress Qdisc\n");
	return -1;
    }

    /* Return the qdisc object to free memory resources */
    rtnl_qdisc_put(qdisc);

    return 0;
}
/* 
 * function that creates a new hash table 
 */
static
int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor)
{

    int err;
    struct rtnl_cls *cls;

    cls=rtnl_cls_alloc();
    if (!(cls)) {
        printf("Can not allocate classifier\n");
        nl_socket_free(sock);
        exit(1);
    }
    
    rtnl_tc_set_link(TC_CAST(cls), rtnlLink);

    if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
        printf("Can not set classifier as u32\n");
        return 1;
    }

    rtnl_cls_set_prio(cls, prio);
    rtnl_cls_set_protocol(cls, ETH_P_IP);
    rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(0xffff, 0));

    rtnl_u32_set_handle(cls, htid, 0x0, 0x0);
    //printf("htid: 0x%X\n", htid);
    rtnl_u32_set_divisor(cls, divisor);

    if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
        printf("Can not add classifier: %s\n", nl_geterror(err));
        return -1;
    }
    rtnl_cls_put(cls);
    return 0;
}
int main(void)
{
    struct nl_sock *sock;
    struct rtnl_link *link;
    uint32_t ht, htlink, htid, direction;
    char chashlink[16]="";
    int err;
    struct nl_cache *link_cache;
    struct rtnl_act *act, *act2;
    uint32_t i;

    if (!(sock = nl_socket_alloc())) {
        printf("Unable to allocate netlink socket\n");
        exit(1);
    }

    if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0 ) {
        printf("Nu s-a putut conecta la NETLINK!\n");
        nl_socket_free(sock);
        exit(1);
    }

    if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
        printf("Unable to allocate link cache: %s\n",
                             nl_geterror(err));
        nl_socket_free(sock);
        exit(1);
    }
    
    /* lookup interface index of eth0 */
    if (!(link = rtnl_link_get_by_name(link_cache, "eth0"))) {
        /* error */
        printf("Interface not found\n");
        nl_socket_free(sock);
        exit(1);
    }
    
    err=qdisc_add_ingress(sock, link);
    //printf("Add main hash table\n");

    /* create u32 first hash filter table
     *
     */
    /* formula calcul handle:
    *         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
    */

    /*
     * Upper limit of number of hash tables: 4096 (0xFFF)
     * Number of hashes in a table: 256 values (0xFF)
     *
     */

    /* using 256 values for hash table 
     * each entry in hash table match a byte from IP address specified later by a hash key
     */

    for (i = 1; i <= 0xf; i++) 
	u32_add_ht(sock, link, 1, i, 256);

    /* 
     * attach a u32 filter to the first hash 
     * that redirects all traffic and make a hash key
     * from the fist byte of the IP address
     *
     */

    //divisor=0x0;	// unused here
    //handle = 0x0;	// unused here
    //hash = 0x0;		// unused here
    //htid = 0x0;		// unused here
    //nodeid = 0x0;	// unused here

    // direction = 12 -> source IP
    // direction = 16 -> destination IP
    direction = 16;

    /*
     * which hash table will use
     * in our case is hash table no 1 defined previous
     *
     * There are 2 posibilities to set the the hash table:
     * 1. Using function get_u32_handle and sent a string in
     *  format 10: where 10 is number of the hash table
     * 2. Create your own value in format: 0xa00000
     *
     */
    strcpy(chashlink, "1:");
    //printf("Hash Link: %s\n", chashlink);
    //chashlink=malloc(sizeof(char) *
    htlink = 0x0;		// is used by get_u32_handle to return the correct value of hash table (link)
    
    if(get_u32_handle(&htlink, chashlink)) {
        printf ("Illegal \"link\"");
        nl_socket_free(sock);
        exit(1);
    }
    //printf ("hash link : 0x%X\n", htlink);
    //printf ("hash link test : %u\n", (htlink && TC_U32_NODE(htlink)));

    if (htlink && TC_U32_NODE(htlink)) {
	printf("\"link\" must be a hash table.\n");
        nl_socket_free(sock);
        exit(1);
    }

    /* the hash mask will hit the hash table (link) no 1: in our case
     */

    /* set the hash key mask */
    //hashmask = 0xFF000000UL;	// the mask that is used to match the hash in specific table, in our case for example 1:a with mean the first byte which is 10 in hash table 1

    /* Here we add a hash filter which match the first byte (see the hashmask value)
     * of the source IP (offset 12 in the packet header)
     * You can use also offset 16 to match the destination IP
     */

    /*
     * Also we need a filter to match our rule
     * This mean that we will put a 0.0.0.0/0 filter in our first rule
     * that match the offset 12 (source IP)
     * Also you can put offset 16 to match the destination IP
     */

    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
	    0x0, 0x0, direction, 0,
	    0, htlink, 0xff000000, direction, NULL, NULL);

    /*
     * For each first byte that we need to match we will create a new hash table
     * For example: you have those clases: 10.0.0.0/24 and 172.16.0.0/23
     * For byte 10 and byte 172 will create a separate hash table that will match the second
     * byte from each class.
     *
     */

    
    /*
     * Now we will create other filter under (ATENTION) our first hash table (link) 1:
     * Previous rule redirects the trafic according the hash mask to hash table (link) no 1:
     * Here we will match the hash tables from 1:0 to 1:ff. Under each hash table we will attach 
     * other rules that matches next byte from IP source/destination IP and we will repeat the 
     * previous steps.
     *
     */
    act = rtnl_act_alloc();
    if (!act) {
            printf("rtnl_act_alloc() returns %p\n", act);
            return -1;
    }
    rtnl_tc_set_kind(TC_CAST(act), "skbedit");
    rtnl_skbedit_set_queue_mapping(act, 4);
    rtnl_skbedit_set_action(act, TC_ACT_PIPE);

    act2 = rtnl_act_alloc();
    if (!act2) {
            printf("rtnl_act_alloc() returns %p\n", act2);
            return -1;
    }
    rtnl_tc_set_kind(TC_CAST(act2), "mirred");
    rtnl_mirred_set_action(act2, TCA_EGRESS_REDIR);
    rtnl_mirred_set_policy(act2, TC_ACT_STOLEN);
    rtnl_mirred_set_ifindex(act2, rtnl_link_name2i(link_cache, "eth1"));
    // /8 check

    // 10.0.0.0/8
    ht=get_u32_parse_handle("1:a:");
    htid = (ht&0xFFFFF000);
    htlink=get_u32_parse_handle("2:");

    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
	    0x0a000000, 0xff000000, direction, 0,
	    htid, htlink, 0x00ff0000, direction, act, act2);

    rtnl_act_put(act);
    nl_socket_free(sock);
    return 0;
}
Example #11
0
File: tc.c Project: acooks/libnl
int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
{
	struct nl_cache *link_cache;
	struct rtnl_tc_ops *ops;
	struct nlattr *tb[TCA_MAX + 1];
	char kind[TCKINDSIZ];
	struct tcmsg *tm;
	int err;

	tc->ce_msgtype = n->nlmsg_type;

	err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
	if (err < 0)
		return err;

	if (tb[TCA_KIND] == NULL)
		return -NLE_MISSING_ATTR;

	nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
	rtnl_tc_set_kind(tc, kind);

	tm = nlmsg_data(n);
	tc->tc_family  = tm->tcm_family;
	tc->tc_ifindex = tm->tcm_ifindex;
	tc->tc_handle  = tm->tcm_handle;
	tc->tc_parent  = tm->tcm_parent;
	tc->tc_info    = tm->tcm_info;

	tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
		        TCA_ATTR_PARENT | TCA_ATTR_INFO);

	if (tb[TCA_OPTIONS]) {
		tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
		if (!tc->tc_opts)
			return -NLE_NOMEM;
		tc->ce_mask |= TCA_ATTR_OPTS;
	}

	if (tb[TCA_STATS2]) {
		struct nlattr *tbs[TCA_STATS_MAX + 1];

		err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
				       tc_stats2_policy);
		if (err < 0)
			return err;

		if (tbs[TCA_STATS_BASIC]) {
			struct gnet_stats_basic *bs;
			
			bs = nla_data(tbs[TCA_STATS_BASIC]);
			tc->tc_stats[RTNL_TC_BYTES]	= bs->bytes;
			tc->tc_stats[RTNL_TC_PACKETS]	= bs->packets;
		}

		if (tbs[TCA_STATS_RATE_EST]) {
			struct gnet_stats_rate_est *re;

			re = nla_data(tbs[TCA_STATS_RATE_EST]);
			tc->tc_stats[RTNL_TC_RATE_BPS]	= re->bps;
			tc->tc_stats[RTNL_TC_RATE_PPS]	= re->pps;
		}
		
		if (tbs[TCA_STATS_QUEUE]) {
			struct gnet_stats_queue *q;

			q = nla_data(tbs[TCA_STATS_QUEUE]);
			tc->tc_stats[RTNL_TC_QLEN]	= q->qlen;
			tc->tc_stats[RTNL_TC_BACKLOG]	= q->backlog;
			tc->tc_stats[RTNL_TC_DROPS]	= q->drops;
			tc->tc_stats[RTNL_TC_REQUEUES]	= q->requeues;
			tc->tc_stats[RTNL_TC_OVERLIMITS]	= q->overlimits;
		}

		tc->ce_mask |= TCA_ATTR_STATS;
		
		if (tbs[TCA_STATS_APP]) {
			tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
			if (tc->tc_xstats == NULL)
				return -NLE_NOMEM;
			tc->ce_mask |= TCA_ATTR_XSTATS;
		} else
			goto compat_xstats;
	} else {
		if (tb[TCA_STATS]) {
			struct tc_stats *st = nla_data(tb[TCA_STATS]);

			tc->tc_stats[RTNL_TC_BYTES]	= st->bytes;
			tc->tc_stats[RTNL_TC_PACKETS]	= st->packets;
			tc->tc_stats[RTNL_TC_RATE_BPS]	= st->bps;
			tc->tc_stats[RTNL_TC_RATE_PPS]	= st->pps;
			tc->tc_stats[RTNL_TC_QLEN]	= st->qlen;
			tc->tc_stats[RTNL_TC_BACKLOG]	= st->backlog;
			tc->tc_stats[RTNL_TC_DROPS]	= st->drops;
			tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits;

			tc->ce_mask |= TCA_ATTR_STATS;
		}

compat_xstats:
		if (tb[TCA_XSTATS]) {
			tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
			if (tc->tc_xstats == NULL)
				return -NLE_NOMEM;
			tc->ce_mask |= TCA_ATTR_XSTATS;
		}
	}

	ops = rtnl_tc_get_ops(tc);
	if (ops && ops->to_msg_parser) {
		void *data = rtnl_tc_data(tc);

		if (!data)
			return -NLE_NOMEM;

		err = ops->to_msg_parser(tc, data);
		if (err < 0)
			return err;
	}

	if ((link_cache = __nl_cache_mngt_require("route/link"))) {
		struct rtnl_link *link;

		if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
			rtnl_tc_set_link(tc, link);

			/* rtnl_tc_set_link incs refcnt */
			rtnl_link_put(link);
		}
	}

	return 0;
}
Example #12
0
int netem_get_params(char *iface, struct netem_params *params)
{
	struct rtnl_link *link;
	struct rtnl_qdisc *filter_qdisc;
	struct rtnl_qdisc *found_qdisc = NULL;
	int err;
	int delay, jitter, loss;

	pthread_mutex_lock(&nl_sock_mutex);
	if ((err = nl_cache_refill(sock, link_cache)) < 0) {
		fprintf(stderr, "Unable to resync link cache: %s\n",
		        nl_geterror(err));
		goto cleanup;
	}

	if ((err = nl_cache_refill(sock, qdisc_cache)) < 0) {
		fprintf(stderr, "Unable to resync link cache: %s\n",
		        nl_geterror(err));
		goto cleanup;
	}

	/* filter link by name */
	if ((link = rtnl_link_get_by_name(link_cache, iface)) == NULL) {
		fprintf(stderr, "unknown interface/link name.\n");
		goto cleanup;
	}

	if (!(filter_qdisc = rtnl_qdisc_alloc())) {
		/* OOM error */
		fprintf(stderr, "couldn't alloc qdisc\n");
		goto cleanup_link;
	}

	rtnl_tc_set_link(TC_CAST(filter_qdisc), link);
	rtnl_tc_set_parent(TC_CAST(filter_qdisc), TC_H_ROOT);
	rtnl_tc_set_kind(TC_CAST(filter_qdisc), "netem");

	found_qdisc = (struct rtnl_qdisc *)nl_cache_find(
	    qdisc_cache, OBJ_CAST(filter_qdisc));
	if (!found_qdisc) {
		/* The iface probably doesn't have a netem qdisc at startup. */
		goto cleanup_filter_qdisc;
	}

	if (0 > (delay = rtnl_netem_get_delay(found_qdisc))) {
		fprintf(stderr, "couldn't get delay for iface: %s\n", iface);
		goto cleanup_qdisc;
	}
	params->delay = (double)delay / 1000;

	if (0 > (jitter = rtnl_netem_get_jitter(found_qdisc))) {
		fprintf(stderr, "couldn't get jitter for iface: %s\n", iface);
		goto cleanup_qdisc;
	}
	params->jitter = (double)jitter / 1000;

	if (0 > (loss = rtnl_netem_get_loss(found_qdisc))) {
		fprintf(stderr, "couldn't get loss for iface: %s\n", iface);
		goto cleanup_qdisc;
	}
	/* loss is specified in 10ths of a percent, ie. 1 ==> 0.1% */
	params->loss = (int)(loss / (UINT_MAX / 1000));

	rtnl_qdisc_put(found_qdisc);
	rtnl_qdisc_put(filter_qdisc);
	rtnl_link_put(link);
	pthread_mutex_unlock(&nl_sock_mutex);
	return 0;

cleanup_qdisc:
	rtnl_qdisc_put(found_qdisc);
cleanup_filter_qdisc:
	rtnl_qdisc_put(filter_qdisc);
cleanup_link:
	rtnl_link_put(link);
cleanup:
	pthread_mutex_unlock(&nl_sock_mutex);
	return -1;
}
Example #13
0
File: tc.c Project: Alenevod/libnl
void nl_cli_tc_parse_kind(struct rtnl_tc *tc, char *arg)
{
	rtnl_tc_set_kind(tc, arg);
}
Example #14
0
int main(int argc, char *argv[])
{
	struct nl_sock *sock;
	struct rtnl_cls *cls;
	struct rtnl_tc *tc;
	struct nl_cache *link_cache;
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_DETAILS,
		.dp_fd = stdout,
	};
	struct nl_cli_tc_module *tm;
	struct rtnl_tc_ops *ops;
	int err, flags = NLM_F_CREATE | NLM_F_EXCL;
	char *kind, *id = NULL;
 
	sock = nl_cli_alloc_socket();
	nl_cli_connect(sock, NETLINK_ROUTE);

	link_cache = nl_cli_link_alloc_cache(sock);

 	cls = nl_cli_cls_alloc();
	tc = (struct rtnl_tc *) cls;
 
	for (;;) {
		int c, optidx = 0;
		enum {
			ARG_UPDATE = 257,
			ARG_UPDATE_ONLY = 258,
			ARG_MTU,
			ARG_MPU,
			ARG_OVERHEAD,
			ARG_LINKTYPE,
			ARG_PROTO,
			ARG_PRIO,
		};
		static struct option long_opts[] = {
			{ "quiet", 0, 0, 'q' },
			{ "help", 0, 0, 'h' },
			{ "version", 0, 0, 'v' },
			{ "dev", 1, 0, 'd' },
			{ "parent", 1, 0, 'p' },
			{ "id", 1, 0, 'i' },
			{ "proto", 1, 0, ARG_PROTO },
			{ "prio", 1, 0, ARG_PRIO },
			{ "update", 0, 0, ARG_UPDATE },
			{ "update-only", 0, 0, ARG_UPDATE_ONLY },
			{ "mtu", 1, 0, ARG_MTU },
			{ "mpu", 1, 0, ARG_MPU },
			{ "overhead", 1, 0, ARG_OVERHEAD },
			{ "linktype", 1, 0, ARG_LINKTYPE },
			{ 0, 0, 0, 0 }
		};
	
		c = getopt_long(argc, argv, "+qhvd:p:i:",
				long_opts, &optidx);
		if (c == -1)
			break;

		switch (c) {
		case 'q': quiet = 1; break;
		case 'h': print_usage(); break;
		case 'v': nl_cli_print_version(); break;
		case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
		case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
		case 'i': id = strdup(optarg); break;
		case ARG_UPDATE: flags = NLM_F_CREATE; break;
		case ARG_UPDATE_ONLY: flags = 0; break;
		case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break;
		case ARG_MPU: nl_cli_tc_parse_mpu(tc, optarg); break;
		case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
		case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
		case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
		case ARG_PRIO:
			rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
			break;
		}
 	}

	if (optind >= argc)
		print_usage();

	if (!rtnl_tc_get_ifindex(tc))
		nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");

	if (!rtnl_tc_get_parent(tc))
		nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)");

	if (id) {
		nl_cli_tc_parse_handle(tc, id, 1);
		free(id);
	}

	kind = argv[optind++];
	rtnl_tc_set_kind(tc, kind);

	if (!(ops = rtnl_tc_get_ops(tc)))
		nl_cli_fatal(ENOENT, "Unknown classifier \"%s\".", kind);

	if (!(tm = nl_cli_tc_lookup(ops)))
		nl_cli_fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);

	tm->tm_parse_argv(tc, argc, argv);

	if (!quiet) {
		printf("Adding ");
		nl_object_dump(OBJ_CAST(cls), &dp);
 	}

	if ((err = rtnl_cls_add(sock, cls, flags)) < 0)
		nl_cli_fatal(EINVAL, "Unable to add classifier: %s", nl_geterror(err));

	return 0;
}
Example #15
0
TError TNlQdisc::Create(const TNl &nl) {
    TError error = TError::Success();
    int ret;
    struct rtnl_qdisc *qdisc;

    if (Kind == "")
        return Delete(nl);

    qdisc = rtnl_qdisc_alloc();
    if (!qdisc)
        return TError(EError::Unknown, std::string("Unable to allocate qdisc object"));

    rtnl_tc_set_ifindex(TC_CAST(qdisc), Index);
    rtnl_tc_set_parent(TC_CAST(qdisc), Parent);
    rtnl_tc_set_handle(TC_CAST(qdisc), Handle);

    ret = rtnl_tc_set_kind(TC_CAST(qdisc), Kind.c_str());
    if (ret < 0) {
        error = nl.Error(ret, "Cannot to set qdisc type: " + Kind);
        goto free_qdisc;
    }

    if (Kind == "bfifo" || Kind == "pfifo") {
        if (Limit)
            rtnl_qdisc_fifo_set_limit(qdisc, Limit);
    }

    if (Kind == "htb") {
        if (Default)
            rtnl_htb_set_defcls(qdisc, Default);
        if (Quantum)
            rtnl_htb_set_rate2quantum(qdisc, Quantum);
    }

    if (Kind == "hfsc") {
        if (Default)
            rtnl_qdisc_hfsc_set_defcls(qdisc, Default);
    }

    if (Kind == "sfq") {
        if (Limit)
            rtnl_sfq_set_limit(qdisc, Limit);
        if (Quantum)
            rtnl_sfq_set_quantum(qdisc, Quantum);
    }

    if (Kind == "fq_codel") {
        if (Limit)
            rtnl_qdisc_fq_codel_set_limit(qdisc, Limit);
        if (Quantum)
            rtnl_qdisc_fq_codel_set_quantum(qdisc, Quantum);
    }

    nl.Dump("create", qdisc);

    ret = rtnl_qdisc_add(nl.GetSock(), qdisc, NLM_F_CREATE  | NLM_F_REPLACE);
    if (ret < 0)
        error = nl.Error(ret, "Cannot create qdisc");

free_qdisc:
    rtnl_qdisc_put(qdisc);

    return error;
}
Example #16
0
Try<Nothing> encode<icmp::Classifier>(
    const Netlink<struct rtnl_cls>& cls,
    const icmp::Classifier& classifier)
{
  // ICMP packets are one type of IP packets.
  rtnl_cls_set_protocol(cls.get(), ETH_P_IP);

  int error = rtnl_tc_set_kind(TC_CAST(cls.get()), "u32");
  if (error != 0) {
    return Error(
        "Failed to set the kind of the classifier: " +
        string(nl_geterror(error)));
  }

  // To avoid confusion, we only use u32 selectors which are used to
  // match arbitrary 32-bit content in a packet.

  // Format of an IP packet at offset 8. The IP protocol field is at
  // offset 9. ICMP has protocol = 1.
  //        +--------+--------+--------+--------+
  //        |   X    | Proto. |   X    |   X    |
  //        +--------+--------+--------+--------+
  // Offset:    8        9        10       11
  uint32_t protocol = 0x00010000;
  uint32_t mask = 0x00ff0000; // Ignore offset 8, 10, 11.

  // To match ICMP packets (protocol = 1).
  error = rtnl_u32_add_key(
      cls.get(),
      htonl(protocol),
      htonl(mask),
      8, // Offset from which to start matching.
      0);

  if (error != 0) {
    return Error(
        "Failed to add selector for IP protocol: " +
        string(nl_geterror(error)));
  }

  if (classifier.destinationIP.isSome()) {
    Try<struct in_addr> in = classifier.destinationIP.get().in();
    if (in.isError()) {
      return Error("Destination IP is not an IPv4 address");
    }

    // To match those IP packets that have the given destination IP.
    error = rtnl_u32_add_key(
        cls.get(),
        in.get().s_addr,
        htonl(0xffffffff),
        16, // Offset from which to start matching.
        0);

    if (error != 0) {
      return Error(
          "Failed to add selector for destination IP address: " +
           string(nl_geterror(error)));
    }
  }

  return Nothing();
}