/* A list of route_vif_entry structs that point to routes that the VIF * instance is used as one of the egress VIFs
*/ struct list_head route_evif_list;
/* A list of route_vif_entry structs that point to routes that the VIF * instance is used as an ingress VIF
*/ struct list_head route_ivif_list;
/* Protocol specific operations for a VIF */ conststruct mlxsw_sp_mr_vif_ops *ops;
};
struct mlxsw_sp_mr_table { struct list_head node; enum mlxsw_sp_l3proto proto; struct mlxsw_sp *mlxsw_sp;
u32 vr_id; struct mlxsw_sp_mr_vif vifs[MAXVIFS]; struct list_head route_list; struct mutex route_list_lock; /* Protects route_list */ struct rhashtable route_ht; conststruct mlxsw_sp_mr_table_ops *ops; char catchall_route_priv[]; /* catchall_route_priv has to be always the last item */
};
struct mlxsw_sp_mr_route { struct list_head node; struct rhash_head ht_node; struct mlxsw_sp_mr_route_key key; enum mlxsw_sp_mr_route_action route_action;
u16 min_mtu; struct mr_mfc *mfc; void *route_priv; conststruct mlxsw_sp_mr_table *mr_table; /* A list of route_vif_entry structs that point to the egress VIFs */ struct list_head evif_list; /* A route_vif_entry struct that point to the ingress VIF */ struct mlxsw_sp_mr_route_vif_entry ivif;
};
/* If the ingress port is not regular and resolved, trap the route */ if (!mlxsw_sp_mr_vif_valid(mr_route->ivif.mr_vif)) return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
/* The kernel does not match a (*,G) route that the ingress interface is * not one of the egress interfaces, so trap these kind of routes.
*/ if (mr_route->mr_table->ops->is_route_starg(mr_route->mr_table,
mr_route) &&
!mlxsw_sp_mr_route_ivif_in_evifs(mr_route)) return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
/* If the route has no valid eVIFs, trap it. */ if (!mlxsw_sp_mr_route_valid_evifs_num(mr_route)) return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
/* If one of the eVIFs has no RIF, trap-and-forward the route as there * is some more routing to do in software too.
*/
list_for_each_entry(rve, &mr_route->evif_list, route_node) if (mlxsw_sp_mr_vif_exists(rve->mr_vif) && !rve->mr_vif->rif) return MLXSW_SP_MR_ROUTE_ACTION_TRAP_AND_FORWARD;
/* Allocate and init a new route and fill it with parameters */
mr_route = kzalloc(sizeof(*mr_route), GFP_KERNEL); if (!mr_route) return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&mr_route->evif_list);
/* Find min_mtu and link iVIF and eVIFs */
mr_route->min_mtu = ETH_MAX_MTU;
mr_cache_hold(mfc);
mr_route->mfc = mfc;
mr_table->ops->key_create(mr_table, &mr_route->key, mr_route->mfc);
mr_route->mr_table = mr_table; for (i = 0; i < MAXVIFS; i++) { if (mfc->mfc_un.res.ttls[i] != 255) {
err = mlxsw_sp_mr_route_evif_link(mr_route,
&mr_table->vifs[i]); if (err) goto err; if (mr_table->vifs[i].dev &&
mr_table->vifs[i].dev->mtu < mr_route->min_mtu)
mr_route->min_mtu = mr_table->vifs[i].dev->mtu;
}
}
mlxsw_sp_mr_route_ivif_link(mr_route,
&mr_table->vifs[mfc->mfc_parent]);
int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table, struct mr_mfc *mfc, bool replace)
{ struct mlxsw_sp_mr_route *mr_orig_route = NULL; struct mlxsw_sp_mr_route *mr_route; int err;
if (!mr_table->ops->is_route_valid(mr_table, mfc)) return -EINVAL;
/* Create a new route */
mr_route = mlxsw_sp_mr_route_create(mr_table, mfc); if (IS_ERR(mr_route)) return PTR_ERR(mr_route);
/* Find any route with a matching key */
mr_orig_route = rhashtable_lookup_fast(&mr_table->route_ht,
&mr_route->key,
mlxsw_sp_mr_route_ht_params); if (replace) { /* On replace case, make the route point to the new route_priv.
*/ if (WARN_ON(!mr_orig_route)) {
err = -ENOENT; goto err_no_orig_route;
}
mr_route->route_priv = mr_orig_route->route_priv;
} elseif (mr_orig_route) { /* On non replace case, if another route with the same key was * found, abort, as duplicate routes are used for proxy routes.
*/
dev_warn(mr_table->mlxsw_sp->bus_info->dev, "Offloading proxy routes is not supported.\n");
err = -EINVAL; goto err_duplicate_route;
}
/* Write the route to the hardware */
err = mlxsw_sp_mr_route_write(mr_table, mr_route, replace); if (err) goto err_mr_route_write;
/* Put it in the table data-structures */
mutex_lock(&mr_table->route_list_lock);
list_add_tail(&mr_route->node, &mr_table->route_list);
mutex_unlock(&mr_table->route_list_lock);
err = rhashtable_insert_fast(&mr_table->route_ht,
&mr_route->ht_node,
mlxsw_sp_mr_route_ht_params); if (err) goto err_rhashtable_insert;
/* Destroy the original route */ if (replace) {
rhashtable_remove_fast(&mr_table->route_ht,
&mr_orig_route->ht_node,
mlxsw_sp_mr_route_ht_params);
list_del(&mr_orig_route->node);
mlxsw_sp_mr_route_destroy(mr_table, mr_orig_route);
}
/* Should be called after the VIF struct is updated */ staticint
mlxsw_sp_mr_route_ivif_resolve(struct mlxsw_sp_mr_table *mr_table, struct mlxsw_sp_mr_route_vif_entry *rve)
{ struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp; enum mlxsw_sp_mr_route_action route_action; struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
u16 irif_index; int err;
route_action = mlxsw_sp_mr_route_action(rve->mr_route); if (route_action == MLXSW_SP_MR_ROUTE_ACTION_TRAP) return 0;
/* rve->mr_vif->rif is guaranteed to be valid at this stage */
irif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
err = mr->mr_ops->route_irif_update(mlxsw_sp, rve->mr_route->route_priv,
irif_index); if (err) return err;
err = mr->mr_ops->route_action_update(mlxsw_sp,
rve->mr_route->route_priv,
route_action); if (err) /* No need to rollback here because the iRIF change only takes * place after the action has been updated.
*/ return err;
/* Should be called after the RIF struct is updated */ staticint
mlxsw_sp_mr_route_evif_resolve(struct mlxsw_sp_mr_table *mr_table, struct mlxsw_sp_mr_route_vif_entry *rve)
{ struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp; enum mlxsw_sp_mr_route_action route_action; struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
u16 erif_index = 0; int err;
/* Add the eRIF */ if (mlxsw_sp_mr_vif_valid(rve->mr_vif)) {
erif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
err = mr->mr_ops->route_erif_add(mlxsw_sp,
rve->mr_route->route_priv,
erif_index); if (err) return err;
}
/* Update the route action, as the new eVIF can be a tunnel or a pimreg * device which will require updating the action.
*/
route_action = mlxsw_sp_mr_route_action(rve->mr_route); if (route_action != rve->mr_route->route_action) {
err = mr->mr_ops->route_action_update(mlxsw_sp,
rve->mr_route->route_priv,
route_action); if (err) goto err_route_action_update;
}
/* Update the minimum MTU */ if (rve->mr_vif->dev->mtu < rve->mr_route->min_mtu) {
rve->mr_route->min_mtu = rve->mr_vif->dev->mtu;
err = mr->mr_ops->route_min_mtu_update(mlxsw_sp,
rve->mr_route->route_priv,
rve->mr_route->min_mtu); if (err) goto err_route_min_mtu_update;
}
err_route_min_mtu_update: if (route_action != rve->mr_route->route_action)
mr->mr_ops->route_action_update(mlxsw_sp,
rve->mr_route->route_priv,
rve->mr_route->route_action);
err_route_action_update: if (mlxsw_sp_mr_vif_valid(rve->mr_vif))
mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv,
erif_index); return err;
}
/* Should be called before the RIF struct is updated */ staticvoid
mlxsw_sp_mr_route_evif_unresolve(struct mlxsw_sp_mr_table *mr_table, struct mlxsw_sp_mr_route_vif_entry *rve)
{ struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp; enum mlxsw_sp_mr_route_action route_action; struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
u16 rifi;
/* If the unresolved RIF was not valid, no need to delete it */ if (!mlxsw_sp_mr_vif_valid(rve->mr_vif)) return;
/* Update the route action: if there is only one valid eVIF in the * route, set the action to trap as the VIF deletion will lead to zero * valid eVIFs. On any other case, use the mlxsw_sp_mr_route_action to * determine the route action.
*/ if (mlxsw_sp_mr_route_valid_evifs_num(rve->mr_route) == 1)
route_action = MLXSW_SP_MR_ROUTE_ACTION_TRAP; else
route_action = mlxsw_sp_mr_route_action(rve->mr_route); if (route_action != rve->mr_route->route_action)
mr->mr_ops->route_action_update(mlxsw_sp,
rve->mr_route->route_priv,
route_action);
/* Delete the erif from the route */
rifi = mlxsw_sp_rif_index(rve->mr_vif->rif);
mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv, rifi);
rve->mr_route->route_action = route_action;
mlxsw_sp_mr_mfc_offload_update(rve->mr_route);
}
/* Update all routes where this VIF is used as an unresolved iRIF */
list_for_each_entry(irve, &mr_vif->route_ivif_list, vif_node) {
err = mlxsw_sp_mr_route_ivif_resolve(mr_table, irve); if (err) goto err_irif_unresolve;
}
/* Update all routes where this VIF is used as an unresolved eRIF */
list_for_each_entry(erve, &mr_vif->route_evif_list, vif_node) {
err = mlxsw_sp_mr_route_evif_resolve(mr_table, erve); if (err) goto err_erif_unresolve;
} return 0;
/* Update all routes where this VIF is used as an unresolved eRIF */
list_for_each_entry(rve, &mr_vif->route_evif_list, vif_node)
mlxsw_sp_mr_route_evif_unresolve(mr_table, rve);
/* Update all routes where this VIF is used as an unresolved iRIF */
list_for_each_entry(rve, &mr_vif->route_ivif_list, vif_node)
mlxsw_sp_mr_route_ivif_unresolve(mr_table, rve);
/* Search for a VIF that use that RIF */
mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif); if (!mr_vif) return;
/* Update all the routes that uses that VIF as eVIF */
list_for_each_entry(rve, &mr_vif->route_evif_list, vif_node) { if (mtu < rve->mr_route->min_mtu) {
rve->mr_route->min_mtu = mtu;
mr->mr_ops->route_min_mtu_update(mlxsw_sp,
rve->mr_route->route_priv,
mtu);
}
}
}
/* If the route is a (*,*) route, abort, as these kind of routes are * used for proxy routes.
*/ if (mfc->mfc_origin == htonl(INADDR_ANY) &&
mfc->mfc_mcastgrp == htonl(INADDR_ANY)) {
dev_warn(mr_table->mlxsw_sp->bus_info->dev, "Offloading proxy routes is not supported.\n"); returnfalse;
} returntrue;
}
/* If the route is a (*,*) route, abort, as these kind of routes are * used for proxy routes.
*/ if (ipv6_addr_any(&mfc->mf6c_origin) &&
ipv6_addr_any(&mfc->mf6c_mcastgrp)) {
dev_warn(mr_table->mlxsw_sp->bus_info->dev, "Offloading proxy routes is not supported.\n"); returnfalse;
} returntrue;
}
err = rhashtable_init(&mr_table->route_ht,
&mlxsw_sp_mr_route_ht_params); if (err) goto err_route_rhashtable_init;
for (i = 0; i < MAXVIFS; i++) {
INIT_LIST_HEAD(&mr_table->vifs[i].route_evif_list);
INIT_LIST_HEAD(&mr_table->vifs[i].route_ivif_list);
mr_table->vifs[i].ops = &mlxsw_sp_mr_vif_ops_arr[proto];
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.