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