root/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_mr_vif_valid
  2. mlxsw_sp_mr_vif_exists
  3. mlxsw_sp_mr_route_ivif_in_evifs
  4. mlxsw_sp_mr_route_valid_evifs_num
  5. mlxsw_sp_mr_route_action
  6. mlxsw_sp_mr_route_prio
  7. mlxsw_sp_mr_route_evif_link
  8. mlxsw_sp_mr_route_evif_unlink
  9. mlxsw_sp_mr_route_ivif_link
  10. mlxsw_sp_mr_route_ivif_unlink
  11. mlxsw_sp_mr_route_info_create
  12. mlxsw_sp_mr_route_info_destroy
  13. mlxsw_sp_mr_route_write
  14. mlxsw_sp_mr_route_erase
  15. mlxsw_sp_mr_route_create
  16. mlxsw_sp_mr_route_destroy
  17. mlxsw_sp_mr_mfc_offload_set
  18. mlxsw_sp_mr_mfc_offload_update
  19. __mlxsw_sp_mr_route_del
  20. mlxsw_sp_mr_route_add
  21. mlxsw_sp_mr_route_del
  22. mlxsw_sp_mr_route_ivif_resolve
  23. mlxsw_sp_mr_route_ivif_unresolve
  24. mlxsw_sp_mr_route_evif_resolve
  25. mlxsw_sp_mr_route_evif_unresolve
  26. mlxsw_sp_mr_vif_resolve
  27. mlxsw_sp_mr_vif_unresolve
  28. mlxsw_sp_mr_vif_add
  29. mlxsw_sp_mr_vif_del
  30. mlxsw_sp_mr_dev_vif_lookup
  31. mlxsw_sp_mr_rif_add
  32. mlxsw_sp_mr_rif_del
  33. mlxsw_sp_mr_rif_mtu_update
  34. mlxsw_sp_mr_route4_validate
  35. mlxsw_sp_mr_route4_key
  36. mlxsw_sp_mr_route4_starg
  37. mlxsw_sp_mr_vif4_is_regular
  38. mlxsw_sp_mr_route6_validate
  39. mlxsw_sp_mr_route6_key
  40. mlxsw_sp_mr_route6_starg
  41. mlxsw_sp_mr_vif6_is_regular
  42. mlxsw_sp_mr_table_create
  43. mlxsw_sp_mr_table_destroy
  44. mlxsw_sp_mr_table_flush
  45. mlxsw_sp_mr_table_empty
  46. mlxsw_sp_mr_route_stats_update
  47. mlxsw_sp_mr_stats_update
  48. mlxsw_sp_mr_init
  49. mlxsw_sp_mr_fini

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/rhashtable.h>
   5 #include <net/ipv6.h>
   6 
   7 #include "spectrum_mr.h"
   8 #include "spectrum_router.h"
   9 
  10 struct mlxsw_sp_mr {
  11         const struct mlxsw_sp_mr_ops *mr_ops;
  12         void *catchall_route_priv;
  13         struct delayed_work stats_update_dw;
  14         struct list_head table_list;
  15 #define MLXSW_SP_MR_ROUTES_COUNTER_UPDATE_INTERVAL 5000 /* ms */
  16         unsigned long priv[0];
  17         /* priv has to be always the last item */
  18 };
  19 
  20 struct mlxsw_sp_mr_vif;
  21 struct mlxsw_sp_mr_vif_ops {
  22         bool (*is_regular)(const struct mlxsw_sp_mr_vif *vif);
  23 };
  24 
  25 struct mlxsw_sp_mr_vif {
  26         struct net_device *dev;
  27         const struct mlxsw_sp_rif *rif;
  28         unsigned long vif_flags;
  29 
  30         /* A list of route_vif_entry structs that point to routes that the VIF
  31          * instance is used as one of the egress VIFs
  32          */
  33         struct list_head route_evif_list;
  34 
  35         /* A list of route_vif_entry structs that point to routes that the VIF
  36          * instance is used as an ingress VIF
  37          */
  38         struct list_head route_ivif_list;
  39 
  40         /* Protocol specific operations for a VIF */
  41         const struct mlxsw_sp_mr_vif_ops *ops;
  42 };
  43 
  44 struct mlxsw_sp_mr_route_vif_entry {
  45         struct list_head vif_node;
  46         struct list_head route_node;
  47         struct mlxsw_sp_mr_vif *mr_vif;
  48         struct mlxsw_sp_mr_route *mr_route;
  49 };
  50 
  51 struct mlxsw_sp_mr_table;
  52 struct mlxsw_sp_mr_table_ops {
  53         bool (*is_route_valid)(const struct mlxsw_sp_mr_table *mr_table,
  54                                const struct mr_mfc *mfc);
  55         void (*key_create)(struct mlxsw_sp_mr_table *mr_table,
  56                            struct mlxsw_sp_mr_route_key *key,
  57                            struct mr_mfc *mfc);
  58         bool (*is_route_starg)(const struct mlxsw_sp_mr_table *mr_table,
  59                                const struct mlxsw_sp_mr_route *mr_route);
  60 };
  61 
  62 struct mlxsw_sp_mr_table {
  63         struct list_head node;
  64         enum mlxsw_sp_l3proto proto;
  65         struct mlxsw_sp *mlxsw_sp;
  66         u32 vr_id;
  67         struct mlxsw_sp_mr_vif vifs[MAXVIFS];
  68         struct list_head route_list;
  69         struct rhashtable route_ht;
  70         const struct mlxsw_sp_mr_table_ops *ops;
  71         char catchall_route_priv[0];
  72         /* catchall_route_priv has to be always the last item */
  73 };
  74 
  75 struct mlxsw_sp_mr_route {
  76         struct list_head node;
  77         struct rhash_head ht_node;
  78         struct mlxsw_sp_mr_route_key key;
  79         enum mlxsw_sp_mr_route_action route_action;
  80         u16 min_mtu;
  81         struct mr_mfc *mfc;
  82         void *route_priv;
  83         const struct mlxsw_sp_mr_table *mr_table;
  84         /* A list of route_vif_entry structs that point to the egress VIFs */
  85         struct list_head evif_list;
  86         /* A route_vif_entry struct that point to the ingress VIF */
  87         struct mlxsw_sp_mr_route_vif_entry ivif;
  88 };
  89 
  90 static const struct rhashtable_params mlxsw_sp_mr_route_ht_params = {
  91         .key_len = sizeof(struct mlxsw_sp_mr_route_key),
  92         .key_offset = offsetof(struct mlxsw_sp_mr_route, key),
  93         .head_offset = offsetof(struct mlxsw_sp_mr_route, ht_node),
  94         .automatic_shrinking = true,
  95 };
  96 
  97 static bool mlxsw_sp_mr_vif_valid(const struct mlxsw_sp_mr_vif *vif)
  98 {
  99         return vif->ops->is_regular(vif) && vif->dev && vif->rif;
 100 }
 101 
 102 static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif)
 103 {
 104         return vif->dev;
 105 }
 106 
 107 static bool
 108 mlxsw_sp_mr_route_ivif_in_evifs(const struct mlxsw_sp_mr_route *mr_route)
 109 {
 110         vifi_t ivif = mr_route->mfc->mfc_parent;
 111 
 112         return mr_route->mfc->mfc_un.res.ttls[ivif] != 255;
 113 }
 114 
 115 static int
 116 mlxsw_sp_mr_route_valid_evifs_num(const struct mlxsw_sp_mr_route *mr_route)
 117 {
 118         struct mlxsw_sp_mr_route_vif_entry *rve;
 119         int valid_evifs;
 120 
 121         valid_evifs = 0;
 122         list_for_each_entry(rve, &mr_route->evif_list, route_node)
 123                 if (mlxsw_sp_mr_vif_valid(rve->mr_vif))
 124                         valid_evifs++;
 125         return valid_evifs;
 126 }
 127 
 128 static enum mlxsw_sp_mr_route_action
 129 mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route)
 130 {
 131         struct mlxsw_sp_mr_route_vif_entry *rve;
 132 
 133         /* If the ingress port is not regular and resolved, trap the route */
 134         if (!mlxsw_sp_mr_vif_valid(mr_route->ivif.mr_vif))
 135                 return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 136 
 137         /* The kernel does not match a (*,G) route that the ingress interface is
 138          * not one of the egress interfaces, so trap these kind of routes.
 139          */
 140         if (mr_route->mr_table->ops->is_route_starg(mr_route->mr_table,
 141                                                     mr_route) &&
 142             !mlxsw_sp_mr_route_ivif_in_evifs(mr_route))
 143                 return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 144 
 145         /* If the route has no valid eVIFs, trap it. */
 146         if (!mlxsw_sp_mr_route_valid_evifs_num(mr_route))
 147                 return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 148 
 149         /* If one of the eVIFs has no RIF, trap-and-forward the route as there
 150          * is some more routing to do in software too.
 151          */
 152         list_for_each_entry(rve, &mr_route->evif_list, route_node)
 153                 if (mlxsw_sp_mr_vif_exists(rve->mr_vif) && !rve->mr_vif->rif)
 154                         return MLXSW_SP_MR_ROUTE_ACTION_TRAP_AND_FORWARD;
 155 
 156         return MLXSW_SP_MR_ROUTE_ACTION_FORWARD;
 157 }
 158 
 159 static enum mlxsw_sp_mr_route_prio
 160 mlxsw_sp_mr_route_prio(const struct mlxsw_sp_mr_route *mr_route)
 161 {
 162         return mr_route->mr_table->ops->is_route_starg(mr_route->mr_table,
 163                                                        mr_route) ?
 164                 MLXSW_SP_MR_ROUTE_PRIO_STARG : MLXSW_SP_MR_ROUTE_PRIO_SG;
 165 }
 166 
 167 static int mlxsw_sp_mr_route_evif_link(struct mlxsw_sp_mr_route *mr_route,
 168                                        struct mlxsw_sp_mr_vif *mr_vif)
 169 {
 170         struct mlxsw_sp_mr_route_vif_entry *rve;
 171 
 172         rve = kzalloc(sizeof(*rve), GFP_KERNEL);
 173         if (!rve)
 174                 return -ENOMEM;
 175         rve->mr_route = mr_route;
 176         rve->mr_vif = mr_vif;
 177         list_add_tail(&rve->route_node, &mr_route->evif_list);
 178         list_add_tail(&rve->vif_node, &mr_vif->route_evif_list);
 179         return 0;
 180 }
 181 
 182 static void
 183 mlxsw_sp_mr_route_evif_unlink(struct mlxsw_sp_mr_route_vif_entry *rve)
 184 {
 185         list_del(&rve->route_node);
 186         list_del(&rve->vif_node);
 187         kfree(rve);
 188 }
 189 
 190 static void mlxsw_sp_mr_route_ivif_link(struct mlxsw_sp_mr_route *mr_route,
 191                                         struct mlxsw_sp_mr_vif *mr_vif)
 192 {
 193         mr_route->ivif.mr_route = mr_route;
 194         mr_route->ivif.mr_vif = mr_vif;
 195         list_add_tail(&mr_route->ivif.vif_node, &mr_vif->route_ivif_list);
 196 }
 197 
 198 static void mlxsw_sp_mr_route_ivif_unlink(struct mlxsw_sp_mr_route *mr_route)
 199 {
 200         list_del(&mr_route->ivif.vif_node);
 201 }
 202 
 203 static int
 204 mlxsw_sp_mr_route_info_create(struct mlxsw_sp_mr_table *mr_table,
 205                               struct mlxsw_sp_mr_route *mr_route,
 206                               struct mlxsw_sp_mr_route_info *route_info)
 207 {
 208         struct mlxsw_sp_mr_route_vif_entry *rve;
 209         u16 *erif_indices;
 210         u16 irif_index;
 211         u16 erif = 0;
 212 
 213         erif_indices = kmalloc_array(MAXVIFS, sizeof(*erif_indices),
 214                                      GFP_KERNEL);
 215         if (!erif_indices)
 216                 return -ENOMEM;
 217 
 218         list_for_each_entry(rve, &mr_route->evif_list, route_node) {
 219                 if (mlxsw_sp_mr_vif_valid(rve->mr_vif)) {
 220                         u16 rifi = mlxsw_sp_rif_index(rve->mr_vif->rif);
 221 
 222                         erif_indices[erif++] = rifi;
 223                 }
 224         }
 225 
 226         if (mlxsw_sp_mr_vif_valid(mr_route->ivif.mr_vif))
 227                 irif_index = mlxsw_sp_rif_index(mr_route->ivif.mr_vif->rif);
 228         else
 229                 irif_index = 0;
 230 
 231         route_info->irif_index = irif_index;
 232         route_info->erif_indices = erif_indices;
 233         route_info->min_mtu = mr_route->min_mtu;
 234         route_info->route_action = mr_route->route_action;
 235         route_info->erif_num = erif;
 236         return 0;
 237 }
 238 
 239 static void
 240 mlxsw_sp_mr_route_info_destroy(struct mlxsw_sp_mr_route_info *route_info)
 241 {
 242         kfree(route_info->erif_indices);
 243 }
 244 
 245 static int mlxsw_sp_mr_route_write(struct mlxsw_sp_mr_table *mr_table,
 246                                    struct mlxsw_sp_mr_route *mr_route,
 247                                    bool replace)
 248 {
 249         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 250         struct mlxsw_sp_mr_route_info route_info;
 251         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 252         int err;
 253 
 254         err = mlxsw_sp_mr_route_info_create(mr_table, mr_route, &route_info);
 255         if (err)
 256                 return err;
 257 
 258         if (!replace) {
 259                 struct mlxsw_sp_mr_route_params route_params;
 260 
 261                 mr_route->route_priv = kzalloc(mr->mr_ops->route_priv_size,
 262                                                GFP_KERNEL);
 263                 if (!mr_route->route_priv) {
 264                         err = -ENOMEM;
 265                         goto out;
 266                 }
 267 
 268                 route_params.key = mr_route->key;
 269                 route_params.value = route_info;
 270                 route_params.prio = mlxsw_sp_mr_route_prio(mr_route);
 271                 err = mr->mr_ops->route_create(mlxsw_sp, mr->priv,
 272                                                mr_route->route_priv,
 273                                                &route_params);
 274                 if (err)
 275                         kfree(mr_route->route_priv);
 276         } else {
 277                 err = mr->mr_ops->route_update(mlxsw_sp, mr_route->route_priv,
 278                                                &route_info);
 279         }
 280 out:
 281         mlxsw_sp_mr_route_info_destroy(&route_info);
 282         return err;
 283 }
 284 
 285 static void mlxsw_sp_mr_route_erase(struct mlxsw_sp_mr_table *mr_table,
 286                                     struct mlxsw_sp_mr_route *mr_route)
 287 {
 288         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 289         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 290 
 291         mr->mr_ops->route_destroy(mlxsw_sp, mr->priv, mr_route->route_priv);
 292         kfree(mr_route->route_priv);
 293 }
 294 
 295 static struct mlxsw_sp_mr_route *
 296 mlxsw_sp_mr_route_create(struct mlxsw_sp_mr_table *mr_table,
 297                          struct mr_mfc *mfc)
 298 {
 299         struct mlxsw_sp_mr_route_vif_entry *rve, *tmp;
 300         struct mlxsw_sp_mr_route *mr_route;
 301         int err = 0;
 302         int i;
 303 
 304         /* Allocate and init a new route and fill it with parameters */
 305         mr_route = kzalloc(sizeof(*mr_route), GFP_KERNEL);
 306         if (!mr_route)
 307                 return ERR_PTR(-ENOMEM);
 308         INIT_LIST_HEAD(&mr_route->evif_list);
 309 
 310         /* Find min_mtu and link iVIF and eVIFs */
 311         mr_route->min_mtu = ETH_MAX_MTU;
 312         mr_cache_hold(mfc);
 313         mr_route->mfc = mfc;
 314         mr_table->ops->key_create(mr_table, &mr_route->key, mr_route->mfc);
 315 
 316         mr_route->mr_table = mr_table;
 317         for (i = 0; i < MAXVIFS; i++) {
 318                 if (mfc->mfc_un.res.ttls[i] != 255) {
 319                         err = mlxsw_sp_mr_route_evif_link(mr_route,
 320                                                           &mr_table->vifs[i]);
 321                         if (err)
 322                                 goto err;
 323                         if (mr_table->vifs[i].dev &&
 324                             mr_table->vifs[i].dev->mtu < mr_route->min_mtu)
 325                                 mr_route->min_mtu = mr_table->vifs[i].dev->mtu;
 326                 }
 327         }
 328         mlxsw_sp_mr_route_ivif_link(mr_route,
 329                                     &mr_table->vifs[mfc->mfc_parent]);
 330 
 331         mr_route->route_action = mlxsw_sp_mr_route_action(mr_route);
 332         return mr_route;
 333 err:
 334         mr_cache_put(mfc);
 335         list_for_each_entry_safe(rve, tmp, &mr_route->evif_list, route_node)
 336                 mlxsw_sp_mr_route_evif_unlink(rve);
 337         kfree(mr_route);
 338         return ERR_PTR(err);
 339 }
 340 
 341 static void mlxsw_sp_mr_route_destroy(struct mlxsw_sp_mr_table *mr_table,
 342                                       struct mlxsw_sp_mr_route *mr_route)
 343 {
 344         struct mlxsw_sp_mr_route_vif_entry *rve, *tmp;
 345 
 346         mlxsw_sp_mr_route_ivif_unlink(mr_route);
 347         mr_cache_put(mr_route->mfc);
 348         list_for_each_entry_safe(rve, tmp, &mr_route->evif_list, route_node)
 349                 mlxsw_sp_mr_route_evif_unlink(rve);
 350         kfree(mr_route);
 351 }
 352 
 353 static void mlxsw_sp_mr_mfc_offload_set(struct mlxsw_sp_mr_route *mr_route,
 354                                         bool offload)
 355 {
 356         if (offload)
 357                 mr_route->mfc->mfc_flags |= MFC_OFFLOAD;
 358         else
 359                 mr_route->mfc->mfc_flags &= ~MFC_OFFLOAD;
 360 }
 361 
 362 static void mlxsw_sp_mr_mfc_offload_update(struct mlxsw_sp_mr_route *mr_route)
 363 {
 364         bool offload;
 365 
 366         offload = mr_route->route_action != MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 367         mlxsw_sp_mr_mfc_offload_set(mr_route, offload);
 368 }
 369 
 370 static void __mlxsw_sp_mr_route_del(struct mlxsw_sp_mr_table *mr_table,
 371                                     struct mlxsw_sp_mr_route *mr_route)
 372 {
 373         mlxsw_sp_mr_mfc_offload_set(mr_route, false);
 374         mlxsw_sp_mr_route_erase(mr_table, mr_route);
 375         rhashtable_remove_fast(&mr_table->route_ht, &mr_route->ht_node,
 376                                mlxsw_sp_mr_route_ht_params);
 377         list_del(&mr_route->node);
 378         mlxsw_sp_mr_route_destroy(mr_table, mr_route);
 379 }
 380 
 381 int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table,
 382                           struct mr_mfc *mfc, bool replace)
 383 {
 384         struct mlxsw_sp_mr_route *mr_orig_route = NULL;
 385         struct mlxsw_sp_mr_route *mr_route;
 386         int err;
 387 
 388         if (!mr_table->ops->is_route_valid(mr_table, mfc))
 389                 return -EINVAL;
 390 
 391         /* Create a new route */
 392         mr_route = mlxsw_sp_mr_route_create(mr_table, mfc);
 393         if (IS_ERR(mr_route))
 394                 return PTR_ERR(mr_route);
 395 
 396         /* Find any route with a matching key */
 397         mr_orig_route = rhashtable_lookup_fast(&mr_table->route_ht,
 398                                                &mr_route->key,
 399                                                mlxsw_sp_mr_route_ht_params);
 400         if (replace) {
 401                 /* On replace case, make the route point to the new route_priv.
 402                  */
 403                 if (WARN_ON(!mr_orig_route)) {
 404                         err = -ENOENT;
 405                         goto err_no_orig_route;
 406                 }
 407                 mr_route->route_priv = mr_orig_route->route_priv;
 408         } else if (mr_orig_route) {
 409                 /* On non replace case, if another route with the same key was
 410                  * found, abort, as duplicate routes are used for proxy routes.
 411                  */
 412                 dev_warn(mr_table->mlxsw_sp->bus_info->dev,
 413                          "Offloading proxy routes is not supported.\n");
 414                 err = -EINVAL;
 415                 goto err_duplicate_route;
 416         }
 417 
 418         /* Put it in the table data-structures */
 419         list_add_tail(&mr_route->node, &mr_table->route_list);
 420         err = rhashtable_insert_fast(&mr_table->route_ht,
 421                                      &mr_route->ht_node,
 422                                      mlxsw_sp_mr_route_ht_params);
 423         if (err)
 424                 goto err_rhashtable_insert;
 425 
 426         /* Write the route to the hardware */
 427         err = mlxsw_sp_mr_route_write(mr_table, mr_route, replace);
 428         if (err)
 429                 goto err_mr_route_write;
 430 
 431         /* Destroy the original route */
 432         if (replace) {
 433                 rhashtable_remove_fast(&mr_table->route_ht,
 434                                        &mr_orig_route->ht_node,
 435                                        mlxsw_sp_mr_route_ht_params);
 436                 list_del(&mr_orig_route->node);
 437                 mlxsw_sp_mr_route_destroy(mr_table, mr_orig_route);
 438         }
 439 
 440         mlxsw_sp_mr_mfc_offload_update(mr_route);
 441         return 0;
 442 
 443 err_mr_route_write:
 444         rhashtable_remove_fast(&mr_table->route_ht, &mr_route->ht_node,
 445                                mlxsw_sp_mr_route_ht_params);
 446 err_rhashtable_insert:
 447         list_del(&mr_route->node);
 448 err_no_orig_route:
 449 err_duplicate_route:
 450         mlxsw_sp_mr_route_destroy(mr_table, mr_route);
 451         return err;
 452 }
 453 
 454 void mlxsw_sp_mr_route_del(struct mlxsw_sp_mr_table *mr_table,
 455                            struct mr_mfc *mfc)
 456 {
 457         struct mlxsw_sp_mr_route *mr_route;
 458         struct mlxsw_sp_mr_route_key key;
 459 
 460         mr_table->ops->key_create(mr_table, &key, mfc);
 461         mr_route = rhashtable_lookup_fast(&mr_table->route_ht, &key,
 462                                           mlxsw_sp_mr_route_ht_params);
 463         if (mr_route)
 464                 __mlxsw_sp_mr_route_del(mr_table, mr_route);
 465 }
 466 
 467 /* Should be called after the VIF struct is updated */
 468 static int
 469 mlxsw_sp_mr_route_ivif_resolve(struct mlxsw_sp_mr_table *mr_table,
 470                                struct mlxsw_sp_mr_route_vif_entry *rve)
 471 {
 472         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 473         enum mlxsw_sp_mr_route_action route_action;
 474         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 475         u16 irif_index;
 476         int err;
 477 
 478         route_action = mlxsw_sp_mr_route_action(rve->mr_route);
 479         if (route_action == MLXSW_SP_MR_ROUTE_ACTION_TRAP)
 480                 return 0;
 481 
 482         /* rve->mr_vif->rif is guaranteed to be valid at this stage */
 483         irif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
 484         err = mr->mr_ops->route_irif_update(mlxsw_sp, rve->mr_route->route_priv,
 485                                             irif_index);
 486         if (err)
 487                 return err;
 488 
 489         err = mr->mr_ops->route_action_update(mlxsw_sp,
 490                                               rve->mr_route->route_priv,
 491                                               route_action);
 492         if (err)
 493                 /* No need to rollback here because the iRIF change only takes
 494                  * place after the action has been updated.
 495                  */
 496                 return err;
 497 
 498         rve->mr_route->route_action = route_action;
 499         mlxsw_sp_mr_mfc_offload_update(rve->mr_route);
 500         return 0;
 501 }
 502 
 503 static void
 504 mlxsw_sp_mr_route_ivif_unresolve(struct mlxsw_sp_mr_table *mr_table,
 505                                  struct mlxsw_sp_mr_route_vif_entry *rve)
 506 {
 507         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 508         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 509 
 510         mr->mr_ops->route_action_update(mlxsw_sp, rve->mr_route->route_priv,
 511                                         MLXSW_SP_MR_ROUTE_ACTION_TRAP);
 512         rve->mr_route->route_action = MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 513         mlxsw_sp_mr_mfc_offload_update(rve->mr_route);
 514 }
 515 
 516 /* Should be called after the RIF struct is updated */
 517 static int
 518 mlxsw_sp_mr_route_evif_resolve(struct mlxsw_sp_mr_table *mr_table,
 519                                struct mlxsw_sp_mr_route_vif_entry *rve)
 520 {
 521         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 522         enum mlxsw_sp_mr_route_action route_action;
 523         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 524         u16 erif_index = 0;
 525         int err;
 526 
 527         /* Update the route action, as the new eVIF can be a tunnel or a pimreg
 528          * device which will require updating the action.
 529          */
 530         route_action = mlxsw_sp_mr_route_action(rve->mr_route);
 531         if (route_action != rve->mr_route->route_action) {
 532                 err = mr->mr_ops->route_action_update(mlxsw_sp,
 533                                                       rve->mr_route->route_priv,
 534                                                       route_action);
 535                 if (err)
 536                         return err;
 537         }
 538 
 539         /* Add the eRIF */
 540         if (mlxsw_sp_mr_vif_valid(rve->mr_vif)) {
 541                 erif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
 542                 err = mr->mr_ops->route_erif_add(mlxsw_sp,
 543                                                  rve->mr_route->route_priv,
 544                                                  erif_index);
 545                 if (err)
 546                         goto err_route_erif_add;
 547         }
 548 
 549         /* Update the minimum MTU */
 550         if (rve->mr_vif->dev->mtu < rve->mr_route->min_mtu) {
 551                 rve->mr_route->min_mtu = rve->mr_vif->dev->mtu;
 552                 err = mr->mr_ops->route_min_mtu_update(mlxsw_sp,
 553                                                        rve->mr_route->route_priv,
 554                                                        rve->mr_route->min_mtu);
 555                 if (err)
 556                         goto err_route_min_mtu_update;
 557         }
 558 
 559         rve->mr_route->route_action = route_action;
 560         mlxsw_sp_mr_mfc_offload_update(rve->mr_route);
 561         return 0;
 562 
 563 err_route_min_mtu_update:
 564         if (mlxsw_sp_mr_vif_valid(rve->mr_vif))
 565                 mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv,
 566                                            erif_index);
 567 err_route_erif_add:
 568         if (route_action != rve->mr_route->route_action)
 569                 mr->mr_ops->route_action_update(mlxsw_sp,
 570                                                 rve->mr_route->route_priv,
 571                                                 rve->mr_route->route_action);
 572         return err;
 573 }
 574 
 575 /* Should be called before the RIF struct is updated */
 576 static void
 577 mlxsw_sp_mr_route_evif_unresolve(struct mlxsw_sp_mr_table *mr_table,
 578                                  struct mlxsw_sp_mr_route_vif_entry *rve)
 579 {
 580         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 581         enum mlxsw_sp_mr_route_action route_action;
 582         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 583         u16 rifi;
 584 
 585         /* If the unresolved RIF was not valid, no need to delete it */
 586         if (!mlxsw_sp_mr_vif_valid(rve->mr_vif))
 587                 return;
 588 
 589         /* Update the route action: if there is only one valid eVIF in the
 590          * route, set the action to trap as the VIF deletion will lead to zero
 591          * valid eVIFs. On any other case, use the mlxsw_sp_mr_route_action to
 592          * determine the route action.
 593          */
 594         if (mlxsw_sp_mr_route_valid_evifs_num(rve->mr_route) == 1)
 595                 route_action = MLXSW_SP_MR_ROUTE_ACTION_TRAP;
 596         else
 597                 route_action = mlxsw_sp_mr_route_action(rve->mr_route);
 598         if (route_action != rve->mr_route->route_action)
 599                 mr->mr_ops->route_action_update(mlxsw_sp,
 600                                                 rve->mr_route->route_priv,
 601                                                 route_action);
 602 
 603         /* Delete the erif from the route */
 604         rifi = mlxsw_sp_rif_index(rve->mr_vif->rif);
 605         mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv, rifi);
 606         rve->mr_route->route_action = route_action;
 607         mlxsw_sp_mr_mfc_offload_update(rve->mr_route);
 608 }
 609 
 610 static int mlxsw_sp_mr_vif_resolve(struct mlxsw_sp_mr_table *mr_table,
 611                                    struct net_device *dev,
 612                                    struct mlxsw_sp_mr_vif *mr_vif,
 613                                    unsigned long vif_flags,
 614                                    const struct mlxsw_sp_rif *rif)
 615 {
 616         struct mlxsw_sp_mr_route_vif_entry *irve, *erve;
 617         int err;
 618 
 619         /* Update the VIF */
 620         mr_vif->dev = dev;
 621         mr_vif->rif = rif;
 622         mr_vif->vif_flags = vif_flags;
 623 
 624         /* Update all routes where this VIF is used as an unresolved iRIF */
 625         list_for_each_entry(irve, &mr_vif->route_ivif_list, vif_node) {
 626                 err = mlxsw_sp_mr_route_ivif_resolve(mr_table, irve);
 627                 if (err)
 628                         goto err_irif_unresolve;
 629         }
 630 
 631         /* Update all routes where this VIF is used as an unresolved eRIF */
 632         list_for_each_entry(erve, &mr_vif->route_evif_list, vif_node) {
 633                 err = mlxsw_sp_mr_route_evif_resolve(mr_table, erve);
 634                 if (err)
 635                         goto err_erif_unresolve;
 636         }
 637         return 0;
 638 
 639 err_erif_unresolve:
 640         list_for_each_entry_continue_reverse(erve, &mr_vif->route_evif_list,
 641                                              vif_node)
 642                 mlxsw_sp_mr_route_evif_unresolve(mr_table, erve);
 643 err_irif_unresolve:
 644         list_for_each_entry_continue_reverse(irve, &mr_vif->route_ivif_list,
 645                                              vif_node)
 646                 mlxsw_sp_mr_route_ivif_unresolve(mr_table, irve);
 647         mr_vif->rif = NULL;
 648         return err;
 649 }
 650 
 651 static void mlxsw_sp_mr_vif_unresolve(struct mlxsw_sp_mr_table *mr_table,
 652                                       struct net_device *dev,
 653                                       struct mlxsw_sp_mr_vif *mr_vif)
 654 {
 655         struct mlxsw_sp_mr_route_vif_entry *rve;
 656 
 657         /* Update all routes where this VIF is used as an unresolved eRIF */
 658         list_for_each_entry(rve, &mr_vif->route_evif_list, vif_node)
 659                 mlxsw_sp_mr_route_evif_unresolve(mr_table, rve);
 660 
 661         /* Update all routes where this VIF is used as an unresolved iRIF */
 662         list_for_each_entry(rve, &mr_vif->route_ivif_list, vif_node)
 663                 mlxsw_sp_mr_route_ivif_unresolve(mr_table, rve);
 664 
 665         /* Update the VIF */
 666         mr_vif->dev = dev;
 667         mr_vif->rif = NULL;
 668 }
 669 
 670 int mlxsw_sp_mr_vif_add(struct mlxsw_sp_mr_table *mr_table,
 671                         struct net_device *dev, vifi_t vif_index,
 672                         unsigned long vif_flags, const struct mlxsw_sp_rif *rif)
 673 {
 674         struct mlxsw_sp_mr_vif *mr_vif = &mr_table->vifs[vif_index];
 675 
 676         if (WARN_ON(vif_index >= MAXVIFS))
 677                 return -EINVAL;
 678         if (mr_vif->dev)
 679                 return -EEXIST;
 680         return mlxsw_sp_mr_vif_resolve(mr_table, dev, mr_vif, vif_flags, rif);
 681 }
 682 
 683 void mlxsw_sp_mr_vif_del(struct mlxsw_sp_mr_table *mr_table, vifi_t vif_index)
 684 {
 685         struct mlxsw_sp_mr_vif *mr_vif = &mr_table->vifs[vif_index];
 686 
 687         if (WARN_ON(vif_index >= MAXVIFS))
 688                 return;
 689         if (WARN_ON(!mr_vif->dev))
 690                 return;
 691         mlxsw_sp_mr_vif_unresolve(mr_table, NULL, mr_vif);
 692 }
 693 
 694 static struct mlxsw_sp_mr_vif *
 695 mlxsw_sp_mr_dev_vif_lookup(struct mlxsw_sp_mr_table *mr_table,
 696                            const struct net_device *dev)
 697 {
 698         vifi_t vif_index;
 699 
 700         for (vif_index = 0; vif_index < MAXVIFS; vif_index++)
 701                 if (mr_table->vifs[vif_index].dev == dev)
 702                         return &mr_table->vifs[vif_index];
 703         return NULL;
 704 }
 705 
 706 int mlxsw_sp_mr_rif_add(struct mlxsw_sp_mr_table *mr_table,
 707                         const struct mlxsw_sp_rif *rif)
 708 {
 709         const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif);
 710         struct mlxsw_sp_mr_vif *mr_vif;
 711 
 712         if (!rif_dev)
 713                 return 0;
 714 
 715         mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev);
 716         if (!mr_vif)
 717                 return 0;
 718         return mlxsw_sp_mr_vif_resolve(mr_table, mr_vif->dev, mr_vif,
 719                                        mr_vif->vif_flags, rif);
 720 }
 721 
 722 void mlxsw_sp_mr_rif_del(struct mlxsw_sp_mr_table *mr_table,
 723                          const struct mlxsw_sp_rif *rif)
 724 {
 725         const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif);
 726         struct mlxsw_sp_mr_vif *mr_vif;
 727 
 728         if (!rif_dev)
 729                 return;
 730 
 731         mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev);
 732         if (!mr_vif)
 733                 return;
 734         mlxsw_sp_mr_vif_unresolve(mr_table, mr_vif->dev, mr_vif);
 735 }
 736 
 737 void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table,
 738                                 const struct mlxsw_sp_rif *rif, int mtu)
 739 {
 740         const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif);
 741         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 742         struct mlxsw_sp_mr_route_vif_entry *rve;
 743         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 744         struct mlxsw_sp_mr_vif *mr_vif;
 745 
 746         if (!rif_dev)
 747                 return;
 748 
 749         /* Search for a VIF that use that RIF */
 750         mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev);
 751         if (!mr_vif)
 752                 return;
 753 
 754         /* Update all the routes that uses that VIF as eVIF */
 755         list_for_each_entry(rve, &mr_vif->route_evif_list, vif_node) {
 756                 if (mtu < rve->mr_route->min_mtu) {
 757                         rve->mr_route->min_mtu = mtu;
 758                         mr->mr_ops->route_min_mtu_update(mlxsw_sp,
 759                                                          rve->mr_route->route_priv,
 760                                                          mtu);
 761                 }
 762         }
 763 }
 764 
 765 /* Protocol specific functions */
 766 static bool
 767 mlxsw_sp_mr_route4_validate(const struct mlxsw_sp_mr_table *mr_table,
 768                             const struct mr_mfc *c)
 769 {
 770         struct mfc_cache *mfc = (struct mfc_cache *) c;
 771 
 772         /* If the route is a (*,*) route, abort, as these kind of routes are
 773          * used for proxy routes.
 774          */
 775         if (mfc->mfc_origin == htonl(INADDR_ANY) &&
 776             mfc->mfc_mcastgrp == htonl(INADDR_ANY)) {
 777                 dev_warn(mr_table->mlxsw_sp->bus_info->dev,
 778                          "Offloading proxy routes is not supported.\n");
 779                 return false;
 780         }
 781         return true;
 782 }
 783 
 784 static void mlxsw_sp_mr_route4_key(struct mlxsw_sp_mr_table *mr_table,
 785                                    struct mlxsw_sp_mr_route_key *key,
 786                                    struct mr_mfc *c)
 787 {
 788         const struct mfc_cache *mfc = (struct mfc_cache *) c;
 789         bool starg;
 790 
 791         starg = (mfc->mfc_origin == htonl(INADDR_ANY));
 792 
 793         memset(key, 0, sizeof(*key));
 794         key->vrid = mr_table->vr_id;
 795         key->proto = MLXSW_SP_L3_PROTO_IPV4;
 796         key->group.addr4 = mfc->mfc_mcastgrp;
 797         key->group_mask.addr4 = htonl(0xffffffff);
 798         key->source.addr4 = mfc->mfc_origin;
 799         key->source_mask.addr4 = htonl(starg ? 0 : 0xffffffff);
 800 }
 801 
 802 static bool mlxsw_sp_mr_route4_starg(const struct mlxsw_sp_mr_table *mr_table,
 803                                      const struct mlxsw_sp_mr_route *mr_route)
 804 {
 805         return mr_route->key.source_mask.addr4 == htonl(INADDR_ANY);
 806 }
 807 
 808 static bool mlxsw_sp_mr_vif4_is_regular(const struct mlxsw_sp_mr_vif *vif)
 809 {
 810         return !(vif->vif_flags & (VIFF_TUNNEL | VIFF_REGISTER));
 811 }
 812 
 813 static bool
 814 mlxsw_sp_mr_route6_validate(const struct mlxsw_sp_mr_table *mr_table,
 815                             const struct mr_mfc *c)
 816 {
 817         struct mfc6_cache *mfc = (struct mfc6_cache *) c;
 818 
 819         /* If the route is a (*,*) route, abort, as these kind of routes are
 820          * used for proxy routes.
 821          */
 822         if (ipv6_addr_any(&mfc->mf6c_origin) &&
 823             ipv6_addr_any(&mfc->mf6c_mcastgrp)) {
 824                 dev_warn(mr_table->mlxsw_sp->bus_info->dev,
 825                          "Offloading proxy routes is not supported.\n");
 826                 return false;
 827         }
 828         return true;
 829 }
 830 
 831 static void mlxsw_sp_mr_route6_key(struct mlxsw_sp_mr_table *mr_table,
 832                                    struct mlxsw_sp_mr_route_key *key,
 833                                    struct mr_mfc *c)
 834 {
 835         const struct mfc6_cache *mfc = (struct mfc6_cache *) c;
 836 
 837         memset(key, 0, sizeof(*key));
 838         key->vrid = mr_table->vr_id;
 839         key->proto = MLXSW_SP_L3_PROTO_IPV6;
 840         key->group.addr6 = mfc->mf6c_mcastgrp;
 841         memset(&key->group_mask.addr6, 0xff, sizeof(key->group_mask.addr6));
 842         key->source.addr6 = mfc->mf6c_origin;
 843         if (!ipv6_addr_any(&mfc->mf6c_origin))
 844                 memset(&key->source_mask.addr6, 0xff,
 845                        sizeof(key->source_mask.addr6));
 846 }
 847 
 848 static bool mlxsw_sp_mr_route6_starg(const struct mlxsw_sp_mr_table *mr_table,
 849                                      const struct mlxsw_sp_mr_route *mr_route)
 850 {
 851         return ipv6_addr_any(&mr_route->key.source_mask.addr6);
 852 }
 853 
 854 static bool mlxsw_sp_mr_vif6_is_regular(const struct mlxsw_sp_mr_vif *vif)
 855 {
 856         return !(vif->vif_flags & MIFF_REGISTER);
 857 }
 858 
 859 static struct
 860 mlxsw_sp_mr_vif_ops mlxsw_sp_mr_vif_ops_arr[] = {
 861         {
 862                 .is_regular = mlxsw_sp_mr_vif4_is_regular,
 863         },
 864         {
 865                 .is_regular = mlxsw_sp_mr_vif6_is_regular,
 866         },
 867 };
 868 
 869 static struct
 870 mlxsw_sp_mr_table_ops mlxsw_sp_mr_table_ops_arr[] = {
 871         {
 872                 .is_route_valid = mlxsw_sp_mr_route4_validate,
 873                 .key_create = mlxsw_sp_mr_route4_key,
 874                 .is_route_starg = mlxsw_sp_mr_route4_starg,
 875         },
 876         {
 877                 .is_route_valid = mlxsw_sp_mr_route6_validate,
 878                 .key_create = mlxsw_sp_mr_route6_key,
 879                 .is_route_starg = mlxsw_sp_mr_route6_starg,
 880         },
 881 
 882 };
 883 
 884 struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp,
 885                                                    u32 vr_id,
 886                                                    enum mlxsw_sp_l3proto proto)
 887 {
 888         struct mlxsw_sp_mr_route_params catchall_route_params = {
 889                 .prio = MLXSW_SP_MR_ROUTE_PRIO_CATCHALL,
 890                 .key = {
 891                         .vrid = vr_id,
 892                         .proto = proto,
 893                 },
 894                 .value = {
 895                         .route_action = MLXSW_SP_MR_ROUTE_ACTION_TRAP,
 896                 }
 897         };
 898         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 899         struct mlxsw_sp_mr_table *mr_table;
 900         int err;
 901         int i;
 902 
 903         mr_table = kzalloc(sizeof(*mr_table) + mr->mr_ops->route_priv_size,
 904                            GFP_KERNEL);
 905         if (!mr_table)
 906                 return ERR_PTR(-ENOMEM);
 907 
 908         mr_table->vr_id = vr_id;
 909         mr_table->mlxsw_sp = mlxsw_sp;
 910         mr_table->proto = proto;
 911         mr_table->ops = &mlxsw_sp_mr_table_ops_arr[proto];
 912         INIT_LIST_HEAD(&mr_table->route_list);
 913 
 914         err = rhashtable_init(&mr_table->route_ht,
 915                               &mlxsw_sp_mr_route_ht_params);
 916         if (err)
 917                 goto err_route_rhashtable_init;
 918 
 919         for (i = 0; i < MAXVIFS; i++) {
 920                 INIT_LIST_HEAD(&mr_table->vifs[i].route_evif_list);
 921                 INIT_LIST_HEAD(&mr_table->vifs[i].route_ivif_list);
 922                 mr_table->vifs[i].ops = &mlxsw_sp_mr_vif_ops_arr[proto];
 923         }
 924 
 925         err = mr->mr_ops->route_create(mlxsw_sp, mr->priv,
 926                                        mr_table->catchall_route_priv,
 927                                        &catchall_route_params);
 928         if (err)
 929                 goto err_ops_route_create;
 930         list_add_tail(&mr_table->node, &mr->table_list);
 931         return mr_table;
 932 
 933 err_ops_route_create:
 934         rhashtable_destroy(&mr_table->route_ht);
 935 err_route_rhashtable_init:
 936         kfree(mr_table);
 937         return ERR_PTR(err);
 938 }
 939 
 940 void mlxsw_sp_mr_table_destroy(struct mlxsw_sp_mr_table *mr_table)
 941 {
 942         struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp;
 943         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 944 
 945         WARN_ON(!mlxsw_sp_mr_table_empty(mr_table));
 946         list_del(&mr_table->node);
 947         mr->mr_ops->route_destroy(mlxsw_sp, mr->priv,
 948                                   &mr_table->catchall_route_priv);
 949         rhashtable_destroy(&mr_table->route_ht);
 950         kfree(mr_table);
 951 }
 952 
 953 void mlxsw_sp_mr_table_flush(struct mlxsw_sp_mr_table *mr_table)
 954 {
 955         struct mlxsw_sp_mr_route *mr_route, *tmp;
 956         int i;
 957 
 958         list_for_each_entry_safe(mr_route, tmp, &mr_table->route_list, node)
 959                 __mlxsw_sp_mr_route_del(mr_table, mr_route);
 960 
 961         for (i = 0; i < MAXVIFS; i++) {
 962                 mr_table->vifs[i].dev = NULL;
 963                 mr_table->vifs[i].rif = NULL;
 964         }
 965 }
 966 
 967 bool mlxsw_sp_mr_table_empty(const struct mlxsw_sp_mr_table *mr_table)
 968 {
 969         int i;
 970 
 971         for (i = 0; i < MAXVIFS; i++)
 972                 if (mr_table->vifs[i].dev)
 973                         return false;
 974         return list_empty(&mr_table->route_list);
 975 }
 976 
 977 static void mlxsw_sp_mr_route_stats_update(struct mlxsw_sp *mlxsw_sp,
 978                                            struct mlxsw_sp_mr_route *mr_route)
 979 {
 980         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
 981         u64 packets, bytes;
 982 
 983         if (mr_route->route_action == MLXSW_SP_MR_ROUTE_ACTION_TRAP)
 984                 return;
 985 
 986         mr->mr_ops->route_stats(mlxsw_sp, mr_route->route_priv, &packets,
 987                                 &bytes);
 988 
 989         if (mr_route->mfc->mfc_un.res.pkt != packets)
 990                 mr_route->mfc->mfc_un.res.lastuse = jiffies;
 991         mr_route->mfc->mfc_un.res.pkt = packets;
 992         mr_route->mfc->mfc_un.res.bytes = bytes;
 993 }
 994 
 995 static void mlxsw_sp_mr_stats_update(struct work_struct *work)
 996 {
 997         struct mlxsw_sp_mr *mr = container_of(work, struct mlxsw_sp_mr,
 998                                               stats_update_dw.work);
 999         struct mlxsw_sp_mr_table *mr_table;
1000         struct mlxsw_sp_mr_route *mr_route;
1001         unsigned long interval;
1002 
1003         rtnl_lock();
1004         list_for_each_entry(mr_table, &mr->table_list, node)
1005                 list_for_each_entry(mr_route, &mr_table->route_list, node)
1006                         mlxsw_sp_mr_route_stats_update(mr_table->mlxsw_sp,
1007                                                        mr_route);
1008         rtnl_unlock();
1009 
1010         interval = msecs_to_jiffies(MLXSW_SP_MR_ROUTES_COUNTER_UPDATE_INTERVAL);
1011         mlxsw_core_schedule_dw(&mr->stats_update_dw, interval);
1012 }
1013 
1014 int mlxsw_sp_mr_init(struct mlxsw_sp *mlxsw_sp,
1015                      const struct mlxsw_sp_mr_ops *mr_ops)
1016 {
1017         struct mlxsw_sp_mr *mr;
1018         unsigned long interval;
1019         int err;
1020 
1021         mr = kzalloc(sizeof(*mr) + mr_ops->priv_size, GFP_KERNEL);
1022         if (!mr)
1023                 return -ENOMEM;
1024         mr->mr_ops = mr_ops;
1025         mlxsw_sp->mr = mr;
1026         INIT_LIST_HEAD(&mr->table_list);
1027 
1028         err = mr_ops->init(mlxsw_sp, mr->priv);
1029         if (err)
1030                 goto err;
1031 
1032         /* Create the delayed work for counter updates */
1033         INIT_DELAYED_WORK(&mr->stats_update_dw, mlxsw_sp_mr_stats_update);
1034         interval = msecs_to_jiffies(MLXSW_SP_MR_ROUTES_COUNTER_UPDATE_INTERVAL);
1035         mlxsw_core_schedule_dw(&mr->stats_update_dw, interval);
1036         return 0;
1037 err:
1038         kfree(mr);
1039         return err;
1040 }
1041 
1042 void mlxsw_sp_mr_fini(struct mlxsw_sp *mlxsw_sp)
1043 {
1044         struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
1045 
1046         cancel_delayed_work_sync(&mr->stats_update_dw);
1047         mr->mr_ops->fini(mlxsw_sp, mr->priv);
1048         kfree(mr);
1049 }

/* [<][>][^][v][top][bottom][index][help] */