mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net_sched: act: use standard struct list_head
Currently actions are chained by a singly linked list, therefore it is a bit hard to add and remove a specific entry. Convert it to struct list_head so that in the latter patch we can remove an action without finding its head. Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									d84231d3a2
								
							
						
					
					
						commit
						33be627159
					
				
					 13 changed files with 101 additions and 99 deletions
				
			
		| 
						 | 
					@ -60,7 +60,7 @@ struct tc_action {
 | 
				
			||||||
	const struct tc_action_ops	*ops;
 | 
						const struct tc_action_ops	*ops;
 | 
				
			||||||
	__u32			type; /* for backward compat(TCA_OLD_COMPAT) */
 | 
						__u32			type; /* for backward compat(TCA_OLD_COMPAT) */
 | 
				
			||||||
	__u32			order;
 | 
						__u32			order;
 | 
				
			||||||
	struct tc_action	*next;
 | 
						struct list_head	list;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TCA_CAP_NONE 0
 | 
					#define TCA_CAP_NONE 0
 | 
				
			||||||
| 
						 | 
					@ -99,16 +99,16 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcf_register_action(struct tc_action_ops *a);
 | 
					int tcf_register_action(struct tc_action_ops *a);
 | 
				
			||||||
int tcf_unregister_action(struct tc_action_ops *a);
 | 
					int tcf_unregister_action(struct tc_action_ops *a);
 | 
				
			||||||
void tcf_action_destroy(struct tc_action *a, int bind);
 | 
					void tcf_action_destroy(struct list_head *actions, int bind);
 | 
				
			||||||
int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a,
 | 
					int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
 | 
				
			||||||
		    struct tcf_result *res);
 | 
							    struct tcf_result *res);
 | 
				
			||||||
struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
 | 
					int tcf_action_init(struct net *net, struct nlattr *nla,
 | 
				
			||||||
				  struct nlattr *est, char *n, int ovr,
 | 
									  struct nlattr *est, char *n, int ovr,
 | 
				
			||||||
				  int bind);
 | 
									  int bind, struct list_head *);
 | 
				
			||||||
struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 | 
					struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 | 
				
			||||||
				    struct nlattr *est, char *n, int ovr,
 | 
									    struct nlattr *est, char *n, int ovr,
 | 
				
			||||||
				    int bind);
 | 
									    int bind);
 | 
				
			||||||
int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
 | 
					int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
 | 
				
			||||||
int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 | 
					int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 | 
				
			||||||
int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
 | 
					int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
 | 
				
			||||||
int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
 | 
					int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tcf_exts {
 | 
					struct tcf_exts {
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	struct tc_action *action;
 | 
						__u32	type; /* for backward compat(TCA_OLD_COMPAT) */
 | 
				
			||||||
 | 
						struct list_head actions;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,6 +75,13 @@ struct tcf_ext_map {
 | 
				
			||||||
	int police;
 | 
						int police;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void tcf_exts_init(struct tcf_exts *exts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&exts->actions);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * tcf_exts_is_predicative - check if a predicative extension is present
 | 
					 * tcf_exts_is_predicative - check if a predicative extension is present
 | 
				
			||||||
 * @exts: tc filter extensions handle
 | 
					 * @exts: tc filter extensions handle
 | 
				
			||||||
| 
						 | 
					@ -85,7 +93,7 @@ static inline int
 | 
				
			||||||
tcf_exts_is_predicative(struct tcf_exts *exts)
 | 
					tcf_exts_is_predicative(struct tcf_exts *exts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	return !!exts->action;
 | 
						return !list_empty(&exts->actions);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -120,8 +128,8 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
 | 
				
			||||||
	       struct tcf_result *res)
 | 
						       struct tcf_result *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (exts->action)
 | 
						if (!list_empty(&exts->actions))
 | 
				
			||||||
		return tcf_action_exec(skb, exts->action, res);
 | 
							return tcf_action_exec(skb, &exts->actions, res);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -379,7 +379,7 @@ static struct tc_action_ops *tc_lookup_action_id(u32 type)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
 | 
					int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
 | 
				
			||||||
		    struct tcf_result *res)
 | 
							    struct tcf_result *res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct tc_action *a;
 | 
						const struct tc_action *a;
 | 
				
			||||||
| 
						 | 
					@ -390,7 +390,7 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
 | 
				
			||||||
		ret = TC_ACT_OK;
 | 
							ret = TC_ACT_OK;
 | 
				
			||||||
		goto exec_done;
 | 
							goto exec_done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	while ((a = act) != NULL) {
 | 
						list_for_each_entry(a, actions, list) {
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		if (a->ops) {
 | 
							if (a->ops) {
 | 
				
			||||||
			ret = a->ops->act(skb, a, res);
 | 
								ret = a->ops->act(skb, a, res);
 | 
				
			||||||
| 
						 | 
					@ -404,27 +404,26 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
 | 
				
			||||||
			if (ret != TC_ACT_PIPE)
 | 
								if (ret != TC_ACT_PIPE)
 | 
				
			||||||
				goto exec_done;
 | 
									goto exec_done;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		act = a->next;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
exec_done:
 | 
					exec_done:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tcf_action_exec);
 | 
					EXPORT_SYMBOL(tcf_action_exec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tcf_action_destroy(struct tc_action *act, int bind)
 | 
					void tcf_action_destroy(struct list_head *actions, int bind)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tc_action *a;
 | 
						struct tc_action *a, *tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (a = act; a; a = act) {
 | 
						list_for_each_entry_safe(a, tmp, actions, list) {
 | 
				
			||||||
		if (a->ops) {
 | 
							if (a->ops) {
 | 
				
			||||||
			if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
 | 
								if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
 | 
				
			||||||
				module_put(a->ops->owner);
 | 
									module_put(a->ops->owner);
 | 
				
			||||||
			act = act->next;
 | 
								list_del(&a->list);
 | 
				
			||||||
			kfree(a);
 | 
								kfree(a);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			/*FIXME: Remove later - catch insertion bugs*/
 | 
								/*FIXME: Remove later - catch insertion bugs*/
 | 
				
			||||||
			WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
 | 
								WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
 | 
				
			||||||
			act = act->next;
 | 
								list_del(&a->list);
 | 
				
			||||||
			kfree(a);
 | 
								kfree(a);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -470,14 +469,13 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 | 
				
			||||||
EXPORT_SYMBOL(tcf_action_dump_1);
 | 
					EXPORT_SYMBOL(tcf_action_dump_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
 | 
					tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tc_action *a;
 | 
						struct tc_action *a;
 | 
				
			||||||
	int err = -EINVAL;
 | 
						int err = -EINVAL;
 | 
				
			||||||
	struct nlattr *nest;
 | 
						struct nlattr *nest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((a = act) != NULL) {
 | 
						list_for_each_entry(a, actions, list) {
 | 
				
			||||||
		act = a->next;
 | 
					 | 
				
			||||||
		nest = nla_nest_start(skb, a->order);
 | 
							nest = nla_nest_start(skb, a->order);
 | 
				
			||||||
		if (nest == NULL)
 | 
							if (nest == NULL)
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
| 
						 | 
					@ -552,6 +550,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 | 
				
			||||||
	if (a == NULL)
 | 
						if (a == NULL)
 | 
				
			||||||
		goto err_mod;
 | 
							goto err_mod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&a->list);
 | 
				
			||||||
	/* backward compatibility for policer */
 | 
						/* backward compatibility for policer */
 | 
				
			||||||
	if (name == NULL)
 | 
						if (name == NULL)
 | 
				
			||||||
		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
 | 
							err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
 | 
				
			||||||
| 
						 | 
					@ -578,37 +577,33 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 | 
				
			||||||
	return ERR_PTR(err);
 | 
						return ERR_PTR(err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
 | 
					int tcf_action_init(struct net *net, struct nlattr *nla,
 | 
				
			||||||
				  struct nlattr *est, char *name, int ovr,
 | 
									  struct nlattr *est, char *name, int ovr,
 | 
				
			||||||
				  int bind)
 | 
									  int bind, struct list_head *actions)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 | 
						struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 | 
				
			||||||
	struct tc_action *head = NULL, *act, *act_prev = NULL;
 | 
						struct tc_action *act;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
 | 
						err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
 | 
						for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
 | 
				
			||||||
		act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
 | 
							act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
 | 
				
			||||||
		if (IS_ERR(act))
 | 
							if (IS_ERR(act)) {
 | 
				
			||||||
 | 
								err = PTR_ERR(act);
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		act->order = i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (head == NULL)
 | 
					 | 
				
			||||||
			head = act;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			act_prev->next = act;
 | 
					 | 
				
			||||||
		act_prev = act;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	return head;
 | 
							act->order = i;
 | 
				
			||||||
 | 
							list_add_tail(&act->list, actions);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err:
 | 
					err:
 | 
				
			||||||
	if (head != NULL)
 | 
						tcf_action_destroy(actions, bind);
 | 
				
			||||||
		tcf_action_destroy(head, bind);
 | 
						return err;
 | 
				
			||||||
	return act;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 | 
					int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 | 
				
			||||||
| 
						 | 
					@ -653,7 +648,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
 | 
					tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq,
 | 
				
			||||||
	     u16 flags, int event, int bind, int ref)
 | 
						     u16 flags, int event, int bind, int ref)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tcamsg *t;
 | 
						struct tcamsg *t;
 | 
				
			||||||
| 
						 | 
					@ -673,7 +668,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
 | 
				
			||||||
	if (nest == NULL)
 | 
						if (nest == NULL)
 | 
				
			||||||
		goto out_nlmsg_trim;
 | 
							goto out_nlmsg_trim;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcf_action_dump(skb, a, bind, ref) < 0)
 | 
						if (tcf_action_dump(skb, actions, bind, ref) < 0)
 | 
				
			||||||
		goto out_nlmsg_trim;
 | 
							goto out_nlmsg_trim;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nla_nest_end(skb, nest);
 | 
						nla_nest_end(skb, nest);
 | 
				
			||||||
| 
						 | 
					@ -688,14 +683,14 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
 | 
					act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
 | 
				
			||||||
	       struct tc_action *a, int event)
 | 
						       struct list_head *actions, int event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sk_buff *skb;
 | 
						struct sk_buff *skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 | 
						skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 | 
				
			||||||
	if (!skb)
 | 
						if (!skb)
 | 
				
			||||||
		return -ENOBUFS;
 | 
							return -ENOBUFS;
 | 
				
			||||||
	if (tca_get_fill(skb, a, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
 | 
						if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
 | 
				
			||||||
		kfree_skb(skb);
 | 
							kfree_skb(skb);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -726,6 +721,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
 | 
				
			||||||
	if (a == NULL)
 | 
						if (a == NULL)
 | 
				
			||||||
		goto err_out;
 | 
							goto err_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&a->list);
 | 
				
			||||||
	err = -EINVAL;
 | 
						err = -EINVAL;
 | 
				
			||||||
	a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
 | 
						a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
 | 
				
			||||||
	if (a->ops == NULL)
 | 
						if (a->ops == NULL)
 | 
				
			||||||
| 
						 | 
					@ -745,12 +741,12 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
 | 
				
			||||||
	return ERR_PTR(err);
 | 
						return ERR_PTR(err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cleanup_a(struct tc_action *act)
 | 
					static void cleanup_a(struct list_head *actions)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tc_action *a;
 | 
						struct tc_action *a, *tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (a = act; a; a = act) {
 | 
						list_for_each_entry_safe(a, tmp, actions, list) {
 | 
				
			||||||
		act = a->next;
 | 
							list_del(&a->list);
 | 
				
			||||||
		kfree(a);
 | 
							kfree(a);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -765,6 +761,7 @@ static struct tc_action *create_a(int i)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	act->order = i;
 | 
						act->order = i;
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&act->list);
 | 
				
			||||||
	return act;
 | 
						return act;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -852,7 +849,8 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, ret;
 | 
						int i, ret;
 | 
				
			||||||
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 | 
						struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 | 
				
			||||||
	struct tc_action *head = NULL, *act, *act_prev = NULL;
 | 
						struct tc_action *act;
 | 
				
			||||||
 | 
						LIST_HEAD(actions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
 | 
						ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
| 
						 | 
					@ -872,16 +870,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		act->order = i;
 | 
							act->order = i;
 | 
				
			||||||
 | 
							list_add_tail(&act->list, &actions);
 | 
				
			||||||
		if (head == NULL)
 | 
					 | 
				
			||||||
			head = act;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			act_prev->next = act;
 | 
					 | 
				
			||||||
		act_prev = act;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (event == RTM_GETACTION)
 | 
						if (event == RTM_GETACTION)
 | 
				
			||||||
		ret = act_get_notify(net, portid, n, head, event);
 | 
							ret = act_get_notify(net, portid, n, &actions, event);
 | 
				
			||||||
	else { /* delete */
 | 
						else { /* delete */
 | 
				
			||||||
		struct sk_buff *skb;
 | 
							struct sk_buff *skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -891,7 +884,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (tca_get_fill(skb, head, portid, n->nlmsg_seq, 0, event,
 | 
							if (tca_get_fill(skb, &actions, portid, n->nlmsg_seq, 0, event,
 | 
				
			||||||
				 0, 1) <= 0) {
 | 
									 0, 1) <= 0) {
 | 
				
			||||||
			kfree_skb(skb);
 | 
								kfree_skb(skb);
 | 
				
			||||||
			ret = -EINVAL;
 | 
								ret = -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -899,7 +892,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* now do the delete */
 | 
							/* now do the delete */
 | 
				
			||||||
		tcf_action_destroy(head, 0);
 | 
							tcf_action_destroy(&actions, 0);
 | 
				
			||||||
		ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
 | 
							ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
 | 
				
			||||||
				     n->nlmsg_flags & NLM_F_ECHO);
 | 
									     n->nlmsg_flags & NLM_F_ECHO);
 | 
				
			||||||
		if (ret > 0)
 | 
							if (ret > 0)
 | 
				
			||||||
| 
						 | 
					@ -907,11 +900,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
err:
 | 
					err:
 | 
				
			||||||
	cleanup_a(head);
 | 
						cleanup_a(&actions);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tcf_add_notify(struct net *net, struct tc_action *a,
 | 
					static int tcf_add_notify(struct net *net, struct list_head *actions,
 | 
				
			||||||
			  u32 portid, u32 seq, int event, u16 flags)
 | 
								  u32 portid, u32 seq, int event, u16 flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tcamsg *t;
 | 
						struct tcamsg *t;
 | 
				
			||||||
| 
						 | 
					@ -939,7 +932,7 @@ static int tcf_add_notify(struct net *net, struct tc_action *a,
 | 
				
			||||||
	if (nest == NULL)
 | 
						if (nest == NULL)
 | 
				
			||||||
		goto out_kfree_skb;
 | 
							goto out_kfree_skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcf_action_dump(skb, a, 0, 0) < 0)
 | 
						if (tcf_action_dump(skb, actions, 0, 0) < 0)
 | 
				
			||||||
		goto out_kfree_skb;
 | 
							goto out_kfree_skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nla_nest_end(skb, nest);
 | 
						nla_nest_end(skb, nest);
 | 
				
			||||||
| 
						 | 
					@ -963,26 +956,18 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 | 
				
			||||||
	       u32 portid, int ovr)
 | 
						       u32 portid, int ovr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
	struct tc_action *act;
 | 
						LIST_HEAD(actions);
 | 
				
			||||||
	struct tc_action *a;
 | 
					 | 
				
			||||||
	u32 seq = n->nlmsg_seq;
 | 
						u32 seq = n->nlmsg_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	act = tcf_action_init(net, nla, NULL, NULL, ovr, 0);
 | 
						ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
 | 
				
			||||||
	if (act == NULL)
 | 
						if (ret)
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
	if (IS_ERR(act)) {
 | 
					 | 
				
			||||||
		ret = PTR_ERR(act);
 | 
					 | 
				
			||||||
		goto done;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dump then free all the actions after update; inserted policy
 | 
						/* dump then free all the actions after update; inserted policy
 | 
				
			||||||
	 * stays intact
 | 
						 * stays intact
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
 | 
						ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
 | 
				
			||||||
	for (a = act; a; a = act) {
 | 
						cleanup_a(&actions);
 | 
				
			||||||
		act = a->next;
 | 
					 | 
				
			||||||
		kfree(a);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -500,10 +500,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
 | 
				
			||||||
void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 | 
					void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (exts->action) {
 | 
						tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND);
 | 
				
			||||||
		tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
 | 
						INIT_LIST_HEAD(&exts->actions);
 | 
				
			||||||
		exts->action = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tcf_exts_destroy);
 | 
					EXPORT_SYMBOL(tcf_exts_destroy);
 | 
				
			||||||
| 
						 | 
					@ -518,6 +516,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		struct tc_action *act;
 | 
							struct tc_action *act;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							INIT_LIST_HEAD(&exts->actions);
 | 
				
			||||||
		if (map->police && tb[map->police]) {
 | 
							if (map->police && tb[map->police]) {
 | 
				
			||||||
			act = tcf_action_init_1(net, tb[map->police], rate_tlv,
 | 
								act = tcf_action_init_1(net, tb[map->police], rate_tlv,
 | 
				
			||||||
						"police", TCA_ACT_NOREPLACE,
 | 
											"police", TCA_ACT_NOREPLACE,
 | 
				
			||||||
| 
						 | 
					@ -525,16 +524,15 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
 | 
				
			||||||
			if (IS_ERR(act))
 | 
								if (IS_ERR(act))
 | 
				
			||||||
				return PTR_ERR(act);
 | 
									return PTR_ERR(act);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			act->type = TCA_OLD_COMPAT;
 | 
								act->type = exts->type = TCA_OLD_COMPAT;
 | 
				
			||||||
			exts->action = act;
 | 
								list_add(&act->list, &exts->actions);
 | 
				
			||||||
		} else if (map->action && tb[map->action]) {
 | 
							} else if (map->action && tb[map->action]) {
 | 
				
			||||||
			act = tcf_action_init(net, tb[map->action], rate_tlv,
 | 
								int err;
 | 
				
			||||||
 | 
								err = tcf_action_init(net, tb[map->action], rate_tlv,
 | 
				
			||||||
					      NULL, TCA_ACT_NOREPLACE,
 | 
										      NULL, TCA_ACT_NOREPLACE,
 | 
				
			||||||
					      TCA_ACT_BIND);
 | 
										      TCA_ACT_BIND, &exts->actions);
 | 
				
			||||||
			if (IS_ERR(act))
 | 
								if (err)
 | 
				
			||||||
				return PTR_ERR(act);
 | 
									return err;
 | 
				
			||||||
 | 
					 | 
				
			||||||
			exts->action = act;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -551,43 +549,45 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
 | 
				
			||||||
		     struct tcf_exts *src)
 | 
							     struct tcf_exts *src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (src->action) {
 | 
						if (!list_empty(&src->actions)) {
 | 
				
			||||||
		struct tc_action *act;
 | 
							LIST_HEAD(tmp);
 | 
				
			||||||
		tcf_tree_lock(tp);
 | 
							tcf_tree_lock(tp);
 | 
				
			||||||
		act = dst->action;
 | 
							list_splice_init(&dst->actions, &tmp);
 | 
				
			||||||
		dst->action = src->action;
 | 
							list_splice(&src->actions, &dst->actions);
 | 
				
			||||||
		tcf_tree_unlock(tp);
 | 
							tcf_tree_unlock(tp);
 | 
				
			||||||
		if (act)
 | 
							tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
 | 
				
			||||||
			tcf_action_destroy(act, TCA_ACT_UNBIND);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tcf_exts_change);
 | 
					EXPORT_SYMBOL(tcf_exts_change);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define tcf_exts_first_act(ext) \
 | 
				
			||||||
 | 
							list_first_entry(&(exts)->actions, struct tc_action, list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
 | 
					int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
 | 
				
			||||||
		  const struct tcf_ext_map *map)
 | 
							  const struct tcf_ext_map *map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (map->action && exts->action) {
 | 
						if (map->action && !list_empty(&exts->actions)) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * again for backward compatible mode - we want
 | 
							 * again for backward compatible mode - we want
 | 
				
			||||||
		 * to work with both old and new modes of entering
 | 
							 * to work with both old and new modes of entering
 | 
				
			||||||
		 * tc data even if iproute2  was newer - jhs
 | 
							 * tc data even if iproute2  was newer - jhs
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		struct nlattr *nest;
 | 
							struct nlattr *nest;
 | 
				
			||||||
 | 
							if (exts->type != TCA_OLD_COMPAT) {
 | 
				
			||||||
		if (exts->action->type != TCA_OLD_COMPAT) {
 | 
					 | 
				
			||||||
			nest = nla_nest_start(skb, map->action);
 | 
								nest = nla_nest_start(skb, map->action);
 | 
				
			||||||
			if (nest == NULL)
 | 
								if (nest == NULL)
 | 
				
			||||||
				goto nla_put_failure;
 | 
									goto nla_put_failure;
 | 
				
			||||||
			if (tcf_action_dump(skb, exts->action, 0, 0) < 0)
 | 
								if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0)
 | 
				
			||||||
				goto nla_put_failure;
 | 
									goto nla_put_failure;
 | 
				
			||||||
			nla_nest_end(skb, nest);
 | 
								nla_nest_end(skb, nest);
 | 
				
			||||||
		} else if (map->police) {
 | 
							} else if (map->police) {
 | 
				
			||||||
 | 
								struct tc_action *act = tcf_exts_first_act(exts);
 | 
				
			||||||
			nest = nla_nest_start(skb, map->police);
 | 
								nest = nla_nest_start(skb, map->police);
 | 
				
			||||||
			if (nest == NULL)
 | 
								if (nest == NULL)
 | 
				
			||||||
				goto nla_put_failure;
 | 
									goto nla_put_failure;
 | 
				
			||||||
			if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0)
 | 
								if (tcf_action_dump_old(skb, act, 0, 0) < 0)
 | 
				
			||||||
				goto nla_put_failure;
 | 
									goto nla_put_failure;
 | 
				
			||||||
			nla_nest_end(skb, nest);
 | 
								nla_nest_end(skb, nest);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -604,13 +604,11 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
 | 
				
			||||||
			const struct tcf_ext_map *map)
 | 
								const struct tcf_ext_map *map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (exts->action)
 | 
						struct tc_action *a = tcf_exts_first_act(exts);
 | 
				
			||||||
		if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
 | 
						if (tcf_action_copy_stats(skb, a, 1) < 0)
 | 
				
			||||||
			goto nla_put_failure;
 | 
							return -1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
nla_put_failure: __attribute__ ((unused))
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tcf_exts_dump_stats);
 | 
					EXPORT_SYMBOL(tcf_exts_dump_stats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,6 +191,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	if (f == NULL)
 | 
						if (f == NULL)
 | 
				
			||||||
		goto errout;
 | 
							goto errout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcf_exts_init(&f->exts);
 | 
				
			||||||
	err = -EINVAL;
 | 
						err = -EINVAL;
 | 
				
			||||||
	if (handle)
 | 
						if (handle)
 | 
				
			||||||
		f->handle = handle;
 | 
							f->handle = handle;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -271,6 +271,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	if (prog == NULL)
 | 
						if (prog == NULL)
 | 
				
			||||||
		return -ENOBUFS;
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcf_exts_init(&prog->exts);
 | 
				
			||||||
	if (handle == 0)
 | 
						if (handle == 0)
 | 
				
			||||||
		prog->handle = cls_bpf_grab_new_handle(tp, head);
 | 
							prog->handle = cls_bpf_grab_new_handle(tp, head);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,6 +203,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
		if (head == NULL)
 | 
							if (head == NULL)
 | 
				
			||||||
			return -ENOBUFS;
 | 
								return -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tcf_exts_init(&head->exts);
 | 
				
			||||||
		head->handle = handle;
 | 
							head->handle = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tcf_tree_lock(tp);
 | 
							tcf_tree_lock(tp);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -455,6 +455,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		f->handle = handle;
 | 
							f->handle = handle;
 | 
				
			||||||
		f->mask	  = ~0U;
 | 
							f->mask	  = ~0U;
 | 
				
			||||||
 | 
							tcf_exts_init(&f->exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		get_random_bytes(&f->hashrnd, 4);
 | 
							get_random_bytes(&f->hashrnd, 4);
 | 
				
			||||||
		f->perturb_timer.function = flow_perturbation;
 | 
							f->perturb_timer.function = flow_perturbation;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -280,6 +280,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	if (f == NULL)
 | 
						if (f == NULL)
 | 
				
			||||||
		return -ENOBUFS;
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcf_exts_init(&f->exts);
 | 
				
			||||||
	f->id = handle;
 | 
						f->id = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = fw_change_attrs(net, tp, f, tb, tca, base);
 | 
						err = fw_change_attrs(net, tp, f, tb, tca, base);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -481,6 +481,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	if (f == NULL)
 | 
						if (f == NULL)
 | 
				
			||||||
		goto errout;
 | 
							goto errout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcf_exts_init(&f->exts);
 | 
				
			||||||
	err = route4_set_parms(net, tp, base, f, handle, head, tb,
 | 
						err = route4_set_parms(net, tp, base, f, handle, head, tb,
 | 
				
			||||||
		tca[TCA_RATE], 1);
 | 
							tca[TCA_RATE], 1);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -471,6 +471,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	if (f == NULL)
 | 
						if (f == NULL)
 | 
				
			||||||
		goto errout2;
 | 
							goto errout2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcf_exts_init(&f->exts);
 | 
				
			||||||
	h2 = 16;
 | 
						h2 = 16;
 | 
				
			||||||
	if (tb[TCA_RSVP_SRC]) {
 | 
						if (tb[TCA_RSVP_SRC]) {
 | 
				
			||||||
		memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
 | 
							memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -215,11 +215,14 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(&cp, p, sizeof(cp));
 | 
						memcpy(&cp, p, sizeof(cp));
 | 
				
			||||||
	memset(&new_filter_result, 0, sizeof(new_filter_result));
 | 
						memset(&new_filter_result, 0, sizeof(new_filter_result));
 | 
				
			||||||
 | 
						tcf_exts_init(&new_filter_result.exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_r)
 | 
						if (old_r)
 | 
				
			||||||
		memcpy(&cr, r, sizeof(cr));
 | 
							memcpy(&cr, r, sizeof(cr));
 | 
				
			||||||
	else
 | 
						else {
 | 
				
			||||||
		memset(&cr, 0, sizeof(cr));
 | 
							memset(&cr, 0, sizeof(cr));
 | 
				
			||||||
 | 
							tcf_exts_init(&cr.exts);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tb[TCA_TCINDEX_HASH])
 | 
						if (tb[TCA_TCINDEX_HASH])
 | 
				
			||||||
		cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
 | 
							cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -646,6 +646,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
 | 
				
			||||||
	n->ht_up = ht;
 | 
						n->ht_up = ht;
 | 
				
			||||||
	n->handle = handle;
 | 
						n->handle = handle;
 | 
				
			||||||
	n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
 | 
						n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
 | 
				
			||||||
 | 
						tcf_exts_init(&n->exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CLS_U32_MARK
 | 
					#ifdef CONFIG_CLS_U32_MARK
 | 
				
			||||||
	if (tb[TCA_U32_MARK]) {
 | 
						if (tb[TCA_U32_MARK]) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue