Currently all users of FIB notifier only cares about events in init_net. Later in this patchset, users get interested in other namespaces too. However, for every registered block user is interested only about one namespace. Make the FIB notifier registration per-netns and avoid unnecessary calls of notifier block for other namespaces.
Unified · Split
| @@ -248,9 +248,6 @@ static int mlx5_lag_fib_event(struct notifier_block *nb, · 247 unmodified lines | |||
| 248 | struct net_device *fib_dev; | 248 | struct net_device *fib_dev; |
| 249 | struct fib_info *fi; | 249 | struct fib_info *fi; |
| 250 | 250 | ||
| 251 | if (!net_eq(info->net, &init_net)) | ||
| 252 | return NOTIFY_DONE; | ||
| 253 | |||
| 254 | if (info->family != AF_INET) | 251 | if (info->family != AF_INET) |
| 255 | return NOTIFY_DONE; | 252 | return NOTIFY_DONE; |
| 256 | 253 | ||
| @@ -311,7 +308,7 @@ int mlx5_lag_mp_init(struct mlx5_lag *ldev) · 54 unmodified lines | |||
| 311 | return 0; | 308 | return 0; |
| 312 | 309 | ||
| 313 | mp->fib_nb.notifier_call = mlx5_lag_fib_event; | 310 | mp->fib_nb.notifier_call = mlx5_lag_fib_event; |
| 314 | err = register_fib_notifier(&mp->fib_nb, | 311 | err = register_fib_notifier(&init_net, &mp->fib_nb, |
| 315 | mlx5_lag_fib_event_flush); | 312 | mlx5_lag_fib_event_flush); |
| 316 | if (err) | 313 | if (err) |
| 317 | mp->fib_nb.notifier_call = NULL; | 314 | mp->fib_nb.notifier_call = NULL; |
| @@ -326,6 +323,6 @@ void mlx5_lag_mp_cleanup(struct mlx5_lag *ldev) · 8 unmodified lines | |||
| 326 | if (!mp->fib_nb.notifier_call) | 323 | if (!mp->fib_nb.notifier_call) |
| 327 | return; | 324 | return; |
| 328 | 325 | ||
| 329 | unregister_fib_notifier(&mp->fib_nb); | 326 | unregister_fib_notifier(&init_net, &mp->fib_nb); |
| 330 | mp->fib_nb.notifier_call = NULL; | 327 | mp->fib_nb.notifier_call = NULL; |
| 331 | } | 328 | } |
| @@ -6213,7 +6213,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event, · 6212 unmodified lines | |||
| 6213 | rule = fr_info->rule; | 6213 | rule = fr_info->rule; |
| 6214 | 6214 | ||
| 6215 | /* Rule only affects locally generated traffic */ | 6215 | /* Rule only affects locally generated traffic */ |
| 6216 | if (rule->iifindex == info->net->loopback_dev->ifindex) | 6216 | if (rule->iifindex == init_net.loopback_dev->ifindex) |
| 6217 | return 0; | 6217 | return 0; |
| 6218 | 6218 | ||
| 6219 | switch (info->family) { | 6219 | switch (info->family) { |
| @@ -6250,8 +6250,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, · 30 unmodified lines | |||
| 6250 | struct mlxsw_sp_router *router; | 6250 | struct mlxsw_sp_router *router; |
| 6251 | int err; | 6251 | int err; |
| 6252 | 6252 | ||
| 6253 | if (!net_eq(info->net, &init_net) || | 6253 | if ((info->family != AF_INET && info->family != AF_INET6 && |
| 6254 | (info->family != AF_INET && info->family != AF_INET6 && | ||
| 6255 | info->family != RTNL_FAMILY_IPMR && | 6254 | info->family != RTNL_FAMILY_IPMR && |
| 6256 | info->family != RTNL_FAMILY_IP6MR)) | 6255 | info->family != RTNL_FAMILY_IP6MR)) |
| 6257 | return NOTIFY_DONE; | 6256 | return NOTIFY_DONE; |
| @@ -8155,7 +8154,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) · 1897 unmodified lines | |||
| 8155 | goto err_dscp_init; | 8154 | goto err_dscp_init; |
| 8156 | 8155 | ||
| 8157 | mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; | 8156 | mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; |
| 8158 | err = register_fib_notifier(&mlxsw_sp->router->fib_nb, | 8157 | err = register_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb, |
| 8159 | mlxsw_sp_router_fib_dump_flush); | 8158 | mlxsw_sp_router_fib_dump_flush); |
| 8160 | if (err) | 8159 | if (err) |
| 8161 | goto err_register_fib_notifier; | 8160 | goto err_register_fib_notifier; |
| @@ -8195,7 +8194,7 @@ err_register_inetaddr_notifier: · 33 unmodified lines | |||
| 8195 | 8194 | ||
| 8196 | void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) | 8195 | void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) |
| 8197 | { | 8196 | { |
| 8198 | unregister_fib_notifier(&mlxsw_sp->router->fib_nb); | 8197 | unregister_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb); |
| 8199 | unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); | 8198 | unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); |
| 8200 | mlxsw_sp_neigh_fini(mlxsw_sp); | 8199 | mlxsw_sp_neigh_fini(mlxsw_sp); |
| 8201 | mlxsw_sp_vrs_fini(mlxsw_sp); | 8200 | mlxsw_sp_vrs_fini(mlxsw_sp); |
| @@ -2189,9 +2189,6 @@ static int rocker_router_fib_event(struct notifier_block *nb, · 2188 unmodified lines | |||
| 2189 | struct rocker_fib_event_work *fib_work; | 2189 | struct rocker_fib_event_work *fib_work; |
| 2190 | struct fib_notifier_info *info = ptr; | 2190 | struct fib_notifier_info *info = ptr; |
| 2191 | 2191 | ||
| 2192 | if (!net_eq(info->net, &init_net)) | ||
| 2193 | return NOTIFY_DONE; | ||
| 2194 | |||
| 2195 | if (info->family != AF_INET) | 2192 | if (info->family != AF_INET) |
| 2196 | return NOTIFY_DONE; | 2193 | return NOTIFY_DONE; |
| 2197 | 2194 | ||
| @@ -2994,7 +2991,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 796 unmodified lines | |||
| 2994 | * the device, so no need to pass a callback. | 2991 | * the device, so no need to pass a callback. |
| 2995 | */ | 2992 | */ |
| 2996 | rocker->fib_nb.notifier_call = rocker_router_fib_event; | 2993 | rocker->fib_nb.notifier_call = rocker_router_fib_event; |
| 2997 | err = register_fib_notifier(&rocker->fib_nb, NULL); | 2994 | err = register_fib_notifier(&init_net, &rocker->fib_nb, NULL); |
| 2998 | if (err) | 2995 | if (err) |
| 2999 | goto err_register_fib_notifier; | 2996 | goto err_register_fib_notifier; |
| 3000 | 2997 | ||
| @@ -3021,7 +3018,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 20 unmodified lines | |||
| 3021 | err_register_switchdev_blocking_notifier: | 3018 | err_register_switchdev_blocking_notifier: |
| 3022 | unregister_switchdev_notifier(&rocker_switchdev_notifier); | 3019 | unregister_switchdev_notifier(&rocker_switchdev_notifier); |
| 3023 | err_register_switchdev_notifier: | 3020 | err_register_switchdev_notifier: |
| 3024 | unregister_fib_notifier(&rocker->fib_nb); | 3021 | unregister_fib_notifier(&init_net, &rocker->fib_nb); |
| 3025 | err_register_fib_notifier: | 3022 | err_register_fib_notifier: |
| 3026 | rocker_remove_ports(rocker); | 3023 | rocker_remove_ports(rocker); |
| 3027 | err_probe_ports: | 3024 | err_probe_ports: |
| @@ -3057,7 +3054,7 @@ static void rocker_remove(struct pci_dev *pdev) · 29 unmodified lines | |||
| 3057 | unregister_switchdev_blocking_notifier(nb); | 3054 | unregister_switchdev_blocking_notifier(nb); |
| 3058 | 3055 | ||
| 3059 | unregister_switchdev_notifier(&rocker_switchdev_notifier); | 3056 | unregister_switchdev_notifier(&rocker_switchdev_notifier); |
| 3060 | unregister_fib_notifier(&rocker->fib_nb); | 3057 | unregister_fib_notifier(&init_net, &rocker->fib_nb); |
| 3061 | rocker_remove_ports(rocker); | 3058 | rocker_remove_ports(rocker); |
| 3062 | rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); | 3059 | rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); |
| 3063 | destroy_workqueue(rocker->rocker_owq); | 3060 | destroy_workqueue(rocker->rocker_owq); |
| @@ -182,9 +182,6 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event, · 181 unmodified lines | |||
| 182 | struct fib_notifier_info *info = ptr; | 182 | struct fib_notifier_info *info = ptr; |
| 183 | int err = 0; | 183 | int err = 0; |
| 184 | 184 | ||
| 185 | if (!net_eq(info->net, &init_net)) | ||
| 186 | return NOTIFY_DONE; | ||
| 187 | |||
| 188 | switch (event) { | 185 | switch (event) { |
| 189 | case FIB_EVENT_RULE_ADD: /* fall through */ | 186 | case FIB_EVENT_RULE_ADD: /* fall through */ |
| 190 | case FIB_EVENT_RULE_DEL: | 187 | case FIB_EVENT_RULE_DEL: |
| @@ -258,7 +255,8 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) · 67 unmodified lines | |||
| 258 | data->ipv6.rules.max = (u64)-1; | 255 | data->ipv6.rules.max = (u64)-1; |
| 259 | 256 | ||
| 260 | data->fib_nb.notifier_call = nsim_fib_event_nb; | 257 | data->fib_nb.notifier_call = nsim_fib_event_nb; |
| 261 | err = register_fib_notifier(&data->fib_nb, nsim_fib_dump_inconsistent); | 258 | err = register_fib_notifier(&init_net, &data->fib_nb, |
| 259 | nsim_fib_dump_inconsistent); | ||
| 262 | if (err) { | 260 | if (err) { |
| 263 | pr_err("Failed to register fib notifier\n"); | 261 | pr_err("Failed to register fib notifier\n"); |
| 264 | goto err_out; | 262 | goto err_out; |
| @@ -297,6 +295,6 @@ void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) · 32 unmodified lines | |||
| 297 | NSIM_RESOURCE_IPV4_FIB_RULES); | 295 | NSIM_RESOURCE_IPV4_FIB_RULES); |
| 298 | devlink_resource_occ_get_unregister(devlink, | 296 | devlink_resource_occ_get_unregister(devlink, |
| 299 | NSIM_RESOURCE_IPV4_FIB); | 297 | NSIM_RESOURCE_IPV4_FIB); |
| 300 | unregister_fib_notifier(&data->fib_nb); | 298 | unregister_fib_notifier(&init_net, &data->fib_nb); |
| 301 | kfree(data); | 299 | kfree(data); |
| 302 | } | 300 | } |
| @@ -47,7 +47,6 @@ struct vif_entry_notifier_info { · 46 unmodified lines | |||
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | static inline int mr_call_vif_notifier(struct notifier_block *nb, | 49 | static inline int mr_call_vif_notifier(struct notifier_block *nb, |
| 50 | struct net *net, | ||
| 51 | unsigned short family, | 50 | unsigned short family, |
| 52 | enum fib_event_type event_type, | 51 | enum fib_event_type event_type, |
| 53 | struct vif_device *vif, | 52 | struct vif_device *vif, |
| @@ -56,7 +55,6 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb, · 2 unmodified lines | |||
| 56 | struct vif_entry_notifier_info info = { | 55 | struct vif_entry_notifier_info info = { |
| 57 | .info = { | 56 | .info = { |
| 58 | .family = family, | 57 | .family = family, |
| 59 | .net = net, | ||
| 60 | }, | 58 | }, |
| 61 | .dev = vif->dev, | 59 | .dev = vif->dev, |
| 62 | .vif_index = vif_index, | 60 | .vif_index = vif_index, |
| @@ -64,7 +62,7 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb, · 1 unmodified line | |||
| 64 | .tb_id = tb_id, | 62 | .tb_id = tb_id, |
| 65 | }; | 63 | }; |
| 66 | 64 | ||
| 67 | return call_fib_notifier(nb, net, event_type, &info.info); | 65 | return call_fib_notifier(nb, event_type, &info.info); |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | static inline int mr_call_vif_notifiers(struct net *net, | 68 | static inline int mr_call_vif_notifiers(struct net *net, |
| @@ -77,7 +75,6 @@ static inline int mr_call_vif_notifiers(struct net *net, · 6 unmodified lines | |||
| 77 | struct vif_entry_notifier_info info = { | 75 | struct vif_entry_notifier_info info = { |
| 78 | .info = { | 76 | .info = { |
| 79 | .family = family, | 77 | .family = family, |
| 80 | .net = net, | ||
| 81 | }, | 78 | }, |
| 82 | .dev = vif->dev, | 79 | .dev = vif->dev, |
| 83 | .vif_index = vif_index, | 80 | .vif_index = vif_index, |
| @@ -173,7 +170,6 @@ struct mfc_entry_notifier_info { · 89 unmodified lines | |||
| 173 | }; | 170 | }; |
| 174 | 171 | ||
| 175 | static inline int mr_call_mfc_notifier(struct notifier_block *nb, | 172 | static inline int mr_call_mfc_notifier(struct notifier_block *nb, |
| 176 | struct net *net, | ||
| 177 | unsigned short family, | 173 | unsigned short family, |
| 178 | enum fib_event_type event_type, | 174 | enum fib_event_type event_type, |
| 179 | struct mr_mfc *mfc, u32 tb_id) | 175 | struct mr_mfc *mfc, u32 tb_id) |
| @@ -181,13 +177,12 @@ static inline int mr_call_mfc_notifier(struct notifier_block *nb, · 1 unmodified line | |||
| 181 | struct mfc_entry_notifier_info info = { | 177 | struct mfc_entry_notifier_info info = { |
| 182 | .info = { | 178 | .info = { |
| 183 | .family = family, | 179 | .family = family, |
| 184 | .net = net, | ||
| 185 | }, | 180 | }, |
| 186 | .mfc = mfc, | 181 | .mfc = mfc, |
| 187 | .tb_id = tb_id | 182 | .tb_id = tb_id |
| 188 | }; | 183 | }; |
| 189 | 184 | ||
| 190 | return call_fib_notifier(nb, net, event_type, &info.info); | 185 | return call_fib_notifier(nb, event_type, &info.info); |
| 191 | } | 186 | } |
| 192 | 187 | ||
| 193 | static inline int mr_call_mfc_notifiers(struct net *net, | 188 | static inline int mr_call_mfc_notifiers(struct net *net, |
| @@ -199,7 +194,6 @@ static inline int mr_call_mfc_notifiers(struct net *net, · 5 unmodified lines | |||
| 199 | struct mfc_entry_notifier_info info = { | 194 | struct mfc_entry_notifier_info info = { |
| 200 | .info = { | 195 | .info = { |
| 201 | .family = family, | 196 | .family = family, |
| 202 | .net = net, | ||
| 203 | }, | 197 | }, |
| 204 | .mfc = mfc, | 198 | .mfc = mfc, |
| 205 | .tb_id = tb_id | 199 | .tb_id = tb_id |
| @@ -8,7 +8,6 @@ · 7 unmodified lines | |||
| 8 | struct module; | 8 | struct module; |
| 9 | 9 | ||
| 10 | struct fib_notifier_info { | 10 | struct fib_notifier_info { |
| 11 | struct net *net; | ||
| 12 | int family; | 11 | int family; |
| 13 | struct netlink_ext_ack *extack; | 12 | struct netlink_ext_ack *extack; |
| 14 | }; | 13 | }; |
| @@ -35,14 +34,14 @@ struct fib_notifier_ops { · 20 unmodified lines | |||
| 35 | struct rcu_head rcu; | 34 | struct rcu_head rcu; |
| 36 | }; | 35 | }; |
| 37 | 36 | ||
| 38 | int call_fib_notifier(struct notifier_block *nb, struct net *net, | 37 | int call_fib_notifier(struct notifier_block *nb, |
| 39 | enum fib_event_type event_type, | 38 | enum fib_event_type event_type, |
| 40 | struct fib_notifier_info *info); | 39 | struct fib_notifier_info *info); |
| 41 | int call_fib_notifiers(struct net *net, enum fib_event_type event_type, | 40 | int call_fib_notifiers(struct net *net, enum fib_event_type event_type, |
| 42 | struct fib_notifier_info *info); | 41 | struct fib_notifier_info *info); |
| 43 | int register_fib_notifier(struct notifier_block *nb, | 42 | int register_fib_notifier(struct net *net, struct notifier_block *nb, |
| 44 | void (*cb)(struct notifier_block *nb)); | 43 | void (*cb)(struct notifier_block *nb)); |
| 45 | int unregister_fib_notifier(struct notifier_block *nb); | 44 | int unregister_fib_notifier(struct net *net, struct notifier_block *nb); |
| 46 | struct fib_notifier_ops * | 45 | struct fib_notifier_ops * |
| 47 | fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net); | 46 | fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net); |
| 48 | void fib_notifier_ops_unregister(struct fib_notifier_ops *ops); | 47 | void fib_notifier_ops_unregister(struct fib_notifier_ops *ops); |
| @@ -478,7 +478,7 @@ struct ipv6_route_iter { · 477 unmodified lines | |||
| 478 | 478 | ||
| 479 | extern const struct seq_operations ipv6_route_seq_ops; | 479 | extern const struct seq_operations ipv6_route_seq_ops; |
| 480 | 480 | ||
| 481 | int call_fib6_notifier(struct notifier_block *nb, struct net *net, | 481 | int call_fib6_notifier(struct notifier_block *nb, |
| 482 | enum fib_event_type event_type, | 482 | enum fib_event_type event_type, |
| 483 | struct fib_notifier_info *info); | 483 | struct fib_notifier_info *info); |
| 484 | int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, | 484 | int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, |
| @@ -219,7 +219,7 @@ struct fib_nh_notifier_info { · 218 unmodified lines | |||
| 219 | struct fib_nh *fib_nh; | 219 | struct fib_nh *fib_nh; |
| 220 | }; | 220 | }; |
| 221 | 221 | ||
| 222 | int call_fib4_notifier(struct notifier_block *nb, struct net *net, | 222 | int call_fib4_notifier(struct notifier_block *nb, |
| 223 | enum fib_event_type event_type, | 223 | enum fib_event_type event_type, |
| 224 | struct fib_notifier_info *info); | 224 | struct fib_notifier_info *info); |
| 225 | int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, | 225 | int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, |
| @@ -12,17 +12,15 @@ static unsigned int fib_notifier_net_id; · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | struct fib_notifier_net { | 13 | struct fib_notifier_net { |
| 14 | struct list_head fib_notifier_ops; | 14 | struct list_head fib_notifier_ops; |
| 15 | struct atomic_notifier_head fib_chain; | ||
| 15 | }; | 16 | }; |
| 16 | 17 | ||
| 17 | static ATOMIC_NOTIFIER_HEAD(fib_chain); | 18 | int call_fib_notifier(struct notifier_block *nb, |
| 18 | |||
| 19 | int call_fib_notifier(struct notifier_block *nb, struct net *net, | ||
| 20 | enum fib_event_type event_type, | 19 | enum fib_event_type event_type, |
| 21 | struct fib_notifier_info *info) | 20 | struct fib_notifier_info *info) |
| 22 | { | 21 | { |
| 23 | int err; | 22 | int err; |
| 24 | 23 | ||
| 25 | info->net = net; | ||
| 26 | err = nb->notifier_call(nb, event_type, info); | 24 | err = nb->notifier_call(nb, event_type, info); |
| 27 | return notifier_to_errno(err); | 25 | return notifier_to_errno(err); |
| 28 | } | 26 | } |
| @@ -31,35 +29,29 @@ EXPORT_SYMBOL(call_fib_notifier); · 2 unmodified lines | |||
| 31 | int call_fib_notifiers(struct net *net, enum fib_event_type event_type, | 29 | int call_fib_notifiers(struct net *net, enum fib_event_type event_type, |
| 32 | struct fib_notifier_info *info) | 30 | struct fib_notifier_info *info) |
| 33 | { | 31 | { |
| 32 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); | ||
| 34 | int err; | 33 | int err; |
| 35 | 34 | ||
| 36 | info->net = net; | 35 | err = atomic_notifier_call_chain(&fn_net->fib_chain, event_type, info); |
| 37 | err = atomic_notifier_call_chain(&fib_chain, event_type, info); | ||
| 38 | return notifier_to_errno(err); | 36 | return notifier_to_errno(err); |
| 39 | } | 37 | } |
| 40 | EXPORT_SYMBOL(call_fib_notifiers); | 38 | EXPORT_SYMBOL(call_fib_notifiers); |
| 41 | 39 | ||
| 42 | static unsigned int fib_seq_sum(void) | 40 | static unsigned int fib_seq_sum(struct net *net) |
| 43 | { | 41 | { |
| 44 | struct fib_notifier_net *fn_net; | 42 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); |
| 45 | struct fib_notifier_ops *ops; | 43 | struct fib_notifier_ops *ops; |
| 46 | unsigned int fib_seq = 0; | 44 | unsigned int fib_seq = 0; |
| 47 | struct net *net; | ||
| 48 | 45 | ||
| 49 | rtnl_lock(); | 46 | rtnl_lock(); |
| 50 | down_read(&net_rwsem); | 47 | rcu_read_lock(); |
| 51 | for_each_net(net) { | 48 | list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { |
| 52 | fn_net = net_generic(net, fib_notifier_net_id); | 49 | if (!try_module_get(ops->owner)) |
| 53 | rcu_read_lock(); | 50 | continue; |
| 54 | list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { | 51 | fib_seq += ops->fib_seq_read(net); |
| 55 | if (!try_module_get(ops->owner)) | 52 | module_put(ops->owner); |
| 56 | continue; | ||
| 57 | fib_seq += ops->fib_seq_read(net); | ||
| 58 | module_put(ops->owner); | ||
| 59 | } | ||
| 60 | rcu_read_unlock(); | ||
| 61 | } | 53 | } |
| 62 | up_read(&net_rwsem); | 54 | rcu_read_unlock(); |
| 63 | rtnl_unlock(); | 55 | rtnl_unlock(); |
| 64 | 56 | ||
| 65 | return fib_seq; | 57 | return fib_seq; |
| @@ -69,68 +61,66 @@ static int fib_net_dump(struct net *net, struct notifier_block *nb) · 3 unmodified lines | |||
| 69 | { | 61 | { |
| 70 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); | 62 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); |
| 71 | struct fib_notifier_ops *ops; | 63 | struct fib_notifier_ops *ops; |
| 64 | int err = 0; | ||
| 72 | 65 | ||
| 66 | rcu_read_lock(); | ||
| 73 | list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { | 67 | list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { |
| 74 | int err; | ||
| 75 | |||
| 76 | if (!try_module_get(ops->owner)) | 68 | if (!try_module_get(ops->owner)) |
| 77 | continue; | 69 | continue; |
| 78 | err = ops->fib_dump(net, nb); | 70 | err = ops->fib_dump(net, nb); |
| 79 | module_put(ops->owner); | 71 | module_put(ops->owner); |
| 80 | if (err) | 72 | if (err) |
| 81 | return err; | 73 | goto unlock; |
| 82 | } | 74 | } |
| 83 | 75 | ||
| 84 | return 0; | 76 | unlock: |
| 77 | rcu_read_unlock(); | ||
| 78 | |||
| 79 | return err; | ||
| 85 | } | 80 | } |
| 86 | 81 | ||
| 87 | static bool fib_dump_is_consistent(struct notifier_block *nb, | 82 | static bool fib_dump_is_consistent(struct net *net, struct notifier_block *nb, |
| 88 | void (*cb)(struct notifier_block *nb), | 83 | void (*cb)(struct notifier_block *nb), |
| 89 | unsigned int fib_seq) | 84 | unsigned int fib_seq) |
| 90 | { | 85 | { |
| 91 | atomic_notifier_chain_register(&fib_chain, nb); | 86 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); |
| 92 | if (fib_seq == fib_seq_sum()) | 87 | |
| 88 | atomic_notifier_chain_register(&fn_net->fib_chain, nb); | ||
| 89 | if (fib_seq == fib_seq_sum(net)) | ||
| 93 | return true; | 90 | return true; |
| 94 | atomic_notifier_chain_unregister(&fib_chain, nb); | 91 | atomic_notifier_chain_unregister(&fn_net->fib_chain, nb); |
| 95 | if (cb) | 92 | if (cb) |
| 96 | cb(nb); | 93 | cb(nb); |
| 97 | return false; | 94 | return false; |
| 98 | } | 95 | } |
| 99 | 96 | ||
| 100 | #define FIB_DUMP_MAX_RETRIES 5 | 97 | #define FIB_DUMP_MAX_RETRIES 5 |
| 101 | int register_fib_notifier(struct notifier_block *nb, | 98 | int register_fib_notifier(struct net *net, struct notifier_block *nb, |
| 102 | void (*cb)(struct notifier_block *nb)) | 99 | void (*cb)(struct notifier_block *nb)) |
| 103 | { | 100 | { |
| 104 | int retries = 0; | 101 | int retries = 0; |
| 105 | int err; | 102 | int err; |
| 106 | 103 | ||
| 107 | do { | 104 | do { |
| 108 | unsigned int fib_seq = fib_seq_sum(); | 105 | unsigned int fib_seq = fib_seq_sum(net); |
| 109 | struct net *net; | 106 | |
| 110 | 107 | err = fib_net_dump(net, nb); | |
| 111 | rcu_read_lock(); | 108 | if (err) |
| 112 | for_each_net_rcu(net) { | 109 | return err; |
| 113 | err = fib_net_dump(net, nb); | 110 | |
| 114 | if (err) | 111 | if (fib_dump_is_consistent(net, nb, cb, fib_seq)) |
| 115 | goto err_fib_net_dump; | ||
| 116 | } | ||
| 117 | rcu_read_unlock(); | ||
| 118 | |||
| 119 | if (fib_dump_is_consistent(nb, cb, fib_seq)) | ||
| 120 | return 0; | 112 | return 0; |
| 121 | } while (++retries < FIB_DUMP_MAX_RETRIES); | 113 | } while (++retries < FIB_DUMP_MAX_RETRIES); |
| 122 | 114 | ||
| 123 | return -EBUSY; | 115 | return -EBUSY; |
| 124 | |||
| 125 | err_fib_net_dump: | ||
| 126 | rcu_read_unlock(); | ||
| 127 | return err; | ||
| 128 | } | 116 | } |
| 129 | EXPORT_SYMBOL(register_fib_notifier); | 117 | EXPORT_SYMBOL(register_fib_notifier); |
| 130 | 118 | ||
| 131 | int unregister_fib_notifier(struct notifier_block *nb) | 119 | int unregister_fib_notifier(struct net *net, struct notifier_block *nb) |
| 132 | { | 120 | { |
| 133 | return atomic_notifier_chain_unregister(&fib_chain, nb); | 121 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); |
| 122 | |||
| 123 | return atomic_notifier_chain_unregister(&fn_net->fib_chain, nb); | ||
| 134 | } | 124 | } |
| 135 | EXPORT_SYMBOL(unregister_fib_notifier); | 125 | EXPORT_SYMBOL(unregister_fib_notifier); |
| 136 | 126 | ||
| @@ -181,6 +171,7 @@ static int __net_init fib_notifier_net_init(struct net *net) · 44 unmodified lines | |||
| 181 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); | 171 | struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); |
| 182 | 172 | ||
| 183 | INIT_LIST_HEAD(&fn_net->fib_notifier_ops); | 173 | INIT_LIST_HEAD(&fn_net->fib_notifier_ops); |
| 174 | ATOMIC_INIT_NOTIFIER_HEAD(&fn_net->fib_chain); | ||
| 184 | return 0; | 175 | return 0; |
| 185 | } | 176 | } |
| 186 | 177 | ||
| @@ -321,7 +321,7 @@ out: · 320 unmodified lines | |||
| 321 | } | 321 | } |
| 322 | EXPORT_SYMBOL_GPL(fib_rules_lookup); | 322 | EXPORT_SYMBOL_GPL(fib_rules_lookup); |
| 323 | 323 | ||
| 324 | static int call_fib_rule_notifier(struct notifier_block *nb, struct net *net, | 324 | static int call_fib_rule_notifier(struct notifier_block *nb, |
| 325 | enum fib_event_type event_type, | 325 | enum fib_event_type event_type, |
| 326 | struct fib_rule *rule, int family) | 326 | struct fib_rule *rule, int family) |
| 327 | { | 327 | { |
| @@ -330,7 +330,7 @@ static int call_fib_rule_notifier(struct notifier_block *nb, struct net *net, · 2 unmodified lines | |||
| 330 | .rule = rule, | 330 | .rule = rule, |
| 331 | }; | 331 | }; |
| 332 | 332 | ||
| 333 | return call_fib_notifier(nb, net, event_type, &info.info); | 333 | return call_fib_notifier(nb, event_type, &info.info); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | static int call_fib_rule_notifiers(struct net *net, | 336 | static int call_fib_rule_notifiers(struct net *net, |
| @@ -359,8 +359,7 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family) · 22 unmodified lines | |||
| 359 | if (!ops) | 359 | if (!ops) |
| 360 | return -EAFNOSUPPORT; | 360 | return -EAFNOSUPPORT; |
| 361 | list_for_each_entry_rcu(rule, &ops->rules_list, list) | 361 | list_for_each_entry_rcu(rule, &ops->rules_list, list) |
| 362 | call_fib_rule_notifier(nb, net, FIB_EVENT_RULE_ADD, rule, | 362 | call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD, rule, family); |
| 363 | family); | ||
| 364 | rules_ops_put(ops); | 363 | rules_ops_put(ops); |
| 365 | 364 | ||
| 366 | return 0; | 365 | return 0; |
| @@ -9,12 +9,12 @@ · 8 unmodified lines | |||
| 9 | #include <net/netns/ipv4.h> | 9 | #include <net/netns/ipv4.h> |
| 10 | #include <net/ip_fib.h> | 10 | #include <net/ip_fib.h> |
| 11 | 11 | ||
| 12 | int call_fib4_notifier(struct notifier_block *nb, struct net *net, | 12 | int call_fib4_notifier(struct notifier_block *nb, |
| 13 | enum fib_event_type event_type, | 13 | enum fib_event_type event_type, |
| 14 | struct fib_notifier_info *info) | 14 | struct fib_notifier_info *info) |
| 15 | { | 15 | { |
| 16 | info->family = AF_INET; | 16 | info->family = AF_INET; |
| 17 | return call_fib_notifier(nb, net, event_type, info); | 17 | return call_fib_notifier(nb, event_type, info); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, | 20 | int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, |
| @@ -74,7 +74,7 @@ · 73 unmodified lines | |||
| 74 | #include <trace/events/fib.h> | 74 | #include <trace/events/fib.h> |
| 75 | #include "fib_lookup.h" | 75 | #include "fib_lookup.h" |
| 76 | 76 | ||
| 77 | static int call_fib_entry_notifier(struct notifier_block *nb, struct net *net, | 77 | static int call_fib_entry_notifier(struct notifier_block *nb, |
| 78 | enum fib_event_type event_type, u32 dst, | 78 | enum fib_event_type event_type, u32 dst, |
| 79 | int dst_len, struct fib_alias *fa) | 79 | int dst_len, struct fib_alias *fa) |
| 80 | { | 80 | { |
| @@ -86,7 +86,7 @@ static int call_fib_entry_notifier(struct notifier_block *nb, struct net *net, · 5 unmodified lines | |||
| 86 | .type = fa->fa_type, | 86 | .type = fa->fa_type, |
| 87 | .tb_id = fa->tb_id, | 87 | .tb_id = fa->tb_id, |
| 88 | }; | 88 | }; |
| 89 | return call_fib4_notifier(nb, net, event_type, &info.info); | 89 | return call_fib4_notifier(nb, event_type, &info.info); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static int call_fib_entry_notifiers(struct net *net, | 92 | static int call_fib_entry_notifiers(struct net *net, |
| @@ -2015,8 +2015,8 @@ void fib_info_notify_update(struct net *net, struct nl_info *info) · 1922 unmodified lines | |||
| 2015 | } | 2015 | } |
| 2016 | } | 2016 | } |
| 2017 | 2017 | ||
| 2018 | static void fib_leaf_notify(struct net *net, struct key_vector *l, | 2018 | static void fib_leaf_notify(struct key_vector *l, struct fib_table *tb, |
| 2019 | struct fib_table *tb, struct notifier_block *nb) | 2019 | struct notifier_block *nb) |
| 2020 | { | 2020 | { |
| 2021 | struct fib_alias *fa; | 2021 | struct fib_alias *fa; |
| 2022 | 2022 | ||
| @@ -2032,20 +2032,19 @@ static void fib_leaf_notify(struct net *net, struct key_vector *l, · 9 unmodified lines | |||
| 2032 | if (tb->tb_id != fa->tb_id) | 2032 | if (tb->tb_id != fa->tb_id) |
| 2033 | continue; | 2033 | continue; |
| 2034 | 2034 | ||
| 2035 | call_fib_entry_notifier(nb, net, FIB_EVENT_ENTRY_ADD, l->key, | 2035 | call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_ADD, l->key, |
| 2036 | KEYLENGTH - fa->fa_slen, fa); | 2036 | KEYLENGTH - fa->fa_slen, fa); |
| 2037 | } | 2037 | } |
| 2038 | } | 2038 | } |
| 2039 | 2039 | ||
| 2040 | static void fib_table_notify(struct net *net, struct fib_table *tb, | 2040 | static void fib_table_notify(struct fib_table *tb, struct notifier_block *nb) |
| 2041 | struct notifier_block *nb) | ||
| 2042 | { | 2041 | { |
| 2043 | struct trie *t = (struct trie *)tb->tb_data; | 2042 | struct trie *t = (struct trie *)tb->tb_data; |
| 2044 | struct key_vector *l, *tp = t->kv; | 2043 | struct key_vector *l, *tp = t->kv; |
| 2045 | t_key key = 0; | 2044 | t_key key = 0; |
| 2046 | 2045 | ||
| 2047 | while ((l = leaf_walk_rcu(&tp, key)) != NULL) { | 2046 | while ((l = leaf_walk_rcu(&tp, key)) != NULL) { |
| 2048 | fib_leaf_notify(net, l, tb, nb); | 2047 | fib_leaf_notify(l, tb, nb); |
| 2049 | 2048 | ||
| 2050 | key = l->key + 1; | 2049 | key = l->key + 1; |
| 2051 | /* stop in case of wrap around */ | 2050 | /* stop in case of wrap around */ |
| @@ -2063,7 +2062,7 @@ void fib_notify(struct net *net, struct notifier_block *nb) · 11 unmodified lines | |||
| 2063 | struct fib_table *tb; | 2062 | struct fib_table *tb; |
| 2064 | 2063 | ||
| 2065 | hlist_for_each_entry_rcu(tb, head, tb_hlist) | 2064 | hlist_for_each_entry_rcu(tb, head, tb_hlist) |
| 2066 | fib_table_notify(net, tb, nb); | 2065 | fib_table_notify(tb, nb); |
| 2067 | } | 2066 | } |
| 2068 | } | 2067 | } |
| 2069 | 2068 | ||
| @@ -409,7 +409,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, · 408 unmodified lines | |||
| 409 | if (!v->dev) | 409 | if (!v->dev) |
| 410 | continue; | 410 | continue; |
| 411 | 411 | ||
| 412 | mr_call_vif_notifier(nb, net, family, | 412 | mr_call_vif_notifier(nb, family, |
| 413 | FIB_EVENT_VIF_ADD, | 413 | FIB_EVENT_VIF_ADD, |
| 414 | v, vifi, mrt->id); | 414 | v, vifi, mrt->id); |
| 415 | } | 415 | } |
| @@ -417,7 +417,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, · 1 unmodified line | |||
| 417 | 417 | ||
| 418 | /* Notify on table MFC entries */ | 418 | /* Notify on table MFC entries */ |
| 419 | list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) | 419 | list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) |
| 420 | mr_call_mfc_notifier(nb, net, family, | 420 | mr_call_mfc_notifier(nb, family, |
| 421 | FIB_EVENT_ENTRY_ADD, | 421 | FIB_EVENT_ENTRY_ADD, |
| 422 | mfc, mrt->id); | 422 | mfc, mrt->id); |
| 423 | } | 423 | } |
| @@ -7,12 +7,12 @@ · 6 unmodified lines | |||
| 7 | #include <net/netns/ipv6.h> | 7 | #include <net/netns/ipv6.h> |
| 8 | #include <net/ip6_fib.h> | 8 | #include <net/ip6_fib.h> |
| 9 | 9 | ||
| 10 | int call_fib6_notifier(struct notifier_block *nb, struct net *net, | 10 | int call_fib6_notifier(struct notifier_block *nb, |
| 11 | enum fib_event_type event_type, | 11 | enum fib_event_type event_type, |
| 12 | struct fib_notifier_info *info) | 12 | struct fib_notifier_info *info) |
| 13 | { | 13 | { |
| 14 | info->family = AF_INET6; | 14 | info->family = AF_INET6; |
| 15 | return call_fib_notifier(nb, net, event_type, info); | 15 | return call_fib_notifier(nb, event_type, info); |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, | 18 | int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, |
| @@ -357,7 +357,7 @@ unsigned int fib6_tables_seq_read(struct net *net) · 356 unmodified lines | |||
| 357 | return fib_seq; | 357 | return fib_seq; |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net, | 360 | static int call_fib6_entry_notifier(struct notifier_block *nb, |
| 361 | enum fib_event_type event_type, | 361 | enum fib_event_type event_type, |
| 362 | struct fib6_info *rt) | 362 | struct fib6_info *rt) |
| 363 | { | 363 | { |
| @@ -365,7 +365,7 @@ static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net, · 1 unmodified line | |||
| 365 | .rt = rt, | 365 | .rt = rt, |
| 366 | }; | 366 | }; |
| 367 | 367 | ||
| 368 | return call_fib6_notifier(nb, net, event_type, &info.info); | 368 | return call_fib6_notifier(nb, event_type, &info.info); |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | int call_fib6_entry_notifiers(struct net *net, | 371 | int call_fib6_entry_notifiers(struct net *net, |
| @@ -407,7 +407,7 @@ static void fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg) · 35 unmodified lines | |||
| 407 | { | 407 | { |
| 408 | if (rt == arg->net->ipv6.fib6_null_entry) | 408 | if (rt == arg->net->ipv6.fib6_null_entry) |
| 409 | return; | 409 | return; |
| 410 | call_fib6_entry_notifier(arg->nb, arg->net, FIB_EVENT_ENTRY_ADD, rt); | 410 | call_fib6_entry_notifier(arg->nb, FIB_EVENT_ENTRY_ADD, rt); |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | static int fib6_node_dump(struct fib6_walker *w) | 413 | static int fib6_node_dump(struct fib6_walker *w) |