| .. | .. |
|---|
| 228 | 228 | if (c->mfc_flags & MFC_OFFLOAD) |
|---|
| 229 | 229 | rtm->rtm_flags |= RTNH_F_OFFLOAD; |
|---|
| 230 | 230 | |
|---|
| 231 | | - mp_attr = nla_nest_start(skb, RTA_MULTIPATH); |
|---|
| 231 | + mp_attr = nla_nest_start_noflag(skb, RTA_MULTIPATH); |
|---|
| 232 | 232 | if (!mp_attr) |
|---|
| 233 | 233 | return -EMSGSIZE; |
|---|
| 234 | 234 | |
|---|
| .. | .. |
|---|
| 268 | 268 | } |
|---|
| 269 | 269 | EXPORT_SYMBOL(mr_fill_mroute); |
|---|
| 270 | 270 | |
|---|
| 271 | +static bool mr_mfc_uses_dev(const struct mr_table *mrt, |
|---|
| 272 | + const struct mr_mfc *c, |
|---|
| 273 | + const struct net_device *dev) |
|---|
| 274 | +{ |
|---|
| 275 | + int ct; |
|---|
| 276 | + |
|---|
| 277 | + for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { |
|---|
| 278 | + if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) { |
|---|
| 279 | + const struct vif_device *vif; |
|---|
| 280 | + |
|---|
| 281 | + vif = &mrt->vif_table[ct]; |
|---|
| 282 | + if (vif->dev == dev) |
|---|
| 283 | + return true; |
|---|
| 284 | + } |
|---|
| 285 | + } |
|---|
| 286 | + return false; |
|---|
| 287 | +} |
|---|
| 288 | + |
|---|
| 289 | +int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, |
|---|
| 290 | + struct netlink_callback *cb, |
|---|
| 291 | + int (*fill)(struct mr_table *mrt, struct sk_buff *skb, |
|---|
| 292 | + u32 portid, u32 seq, struct mr_mfc *c, |
|---|
| 293 | + int cmd, int flags), |
|---|
| 294 | + spinlock_t *lock, struct fib_dump_filter *filter) |
|---|
| 295 | +{ |
|---|
| 296 | + unsigned int e = 0, s_e = cb->args[1]; |
|---|
| 297 | + unsigned int flags = NLM_F_MULTI; |
|---|
| 298 | + struct mr_mfc *mfc; |
|---|
| 299 | + int err; |
|---|
| 300 | + |
|---|
| 301 | + if (filter->filter_set) |
|---|
| 302 | + flags |= NLM_F_DUMP_FILTERED; |
|---|
| 303 | + |
|---|
| 304 | + list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { |
|---|
| 305 | + if (e < s_e) |
|---|
| 306 | + goto next_entry; |
|---|
| 307 | + if (filter->dev && |
|---|
| 308 | + !mr_mfc_uses_dev(mrt, mfc, filter->dev)) |
|---|
| 309 | + goto next_entry; |
|---|
| 310 | + |
|---|
| 311 | + err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, |
|---|
| 312 | + cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); |
|---|
| 313 | + if (err < 0) |
|---|
| 314 | + goto out; |
|---|
| 315 | +next_entry: |
|---|
| 316 | + e++; |
|---|
| 317 | + } |
|---|
| 318 | + |
|---|
| 319 | + spin_lock_bh(lock); |
|---|
| 320 | + list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) { |
|---|
| 321 | + if (e < s_e) |
|---|
| 322 | + goto next_entry2; |
|---|
| 323 | + if (filter->dev && |
|---|
| 324 | + !mr_mfc_uses_dev(mrt, mfc, filter->dev)) |
|---|
| 325 | + goto next_entry2; |
|---|
| 326 | + |
|---|
| 327 | + err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, |
|---|
| 328 | + cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); |
|---|
| 329 | + if (err < 0) { |
|---|
| 330 | + spin_unlock_bh(lock); |
|---|
| 331 | + goto out; |
|---|
| 332 | + } |
|---|
| 333 | +next_entry2: |
|---|
| 334 | + e++; |
|---|
| 335 | + } |
|---|
| 336 | + spin_unlock_bh(lock); |
|---|
| 337 | + err = 0; |
|---|
| 338 | +out: |
|---|
| 339 | + cb->args[1] = e; |
|---|
| 340 | + return err; |
|---|
| 341 | +} |
|---|
| 342 | +EXPORT_SYMBOL(mr_table_dump); |
|---|
| 343 | + |
|---|
| 271 | 344 | int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, |
|---|
| 272 | 345 | struct mr_table *(*iter)(struct net *net, |
|---|
| 273 | 346 | struct mr_table *mrt), |
|---|
| .. | .. |
|---|
| 275 | 348 | struct sk_buff *skb, |
|---|
| 276 | 349 | u32 portid, u32 seq, struct mr_mfc *c, |
|---|
| 277 | 350 | int cmd, int flags), |
|---|
| 278 | | - spinlock_t *lock) |
|---|
| 351 | + spinlock_t *lock, struct fib_dump_filter *filter) |
|---|
| 279 | 352 | { |
|---|
| 280 | | - unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1]; |
|---|
| 353 | + unsigned int t = 0, s_t = cb->args[0]; |
|---|
| 281 | 354 | struct net *net = sock_net(skb->sk); |
|---|
| 282 | 355 | struct mr_table *mrt; |
|---|
| 283 | | - struct mr_mfc *mfc; |
|---|
| 356 | + int err; |
|---|
| 357 | + |
|---|
| 358 | + /* multicast does not track protocol or have route type other |
|---|
| 359 | + * than RTN_MULTICAST |
|---|
| 360 | + */ |
|---|
| 361 | + if (filter->filter_set) { |
|---|
| 362 | + if (filter->protocol || filter->flags || |
|---|
| 363 | + (filter->rt_type && filter->rt_type != RTN_MULTICAST)) |
|---|
| 364 | + return skb->len; |
|---|
| 365 | + } |
|---|
| 284 | 366 | |
|---|
| 285 | 367 | rcu_read_lock(); |
|---|
| 286 | 368 | for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) { |
|---|
| 287 | 369 | if (t < s_t) |
|---|
| 288 | 370 | goto next_table; |
|---|
| 289 | | - list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { |
|---|
| 290 | | - if (e < s_e) |
|---|
| 291 | | - goto next_entry; |
|---|
| 292 | | - if (fill(mrt, skb, NETLINK_CB(cb->skb).portid, |
|---|
| 293 | | - cb->nlh->nlmsg_seq, mfc, |
|---|
| 294 | | - RTM_NEWROUTE, NLM_F_MULTI) < 0) |
|---|
| 295 | | - goto done; |
|---|
| 296 | | -next_entry: |
|---|
| 297 | | - e++; |
|---|
| 298 | | - } |
|---|
| 299 | 371 | |
|---|
| 300 | | - spin_lock_bh(lock); |
|---|
| 301 | | - list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) { |
|---|
| 302 | | - if (e < s_e) |
|---|
| 303 | | - goto next_entry2; |
|---|
| 304 | | - if (fill(mrt, skb, NETLINK_CB(cb->skb).portid, |
|---|
| 305 | | - cb->nlh->nlmsg_seq, mfc, |
|---|
| 306 | | - RTM_NEWROUTE, NLM_F_MULTI) < 0) { |
|---|
| 307 | | - spin_unlock_bh(lock); |
|---|
| 308 | | - goto done; |
|---|
| 309 | | - } |
|---|
| 310 | | -next_entry2: |
|---|
| 311 | | - e++; |
|---|
| 312 | | - } |
|---|
| 313 | | - spin_unlock_bh(lock); |
|---|
| 314 | | - e = 0; |
|---|
| 315 | | - s_e = 0; |
|---|
| 372 | + err = mr_table_dump(mrt, skb, cb, fill, lock, filter); |
|---|
| 373 | + if (err < 0) |
|---|
| 374 | + break; |
|---|
| 375 | + cb->args[1] = 0; |
|---|
| 316 | 376 | next_table: |
|---|
| 317 | 377 | t++; |
|---|
| 318 | 378 | } |
|---|
| 319 | | -done: |
|---|
| 320 | 379 | rcu_read_unlock(); |
|---|
| 321 | 380 | |
|---|
| 322 | | - cb->args[1] = e; |
|---|
| 323 | 381 | cb->args[0] = t; |
|---|
| 324 | 382 | |
|---|
| 325 | 383 | return skb->len; |
|---|
| .. | .. |
|---|
| 328 | 386 | |
|---|
| 329 | 387 | int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, |
|---|
| 330 | 388 | int (*rules_dump)(struct net *net, |
|---|
| 331 | | - struct notifier_block *nb), |
|---|
| 389 | + struct notifier_block *nb, |
|---|
| 390 | + struct netlink_ext_ack *extack), |
|---|
| 332 | 391 | struct mr_table *(*mr_iter)(struct net *net, |
|---|
| 333 | 392 | struct mr_table *mrt), |
|---|
| 334 | | - rwlock_t *mrt_lock) |
|---|
| 393 | + rwlock_t *mrt_lock, |
|---|
| 394 | + struct netlink_ext_ack *extack) |
|---|
| 335 | 395 | { |
|---|
| 336 | 396 | struct mr_table *mrt; |
|---|
| 337 | 397 | int err; |
|---|
| 338 | 398 | |
|---|
| 339 | | - err = rules_dump(net, nb); |
|---|
| 399 | + err = rules_dump(net, nb, extack); |
|---|
| 340 | 400 | if (err) |
|---|
| 341 | 401 | return err; |
|---|
| 342 | 402 | |
|---|
| .. | .. |
|---|
| 351 | 411 | if (!v->dev) |
|---|
| 352 | 412 | continue; |
|---|
| 353 | 413 | |
|---|
| 354 | | - mr_call_vif_notifier(nb, net, family, |
|---|
| 355 | | - FIB_EVENT_VIF_ADD, |
|---|
| 356 | | - v, vifi, mrt->id); |
|---|
| 414 | + err = mr_call_vif_notifier(nb, family, |
|---|
| 415 | + FIB_EVENT_VIF_ADD, |
|---|
| 416 | + v, vifi, mrt->id, extack); |
|---|
| 417 | + if (err) |
|---|
| 418 | + break; |
|---|
| 357 | 419 | } |
|---|
| 358 | 420 | read_unlock(mrt_lock); |
|---|
| 359 | 421 | |
|---|
| 422 | + if (err) |
|---|
| 423 | + return err; |
|---|
| 424 | + |
|---|
| 360 | 425 | /* Notify on table MFC entries */ |
|---|
| 361 | | - list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) |
|---|
| 362 | | - mr_call_mfc_notifier(nb, net, family, |
|---|
| 363 | | - FIB_EVENT_ENTRY_ADD, |
|---|
| 364 | | - mfc, mrt->id); |
|---|
| 426 | + list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { |
|---|
| 427 | + err = mr_call_mfc_notifier(nb, family, |
|---|
| 428 | + FIB_EVENT_ENTRY_ADD, |
|---|
| 429 | + mfc, mrt->id, extack); |
|---|
| 430 | + if (err) |
|---|
| 431 | + return err; |
|---|
| 432 | + } |
|---|
| 365 | 433 | } |
|---|
| 366 | 434 | |
|---|
| 367 | 435 | return 0; |
|---|