forked from mirrors/linux
		
	sched: introduce vlan action
This tc action allows to work with vlan tagged skbs. Two supported sub-actions are header pop and header push. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									93515d53b1
								
							
						
					
					
						commit
						c7e2b9689e
					
				
					 5 changed files with 281 additions and 0 deletions
				
			
		
							
								
								
									
										27
									
								
								include/net/tc_act/tc_vlan.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								include/net/tc_act/tc_vlan.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __NET_TC_VLAN_H
 | 
				
			||||||
 | 
					#define __NET_TC_VLAN_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/act_api.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VLAN_F_POP		0x1
 | 
				
			||||||
 | 
					#define VLAN_F_PUSH		0x2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcf_vlan {
 | 
				
			||||||
 | 
						struct tcf_common	common;
 | 
				
			||||||
 | 
						int			tcfv_action;
 | 
				
			||||||
 | 
						__be16			tcfv_push_vid;
 | 
				
			||||||
 | 
						__be16			tcfv_push_proto;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#define to_vlan(a) \
 | 
				
			||||||
 | 
						container_of(a->priv, struct tcf_vlan, common)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __NET_TC_VLAN_H */
 | 
				
			||||||
							
								
								
									
										35
									
								
								include/uapi/linux/tc_act/tc_vlan.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/uapi/linux/tc_act/tc_vlan.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __LINUX_TC_VLAN_H
 | 
				
			||||||
 | 
					#define __LINUX_TC_VLAN_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/pkt_cls.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TCA_ACT_VLAN 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TCA_VLAN_ACT_POP	1
 | 
				
			||||||
 | 
					#define TCA_VLAN_ACT_PUSH	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tc_vlan {
 | 
				
			||||||
 | 
						tc_gen;
 | 
				
			||||||
 | 
						int v_action;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						TCA_VLAN_UNSPEC,
 | 
				
			||||||
 | 
						TCA_VLAN_TM,
 | 
				
			||||||
 | 
						TCA_VLAN_PARMS,
 | 
				
			||||||
 | 
						TCA_VLAN_PUSH_VLAN_ID,
 | 
				
			||||||
 | 
						TCA_VLAN_PUSH_VLAN_PROTOCOL,
 | 
				
			||||||
 | 
						__TCA_VLAN_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -686,6 +686,17 @@ config NET_ACT_CSUM
 | 
				
			||||||
	  To compile this code as a module, choose M here: the
 | 
						  To compile this code as a module, choose M here: the
 | 
				
			||||||
	  module will be called act_csum.
 | 
						  module will be called act_csum.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config NET_ACT_VLAN
 | 
				
			||||||
 | 
					        tristate "Vlan manipulation"
 | 
				
			||||||
 | 
					        depends on NET_CLS_ACT
 | 
				
			||||||
 | 
					        ---help---
 | 
				
			||||||
 | 
						  Say Y here to push or pop vlan headers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If unsure, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  To compile this code as a module, choose M here: the
 | 
				
			||||||
 | 
						  module will be called act_vlan.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config NET_CLS_IND
 | 
					config NET_CLS_IND
 | 
				
			||||||
	bool "Incoming device classification"
 | 
						bool "Incoming device classification"
 | 
				
			||||||
	depends on NET_CLS_U32 || NET_CLS_FW
 | 
						depends on NET_CLS_U32 || NET_CLS_FW
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 | 
				
			||||||
obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 | 
					obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 | 
				
			||||||
obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
 | 
					obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
 | 
				
			||||||
obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
 | 
					obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_NET_ACT_VLAN)	+= act_vlan.o
 | 
				
			||||||
obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 | 
					obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 | 
				
			||||||
obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 | 
					obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 | 
				
			||||||
obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
 | 
					obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										207
									
								
								net/sched/act_vlan.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								net/sched/act_vlan.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,207 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/skbuff.h>
 | 
				
			||||||
 | 
					#include <linux/rtnetlink.h>
 | 
				
			||||||
 | 
					#include <linux/if_vlan.h>
 | 
				
			||||||
 | 
					#include <net/netlink.h>
 | 
				
			||||||
 | 
					#include <net/pkt_sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/tc_act/tc_vlan.h>
 | 
				
			||||||
 | 
					#include <net/tc_act/tc_vlan.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VLAN_TAB_MASK     15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
 | 
				
			||||||
 | 
							    struct tcf_result *res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tcf_vlan *v = a->priv;
 | 
				
			||||||
 | 
						int action;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&v->tcf_lock);
 | 
				
			||||||
 | 
						v->tcf_tm.lastuse = jiffies;
 | 
				
			||||||
 | 
						bstats_update(&v->tcf_bstats, skb);
 | 
				
			||||||
 | 
						action = v->tcf_action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (v->tcfv_action) {
 | 
				
			||||||
 | 
						case TCA_VLAN_ACT_POP:
 | 
				
			||||||
 | 
							err = skb_vlan_pop(skb);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								goto drop;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TCA_VLAN_ACT_PUSH:
 | 
				
			||||||
 | 
							err = skb_vlan_push(skb, v->tcfv_push_proto, v->tcfv_push_vid);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								goto drop;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							BUG();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						goto unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop:
 | 
				
			||||||
 | 
						action = TC_ACT_SHOT;
 | 
				
			||||||
 | 
						v->tcf_qstats.drops++;
 | 
				
			||||||
 | 
					unlock:
 | 
				
			||||||
 | 
						spin_unlock(&v->tcf_lock);
 | 
				
			||||||
 | 
						return action;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
 | 
				
			||||||
 | 
						[TCA_VLAN_PARMS]		= { .len = sizeof(struct tc_vlan) },
 | 
				
			||||||
 | 
						[TCA_VLAN_PUSH_VLAN_ID]		= { .type = NLA_U16 },
 | 
				
			||||||
 | 
						[TCA_VLAN_PUSH_VLAN_PROTOCOL]	= { .type = NLA_U16 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcf_vlan_init(struct net *net, struct nlattr *nla,
 | 
				
			||||||
 | 
								 struct nlattr *est, struct tc_action *a,
 | 
				
			||||||
 | 
								 int ovr, int bind)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nlattr *tb[TCA_VLAN_MAX + 1];
 | 
				
			||||||
 | 
						struct tc_vlan *parm;
 | 
				
			||||||
 | 
						struct tcf_vlan *v;
 | 
				
			||||||
 | 
						int action;
 | 
				
			||||||
 | 
						__be16 push_vid = 0;
 | 
				
			||||||
 | 
						__be16 push_proto = 0;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!nla)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = nla_parse_nested(tb, TCA_VLAN_MAX, nla, vlan_policy);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tb[TCA_VLAN_PARMS])
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						parm = nla_data(tb[TCA_VLAN_PARMS]);
 | 
				
			||||||
 | 
						switch (parm->v_action) {
 | 
				
			||||||
 | 
						case TCA_VLAN_ACT_POP:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TCA_VLAN_ACT_PUSH:
 | 
				
			||||||
 | 
							if (!tb[TCA_VLAN_PUSH_VLAN_ID])
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
 | 
				
			||||||
 | 
							if (push_vid >= VLAN_VID_MASK)
 | 
				
			||||||
 | 
								return -ERANGE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
 | 
				
			||||||
 | 
								push_proto = nla_get_be16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
 | 
				
			||||||
 | 
								switch (push_proto) {
 | 
				
			||||||
 | 
								case htons(ETH_P_8021Q):
 | 
				
			||||||
 | 
								case htons(ETH_P_8021AD):
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return -EPROTONOSUPPORT;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								push_proto = htons(ETH_P_8021Q);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						action = parm->v_action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tcf_hash_check(parm->index, a, bind)) {
 | 
				
			||||||
 | 
							ret = tcf_hash_create(parm->index, est, a, sizeof(*v), bind);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = ACT_P_CREATED;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (bind)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							tcf_hash_release(a, bind);
 | 
				
			||||||
 | 
							if (!ovr)
 | 
				
			||||||
 | 
								return -EEXIST;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v = to_vlan(a);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_bh(&v->tcf_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v->tcfv_action = action;
 | 
				
			||||||
 | 
						v->tcfv_push_vid = push_vid;
 | 
				
			||||||
 | 
						v->tcfv_push_proto = push_proto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v->tcf_action = parm->action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_bh(&v->tcf_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret == ACT_P_CREATED)
 | 
				
			||||||
 | 
							tcf_hash_insert(a);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
 | 
				
			||||||
 | 
								 int bind, int ref)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *b = skb_tail_pointer(skb);
 | 
				
			||||||
 | 
						struct tcf_vlan *v = a->priv;
 | 
				
			||||||
 | 
						struct tc_vlan opt = {
 | 
				
			||||||
 | 
							.index    = v->tcf_index,
 | 
				
			||||||
 | 
							.refcnt   = v->tcf_refcnt - ref,
 | 
				
			||||||
 | 
							.bindcnt  = v->tcf_bindcnt - bind,
 | 
				
			||||||
 | 
							.action   = v->tcf_action,
 | 
				
			||||||
 | 
							.v_action = v->tcfv_action,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct tcf_t t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (v->tcfv_action == TCA_VLAN_ACT_PUSH &&
 | 
				
			||||||
 | 
						    (nla_put_u16(skb, TCA_VLAN_PUSH_VLAN_ID, v->tcfv_push_vid) ||
 | 
				
			||||||
 | 
						     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL, v->tcfv_push_proto)))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.install = jiffies_to_clock_t(jiffies - v->tcf_tm.install);
 | 
				
			||||||
 | 
						t.lastuse = jiffies_to_clock_t(jiffies - v->tcf_tm.lastuse);
 | 
				
			||||||
 | 
						t.expires = jiffies_to_clock_t(v->tcf_tm.expires);
 | 
				
			||||||
 | 
						if (nla_put(skb, TCA_VLAN_TM, sizeof(t), &t))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
						return skb->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nla_put_failure:
 | 
				
			||||||
 | 
						nlmsg_trim(skb, b);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct tc_action_ops act_vlan_ops = {
 | 
				
			||||||
 | 
						.kind		=	"vlan",
 | 
				
			||||||
 | 
						.type		=	TCA_ACT_VLAN,
 | 
				
			||||||
 | 
						.owner		=	THIS_MODULE,
 | 
				
			||||||
 | 
						.act		=	tcf_vlan,
 | 
				
			||||||
 | 
						.dump		=	tcf_vlan_dump,
 | 
				
			||||||
 | 
						.init		=	tcf_vlan_init,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init vlan_init_module(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return tcf_register_action(&act_vlan_ops, VLAN_TAB_MASK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit vlan_cleanup_module(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						tcf_unregister_action(&act_vlan_ops);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_init(vlan_init_module);
 | 
				
			||||||
 | 
					module_exit(vlan_cleanup_module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("vlan manipulation actions");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL v2");
 | 
				
			||||||
		Loading…
	
		Reference in a new issue