| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * net/sched/act_skbmod.c skb data modifier |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2016 Jamal Hadi Salim <jhs@mojatatu.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 17 | 13 | #include <linux/rtnetlink.h> |
|---|
| 18 | 14 | #include <net/netlink.h> |
|---|
| 19 | 15 | #include <net/pkt_sched.h> |
|---|
| 16 | +#include <net/pkt_cls.h> |
|---|
| 20 | 17 | |
|---|
| 21 | 18 | #include <linux/tc_act/tc_skbmod.h> |
|---|
| 22 | 19 | #include <net/tc_act/tc_skbmod.h> |
|---|
| .. | .. |
|---|
| 86 | 83 | static int tcf_skbmod_init(struct net *net, struct nlattr *nla, |
|---|
| 87 | 84 | struct nlattr *est, struct tc_action **a, |
|---|
| 88 | 85 | int ovr, int bind, bool rtnl_held, |
|---|
| 86 | + struct tcf_proto *tp, u32 flags, |
|---|
| 89 | 87 | struct netlink_ext_ack *extack) |
|---|
| 90 | 88 | { |
|---|
| 91 | 89 | struct tc_action_net *tn = net_generic(net, skbmod_net_id); |
|---|
| 92 | 90 | struct nlattr *tb[TCA_SKBMOD_MAX + 1]; |
|---|
| 93 | 91 | struct tcf_skbmod_params *p, *p_old; |
|---|
| 92 | + struct tcf_chain *goto_ch = NULL; |
|---|
| 94 | 93 | struct tc_skbmod *parm; |
|---|
| 95 | 94 | u32 lflags = 0, index; |
|---|
| 96 | 95 | struct tcf_skbmod *d; |
|---|
| .. | .. |
|---|
| 103 | 102 | if (!nla) |
|---|
| 104 | 103 | return -EINVAL; |
|---|
| 105 | 104 | |
|---|
| 106 | | - err = nla_parse_nested(tb, TCA_SKBMOD_MAX, nla, skbmod_policy, NULL); |
|---|
| 105 | + err = nla_parse_nested_deprecated(tb, TCA_SKBMOD_MAX, nla, |
|---|
| 106 | + skbmod_policy, NULL); |
|---|
| 107 | 107 | if (err < 0) |
|---|
| 108 | 108 | return err; |
|---|
| 109 | 109 | |
|---|
| .. | .. |
|---|
| 147 | 147 | |
|---|
| 148 | 148 | if (!exists) { |
|---|
| 149 | 149 | ret = tcf_idr_create(tn, index, est, a, |
|---|
| 150 | | - &act_skbmod_ops, bind, true); |
|---|
| 150 | + &act_skbmod_ops, bind, true, flags); |
|---|
| 151 | 151 | if (ret) { |
|---|
| 152 | 152 | tcf_idr_cleanup(tn, index); |
|---|
| 153 | 153 | return ret; |
|---|
| .. | .. |
|---|
| 158 | 158 | tcf_idr_release(*a, bind); |
|---|
| 159 | 159 | return -EEXIST; |
|---|
| 160 | 160 | } |
|---|
| 161 | + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
|---|
| 162 | + if (err < 0) |
|---|
| 163 | + goto release_idr; |
|---|
| 161 | 164 | |
|---|
| 162 | 165 | d = to_skbmod(*a); |
|---|
| 163 | 166 | |
|---|
| 164 | 167 | p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); |
|---|
| 165 | 168 | if (unlikely(!p)) { |
|---|
| 166 | | - tcf_idr_release(*a, bind); |
|---|
| 167 | | - return -ENOMEM; |
|---|
| 169 | + err = -ENOMEM; |
|---|
| 170 | + goto put_chain; |
|---|
| 168 | 171 | } |
|---|
| 169 | 172 | |
|---|
| 170 | 173 | p->flags = lflags; |
|---|
| 171 | | - d->tcf_action = parm->action; |
|---|
| 172 | 174 | |
|---|
| 173 | 175 | if (ovr) |
|---|
| 174 | 176 | spin_lock_bh(&d->tcf_lock); |
|---|
| 175 | 177 | /* Protected by tcf_lock if overwriting existing action. */ |
|---|
| 178 | + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
|---|
| 176 | 179 | p_old = rcu_dereference_protected(d->skbmod_p, 1); |
|---|
| 177 | 180 | |
|---|
| 178 | 181 | if (lflags & SKBMOD_F_DMAC) |
|---|
| .. | .. |
|---|
| 188 | 191 | |
|---|
| 189 | 192 | if (p_old) |
|---|
| 190 | 193 | kfree_rcu(p_old, rcu); |
|---|
| 194 | + if (goto_ch) |
|---|
| 195 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 191 | 196 | |
|---|
| 192 | | - if (ret == ACT_P_CREATED) |
|---|
| 193 | | - tcf_idr_insert(tn, *a); |
|---|
| 194 | 197 | return ret; |
|---|
| 198 | +put_chain: |
|---|
| 199 | + if (goto_ch) |
|---|
| 200 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 201 | +release_idr: |
|---|
| 202 | + tcf_idr_release(*a, bind); |
|---|
| 203 | + return err; |
|---|
| 195 | 204 | } |
|---|
| 196 | 205 | |
|---|
| 197 | 206 | static void tcf_skbmod_cleanup(struct tc_action *a) |
|---|
| .. | .. |
|---|
| 256 | 265 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
|---|
| 257 | 266 | } |
|---|
| 258 | 267 | |
|---|
| 259 | | -static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index, |
|---|
| 260 | | - struct netlink_ext_ack *extack) |
|---|
| 268 | +static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index) |
|---|
| 261 | 269 | { |
|---|
| 262 | 270 | struct tc_action_net *tn = net_generic(net, skbmod_net_id); |
|---|
| 263 | 271 | |
|---|
| .. | .. |
|---|
| 266 | 274 | |
|---|
| 267 | 275 | static struct tc_action_ops act_skbmod_ops = { |
|---|
| 268 | 276 | .kind = "skbmod", |
|---|
| 269 | | - .type = TCA_ACT_SKBMOD, |
|---|
| 277 | + .id = TCA_ACT_SKBMOD, |
|---|
| 270 | 278 | .owner = THIS_MODULE, |
|---|
| 271 | 279 | .act = tcf_skbmod_act, |
|---|
| 272 | 280 | .dump = tcf_skbmod_dump, |
|---|