| .. | .. | 
|---|
| 33 | 33 |  static DECLARE_RWSEM(bpf_devs_lock); | 
|---|
| 34 | 34 |   | 
|---|
| 35 | 35 |  struct bpf_offload_dev { | 
|---|
 | 36 | +	const struct bpf_prog_offload_ops *ops;  | 
|---|
| 36 | 37 |  	struct list_head netdevs; | 
|---|
 | 38 | +	void *priv;  | 
|---|
| 37 | 39 |  }; | 
|---|
| 38 | 40 |   | 
|---|
| 39 | 41 |  struct bpf_offload_netdev { | 
|---|
| .. | .. | 
|---|
| 106 | 108 |  		err = -EINVAL; | 
|---|
| 107 | 109 |  		goto err_unlock; | 
|---|
| 108 | 110 |  	} | 
|---|
 | 111 | +	offload->offdev = ondev->offdev;  | 
|---|
| 109 | 112 |  	prog->aux->offload = offload; | 
|---|
| 110 | 113 |  	list_add_tail(&offload->offloads, &ondev->progs); | 
|---|
| 111 | 114 |  	dev_put(offload->netdev); | 
|---|
| .. | .. | 
|---|
| 121 | 124 |  	return err; | 
|---|
| 122 | 125 |  } | 
|---|
| 123 | 126 |   | 
|---|
| 124 |  | -static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd,  | 
|---|
| 125 |  | -			     struct netdev_bpf *data)  | 
|---|
 | 127 | +int bpf_prog_offload_verifier_prep(struct bpf_prog *prog)  | 
|---|
| 126 | 128 |  { | 
|---|
| 127 |  | -	struct bpf_prog_offload *offload = prog->aux->offload;  | 
|---|
| 128 |  | -	struct net_device *netdev;  | 
|---|
 | 129 | +	struct bpf_prog_offload *offload;  | 
|---|
 | 130 | +	int ret = -ENODEV;  | 
|---|
| 129 | 131 |   | 
|---|
| 130 |  | -	ASSERT_RTNL();  | 
|---|
 | 132 | +	down_read(&bpf_devs_lock);  | 
|---|
 | 133 | +	offload = prog->aux->offload;  | 
|---|
 | 134 | +	if (offload) {  | 
|---|
 | 135 | +		ret = offload->offdev->ops->prepare(prog);  | 
|---|
 | 136 | +		offload->dev_state = !ret;  | 
|---|
 | 137 | +	}  | 
|---|
 | 138 | +	up_read(&bpf_devs_lock);  | 
|---|
| 131 | 139 |   | 
|---|
| 132 |  | -	if (!offload)  | 
|---|
| 133 |  | -		return -ENODEV;  | 
|---|
| 134 |  | -	netdev = offload->netdev;  | 
|---|
| 135 |  | -  | 
|---|
| 136 |  | -	data->command = cmd;  | 
|---|
| 137 |  | -  | 
|---|
| 138 |  | -	return netdev->netdev_ops->ndo_bpf(netdev, data);  | 
|---|
| 139 |  | -}  | 
|---|
| 140 |  | -  | 
|---|
| 141 |  | -int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)  | 
|---|
| 142 |  | -{  | 
|---|
| 143 |  | -	struct netdev_bpf data = {};  | 
|---|
| 144 |  | -	int err;  | 
|---|
| 145 |  | -  | 
|---|
| 146 |  | -	data.verifier.prog = env->prog;  | 
|---|
| 147 |  | -  | 
|---|
| 148 |  | -	rtnl_lock();  | 
|---|
| 149 |  | -	err = __bpf_offload_ndo(env->prog, BPF_OFFLOAD_VERIFIER_PREP, &data);  | 
|---|
| 150 |  | -	if (err)  | 
|---|
| 151 |  | -		goto exit_unlock;  | 
|---|
| 152 |  | -  | 
|---|
| 153 |  | -	env->prog->aux->offload->dev_ops = data.verifier.ops;  | 
|---|
| 154 |  | -	env->prog->aux->offload->dev_state = true;  | 
|---|
| 155 |  | -exit_unlock:  | 
|---|
| 156 |  | -	rtnl_unlock();  | 
|---|
| 157 |  | -	return err;  | 
|---|
 | 140 | +	return ret;  | 
|---|
| 158 | 141 |  } | 
|---|
| 159 | 142 |   | 
|---|
| 160 | 143 |  int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env, | 
|---|
| .. | .. | 
|---|
| 166 | 149 |  	down_read(&bpf_devs_lock); | 
|---|
| 167 | 150 |  	offload = env->prog->aux->offload; | 
|---|
| 168 | 151 |  	if (offload) | 
|---|
| 169 |  | -		ret = offload->dev_ops->insn_hook(env, insn_idx, prev_insn_idx);  | 
|---|
 | 152 | +		ret = offload->offdev->ops->insn_hook(env, insn_idx,  | 
|---|
 | 153 | +						      prev_insn_idx);  | 
|---|
| 170 | 154 |  	up_read(&bpf_devs_lock); | 
|---|
| 171 | 155 |   | 
|---|
| 172 | 156 |  	return ret; | 
|---|
| 173 | 157 |  } | 
|---|
| 174 | 158 |   | 
|---|
 | 159 | +int bpf_prog_offload_finalize(struct bpf_verifier_env *env)  | 
|---|
 | 160 | +{  | 
|---|
 | 161 | +	struct bpf_prog_offload *offload;  | 
|---|
 | 162 | +	int ret = -ENODEV;  | 
|---|
 | 163 | +  | 
|---|
 | 164 | +	down_read(&bpf_devs_lock);  | 
|---|
 | 165 | +	offload = env->prog->aux->offload;  | 
|---|
 | 166 | +	if (offload) {  | 
|---|
 | 167 | +		if (offload->offdev->ops->finalize)  | 
|---|
 | 168 | +			ret = offload->offdev->ops->finalize(env);  | 
|---|
 | 169 | +		else  | 
|---|
 | 170 | +			ret = 0;  | 
|---|
 | 171 | +	}  | 
|---|
 | 172 | +	up_read(&bpf_devs_lock);  | 
|---|
 | 173 | +  | 
|---|
 | 174 | +	return ret;  | 
|---|
 | 175 | +}  | 
|---|
 | 176 | +  | 
|---|
 | 177 | +void  | 
|---|
 | 178 | +bpf_prog_offload_replace_insn(struct bpf_verifier_env *env, u32 off,  | 
|---|
 | 179 | +			      struct bpf_insn *insn)  | 
|---|
 | 180 | +{  | 
|---|
 | 181 | +	const struct bpf_prog_offload_ops *ops;  | 
|---|
 | 182 | +	struct bpf_prog_offload *offload;  | 
|---|
 | 183 | +	int ret = -EOPNOTSUPP;  | 
|---|
 | 184 | +  | 
|---|
 | 185 | +	down_read(&bpf_devs_lock);  | 
|---|
 | 186 | +	offload = env->prog->aux->offload;  | 
|---|
 | 187 | +	if (offload) {  | 
|---|
 | 188 | +		ops = offload->offdev->ops;  | 
|---|
 | 189 | +		if (!offload->opt_failed && ops->replace_insn)  | 
|---|
 | 190 | +			ret = ops->replace_insn(env, off, insn);  | 
|---|
 | 191 | +		offload->opt_failed |= ret;  | 
|---|
 | 192 | +	}  | 
|---|
 | 193 | +	up_read(&bpf_devs_lock);  | 
|---|
 | 194 | +}  | 
|---|
 | 195 | +  | 
|---|
 | 196 | +void  | 
|---|
 | 197 | +bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)  | 
|---|
 | 198 | +{  | 
|---|
 | 199 | +	struct bpf_prog_offload *offload;  | 
|---|
 | 200 | +	int ret = -EOPNOTSUPP;  | 
|---|
 | 201 | +  | 
|---|
 | 202 | +	down_read(&bpf_devs_lock);  | 
|---|
 | 203 | +	offload = env->prog->aux->offload;  | 
|---|
 | 204 | +	if (offload) {  | 
|---|
 | 205 | +		if (!offload->opt_failed && offload->offdev->ops->remove_insns)  | 
|---|
 | 206 | +			ret = offload->offdev->ops->remove_insns(env, off, cnt);  | 
|---|
 | 207 | +		offload->opt_failed |= ret;  | 
|---|
 | 208 | +	}  | 
|---|
 | 209 | +	up_read(&bpf_devs_lock);  | 
|---|
 | 210 | +}  | 
|---|
 | 211 | +  | 
|---|
| 175 | 212 |  static void __bpf_prog_offload_destroy(struct bpf_prog *prog) | 
|---|
| 176 | 213 |  { | 
|---|
| 177 | 214 |  	struct bpf_prog_offload *offload = prog->aux->offload; | 
|---|
| 178 |  | -	struct netdev_bpf data = {};  | 
|---|
| 179 |  | -  | 
|---|
| 180 |  | -	data.offload.prog = prog;  | 
|---|
| 181 | 215 |   | 
|---|
| 182 | 216 |  	if (offload->dev_state) | 
|---|
| 183 |  | -		WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));  | 
|---|
 | 217 | +		offload->offdev->ops->destroy(prog);  | 
|---|
| 184 | 218 |   | 
|---|
| 185 | 219 |  	/* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */ | 
|---|
| 186 | 220 |  	bpf_prog_free_id(prog, true); | 
|---|
| .. | .. | 
|---|
| 192 | 226 |   | 
|---|
| 193 | 227 |  void bpf_prog_offload_destroy(struct bpf_prog *prog) | 
|---|
| 194 | 228 |  { | 
|---|
| 195 |  | -	rtnl_lock();  | 
|---|
| 196 | 229 |  	down_write(&bpf_devs_lock); | 
|---|
| 197 | 230 |  	if (prog->aux->offload) | 
|---|
| 198 | 231 |  		__bpf_prog_offload_destroy(prog); | 
|---|
| 199 | 232 |  	up_write(&bpf_devs_lock); | 
|---|
| 200 |  | -	rtnl_unlock();  | 
|---|
| 201 | 233 |  } | 
|---|
| 202 | 234 |   | 
|---|
| 203 | 235 |  static int bpf_prog_offload_translate(struct bpf_prog *prog) | 
|---|
| 204 | 236 |  { | 
|---|
| 205 |  | -	struct netdev_bpf data = {};  | 
|---|
| 206 |  | -	int ret;  | 
|---|
 | 237 | +	struct bpf_prog_offload *offload;  | 
|---|
 | 238 | +	int ret = -ENODEV;  | 
|---|
| 207 | 239 |   | 
|---|
| 208 |  | -	data.offload.prog = prog;  | 
|---|
| 209 |  | -  | 
|---|
| 210 |  | -	rtnl_lock();  | 
|---|
| 211 |  | -	ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data);  | 
|---|
| 212 |  | -	rtnl_unlock();  | 
|---|
 | 240 | +	down_read(&bpf_devs_lock);  | 
|---|
 | 241 | +	offload = prog->aux->offload;  | 
|---|
 | 242 | +	if (offload)  | 
|---|
 | 243 | +		ret = offload->offdev->ops->translate(prog);  | 
|---|
 | 244 | +	up_read(&bpf_devs_lock);  | 
|---|
| 213 | 245 |   | 
|---|
| 214 | 246 |  	return ret; | 
|---|
| 215 | 247 |  } | 
|---|
| .. | .. | 
|---|
| 270 | 302 |  	struct inode *ns_inode; | 
|---|
| 271 | 303 |  	struct path ns_path; | 
|---|
| 272 | 304 |  	char __user *uinsns; | 
|---|
| 273 |  | -	void *res;  | 
|---|
 | 305 | +	int res;  | 
|---|
| 274 | 306 |  	u32 ulen; | 
|---|
| 275 | 307 |   | 
|---|
| 276 | 308 |  	res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args); | 
|---|
| 277 |  | -	if (IS_ERR(res)) {  | 
|---|
 | 309 | +	if (res) {  | 
|---|
| 278 | 310 |  		if (!info->ifindex) | 
|---|
| 279 | 311 |  			return -ENODEV; | 
|---|
| 280 |  | -		return PTR_ERR(res);  | 
|---|
 | 312 | +		return res;  | 
|---|
| 281 | 313 |  	} | 
|---|
| 282 | 314 |   | 
|---|
| 283 | 315 |  	down_read(&bpf_devs_lock); | 
|---|
| .. | .. | 
|---|
| 494 | 526 |  	}; | 
|---|
| 495 | 527 |  	struct inode *ns_inode; | 
|---|
| 496 | 528 |  	struct path ns_path; | 
|---|
| 497 |  | -	void *res;  | 
|---|
 | 529 | +	int res;  | 
|---|
| 498 | 530 |   | 
|---|
| 499 | 531 |  	res = ns_get_path_cb(&ns_path, bpf_map_offload_info_fill_ns, &args); | 
|---|
| 500 |  | -	if (IS_ERR(res)) {  | 
|---|
 | 532 | +	if (res) {  | 
|---|
| 501 | 533 |  		if (!info->ifindex) | 
|---|
| 502 | 534 |  			return -ENODEV; | 
|---|
| 503 |  | -		return PTR_ERR(res);  | 
|---|
 | 535 | +		return res;  | 
|---|
| 504 | 536 |  	} | 
|---|
| 505 | 537 |   | 
|---|
| 506 | 538 |  	ns_inode = ns_path.dentry->d_inode; | 
|---|
| .. | .. | 
|---|
| 637 | 669 |  } | 
|---|
| 638 | 670 |  EXPORT_SYMBOL_GPL(bpf_offload_dev_netdev_unregister); | 
|---|
| 639 | 671 |   | 
|---|
| 640 |  | -struct bpf_offload_dev *bpf_offload_dev_create(void)  | 
|---|
 | 672 | +struct bpf_offload_dev *  | 
|---|
 | 673 | +bpf_offload_dev_create(const struct bpf_prog_offload_ops *ops, void *priv)  | 
|---|
| 641 | 674 |  { | 
|---|
| 642 | 675 |  	struct bpf_offload_dev *offdev; | 
|---|
| 643 | 676 |  	int err; | 
|---|
| .. | .. | 
|---|
| 657 | 690 |  	if (!offdev) | 
|---|
| 658 | 691 |  		return ERR_PTR(-ENOMEM); | 
|---|
| 659 | 692 |   | 
|---|
 | 693 | +	offdev->ops = ops;  | 
|---|
 | 694 | +	offdev->priv = priv;  | 
|---|
| 660 | 695 |  	INIT_LIST_HEAD(&offdev->netdevs); | 
|---|
| 661 | 696 |   | 
|---|
| 662 | 697 |  	return offdev; | 
|---|
| .. | .. | 
|---|
| 669 | 704 |  	kfree(offdev); | 
|---|
| 670 | 705 |  } | 
|---|
| 671 | 706 |  EXPORT_SYMBOL_GPL(bpf_offload_dev_destroy); | 
|---|
 | 707 | +  | 
|---|
 | 708 | +void *bpf_offload_dev_priv(struct bpf_offload_dev *offdev)  | 
|---|
 | 709 | +{  | 
|---|
 | 710 | +	return offdev->priv;  | 
|---|
 | 711 | +}  | 
|---|
 | 712 | +EXPORT_SYMBOL_GPL(bpf_offload_dev_priv);  | 
|---|