Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c418b5b authored by Johannes Berg's avatar Johannes Berg
Browse files

fq: support filtering a given tin



Add to the FQ API a way to filter a given tin, in order to
remove frames that fulfil certain criteria according to a
filter function.

This will be used by mac80211 to remove frames belonging to
an AP VLAN interface that's being removed.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Acked-by: default avatarToke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4133da73
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -90,6 +90,13 @@ typedef void fq_skb_free_t(struct fq *,
			   struct fq_flow *,
			   struct sk_buff *);

/* Return %true to filter (drop) the frame. */
typedef bool fq_skb_filter_t(struct fq *,
			     struct fq_tin *,
			     struct fq_flow *,
			     struct sk_buff *,
			     void *);

typedef struct fq_flow *fq_flow_get_default_t(struct fq *,
					      struct fq_tin *,
					      int idx,
+62 −10
Original line number Diff line number Diff line
@@ -12,24 +12,22 @@

/* functions that are embedded into includer */

static struct sk_buff *fq_flow_dequeue(struct fq *fq,
				       struct fq_flow *flow)
static void fq_adjust_removal(struct fq *fq,
			      struct fq_flow *flow,
			      struct sk_buff *skb)
{
	struct fq_tin *tin = flow->tin;
	struct fq_flow *i;
	struct sk_buff *skb;

	lockdep_assert_held(&fq->lock);

	skb = __skb_dequeue(&flow->queue);
	if (!skb)
		return NULL;

	tin->backlog_bytes -= skb->len;
	tin->backlog_packets--;
	flow->backlog -= skb->len;
	fq->backlog--;
	fq->memory_usage -= skb->truesize;
}

static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
{
	struct fq_flow *i;

	if (flow->backlog == 0) {
		list_del_init(&flow->backlogchain);
@@ -43,6 +41,21 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq,
		list_move_tail(&flow->backlogchain,
			       &i->backlogchain);
	}
}

static struct sk_buff *fq_flow_dequeue(struct fq *fq,
				       struct fq_flow *flow)
{
	struct sk_buff *skb;

	lockdep_assert_held(&fq->lock);

	skb = __skb_dequeue(&flow->queue);
	if (!skb)
		return NULL;

	fq_adjust_removal(fq, flow, skb);
	fq_rejigger_backlog(fq, flow);

	return skb;
}
@@ -188,6 +201,45 @@ static void fq_tin_enqueue(struct fq *fq,
	}
}

static void fq_flow_filter(struct fq *fq,
			   struct fq_flow *flow,
			   fq_skb_filter_t filter_func,
			   void *filter_data,
			   fq_skb_free_t free_func)
{
	struct fq_tin *tin = flow->tin;
	struct sk_buff *skb, *tmp;

	lockdep_assert_held(&fq->lock);

	skb_queue_walk_safe(&flow->queue, skb, tmp) {
		if (!filter_func(fq, tin, flow, skb, filter_data))
			continue;

		__skb_unlink(skb, &flow->queue);
		fq_adjust_removal(fq, flow, skb);
		free_func(fq, tin, flow, skb);
	}

	fq_rejigger_backlog(fq, flow);
}

static void fq_tin_filter(struct fq *fq,
			  struct fq_tin *tin,
			  fq_skb_filter_t filter_func,
			  void *filter_data,
			  fq_skb_free_t free_func)
{
	struct fq_flow *flow;

	lockdep_assert_held(&fq->lock);

	list_for_each_entry(flow, &tin->new_flows, flowchain)
		fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
	list_for_each_entry(flow, &tin->old_flows, flowchain)
		fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
}

static void fq_flow_reset(struct fq *fq,
			  struct fq_flow *flow,
			  fq_skb_free_t free_func)