mlxsw: spectrum: Support decap-only IP-in-IP tunnels
Current code for offloading IP-in-IP tunneling assumes that there is no decap without encap. But that's never true for IPv6 overlays, and is not true for IPv4 ones either, if net.ipv4.conf.*.rp_filter is unset. To support decap-only tunnels, an IPIP entry is now created as soon as an offloadable tunneling device is created. When that netdevice is up'd, a decap route is looked up and possibly offloaded. Thus decap is not handled implicitly as part of mlxsw_sp_ipip_entry_get() call anymore, but needs to be done explicitly after the get, if desired. Signed-off-by: Petr Machata <petrm@mellanox.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6698c168bf
commit
0063587d35
@ -4497,13 +4497,17 @@ static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
|
|||||||
return netif_is_l3_master(info->upper_dev);
|
return netif_is_l3_master(info->upper_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
|
static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
|
||||||
unsigned long event, void *ptr)
|
unsigned long event, void *ptr)
|
||||||
{
|
{
|
||||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||||
|
struct mlxsw_sp *mlxsw_sp;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
|
mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
|
||||||
|
if (mlxsw_sp_netdev_is_ipip(mlxsw_sp, dev))
|
||||||
|
err = mlxsw_sp_netdevice_ipip_event(mlxsw_sp, dev, event);
|
||||||
|
else if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
|
||||||
err = mlxsw_sp_netdevice_router_port_event(dev);
|
err = mlxsw_sp_netdevice_router_port_event(dev);
|
||||||
else if (mlxsw_sp_is_vrf_event(event, ptr))
|
else if (mlxsw_sp_is_vrf_event(event, ptr))
|
||||||
err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
|
err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
|
||||||
|
@ -395,6 +395,12 @@ int mlxsw_sp_inet6addr_event(struct notifier_block *unused,
|
|||||||
unsigned long event, void *ptr);
|
unsigned long event, void *ptr);
|
||||||
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
||||||
struct netdev_notifier_changeupper_info *info);
|
struct netdev_notifier_changeupper_info *info);
|
||||||
|
bool mlxsw_sp_netdev_is_ipip(const struct mlxsw_sp *mlxsw_sp,
|
||||||
|
const struct net_device *dev);
|
||||||
|
int
|
||||||
|
mlxsw_sp_netdevice_ipip_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *l3_dev,
|
||||||
|
unsigned long event);
|
||||||
void
|
void
|
||||||
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
|
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
|
||||||
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
|
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
|
||||||
|
@ -1206,7 +1206,6 @@ mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
|
|||||||
{
|
{
|
||||||
u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
|
u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
|
||||||
struct mlxsw_sp_router *router = mlxsw_sp->router;
|
struct mlxsw_sp_router *router = mlxsw_sp->router;
|
||||||
struct mlxsw_sp_fib_entry *decap_fib_entry;
|
|
||||||
struct mlxsw_sp_ipip_entry *ipip_entry;
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
enum mlxsw_sp_l3proto ul_proto;
|
enum mlxsw_sp_l3proto ul_proto;
|
||||||
union mlxsw_sp_l3addr saddr;
|
union mlxsw_sp_l3addr saddr;
|
||||||
@ -1231,11 +1230,6 @@ mlxsw_sp_ipip_entry_get(struct mlxsw_sp *mlxsw_sp,
|
|||||||
if (IS_ERR(ipip_entry))
|
if (IS_ERR(ipip_entry))
|
||||||
return ipip_entry;
|
return ipip_entry;
|
||||||
|
|
||||||
decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp, ipip_entry);
|
|
||||||
if (decap_fib_entry)
|
|
||||||
mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
|
|
||||||
decap_fib_entry);
|
|
||||||
|
|
||||||
list_add_tail(&ipip_entry->ipip_list_node,
|
list_add_tail(&ipip_entry->ipip_list_node,
|
||||||
&mlxsw_sp->router->ipip_list);
|
&mlxsw_sp->router->ipip_list);
|
||||||
|
|
||||||
@ -1250,8 +1244,6 @@ mlxsw_sp_ipip_entry_put(struct mlxsw_sp *mlxsw_sp,
|
|||||||
{
|
{
|
||||||
if (--ipip_entry->ref_count == 0) {
|
if (--ipip_entry->ref_count == 0) {
|
||||||
list_del(&ipip_entry->ipip_list_node);
|
list_del(&ipip_entry->ipip_list_node);
|
||||||
if (ipip_entry->decap_fib_entry)
|
|
||||||
mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
|
|
||||||
mlxsw_sp_ipip_entry_destroy(ipip_entry);
|
mlxsw_sp_ipip_entry_destroy(ipip_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1314,6 +1306,103 @@ static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mlxsw_sp_netdev_is_ipip(const struct mlxsw_sp *mlxsw_sp,
|
||||||
|
const struct net_device *dev)
|
||||||
|
{
|
||||||
|
return mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mlxsw_sp_ipip_entry *
|
||||||
|
mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
const struct net_device *ol_dev)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
|
|
||||||
|
list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
|
||||||
|
ipip_list_node)
|
||||||
|
if (ipip_entry->ol_dev == ol_dev)
|
||||||
|
return ipip_entry;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxsw_sp_netdevice_ipip_reg_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *ol_dev)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp_router *router = mlxsw_sp->router;
|
||||||
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
|
enum mlxsw_sp_ipip_type ipipt;
|
||||||
|
|
||||||
|
mlxsw_sp_netdev_ipip_type(mlxsw_sp, ol_dev, &ipipt);
|
||||||
|
if (router->ipip_ops_arr[ipipt]->can_offload(mlxsw_sp, ol_dev,
|
||||||
|
MLXSW_SP_L3_PROTO_IPV4) ||
|
||||||
|
router->ipip_ops_arr[ipipt]->can_offload(mlxsw_sp, ol_dev,
|
||||||
|
MLXSW_SP_L3_PROTO_IPV6)) {
|
||||||
|
ipip_entry = mlxsw_sp_ipip_entry_get(mlxsw_sp, ipipt, ol_dev);
|
||||||
|
if (IS_ERR(ipip_entry))
|
||||||
|
return PTR_ERR(ipip_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlxsw_sp_netdevice_ipip_unreg_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *ol_dev)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
|
|
||||||
|
ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
|
||||||
|
if (ipip_entry)
|
||||||
|
mlxsw_sp_ipip_entry_put(mlxsw_sp, ipip_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxsw_sp_netdevice_ipip_up_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *ol_dev)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp_fib_entry *decap_fib_entry;
|
||||||
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
|
|
||||||
|
ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
|
||||||
|
if (ipip_entry) {
|
||||||
|
decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp,
|
||||||
|
ipip_entry);
|
||||||
|
if (decap_fib_entry)
|
||||||
|
mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
|
||||||
|
decap_fib_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mlxsw_sp_netdevice_ipip_down_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *ol_dev)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||||
|
|
||||||
|
ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
|
||||||
|
if (ipip_entry && ipip_entry->decap_fib_entry)
|
||||||
|
mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mlxsw_sp_netdevice_ipip_event(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *ol_dev,
|
||||||
|
unsigned long event)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case NETDEV_REGISTER:
|
||||||
|
return mlxsw_sp_netdevice_ipip_reg_event(mlxsw_sp, ol_dev);
|
||||||
|
case NETDEV_UNREGISTER:
|
||||||
|
mlxsw_sp_netdevice_ipip_unreg_event(mlxsw_sp, ol_dev);
|
||||||
|
return 0;
|
||||||
|
case NETDEV_UP:
|
||||||
|
return mlxsw_sp_netdevice_ipip_up_event(mlxsw_sp, ol_dev);
|
||||||
|
case NETDEV_DOWN:
|
||||||
|
mlxsw_sp_netdevice_ipip_down_event(mlxsw_sp, ol_dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct mlxsw_sp_neigh_key {
|
struct mlxsw_sp_neigh_key {
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user