Example #1
0
static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
{
	struct sfq_sched_data *q = qdisc_priv(sch);
	int i;

	q->perturb_timer.function = sfq_perturbation;
	q->perturb_timer.data = (unsigned long)sch;
	init_timer_deferrable(&q->perturb_timer);

	for (i = 0; i < SFQ_MAX_DEPTH + 1; i++) {
		q->dep[i].next = i + SFQ_MAX_FLOWS;
		q->dep[i].prev = i + SFQ_MAX_FLOWS;
	}

	q->limit = SFQ_MAX_DEPTH;
	q->maxdepth = SFQ_MAX_DEPTH;
	q->cur_depth = 0;
	q->tail = NULL;
	q->divisor = SFQ_DEFAULT_HASH_DIVISOR;
	q->maxflows = SFQ_DEFAULT_FLOWS;
	q->quantum = psched_mtu(qdisc_dev(sch));
	q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
	q->perturb_period = 0;
	q->perturbation = prandom_u32();

	if (opt) {
		int err = sfq_change(sch, opt);
		if (err)
			return err;
	}

	q->ht = sfq_alloc(sizeof(q->ht[0]) * q->divisor);
	q->slots = sfq_alloc(sizeof(q->slots[0]) * q->maxflows);
	if (!q->ht || !q->slots) {
		sfq_destroy(sch);
		return -ENOMEM;
	}
	for (i = 0; i < q->divisor; i++)
		q->ht[i] = SFQ_EMPTY_SLOT;

	for (i = 0; i < q->maxflows; i++) {
		slot_queue_init(&q->slots[i]);
		sfq_link(q, i);
	}
	if (q->limit >= 1)
		sch->flags |= TCQ_F_CAN_BYPASS;
	else
		sch->flags &= ~TCQ_F_CAN_BYPASS;
	return 0;
}
static int sfq_msg_parser(struct rtnl_qdisc *qdisc)
{
	struct rtnl_sfq *sfq;
	struct tc_sfq_qopt *opts;

	if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
		return 0;

	if (qdisc->q_opts->d_size < sizeof(*opts))
		return nl_error(EINVAL, "SFQ specific options size mismatch");

	sfq = sfq_alloc(qdisc);
	if (!sfq)
		return nl_errno(ENOMEM);

	opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;

	sfq->qs_quantum = opts->quantum;
	sfq->qs_perturb = opts->perturb_period;
	sfq->qs_limit = opts->limit;
	sfq->qs_divisor = opts->divisor;
	sfq->qs_flows = opts->flows;

	sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
			SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
			SCH_SFQ_ATTR_FLOWS);

	return 0;
}
/**
 * Set limit of SFQ qdisc.
 * @arg qdisc		SFQ qdisc to be modified.
 * @arg limit		New limit in number of packets.
 * @return 0 on success or a negative error code.
 */
int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
{
	struct rtnl_sfq *sfq;

	sfq = sfq_alloc(qdisc);
	if (!sfq)
		return nl_errno(ENOMEM);

	sfq->qs_limit = limit;
	sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;

	return 0;
}
/**
 * Set perturbation interval of SFQ qdisc.
 * @arg qdisc		SFQ qdisc to be modified.
 * @arg perturb		New perturbation interval in seconds.
 * @note A value of 0 disables perturbation altogether.
 * @return 0 on success or a negative error code.
 */
int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
{
	struct rtnl_sfq *sfq;

	sfq = sfq_alloc(qdisc);
	if (!sfq)
		return nl_errno(ENOMEM);

	sfq->qs_perturb = perturb;
	sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;

	return 0;
}
/**
 * Set quantum of SFQ qdisc.
 * @arg qdisc		SFQ qdisc to be modified.
 * @arg quantum		New quantum in bytes.
 * @return 0 on success or a negative error code.
 */
int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
{
	struct rtnl_sfq *sfq;
	
	sfq = sfq_alloc(qdisc);
	if (!sfq)
		return nl_errno(ENOMEM);

	sfq->qs_quantum = quantum;
	sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;

	return 0;
}