aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_mirred.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_mirred.c')
-rw-r--r--net/sched/act_mirred.c107
1 files changed, 56 insertions, 51 deletions
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index b9aaab4e0354..d329170243cb 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -65,48 +65,53 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
65 struct tc_mirred *parm; 65 struct tc_mirred *parm;
66 struct tcf_mirred *m; 66 struct tcf_mirred *m;
67 struct tcf_common *pc; 67 struct tcf_common *pc;
68 struct net_device *dev = NULL; 68 struct net_device *dev;
69 int ret = 0, err; 69 int ret, ok_push = 0;
70 int ok_push = 0;
71 70
72 if (nla == NULL) 71 if (nla == NULL)
73 return -EINVAL; 72 return -EINVAL;
74 73 ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
75 err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); 74 if (ret < 0)
76 if (err < 0) 75 return ret;
77 return err;
78
79 if (tb[TCA_MIRRED_PARMS] == NULL) 76 if (tb[TCA_MIRRED_PARMS] == NULL)
80 return -EINVAL; 77 return -EINVAL;
81 parm = nla_data(tb[TCA_MIRRED_PARMS]); 78 parm = nla_data(tb[TCA_MIRRED_PARMS]);
82 79 switch (parm->eaction) {
80 case TCA_EGRESS_MIRROR:
81 case TCA_EGRESS_REDIR:
82 break;
83 default:
84 return -EINVAL;
85 }
83 if (parm->ifindex) { 86 if (parm->ifindex) {
84 dev = __dev_get_by_index(&init_net, parm->ifindex); 87 dev = __dev_get_by_index(&init_net, parm->ifindex);
85 if (dev == NULL) 88 if (dev == NULL)
86 return -ENODEV; 89 return -ENODEV;
87 switch (dev->type) { 90 switch (dev->type) {
88 case ARPHRD_TUNNEL: 91 case ARPHRD_TUNNEL:
89 case ARPHRD_TUNNEL6: 92 case ARPHRD_TUNNEL6:
90 case ARPHRD_SIT: 93 case ARPHRD_SIT:
91 case ARPHRD_IPGRE: 94 case ARPHRD_IPGRE:
92 case ARPHRD_VOID: 95 case ARPHRD_VOID:
93 case ARPHRD_NONE: 96 case ARPHRD_NONE:
94 ok_push = 0; 97 ok_push = 0;
95 break; 98 break;
96 default: 99 default:
97 ok_push = 1; 100 ok_push = 1;
98 break; 101 break;
99 } 102 }
103 } else {
104 dev = NULL;
100 } 105 }
101 106
102 pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); 107 pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
103 if (!pc) { 108 if (!pc) {
104 if (!parm->ifindex) 109 if (dev == NULL)
105 return -EINVAL; 110 return -EINVAL;
106 pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, 111 pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
107 &mirred_idx_gen, &mirred_hash_info); 112 &mirred_idx_gen, &mirred_hash_info);
108 if (IS_ERR(pc)) 113 if (IS_ERR(pc))
109 return PTR_ERR(pc); 114 return PTR_ERR(pc);
110 ret = ACT_P_CREATED; 115 ret = ACT_P_CREATED;
111 } else { 116 } else {
112 if (!ovr) { 117 if (!ovr) {
@@ -119,12 +124,12 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
119 spin_lock_bh(&m->tcf_lock); 124 spin_lock_bh(&m->tcf_lock);
120 m->tcf_action = parm->action; 125 m->tcf_action = parm->action;
121 m->tcfm_eaction = parm->eaction; 126 m->tcfm_eaction = parm->eaction;
122 if (parm->ifindex) { 127 if (dev != NULL) {
123 m->tcfm_ifindex = parm->ifindex; 128 m->tcfm_ifindex = parm->ifindex;
124 if (ret != ACT_P_CREATED) 129 if (ret != ACT_P_CREATED)
125 dev_put(m->tcfm_dev); 130 dev_put(m->tcfm_dev);
126 m->tcfm_dev = dev;
127 dev_hold(dev); 131 dev_hold(dev);
132 m->tcfm_dev = dev;
128 m->tcfm_ok_push = ok_push; 133 m->tcfm_ok_push = ok_push;
129 } 134 }
130 spin_unlock_bh(&m->tcf_lock); 135 spin_unlock_bh(&m->tcf_lock);
@@ -148,57 +153,57 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
148{ 153{
149 struct tcf_mirred *m = a->priv; 154 struct tcf_mirred *m = a->priv;
150 struct net_device *dev; 155 struct net_device *dev;
151 struct sk_buff *skb2 = NULL; 156 struct sk_buff *skb2;
152 u32 at = G_TC_AT(skb->tc_verd); 157 u32 at;
158 int retval, err = 1;
153 159
154 spin_lock(&m->tcf_lock); 160 spin_lock(&m->tcf_lock);
155
156 dev = m->tcfm_dev;
157 m->tcf_tm.lastuse = jiffies; 161 m->tcf_tm.lastuse = jiffies;
158 162
159 if (!(dev->flags&IFF_UP) ) { 163 dev = m->tcfm_dev;
164 if (!(dev->flags & IFF_UP)) {
160 if (net_ratelimit()) 165 if (net_ratelimit())
161 printk("mirred to Houston: device %s is gone!\n", 166 printk("mirred to Houston: device %s is gone!\n",
162 dev->name); 167 dev->name);
163bad_mirred: 168 goto out;
164 if (skb2 != NULL)
165 kfree_skb(skb2);
166 m->tcf_qstats.overlimits++;
167 m->tcf_bstats.bytes += qdisc_pkt_len(skb);
168 m->tcf_bstats.packets++;
169 spin_unlock(&m->tcf_lock);
170 /* should we be asking for packet to be dropped?
171 * may make sense for redirect case only
172 */
173 return TC_ACT_SHOT;
174 } 169 }
175 170
176 skb2 = skb_act_clone(skb, GFP_ATOMIC); 171 skb2 = skb_act_clone(skb, GFP_ATOMIC);
177 if (skb2 == NULL) 172 if (skb2 == NULL)
178 goto bad_mirred; 173 goto out;
179 if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
180 m->tcfm_eaction != TCA_EGRESS_REDIR) {
181 if (net_ratelimit())
182 printk("tcf_mirred unknown action %d\n",
183 m->tcfm_eaction);
184 goto bad_mirred;
185 }
186 174
187 m->tcf_bstats.bytes += qdisc_pkt_len(skb2); 175 m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
188 m->tcf_bstats.packets++; 176 m->tcf_bstats.packets++;
189 if (!(at & AT_EGRESS)) 177 at = G_TC_AT(skb->tc_verd);
178 if (!(at & AT_EGRESS)) {
190 if (m->tcfm_ok_push) 179 if (m->tcfm_ok_push)
191 skb_push(skb2, skb2->dev->hard_header_len); 180 skb_push(skb2, skb2->dev->hard_header_len);
181 }
192 182
193 /* mirror is always swallowed */ 183 /* mirror is always swallowed */
194 if (m->tcfm_eaction != TCA_EGRESS_MIRROR) 184 if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
195 skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); 185 skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
196 186
197 skb2->dev = dev; 187 skb2->dev = dev;
198 skb2->iif = skb->dev->ifindex; 188 skb2->skb_iif = skb->dev->ifindex;
199 dev_queue_xmit(skb2); 189 dev_queue_xmit(skb2);
190 err = 0;
191
192out:
193 if (err) {
194 m->tcf_qstats.overlimits++;
195 m->tcf_bstats.bytes += qdisc_pkt_len(skb);
196 m->tcf_bstats.packets++;
197 /* should we be asking for packet to be dropped?
198 * may make sense for redirect case only
199 */
200 retval = TC_ACT_SHOT;
201 } else {
202 retval = m->tcf_action;
203 }
200 spin_unlock(&m->tcf_lock); 204 spin_unlock(&m->tcf_lock);
201 return m->tcf_action; 205
206 return retval;
202} 207}
203 208
204static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 209static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)