act_mirred.c (74e630a7582e6b3cb39559d712a0049f08dea8a0) act_mirred.c (a85a970af265f156740977168b542234511b28a8)
1/*
2 * net/sched/act_mirred.c packet mirroring and redirect actions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *

--- 38 unchanged lines hidden (view full) ---

47 spin_unlock_bh(&mirred_list_lock);
48}
49
50static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
51 [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) },
52};
53
54static int mirred_net_id;
1/*
2 * net/sched/act_mirred.c packet mirroring and redirect actions
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *

--- 38 unchanged lines hidden (view full) ---

47 spin_unlock_bh(&mirred_list_lock);
48}
49
50static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
51 [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) },
52};
53
54static int mirred_net_id;
55static struct tc_action_ops act_mirred_ops;
55
56static int tcf_mirred_init(struct net *net, struct nlattr *nla,
56
57static int tcf_mirred_init(struct net *net, struct nlattr *nla,
57 struct nlattr *est, struct tc_action *a, int ovr,
58 struct nlattr *est, struct tc_action **a, int ovr,
58 int bind)
59{
60 struct tc_action_net *tn = net_generic(net, mirred_net_id);
61 struct nlattr *tb[TCA_MIRRED_MAX + 1];
62 struct tc_mirred *parm;
63 struct tcf_mirred *m;
64 struct net_device *dev;
59 int bind)
60{
61 struct tc_action_net *tn = net_generic(net, mirred_net_id);
62 struct nlattr *tb[TCA_MIRRED_MAX + 1];
63 struct tc_mirred *parm;
64 struct tcf_mirred *m;
65 struct net_device *dev;
65 int ret, ok_push = 0, exists = 0;
66 int ret, ok_push = 0;
67 bool exists = false;
66
67 if (nla == NULL)
68 return -EINVAL;
69 ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
70 if (ret < 0)
71 return ret;
72 if (tb[TCA_MIRRED_PARMS] == NULL)
73 return -EINVAL;

--- 4 unchanged lines hidden (view full) ---

78 return 0;
79
80 switch (parm->eaction) {
81 case TCA_EGRESS_MIRROR:
82 case TCA_EGRESS_REDIR:
83 break;
84 default:
85 if (exists)
68
69 if (nla == NULL)
70 return -EINVAL;
71 ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
72 if (ret < 0)
73 return ret;
74 if (tb[TCA_MIRRED_PARMS] == NULL)
75 return -EINVAL;

--- 4 unchanged lines hidden (view full) ---

80 return 0;
81
82 switch (parm->eaction) {
83 case TCA_EGRESS_MIRROR:
84 case TCA_EGRESS_REDIR:
85 break;
86 default:
87 if (exists)
86 tcf_hash_release(a, bind);
88 tcf_hash_release(*a, bind);
87 return -EINVAL;
88 }
89 if (parm->ifindex) {
90 dev = __dev_get_by_index(net, parm->ifindex);
91 if (dev == NULL) {
92 if (exists)
89 return -EINVAL;
90 }
91 if (parm->ifindex) {
92 dev = __dev_get_by_index(net, parm->ifindex);
93 if (dev == NULL) {
94 if (exists)
93 tcf_hash_release(a, bind);
95 tcf_hash_release(*a, bind);
94 return -ENODEV;
95 }
96 switch (dev->type) {
97 case ARPHRD_TUNNEL:
98 case ARPHRD_TUNNEL6:
99 case ARPHRD_SIT:
100 case ARPHRD_IPGRE:
101 case ARPHRD_VOID:

--- 7 unchanged lines hidden (view full) ---

109 } else {
110 dev = NULL;
111 }
112
113 if (!exists) {
114 if (dev == NULL)
115 return -EINVAL;
116 ret = tcf_hash_create(tn, parm->index, est, a,
96 return -ENODEV;
97 }
98 switch (dev->type) {
99 case ARPHRD_TUNNEL:
100 case ARPHRD_TUNNEL6:
101 case ARPHRD_SIT:
102 case ARPHRD_IPGRE:
103 case ARPHRD_VOID:

--- 7 unchanged lines hidden (view full) ---

111 } else {
112 dev = NULL;
113 }
114
115 if (!exists) {
116 if (dev == NULL)
117 return -EINVAL;
118 ret = tcf_hash_create(tn, parm->index, est, a,
117 sizeof(*m), bind, true);
119 &act_mirred_ops, bind, true);
118 if (ret)
119 return ret;
120 ret = ACT_P_CREATED;
121 } else {
120 if (ret)
121 return ret;
122 ret = ACT_P_CREATED;
123 } else {
122 tcf_hash_release(a, bind);
124 tcf_hash_release(*a, bind);
123 if (!ovr)
124 return -EEXIST;
125 }
125 if (!ovr)
126 return -EEXIST;
127 }
126 m = to_mirred(a);
128 m = to_mirred(*a);
127
128 ASSERT_RTNL();
129 m->tcf_action = parm->action;
130 m->tcfm_eaction = parm->eaction;
131 if (dev != NULL) {
132 m->tcfm_ifindex = parm->ifindex;
133 if (ret != ACT_P_CREATED)
134 dev_put(rcu_dereference_protected(m->tcfm_dev, 1));
135 dev_hold(dev);
136 rcu_assign_pointer(m->tcfm_dev, dev);
137 m->tcfm_ok_push = ok_push;
138 }
139
140 if (ret == ACT_P_CREATED) {
141 spin_lock_bh(&mirred_list_lock);
142 list_add(&m->tcfm_list, &mirred_list);
143 spin_unlock_bh(&mirred_list_lock);
129
130 ASSERT_RTNL();
131 m->tcf_action = parm->action;
132 m->tcfm_eaction = parm->eaction;
133 if (dev != NULL) {
134 m->tcfm_ifindex = parm->ifindex;
135 if (ret != ACT_P_CREATED)
136 dev_put(rcu_dereference_protected(m->tcfm_dev, 1));
137 dev_hold(dev);
138 rcu_assign_pointer(m->tcfm_dev, dev);
139 m->tcfm_ok_push = ok_push;
140 }
141
142 if (ret == ACT_P_CREATED) {
143 spin_lock_bh(&mirred_list_lock);
144 list_add(&m->tcfm_list, &mirred_list);
145 spin_unlock_bh(&mirred_list_lock);
144 tcf_hash_insert(tn, a);
146 tcf_hash_insert(tn, *a);
145 }
146
147 return ret;
148}
149
150static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
151 struct tcf_result *res)
152{
147 }
148
149 return ret;
150}
151
152static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
153 struct tcf_result *res)
154{
153 struct tcf_mirred *m = a->priv;
155 struct tcf_mirred *m = to_mirred(a);
154 struct net_device *dev;
155 struct sk_buff *skb2;
156 int retval, err;
157 u32 at;
158
159 tcf_lastuse_update(&m->tcf_tm);
156 struct net_device *dev;
157 struct sk_buff *skb2;
158 int retval, err;
159 u32 at;
160
161 tcf_lastuse_update(&m->tcf_tm);
160
161 bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
162
163 rcu_read_lock();
164 retval = READ_ONCE(m->tcf_action);
165 dev = rcu_dereference(m->tcfm_dev);
166 if (unlikely(!dev)) {
167 pr_notice_once("tc mirred: target device is gone\n");
168 goto out;

--- 32 unchanged lines hidden (view full) ---

201 rcu_read_unlock();
202
203 return retval;
204}
205
206static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
207{
208 unsigned char *b = skb_tail_pointer(skb);
162 bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
163
164 rcu_read_lock();
165 retval = READ_ONCE(m->tcf_action);
166 dev = rcu_dereference(m->tcfm_dev);
167 if (unlikely(!dev)) {
168 pr_notice_once("tc mirred: target device is gone\n");
169 goto out;

--- 32 unchanged lines hidden (view full) ---

202 rcu_read_unlock();
203
204 return retval;
205}
206
207static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
208{
209 unsigned char *b = skb_tail_pointer(skb);
209 struct tcf_mirred *m = a->priv;
210 struct tcf_mirred *m = to_mirred(a);
210 struct tc_mirred opt = {
211 .index = m->tcf_index,
212 .action = m->tcf_action,
213 .refcnt = m->tcf_refcnt - ref,
214 .bindcnt = m->tcf_bindcnt - bind,
215 .eaction = m->tcfm_eaction,
216 .ifindex = m->tcfm_ifindex,
217 };
218 struct tcf_t t;
219
220 if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
221 goto nla_put_failure;
211 struct tc_mirred opt = {
212 .index = m->tcf_index,
213 .action = m->tcf_action,
214 .refcnt = m->tcf_refcnt - ref,
215 .bindcnt = m->tcf_bindcnt - bind,
216 .eaction = m->tcfm_eaction,
217 .ifindex = m->tcfm_ifindex,
218 };
219 struct tcf_t t;
220
221 if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
222 goto nla_put_failure;
222 t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
223 t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
224 t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
223
224 tcf_tm_dump(&t, &m->tcf_tm);
225 if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD))
226 goto nla_put_failure;
227 return skb->len;
228
229nla_put_failure:
230 nlmsg_trim(skb, b);
231 return -1;
232}
233
234static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
235 struct netlink_callback *cb, int type,
225 if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD))
226 goto nla_put_failure;
227 return skb->len;
228
229nla_put_failure:
230 nlmsg_trim(skb, b);
231 return -1;
232}
233
234static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
235 struct netlink_callback *cb, int type,
236 struct tc_action *a)
236 const struct tc_action_ops *ops)
237{
238 struct tc_action_net *tn = net_generic(net, mirred_net_id);
239
237{
238 struct tc_action_net *tn = net_generic(net, mirred_net_id);
239
240 return tcf_generic_walker(tn, skb, cb, type, a);
240 return tcf_generic_walker(tn, skb, cb, type, ops);
241}
242
241}
242
243static int tcf_mirred_search(struct net *net, struct tc_action *a, u32 index)
243static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
244{
245 struct tc_action_net *tn = net_generic(net, mirred_net_id);
246
247 return tcf_hash_search(tn, a, index);
248}
249
250static int mirred_device_event(struct notifier_block *unused,
251 unsigned long event, void *ptr)

--- 28 unchanged lines hidden (view full) ---

280 .type = TCA_ACT_MIRRED,
281 .owner = THIS_MODULE,
282 .act = tcf_mirred,
283 .dump = tcf_mirred_dump,
284 .cleanup = tcf_mirred_release,
285 .init = tcf_mirred_init,
286 .walk = tcf_mirred_walker,
287 .lookup = tcf_mirred_search,
244{
245 struct tc_action_net *tn = net_generic(net, mirred_net_id);
246
247 return tcf_hash_search(tn, a, index);
248}
249
250static int mirred_device_event(struct notifier_block *unused,
251 unsigned long event, void *ptr)

--- 28 unchanged lines hidden (view full) ---

280 .type = TCA_ACT_MIRRED,
281 .owner = THIS_MODULE,
282 .act = tcf_mirred,
283 .dump = tcf_mirred_dump,
284 .cleanup = tcf_mirred_release,
285 .init = tcf_mirred_init,
286 .walk = tcf_mirred_walker,
287 .lookup = tcf_mirred_search,
288 .size = sizeof(struct tcf_mirred),
288};
289
290static __net_init int mirred_init_net(struct net *net)
291{
292 struct tc_action_net *tn = net_generic(net, mirred_net_id);
293
294 return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
295}

--- 37 unchanged lines hidden ---
289};
290
291static __net_init int mirred_init_net(struct net *net)
292{
293 struct tc_action_net *tn = net_generic(net, mirred_net_id);
294
295 return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
296}

--- 37 unchanged lines hidden ---