diff options
author | David S. Miller <davem@davemloft.net> | 2016-11-10 13:02:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-10 13:02:25 -0500 |
commit | 23dd8315485acae0acf4452509e2be9fc587d72c (patch) | |
tree | 16ad24bbf7f30e4639d5864b9b7f012bda8137c9 | |
parent | 2ce0af8fd0a6c2938e49630a0fdf3257464576e3 (diff) | |
parent | 0e3715c9c250747280b1757ea267c577e7591e31 (diff) |
Merge branch 'mlxsw-fixes'
Jiri Pirko says:
====================
mlxsw: Couple of router fixes
v1->v2:
- patch2:
- use net_eq
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 98 |
1 files changed, 37 insertions, 61 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 4573da2c5560..040737e14a3f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | |||
@@ -600,15 +600,13 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp) | |||
600 | } | 600 | } |
601 | 601 | ||
602 | struct mlxsw_sp_neigh_key { | 602 | struct mlxsw_sp_neigh_key { |
603 | unsigned char addr[sizeof(struct in6_addr)]; | 603 | struct neighbour *n; |
604 | struct net_device *dev; | ||
605 | }; | 604 | }; |
606 | 605 | ||
607 | struct mlxsw_sp_neigh_entry { | 606 | struct mlxsw_sp_neigh_entry { |
608 | struct rhash_head ht_node; | 607 | struct rhash_head ht_node; |
609 | struct mlxsw_sp_neigh_key key; | 608 | struct mlxsw_sp_neigh_key key; |
610 | u16 rif; | 609 | u16 rif; |
611 | struct neighbour *n; | ||
612 | bool offloaded; | 610 | bool offloaded; |
613 | struct delayed_work dw; | 611 | struct delayed_work dw; |
614 | struct mlxsw_sp_port *mlxsw_sp_port; | 612 | struct mlxsw_sp_port *mlxsw_sp_port; |
@@ -646,19 +644,15 @@ mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp, | |||
646 | static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work); | 644 | static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work); |
647 | 645 | ||
648 | static struct mlxsw_sp_neigh_entry * | 646 | static struct mlxsw_sp_neigh_entry * |
649 | mlxsw_sp_neigh_entry_create(const void *addr, size_t addr_len, | 647 | mlxsw_sp_neigh_entry_create(struct neighbour *n, u16 rif) |
650 | struct net_device *dev, u16 rif, | ||
651 | struct neighbour *n) | ||
652 | { | 648 | { |
653 | struct mlxsw_sp_neigh_entry *neigh_entry; | 649 | struct mlxsw_sp_neigh_entry *neigh_entry; |
654 | 650 | ||
655 | neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC); | 651 | neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC); |
656 | if (!neigh_entry) | 652 | if (!neigh_entry) |
657 | return NULL; | 653 | return NULL; |
658 | memcpy(neigh_entry->key.addr, addr, addr_len); | 654 | neigh_entry->key.n = n; |
659 | neigh_entry->key.dev = dev; | ||
660 | neigh_entry->rif = rif; | 655 | neigh_entry->rif = rif; |
661 | neigh_entry->n = n; | ||
662 | INIT_DELAYED_WORK(&neigh_entry->dw, mlxsw_sp_router_neigh_update_hw); | 656 | INIT_DELAYED_WORK(&neigh_entry->dw, mlxsw_sp_router_neigh_update_hw); |
663 | INIT_LIST_HEAD(&neigh_entry->nexthop_list); | 657 | INIT_LIST_HEAD(&neigh_entry->nexthop_list); |
664 | return neigh_entry; | 658 | return neigh_entry; |
@@ -671,13 +665,11 @@ mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp_neigh_entry *neigh_entry) | |||
671 | } | 665 | } |
672 | 666 | ||
673 | static struct mlxsw_sp_neigh_entry * | 667 | static struct mlxsw_sp_neigh_entry * |
674 | mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, const void *addr, | 668 | mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n) |
675 | size_t addr_len, struct net_device *dev) | ||
676 | { | 669 | { |
677 | struct mlxsw_sp_neigh_key key = {{ 0 } }; | 670 | struct mlxsw_sp_neigh_key key; |
678 | 671 | ||
679 | memcpy(key.addr, addr, addr_len); | 672 | key.n = n; |
680 | key.dev = dev; | ||
681 | return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht, | 673 | return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht, |
682 | &key, mlxsw_sp_neigh_ht_params); | 674 | &key, mlxsw_sp_neigh_ht_params); |
683 | } | 675 | } |
@@ -689,26 +681,20 @@ int mlxsw_sp_router_neigh_construct(struct net_device *dev, | |||
689 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 681 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
690 | struct mlxsw_sp_neigh_entry *neigh_entry; | 682 | struct mlxsw_sp_neigh_entry *neigh_entry; |
691 | struct mlxsw_sp_rif *r; | 683 | struct mlxsw_sp_rif *r; |
692 | u32 dip; | ||
693 | int err; | 684 | int err; |
694 | 685 | ||
695 | if (n->tbl != &arp_tbl) | 686 | if (n->tbl != &arp_tbl) |
696 | return 0; | 687 | return 0; |
697 | 688 | ||
698 | dip = ntohl(*((__be32 *) n->primary_key)); | 689 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n); |
699 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip), | 690 | if (neigh_entry) |
700 | n->dev); | ||
701 | if (neigh_entry) { | ||
702 | WARN_ON(neigh_entry->n != n); | ||
703 | return 0; | 691 | return 0; |
704 | } | ||
705 | 692 | ||
706 | r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev); | 693 | r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev); |
707 | if (WARN_ON(!r)) | 694 | if (WARN_ON(!r)) |
708 | return -EINVAL; | 695 | return -EINVAL; |
709 | 696 | ||
710 | neigh_entry = mlxsw_sp_neigh_entry_create(&dip, sizeof(dip), n->dev, | 697 | neigh_entry = mlxsw_sp_neigh_entry_create(n, r->rif); |
711 | r->rif, n); | ||
712 | if (!neigh_entry) | 698 | if (!neigh_entry) |
713 | return -ENOMEM; | 699 | return -ENOMEM; |
714 | err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry); | 700 | err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry); |
@@ -727,14 +713,11 @@ void mlxsw_sp_router_neigh_destroy(struct net_device *dev, | |||
727 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); | 713 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
728 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 714 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
729 | struct mlxsw_sp_neigh_entry *neigh_entry; | 715 | struct mlxsw_sp_neigh_entry *neigh_entry; |
730 | u32 dip; | ||
731 | 716 | ||
732 | if (n->tbl != &arp_tbl) | 717 | if (n->tbl != &arp_tbl) |
733 | return; | 718 | return; |
734 | 719 | ||
735 | dip = ntohl(*((__be32 *) n->primary_key)); | 720 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n); |
736 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip), | ||
737 | n->dev); | ||
738 | if (!neigh_entry) | 721 | if (!neigh_entry) |
739 | return; | 722 | return; |
740 | mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry); | 723 | mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry); |
@@ -862,7 +845,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) | |||
862 | * is active regardless of the traffic. | 845 | * is active regardless of the traffic. |
863 | */ | 846 | */ |
864 | if (!list_empty(&neigh_entry->nexthop_list)) | 847 | if (!list_empty(&neigh_entry->nexthop_list)) |
865 | neigh_event_send(neigh_entry->n, NULL); | 848 | neigh_event_send(neigh_entry->key.n, NULL); |
866 | } | 849 | } |
867 | rtnl_unlock(); | 850 | rtnl_unlock(); |
868 | } | 851 | } |
@@ -908,9 +891,9 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) | |||
908 | rtnl_lock(); | 891 | rtnl_lock(); |
909 | list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, | 892 | list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, |
910 | nexthop_neighs_list_node) { | 893 | nexthop_neighs_list_node) { |
911 | if (!(neigh_entry->n->nud_state & NUD_VALID) && | 894 | if (!(neigh_entry->key.n->nud_state & NUD_VALID) && |
912 | !list_empty(&neigh_entry->nexthop_list)) | 895 | !list_empty(&neigh_entry->nexthop_list)) |
913 | neigh_event_send(neigh_entry->n, NULL); | 896 | neigh_event_send(neigh_entry->key.n, NULL); |
914 | } | 897 | } |
915 | rtnl_unlock(); | 898 | rtnl_unlock(); |
916 | 899 | ||
@@ -927,7 +910,7 @@ static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work) | |||
927 | { | 910 | { |
928 | struct mlxsw_sp_neigh_entry *neigh_entry = | 911 | struct mlxsw_sp_neigh_entry *neigh_entry = |
929 | container_of(work, struct mlxsw_sp_neigh_entry, dw.work); | 912 | container_of(work, struct mlxsw_sp_neigh_entry, dw.work); |
930 | struct neighbour *n = neigh_entry->n; | 913 | struct neighbour *n = neigh_entry->key.n; |
931 | struct mlxsw_sp_port *mlxsw_sp_port = neigh_entry->mlxsw_sp_port; | 914 | struct mlxsw_sp_port *mlxsw_sp_port = neigh_entry->mlxsw_sp_port; |
932 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 915 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
933 | char rauht_pl[MLXSW_REG_RAUHT_LEN]; | 916 | char rauht_pl[MLXSW_REG_RAUHT_LEN]; |
@@ -1030,11 +1013,8 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, | |||
1030 | 1013 | ||
1031 | mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 1014 | mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
1032 | dip = ntohl(*((__be32 *) n->primary_key)); | 1015 | dip = ntohl(*((__be32 *) n->primary_key)); |
1033 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, | 1016 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n); |
1034 | &dip, | 1017 | if (WARN_ON(!neigh_entry)) { |
1035 | sizeof(__be32), | ||
1036 | dev); | ||
1037 | if (WARN_ON(!neigh_entry) || WARN_ON(neigh_entry->n != n)) { | ||
1038 | mlxsw_sp_port_dev_put(mlxsw_sp_port); | 1018 | mlxsw_sp_port_dev_put(mlxsw_sp_port); |
1039 | return NOTIFY_DONE; | 1019 | return NOTIFY_DONE; |
1040 | } | 1020 | } |
@@ -1343,33 +1323,26 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp, | |||
1343 | struct fib_nh *fib_nh) | 1323 | struct fib_nh *fib_nh) |
1344 | { | 1324 | { |
1345 | struct mlxsw_sp_neigh_entry *neigh_entry; | 1325 | struct mlxsw_sp_neigh_entry *neigh_entry; |
1346 | u32 gwip = ntohl(fib_nh->nh_gw); | ||
1347 | struct net_device *dev = fib_nh->nh_dev; | 1326 | struct net_device *dev = fib_nh->nh_dev; |
1348 | struct neighbour *n; | 1327 | struct neighbour *n; |
1349 | u8 nud_state; | 1328 | u8 nud_state; |
1350 | 1329 | ||
1351 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &gwip, | 1330 | /* Take a reference of neigh here ensuring that neigh would |
1352 | sizeof(gwip), dev); | 1331 | * not be detructed before the nexthop entry is finished. |
1353 | if (!neigh_entry) { | 1332 | * The reference is taken either in neigh_lookup() or |
1354 | __be32 gwipn = htonl(gwip); | 1333 | * in neith_create() in case n is not found. |
1355 | 1334 | */ | |
1356 | n = neigh_create(&arp_tbl, &gwipn, dev); | 1335 | n = neigh_lookup(&arp_tbl, &fib_nh->nh_gw, dev); |
1336 | if (!n) { | ||
1337 | n = neigh_create(&arp_tbl, &fib_nh->nh_gw, dev); | ||
1357 | if (IS_ERR(n)) | 1338 | if (IS_ERR(n)) |
1358 | return PTR_ERR(n); | 1339 | return PTR_ERR(n); |
1359 | neigh_event_send(n, NULL); | 1340 | neigh_event_send(n, NULL); |
1360 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &gwip, | 1341 | } |
1361 | sizeof(gwip), dev); | 1342 | neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n); |
1362 | if (!neigh_entry) { | 1343 | if (!neigh_entry) { |
1363 | neigh_release(n); | 1344 | neigh_release(n); |
1364 | return -EINVAL; | 1345 | return -EINVAL; |
1365 | } | ||
1366 | } else { | ||
1367 | /* Take a reference of neigh here ensuring that neigh would | ||
1368 | * not be detructed before the nexthop entry is finished. | ||
1369 | * The second branch takes the reference in neith_create() | ||
1370 | */ | ||
1371 | n = neigh_entry->n; | ||
1372 | neigh_clone(n); | ||
1373 | } | 1346 | } |
1374 | 1347 | ||
1375 | /* If that is the first nexthop connected to that neigh, add to | 1348 | /* If that is the first nexthop connected to that neigh, add to |
@@ -1403,7 +1376,7 @@ static void mlxsw_sp_nexthop_fini(struct mlxsw_sp *mlxsw_sp, | |||
1403 | if (list_empty(&nh->neigh_entry->nexthop_list)) | 1376 | if (list_empty(&nh->neigh_entry->nexthop_list)) |
1404 | list_del(&nh->neigh_entry->nexthop_neighs_list_node); | 1377 | list_del(&nh->neigh_entry->nexthop_neighs_list_node); |
1405 | 1378 | ||
1406 | neigh_release(neigh_entry->n); | 1379 | neigh_release(neigh_entry->key.n); |
1407 | } | 1380 | } |
1408 | 1381 | ||
1409 | static struct mlxsw_sp_nexthop_group * | 1382 | static struct mlxsw_sp_nexthop_group * |
@@ -1463,11 +1436,11 @@ static bool mlxsw_sp_nexthop_match(struct mlxsw_sp_nexthop *nh, | |||
1463 | 1436 | ||
1464 | for (i = 0; i < fi->fib_nhs; i++) { | 1437 | for (i = 0; i < fi->fib_nhs; i++) { |
1465 | struct fib_nh *fib_nh = &fi->fib_nh[i]; | 1438 | struct fib_nh *fib_nh = &fi->fib_nh[i]; |
1466 | u32 gwip = ntohl(fib_nh->nh_gw); | 1439 | struct neighbour *n = nh->neigh_entry->key.n; |
1467 | 1440 | ||
1468 | if (memcmp(nh->neigh_entry->key.addr, | 1441 | if (memcmp(n->primary_key, &fib_nh->nh_gw, |
1469 | &gwip, sizeof(u32)) == 0 && | 1442 | sizeof(fib_nh->nh_gw)) == 0 && |
1470 | nh->neigh_entry->key.dev == fib_nh->nh_dev) | 1443 | n->dev == fib_nh->nh_dev) |
1471 | return true; | 1444 | return true; |
1472 | } | 1445 | } |
1473 | return false; | 1446 | return false; |
@@ -1958,6 +1931,9 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, | |||
1958 | struct fib_entry_notifier_info *fen_info = ptr; | 1931 | struct fib_entry_notifier_info *fen_info = ptr; |
1959 | int err; | 1932 | int err; |
1960 | 1933 | ||
1934 | if (!net_eq(fen_info->info.net, &init_net)) | ||
1935 | return NOTIFY_DONE; | ||
1936 | |||
1961 | switch (event) { | 1937 | switch (event) { |
1962 | case FIB_EVENT_ENTRY_ADD: | 1938 | case FIB_EVENT_ENTRY_ADD: |
1963 | err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info); | 1939 | err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info); |