Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netdevsim: fib: Add debugfs to debug route offload failure

Add "fail_route_offload" flag to disallow offloading routes.
It is needed to test "offload failed" notifications.

Create the flag as part of nsim_fib_create() under fib directory and set
it to false by default.

When FIB_EVENT_ENTRY_{REPLACE, APPEND} are triggered and
"fail_route_offload" value is true, set the appropriate hardware flag to
make the kernel emit RTM_NEWROUTE notification with RTM_F_OFFLOAD_FAILED
flag.

Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Amit Cohen and committed by
David S. Miller
134c7532 f57ab5b7

+112 -2
+112 -2
drivers/net/netdevsim/fib.c
··· 26 26 #include <net/fib_rules.h> 27 27 #include <net/net_namespace.h> 28 28 #include <net/nexthop.h> 29 + #include <linux/debugfs.h> 29 30 30 31 #include "netdevsim.h" 31 32 ··· 54 53 struct work_struct fib_event_work; 55 54 struct list_head fib_event_queue; 56 55 spinlock_t fib_event_queue_lock; /* Protects fib event queue list */ 56 + struct dentry *ddir; 57 + bool fail_route_offload; 57 58 }; 58 59 59 60 struct nsim_fib_rt_key { ··· 306 303 return container_of(fib_rt, struct nsim_fib4_rt, common); 307 304 } 308 305 306 + static void 307 + nsim_fib4_rt_offload_failed_flag_set(struct net *net, 308 + struct fib_entry_notifier_info *fen_info) 309 + { 310 + u32 *p_dst = (u32 *)&fen_info->dst; 311 + struct fib_rt_info fri; 312 + 313 + fri.fi = fen_info->fi; 314 + fri.tb_id = fen_info->tb_id; 315 + fri.dst = cpu_to_be32(*p_dst); 316 + fri.dst_len = fen_info->dst_len; 317 + fri.tos = fen_info->tos; 318 + fri.type = fen_info->type; 319 + fri.offload = false; 320 + fri.trap = false; 321 + fri.offload_failed = true; 322 + fib_alias_hw_flags_set(net, &fri); 323 + } 324 + 309 325 static void nsim_fib4_rt_hw_flags_set(struct net *net, 310 326 const struct nsim_fib4_rt *fib4_rt, 311 327 bool trap) ··· 406 384 struct nsim_fib4_rt *fib4_rt, *fib4_rt_old; 407 385 int err; 408 386 387 + if (data->fail_route_offload) { 388 + /* For testing purposes, user set debugfs fail_route_offload 389 + * value to true. Simulate hardware programming latency and then 390 + * fail. 391 + */ 392 + msleep(1); 393 + return -EINVAL; 394 + } 395 + 409 396 fib4_rt = nsim_fib4_rt_create(data, fen_info); 410 397 if (!fib4_rt) 411 398 return -ENOMEM; ··· 454 423 switch (event) { 455 424 case FIB_EVENT_ENTRY_REPLACE: 456 425 err = nsim_fib4_rt_insert(data, fen_info); 426 + if (err) { 427 + struct net *net = devlink_net(data->devlink); 428 + 429 + nsim_fib4_rt_offload_failed_flag_set(net, fen_info); 430 + } 457 431 break; 458 432 case FIB_EVENT_ENTRY_DEL: 459 433 nsim_fib4_rt_remove(data, fen_info); ··· 600 564 struct nsim_fib6_rt *fib6_rt; 601 565 int i, err; 602 566 567 + if (data->fail_route_offload) { 568 + /* For testing purposes, user set debugfs fail_route_offload 569 + * value to true. Simulate hardware programming latency and then 570 + * fail. 571 + */ 572 + msleep(1); 573 + return -EINVAL; 574 + } 575 + 603 576 fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt); 604 577 if (!fib6_rt) 605 578 return -EINVAL; ··· 630 585 } 631 586 return err; 632 587 } 588 + 589 + #if IS_ENABLED(CONFIG_IPV6) 590 + static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data, 591 + struct fib6_info **rt_arr, 592 + unsigned int nrt6) 593 + 594 + { 595 + struct net *net = devlink_net(data->devlink); 596 + int i; 597 + 598 + for (i = 0; i < nrt6; i++) 599 + fib6_info_hw_flags_set(net, rt_arr[i], false, false, true); 600 + } 601 + #else 602 + static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data, 603 + struct fib6_info **rt_arr, 604 + unsigned int nrt6) 605 + { 606 + } 607 + #endif 633 608 634 609 #if IS_ENABLED(CONFIG_IPV6) 635 610 static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data, ··· 731 666 struct fib6_info *rt = fib6_event->rt_arr[0]; 732 667 struct nsim_fib6_rt *fib6_rt, *fib6_rt_old; 733 668 int err; 669 + 670 + if (data->fail_route_offload) { 671 + /* For testing purposes, user set debugfs fail_route_offload 672 + * value to true. Simulate hardware programming latency and then 673 + * fail. 674 + */ 675 + msleep(1); 676 + return -EINVAL; 677 + } 734 678 735 679 fib6_rt = nsim_fib6_rt_create(data, fib6_event->rt_arr, 736 680 fib6_event->nrt6); ··· 838 764 struct nsim_fib6_event *fib6_event, 839 765 unsigned long event) 840 766 { 841 - int err = 0; 767 + int err; 842 768 843 769 if (fib6_event->rt_arr[0]->fib6_src.plen) 844 770 return 0; ··· 846 772 switch (event) { 847 773 case FIB_EVENT_ENTRY_REPLACE: 848 774 err = nsim_fib6_rt_insert(data, fib6_event); 775 + if (err) 776 + goto err_rt_offload_failed_flag_set; 849 777 break; 850 778 case FIB_EVENT_ENTRY_APPEND: 851 779 err = nsim_fib6_rt_append(data, fib6_event); 780 + if (err) 781 + goto err_rt_offload_failed_flag_set; 852 782 break; 853 783 case FIB_EVENT_ENTRY_DEL: 854 784 nsim_fib6_rt_remove(data, fib6_event); ··· 861 783 break; 862 784 } 863 785 786 + return 0; 787 + 788 + err_rt_offload_failed_flag_set: 789 + nsim_fib6_rt_offload_failed_flag_set(data, fib6_event->rt_arr, 790 + fib6_event->nrt6); 864 791 return err; 865 792 } 866 793 ··· 1373 1290 mutex_unlock(&data->fib_lock); 1374 1291 } 1375 1292 1293 + static int 1294 + nsim_fib_debugfs_init(struct nsim_fib_data *data, struct nsim_dev *nsim_dev) 1295 + { 1296 + data->ddir = debugfs_create_dir("fib", nsim_dev->ddir); 1297 + if (IS_ERR(data->ddir)) 1298 + return PTR_ERR(data->ddir); 1299 + 1300 + data->fail_route_offload = false; 1301 + debugfs_create_bool("fail_route_offload", 0600, data->ddir, 1302 + &data->fail_route_offload); 1303 + return 0; 1304 + } 1305 + 1306 + static void nsim_fib_debugfs_exit(struct nsim_fib_data *data) 1307 + { 1308 + debugfs_remove_recursive(data->ddir); 1309 + } 1310 + 1376 1311 struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, 1377 1312 struct netlink_ext_ack *extack) 1378 1313 { 1379 1314 struct nsim_fib_data *data; 1315 + struct nsim_dev *nsim_dev; 1380 1316 int err; 1381 1317 1382 1318 data = kzalloc(sizeof(*data), GFP_KERNEL); ··· 1403 1301 return ERR_PTR(-ENOMEM); 1404 1302 data->devlink = devlink; 1405 1303 1406 - err = rhashtable_init(&data->nexthop_ht, &nsim_nexthop_ht_params); 1304 + nsim_dev = devlink_priv(devlink); 1305 + err = nsim_fib_debugfs_init(data, nsim_dev); 1407 1306 if (err) 1408 1307 goto err_data_free; 1308 + 1309 + err = rhashtable_init(&data->nexthop_ht, &nsim_nexthop_ht_params); 1310 + if (err) 1311 + goto err_debugfs_exit; 1409 1312 1410 1313 mutex_init(&data->fib_lock); 1411 1314 INIT_LIST_HEAD(&data->fib_rt_list); ··· 1472 1365 rhashtable_free_and_destroy(&data->nexthop_ht, nsim_nexthop_free, 1473 1366 data); 1474 1367 mutex_destroy(&data->fib_lock); 1368 + err_debugfs_exit: 1369 + nsim_fib_debugfs_exit(data); 1475 1370 err_data_free: 1476 1371 kfree(data); 1477 1372 return ERR_PTR(err); ··· 1501 1392 WARN_ON_ONCE(!list_empty(&data->fib_event_queue)); 1502 1393 WARN_ON_ONCE(!list_empty(&data->fib_rt_list)); 1503 1394 mutex_destroy(&data->fib_lock); 1395 + nsim_fib_debugfs_exit(data); 1504 1396 kfree(data); 1505 1397 }