Commit 56e66053 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-next'

Ido Schimmel says:

====================
mlxsw: Add support for IP-in-IP with IPv6 underlay

Currently, mlxsw only supports IP-in-IP with IPv4 underlay. Traffic
routed through 'gre' netdevs is encapsulated with IPv4 and GRE headers.
Similarly, incoming IPv4 GRE packets are decapsulated and routed in the
overlay VRF (which can be the same as the underlay VRF).

This patchset adds support for IPv6 underlay using the 'ip6gre' netdev.
Due to architectural differences between Spectrum-1 and later ASICs,
this functionality is only supported on Spectrum-2 onwards (the software
data path is used for Spectrum-1).

Patchset overview:

Patches #1-#5 are preparations.

Patches #6-#9 add and extend required device registers.

Patches #10-#14 gradually add IPv6 underlay support.

A follow-up patchset will add net/forwarding/ selftests.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2fcd14d0 ba1c7132
......@@ -6734,6 +6734,23 @@ mlxsw_reg_ritr_loopback_ipip4_pack(char *payload,
mlxsw_reg_ritr_loopback_ipip_usip4_set(payload, usip);
}
static inline void
mlxsw_reg_ritr_loopback_ipip6_pack(char *payload,
enum mlxsw_reg_ritr_loopback_ipip_type ipip_type,
enum mlxsw_reg_ritr_loopback_ipip_options options,
u16 uvr_id, u16 underlay_rif,
const struct in6_addr *usip, u32 gre_key)
{
enum mlxsw_reg_ritr_loopback_protocol protocol =
MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV6;
mlxsw_reg_ritr_loopback_protocol_set(payload, protocol);
mlxsw_reg_ritr_loopback_ipip_common_pack(payload, ipip_type, options,
uvr_id, underlay_rif, gre_key);
mlxsw_reg_ritr_loopback_ipip_usip6_memcpy_to(payload,
(const char *)usip);
}
/* RTAR - Router TCAM Allocation Register
* --------------------------------------
* This register is used for allocation of regions in the TCAM table.
......@@ -7002,6 +7019,12 @@ static inline void mlxsw_reg_ratr_ipip4_entry_pack(char *payload, u32 ipv4_udip)
mlxsw_reg_ratr_ipip_ipv4_udip_set(payload, ipv4_udip);
}
static inline void mlxsw_reg_ratr_ipip6_entry_pack(char *payload, u32 ipv6_ptr)
{
mlxsw_reg_ratr_ipip_type_set(payload, MLXSW_REG_RATR_IPIP_TYPE_IPV6);
mlxsw_reg_ratr_ipip_ipv6_ptr_set(payload, ipv6_ptr);
}
static inline void mlxsw_reg_ratr_counter_pack(char *payload, u64 counter_index,
bool counter_enable)
{
......@@ -8187,19 +8210,71 @@ static inline void mlxsw_reg_rtdp_pack(char *payload,
}
static inline void
mlxsw_reg_rtdp_ipip4_pack(char *payload, u16 irif,
mlxsw_reg_rtdp_ipip_pack(char *payload, u16 irif,
enum mlxsw_reg_rtdp_ipip_sip_check sip_check,
unsigned int type_check, bool gre_key_check,
u32 ipv4_usip, u32 expected_gre_key)
u32 expected_gre_key)
{
mlxsw_reg_rtdp_ipip_irif_set(payload, irif);
mlxsw_reg_rtdp_ipip_sip_check_set(payload, sip_check);
mlxsw_reg_rtdp_ipip_type_check_set(payload, type_check);
mlxsw_reg_rtdp_ipip_gre_key_check_set(payload, gre_key_check);
mlxsw_reg_rtdp_ipip_ipv4_usip_set(payload, ipv4_usip);
mlxsw_reg_rtdp_ipip_expected_gre_key_set(payload, expected_gre_key);
}
static inline void
mlxsw_reg_rtdp_ipip4_pack(char *payload, u16 irif,
enum mlxsw_reg_rtdp_ipip_sip_check sip_check,
unsigned int type_check, bool gre_key_check,
u32 ipv4_usip, u32 expected_gre_key)
{
mlxsw_reg_rtdp_ipip_pack(payload, irif, sip_check, type_check,
gre_key_check, expected_gre_key);
mlxsw_reg_rtdp_ipip_ipv4_usip_set(payload, ipv4_usip);
}
static inline void
mlxsw_reg_rtdp_ipip6_pack(char *payload, u16 irif,
enum mlxsw_reg_rtdp_ipip_sip_check sip_check,
unsigned int type_check, bool gre_key_check,
u32 ipv6_usip_ptr, u32 expected_gre_key)
{
mlxsw_reg_rtdp_ipip_pack(payload, irif, sip_check, type_check,
gre_key_check, expected_gre_key);
mlxsw_reg_rtdp_ipip_ipv6_usip_ptr_set(payload, ipv6_usip_ptr);
}
/* RIPS - Router IP version Six Register
* -------------------------------------
* The RIPS register is used to store IPv6 addresses for use by the NVE and
* IPinIP
*/
#define MLXSW_REG_RIPS_ID 0x8021
#define MLXSW_REG_RIPS_LEN 0x14
MLXSW_REG_DEFINE(rips, MLXSW_REG_RIPS_ID, MLXSW_REG_RIPS_LEN);
/* reg_rips_index
* Index to IPv6 address.
* For Spectrum, the index is to the KVD linear.
* Access: Index
*/
MLXSW_ITEM32(reg, rips, index, 0x00, 0, 24);
/* reg_rips_ipv6
* IPv6 address
* Access: RW
*/
MLXSW_ITEM_BUF(reg, rips, ipv6, 0x04, 16);
static inline void mlxsw_reg_rips_pack(char *payload, u32 index,
const struct in6_addr *ipv6)
{
MLXSW_REG_ZERO(rips, payload);
mlxsw_reg_rips_index_set(payload, index);
mlxsw_reg_rips_ipv6_memcpy_to(payload, (const char *)ipv6);
}
/* RATRAD - Router Adjacency Table Activity Dump Register
* ------------------------------------------------------
* The RATRAD register is used to dump and optionally clear activity bits of
......@@ -12281,6 +12356,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(rtar),
MLXSW_REG(ratr),
MLXSW_REG(rtdp),
MLXSW_REG(rips),
MLXSW_REG(ratrad),
MLXSW_REG(rdpm),
MLXSW_REG(ricnt),
......
......@@ -747,6 +747,7 @@ enum mlxsw_sp_kvdl_entry_type {
MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
MLXSW_SP_KVDL_ENTRY_TYPE_PBS,
MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR,
MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS,
MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT,
};
......@@ -758,6 +759,7 @@ mlxsw_sp_kvdl_entry_size(enum mlxsw_sp_kvdl_entry_type type)
case MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET:
case MLXSW_SP_KVDL_ENTRY_TYPE_PBS:
case MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR:
case MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS:
case MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT:
default:
return 1;
......
......@@ -35,6 +35,7 @@ static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = {
MAX_KVD_ACTION_SETS),
MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE),
MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE),
MLXSW_SP2_KVDL_PART_INFO(IPV6_ADDRESS, 0x28, KVD_SIZE, KVD_SIZE),
MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE),
};
......
......@@ -24,50 +24,72 @@ mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev)
return tun->parms;
}
static bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms)
static bool mlxsw_sp_ipip_parms4_has_ikey(const struct ip_tunnel_parm *parms)
{
return !!(parms.i_flags & TUNNEL_KEY);
return !!(parms->i_flags & TUNNEL_KEY);
}
static bool mlxsw_sp_ipip_parms4_has_okey(struct ip_tunnel_parm parms)
static bool mlxsw_sp_ipip_parms6_has_ikey(const struct __ip6_tnl_parm *parms)
{
return !!(parms.o_flags & TUNNEL_KEY);
return !!(parms->i_flags & TUNNEL_KEY);
}
static u32 mlxsw_sp_ipip_parms4_ikey(struct ip_tunnel_parm parms)
static bool mlxsw_sp_ipip_parms4_has_okey(const struct ip_tunnel_parm *parms)
{
return !!(parms->o_flags & TUNNEL_KEY);
}
static bool mlxsw_sp_ipip_parms6_has_okey(const struct __ip6_tnl_parm *parms)
{
return !!(parms->o_flags & TUNNEL_KEY);
}
static u32 mlxsw_sp_ipip_parms4_ikey(const struct ip_tunnel_parm *parms)
{
return mlxsw_sp_ipip_parms4_has_ikey(parms) ?
be32_to_cpu(parms.i_key) : 0;
be32_to_cpu(parms->i_key) : 0;
}
static u32 mlxsw_sp_ipip_parms4_okey(struct ip_tunnel_parm parms)
static u32 mlxsw_sp_ipip_parms6_ikey(const struct __ip6_tnl_parm *parms)
{
return mlxsw_sp_ipip_parms6_has_ikey(parms) ?
be32_to_cpu(parms->i_key) : 0;
}
static u32 mlxsw_sp_ipip_parms4_okey(const struct ip_tunnel_parm *parms)
{
return mlxsw_sp_ipip_parms4_has_okey(parms) ?
be32_to_cpu(parms.o_key) : 0;
be32_to_cpu(parms->o_key) : 0;
}
static u32 mlxsw_sp_ipip_parms6_okey(const struct __ip6_tnl_parm *parms)
{
return mlxsw_sp_ipip_parms6_has_okey(parms) ?
be32_to_cpu(parms->o_key) : 0;
}
static union mlxsw_sp_l3addr
mlxsw_sp_ipip_parms4_saddr(struct ip_tunnel_parm parms)
mlxsw_sp_ipip_parms4_saddr(const struct ip_tunnel_parm *parms)
{
return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.saddr };
return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.saddr };
}
static union mlxsw_sp_l3addr
mlxsw_sp_ipip_parms6_saddr(struct __ip6_tnl_parm parms)
mlxsw_sp_ipip_parms6_saddr(const struct __ip6_tnl_parm *parms)
{
return (union mlxsw_sp_l3addr) { .addr6 = parms.laddr };
return (union mlxsw_sp_l3addr) { .addr6 = parms->laddr };
}
static union mlxsw_sp_l3addr
mlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms)
mlxsw_sp_ipip_parms4_daddr(const struct ip_tunnel_parm *parms)
{
return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr };
return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.daddr };
}
static union mlxsw_sp_l3addr
mlxsw_sp_ipip_parms6_daddr(struct __ip6_tnl_parm parms)
mlxsw_sp_ipip_parms6_daddr(const struct __ip6_tnl_parm *parms)
{
return (union mlxsw_sp_l3addr) { .addr6 = parms.raddr };
return (union mlxsw_sp_l3addr) { .addr6 = parms->raddr };
}
union mlxsw_sp_l3addr
......@@ -80,10 +102,10 @@ mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
switch (proto) {
case MLXSW_SP_L3_PROTO_IPV4:
parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
return mlxsw_sp_ipip_parms4_saddr(parms4);
return mlxsw_sp_ipip_parms4_saddr(&parms4);
case MLXSW_SP_L3_PROTO_IPV6:
parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
return mlxsw_sp_ipip_parms6_saddr(parms6);
return mlxsw_sp_ipip_parms6_saddr(&parms6);
}
WARN_ON(1);
......@@ -95,7 +117,7 @@ static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
return mlxsw_sp_ipip_parms4_daddr(parms4).addr4;
return mlxsw_sp_ipip_parms4_daddr(&parms4).addr4;
}
static union mlxsw_sp_l3addr
......@@ -108,10 +130,10 @@ mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
switch (proto) {
case MLXSW_SP_L3_PROTO_IPV4:
parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
return mlxsw_sp_ipip_parms4_daddr(parms4);
return mlxsw_sp_ipip_parms4_daddr(&parms4);
case MLXSW_SP_L3_PROTO_IPV6:
parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
return mlxsw_sp_ipip_parms6_daddr(parms6);
return mlxsw_sp_ipip_parms6_daddr(&parms6);
}
WARN_ON(1);
......@@ -125,6 +147,21 @@ bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr)
return !memcmp(&addr, &naddr, sizeof(naddr));
}
static struct mlxsw_sp_ipip_parms
mlxsw_sp_ipip_netdev_parms_init_gre4(const struct net_device *ol_dev)
{
struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
return (struct mlxsw_sp_ipip_parms) {
.proto = MLXSW_SP_L3_PROTO_IPV4,
.saddr = mlxsw_sp_ipip_parms4_saddr(&parms),
.daddr = mlxsw_sp_ipip_parms4_daddr(&parms),
.link = parms.link,
.ikey = mlxsw_sp_ipip_parms4_ikey(&parms),
.okey = mlxsw_sp_ipip_parms4_okey(&parms),
};
}
static int
mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
struct mlxsw_sp_ipip_entry *ipip_entry,
......@@ -158,8 +195,8 @@ mlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp,
u32 ikey;
parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
has_ikey = mlxsw_sp_ipip_parms4_has_ikey(parms);
ikey = mlxsw_sp_ipip_parms4_ikey(parms);
has_ikey = mlxsw_sp_ipip_parms4_has_ikey(&parms);
ikey = mlxsw_sp_ipip_parms4_ikey(&parms);
mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
......@@ -218,12 +255,12 @@ mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(parms) ?
lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(&parms) ?
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
return (struct mlxsw_sp_rif_ipip_lb_config){
.lb_ipipt = lb_ipipt,
.okey = mlxsw_sp_ipip_parms4_okey(parms),
.okey = mlxsw_sp_ipip_parms4_okey(&parms),
.ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
.saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
ol_dev),
......@@ -231,48 +268,39 @@ mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
}
static int
mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_ipip_ol_netdev_change_gre(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
const struct mlxsw_sp_ipip_parms *new_parms,
struct netlink_ext_ack *extack)
{
union mlxsw_sp_l3addr old_saddr, new_saddr;
union mlxsw_sp_l3addr old_daddr, new_daddr;
struct ip_tunnel_parm new_parms;
const struct mlxsw_sp_ipip_parms *old_parms = &ipip_entry->parms;
bool update_tunnel = false;
bool update_decap = false;
bool update_nhs = false;
int err = 0;
new_parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
new_saddr = mlxsw_sp_ipip_parms4_saddr(new_parms);
old_saddr = mlxsw_sp_ipip_parms4_saddr(ipip_entry->parms4);
new_daddr = mlxsw_sp_ipip_parms4_daddr(new_parms);
old_daddr = mlxsw_sp_ipip_parms4_daddr(ipip_entry->parms4);
if (!mlxsw_sp_l3addr_eq(&new_saddr, &old_saddr)) {
if (!mlxsw_sp_l3addr_eq(&new_parms->saddr, &old_parms->saddr)) {
u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
/* Since the local address has changed, if there is another
* tunnel with a matching saddr, both need to be demoted.
*/
if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp,
MLXSW_SP_L3_PROTO_IPV4,
new_saddr, ul_tb_id,
new_parms->proto,
new_parms->saddr,
ul_tb_id,
ipip_entry)) {
mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
return 0;
}
update_tunnel = true;
} else if ((mlxsw_sp_ipip_parms4_okey(ipip_entry->parms4) !=
mlxsw_sp_ipip_parms4_okey(new_parms)) ||
ipip_entry->parms4.link != new_parms.link) {
} else if (old_parms->okey != new_parms->okey ||
old_parms->link != new_parms->link) {
update_tunnel = true;
} else if (!mlxsw_sp_l3addr_eq(&new_daddr, &old_daddr)) {
} else if (!mlxsw_sp_l3addr_eq(&new_parms->daddr, &old_parms->daddr)) {
update_nhs = true;
} else if (mlxsw_sp_ipip_parms4_ikey(ipip_entry->parms4) !=
mlxsw_sp_ipip_parms4_ikey(new_parms)) {
} else if (old_parms->ikey != new_parms->ikey) {
update_decap = true;
}
......@@ -288,23 +316,308 @@ mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
false, false, false,
extack);
ipip_entry->parms4 = new_parms;
if (err)
return err;
ipip_entry->parms = *new_parms;
return 0;
}
static int
mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp_ipip_parms new_parms;
new_parms = mlxsw_sp_ipip_netdev_parms_init_gre4(ipip_entry->ol_dev);
return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
&new_parms, extack);
}
static int
mlxsw_sp_ipip_rem_addr_set_gre4(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
return 0;
}
static void
mlxsw_sp_ipip_rem_addr_unset_gre4(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_ipip_entry *ipip_entry)
{
}
static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = {
.dev_type = ARPHRD_IPGRE,
.ul_proto = MLXSW_SP_L3_PROTO_IPV4,
.inc_parsing_depth = false,
.parms_init = mlxsw_sp_ipip_netdev_parms_init_gre4,
.nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4,
.decap_config = mlxsw_sp_ipip_decap_config_gre4,
.can_offload = mlxsw_sp_ipip_can_offload_gre4,
.ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4,
.ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4,
.rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre4,
.rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre4,
};
static struct mlxsw_sp_ipip_parms
mlxsw_sp1_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
{
struct mlxsw_sp_ipip_parms parms = {0};
WARN_ON_ONCE(1);
return parms;
}
static int
mlxsw_sp1_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
struct mlxsw_sp_ipip_entry *ipip_entry,
bool force, char *ratr_pl)
{
WARN_ON_ONCE(1);
return -EINVAL;
}
static int
mlxsw_sp1_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
u32 tunnel_index)
{
WARN_ON_ONCE(1);
return -EINVAL;
}
static bool mlxsw_sp1_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *ol_dev)
{
return false;
}
static struct mlxsw_sp_rif_ipip_lb_config
mlxsw_sp1_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
const struct net_device *ol_dev)
{
struct mlxsw_sp_rif_ipip_lb_config config = {0};
WARN_ON_ONCE(1);
return config;
}
static int
mlxsw_sp1_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct netlink_ext_ack *extack)
{
WARN_ON_ONCE(1);
return -EINVAL;
}
static int
mlxsw_sp1_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
WARN_ON_ONCE(1);
return -EINVAL;
}
static void
mlxsw_sp1_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_ipip_entry *ipip_entry)
{
WARN_ON_ONCE(1);
}
static const struct mlxsw_sp_ipip_ops mlxsw_sp1_ipip_gre6_ops = {
.dev_type = ARPHRD_IP6GRE,
.ul_proto = MLXSW_SP_L3_PROTO_IPV6,
.inc_parsing_depth = true,
.parms_init = mlxsw_sp1_ipip_netdev_parms_init_gre6,
.nexthop_update = mlxsw_sp1_ipip_nexthop_update_gre6,
.decap_config = mlxsw_sp1_ipip_decap_config_gre6,
.can_offload = mlxsw_sp1_ipip_can_offload_gre6,
.ol_loopback_config = mlxsw_sp1_ipip_ol_loopback_config_gre6,
.ol_netdev_change = mlxsw_sp1_ipip_ol_netdev_change_gre6,
.rem_ip_addr_set = mlxsw_sp1_ipip_rem_addr_set_gre6,
.rem_ip_addr_unset = mlxsw_sp1_ipip_rem_addr_unset_gre6,
};
const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[] = {
const struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[] = {
[MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
[MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp1_ipip_gre6_ops,
};
static struct mlxsw_sp_ipip_parms
mlxsw_sp2_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
{
struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
return (struct mlxsw_sp_ipip_parms) {
.proto = MLXSW_SP_L3_PROTO_IPV6,
.saddr = mlxsw_sp_ipip_parms6_saddr(&parms),
.daddr = mlxsw_sp_ipip_parms6_daddr(&parms),
.link = parms.link,
.ikey = mlxsw_sp_ipip_parms6_ikey(&parms),
.okey = mlxsw_sp_ipip_parms6_okey(&parms),
};
}
static int
mlxsw_sp2_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
struct mlxsw_sp_ipip_entry *ipip_entry,
bool force, char *ratr_pl)
{
u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
enum mlxsw_reg_ratr_op op;
op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
adj_index, rif_index);
mlxsw_reg_ratr_ipip6_entry_pack(ratr_pl,
ipip_entry->dip_kvdl_index);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
}
static int
mlxsw_sp2_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
u32 tunnel_index)
{
u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb);
char rtdp_pl[MLXSW_REG_RTDP_LEN];
struct __ip6_tnl_parm parms;
unsigned int type_check;
bool has_ikey;
u32 ikey;
parms = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
has_ikey = mlxsw_sp_ipip_parms6_has_ikey(&parms);
ikey = mlxsw_sp_ipip_parms6_ikey(&parms);
mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
type_check = has_ikey ?
MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
/* Linux demuxes tunnels based on packet SIP (which must match tunnel
* remote IP). Thus configure decap so that it filters out packets that
* are not IPv6 or have the wrong SIP. IPIP_DECAP_ERROR trap is
* generated for packets that fail this criterion. Linux then handles
* such packets in slow path and generates ICMP destination unreachable.
*/
mlxsw_reg_rtdp_ipip6_pack(rtdp_pl, rif_index,
MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6,
type_check, has_ikey,
ipip_entry->dip_kvdl_index, ikey);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
}
static bool mlxsw_sp2_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *ol_dev)
{
struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(ol_dev);
bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS;
bool inherit_ttl = tparm.hop_limit == 0;
__be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
return (tparm.i_flags & ~okflags) == 0 &&
(tparm.o_flags & ~okflags) == 0 &&
inherit_ttl && inherit_tos &&
mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV6, ol_dev);
}
static struct mlxsw_sp_rif_ipip_lb_config
mlxsw_sp2_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
const struct net_device *ol_dev)
{
struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
lb_ipipt = mlxsw_sp_ipip_parms6_has_okey(&parms) ?
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
return (struct mlxsw_sp_rif_ipip_lb_config){
.lb_ipipt = lb_ipipt,
.okey = mlxsw_sp_ipip_parms6_okey(&parms),
.ul_protocol = MLXSW_SP_L3_PROTO_IPV6,
.saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV6,
ol_dev),
};
}
static int
mlxsw_sp2_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp_ipip_parms new_parms;
new_parms = mlxsw_sp2_ipip_netdev_parms_init_gre6(ipip_entry->ol_dev);
return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
&new_parms, extack);
}
static int
mlxsw_sp2_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
char rips_pl[MLXSW_REG_RIPS_LEN];
struct __ip6_tnl_parm parms6;
int err;
err = mlxsw_sp_kvdl_alloc(mlxsw_sp,
MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
&ipip_entry->dip_kvdl_index);
if (err)
return err;
parms6 = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
mlxsw_reg_rips_pack(rips_pl, ipip_entry->dip_kvdl_index,
&parms6.raddr);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);
if (err)
goto err_rips_write;
return 0;
err_rips_write:
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
ipip_entry->dip_kvdl_index);
return err;
}
static void
mlxsw_sp2_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_ipip_entry *ipip_entry)
{
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
ipip_entry->dip_kvdl_index);
}
static const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = {
.dev_type = ARPHRD_IP6GRE,
.ul_proto = MLXSW_SP_L3_PROTO_IPV6,
.inc_parsing_depth = true,
.parms_init = mlxsw_sp2_ipip_netdev_parms_init_gre6,
.nexthop_update = mlxsw_sp2_ipip_nexthop_update_gre6,
.decap_config = mlxsw_sp2_ipip_decap_config_gre6,
.can_offload = mlxsw_sp2_ipip_can_offload_gre6,
.ol_loopback_config = mlxsw_sp2_ipip_ol_loopback_config_gre6,
.ol_netdev_change = mlxsw_sp2_ipip_ol_netdev_change_gre6,
.rem_ip_addr_set = mlxsw_sp2_ipip_rem_addr_set_gre6,
.rem_ip_addr_unset = mlxsw_sp2_ipip_rem_addr_unset_gre6,
};
const struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[] = {
[MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
[MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp2_ipip_gre6_ops,
};
static int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp,
......@@ -363,3 +676,22 @@ int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
return 0;
}
struct net_device *
mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
{
struct net *net = dev_net(ol_dev);
struct ip_tunnel *tun4;
struct ip6_tnl *tun6;
switch (ol_dev->type) {
case ARPHRD_IPGRE:
tun4 = netdev_priv(ol_dev);
return dev_get_by_index_rcu(net, tun4->parms.link);
case ARPHRD_IP6GRE:
tun6 = netdev_priv(ol_dev);
return dev_get_by_index_rcu(net, tun6->parms.link);
default:
return NULL;
}
}
......@@ -7,6 +7,7 @@
#include "spectrum_router.h"
#include <net/ip_fib.h>
#include <linux/if_tunnel.h>
#include <net/ip6_tunnel.h>
struct ip_tunnel_parm
mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev);
......@@ -21,23 +22,36 @@ bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr);
enum mlxsw_sp_ipip_type {
MLXSW_SP_IPIP_TYPE_GRE4,
MLXSW_SP_IPIP_TYPE_GRE6,
MLXSW_SP_IPIP_TYPE_MAX,
};
struct mlxsw_sp_ipip_parms {
enum mlxsw_sp_l3proto proto;
union mlxsw_sp_l3addr saddr;
union mlxsw_sp_l3addr daddr;
int link;
u32 ikey;
u32 okey;
};
struct mlxsw_sp_ipip_entry {
enum mlxsw_sp_ipip_type ipipt;
struct net_device *ol_dev; /* Overlay. */
struct mlxsw_sp_rif_ipip_lb *ol_lb;
struct mlxsw_sp_fib_entry *decap_fib_entry;
struct list_head ipip_list_node;
union {
struct ip_tunnel_parm parms4;
};
struct mlxsw_sp_ipip_parms parms;
u32 dip_kvdl_index;
};
struct mlxsw_sp_ipip_ops {
int dev_type;
enum mlxsw_sp_l3proto ul_proto; /* Underlay. */
bool inc_parsing_depth;
struct mlxsw_sp_ipip_parms
(*parms_init)(const struct net_device *ol_dev);
int (*nexthop_update)(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
struct mlxsw_sp_ipip_entry *ipip_entry,
......@@ -58,8 +72,13 @@ struct mlxsw_sp_ipip_ops {
int (*ol_netdev_change)(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct netlink_ext_ack *extack);
int (*rem_ip_addr_set)(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry);
void (*rem_ip_addr_unset)(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_ipip_entry *ipip_entry);
};
extern const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[];
extern const struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[];
extern const struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[];
#endif /* _MLXSW_IPIP_H_*/
......@@ -115,6 +115,7 @@ struct mlxsw_sp_rif_ops {
struct mlxsw_sp_router_ops {
int (*init)(struct mlxsw_sp *mlxsw_sp);
int (*ipips_init)(struct mlxsw_sp *mlxsw_sp);
};
static struct mlxsw_sp_rif *
......@@ -1055,22 +1056,13 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
kfree(mlxsw_sp->router->vrs);
}
static struct net_device *
__mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
{
struct ip_tunnel *tun = netdev_priv(ol_dev);
struct net *net = dev_net(ol_dev);
return dev_get_by_index_rcu(net, tun->parms.link);
}
u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
{
struct net_device *d;
u32 tb_id;
rcu_read_lock();
d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
d = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
if (d)
tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
else
......@@ -1116,6 +1108,7 @@ mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_ipip_ops *ipip_ops;
struct mlxsw_sp_ipip_entry *ipip_entry;
struct mlxsw_sp_ipip_entry *ret = NULL;
int err;
ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
ipip_entry = kzalloc(sizeof(*ipip_entry), GFP_KERNEL);
......@@ -1131,26 +1124,30 @@ mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
ipip_entry->ipipt = ipipt;
ipip_entry->ol_dev = ol_dev;
ipip_entry->parms = ipip_ops->parms_init(ol_dev);
switch (ipip_ops->ul_proto) {
case MLXSW_SP_L3_PROTO_IPV4:
ipip_entry->parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
break;
case MLXSW_SP_L3_PROTO_IPV6:
WARN_ON(1);
break;
err = ipip_ops->rem_ip_addr_set(mlxsw_sp, ipip_entry);
if (err) {
ret = ERR_PTR(err);
goto err_rem_ip_addr_set;
}
return ipip_entry;
err_rem_ip_addr_set:
mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
err_ol_ipip_lb_create:
kfree(ipip_entry);
return ret;
}
static void
mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp_ipip_entry *ipip_entry)
static void mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
const struct mlxsw_sp_ipip_ops *ipip_ops =
mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
ipip_ops->rem_ip_addr_unset(mlxsw_sp, ipip_entry);
mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
kfree(ipip_entry);
}
......@@ -1174,6 +1171,32 @@ mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_l3addr_eq(&tun_saddr, &saddr);
}
static int mlxsw_sp_ipip_decap_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_sp_ipip_type ipipt)
{
const struct mlxsw_sp_ipip_ops *ipip_ops;
ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
/* Not all tunnels require to increase the default pasing depth
* (96 bytes).
*/
if (ipip_ops->inc_parsing_depth)
return mlxsw_sp_parsing_depth_inc(mlxsw_sp);
return 0;
}
static void mlxsw_sp_ipip_decap_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_sp_ipip_type ipipt)
{
const struct mlxsw_sp_ipip_ops *ipip_ops =
mlxsw_sp->router->ipip_ops_arr[ipipt];
if (ipip_ops->inc_parsing_depth)
mlxsw_sp_parsing_depth_dec(mlxsw_sp);
}
static int
mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
......@@ -1187,18 +1210,32 @@ mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp *mlxsw_sp,
if (err)
return err;
err = mlxsw_sp_ipip_decap_parsing_depth_inc(mlxsw_sp,
ipip_entry->ipipt);
if (err)
goto err_parsing_depth_inc;
ipip_entry->decap_fib_entry = fib_entry;
fib_entry->decap.ipip_entry = ipip_entry;
fib_entry->decap.tunnel_index = tunnel_index;
return 0;
err_parsing_depth_inc:
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
fib_entry->decap.tunnel_index);
return err;
}
static void mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{
enum mlxsw_sp_ipip_type ipipt = fib_entry->decap.ipip_entry->ipipt;
/* Unlink this node from the IPIP entry that it's the decap entry of. */
fib_entry->decap.ipip_entry->decap_fib_entry = NULL;
fib_entry->decap.ipip_entry = NULL;
mlxsw_sp_ipip_decap_parsing_depth_dec(mlxsw_sp, ipipt);
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1, fib_entry->decap.tunnel_index);
}
......@@ -1309,6 +1346,11 @@ mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
saddr_len = 4;
saddr_prefix_len = 32;
break;
case MLXSW_SP_L3_PROTO_IPV6:
saddrp = &saddr.addr6;
saddr_len = 16;
saddr_prefix_len = 128;
break;
default:
WARN_ON(1);
return NULL;
......@@ -1345,7 +1387,7 @@ mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry)
{
list_del(&ipip_entry->ipip_list_node);
mlxsw_sp_ipip_entry_dealloc(ipip_entry);
mlxsw_sp_ipip_entry_dealloc(mlxsw_sp, ipip_entry);
}
static bool
......@@ -1450,7 +1492,7 @@ mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp,
struct net_device *ipip_ul_dev;
rcu_read_lock();
ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
ipip_ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
rcu_read_unlock();
if (ipip_ul_dev == ul_dev)
......@@ -1536,23 +1578,34 @@ mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id,
u16 ul_rif_id, bool enable)
{
struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
enum mlxsw_reg_ritr_loopback_ipip_options ipip_options;
struct mlxsw_sp_rif *rif = &lb_rif->common;
struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
char ritr_pl[MLXSW_REG_RITR_LEN];
struct in6_addr *saddr6;
u32 saddr4;
ipip_options = MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET;
switch (lb_cf.ul_protocol) {
case MLXSW_SP_L3_PROTO_IPV4:
saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
rif->rif_index, rif->vr_id, rif->dev->mtu);
mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,
ul_vr_id, ul_rif_id, saddr4, lb_cf.okey);
ipip_options, ul_vr_id,
ul_rif_id, saddr4,
lb_cf.okey);
break;
case MLXSW_SP_L3_PROTO_IPV6:
return -EAFNOSUPPORT;
saddr6 = &lb_cf.saddr.addr6;
mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
rif->rif_index, rif->vr_id, rif->dev->mtu);
mlxsw_reg_ritr_loopback_ipip6_pack(ritr_pl, lb_cf.lb_ipipt,
ipip_options, ul_vr_id,
ul_rif_id, saddr6,
lb_cf.okey);
break;
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
......@@ -1827,7 +1880,7 @@ static void mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp *mlxsw_sp,
struct net_device *ipip_ul_dev;
rcu_read_lock();
ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
ipip_ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
rcu_read_unlock();
if (ipip_ul_dev == ul_dev)
mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
......@@ -4152,7 +4205,7 @@ static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
bool is_up;
rcu_read_lock();
ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
is_up = ul_dev ? (ul_dev->flags & IFF_UP) : true;
rcu_read_unlock();
......@@ -6069,7 +6122,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
}
static void
mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_fib_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{
switch (fib_entry->type) {
......@@ -6081,6 +6134,13 @@ mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
}
}
static void
mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib4_entry *fib4_entry)
{
mlxsw_sp_fib_entry_type_unset(mlxsw_sp, &fib4_entry->common);
}
static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node,
......@@ -6141,7 +6201,7 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
fib_info_put(fib4_entry->fi);
mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common);
mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib4_entry);
mlxsw_sp_nexthop_group_vr_unlink(fib4_entry->common.nh_group,
fib_node->fib);
mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
......@@ -6927,11 +6987,38 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_nexthop6_group_update(mlxsw_sp, op_ctx, fib6_entry);
}
static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
static int
mlxsw_sp_fib6_entry_type_set_local(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
const struct fib6_info *rt)
{
struct mlxsw_sp_nexthop_group_info *nhgi = fib_entry->nh_group->nhgi;
union mlxsw_sp_l3addr dip = { .addr6 = rt->fib6_dst.addr };
int ifindex = nhgi->nexthops[0].ifindex;
struct mlxsw_sp_ipip_entry *ipip_entry;
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, ifindex,
MLXSW_SP_L3_PROTO_IPV6,
dip);
if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
return mlxsw_sp_fib_entry_decap_init(mlxsw_sp, fib_entry,
ipip_entry);
}
return 0;
}
static int mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
const struct fib6_info *rt)
{
if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
if (rt->fib6_flags & RTF_LOCAL)
return mlxsw_sp_fib6_entry_type_set_local(mlxsw_sp, fib_entry,
rt);
if (rt->fib6_flags & RTF_ANYCAST)
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
else if (rt->fib6_type == RTN_BLACKHOLE)
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
......@@ -6941,6 +7028,8 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
else
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
return 0;
}
static void
......@@ -6998,12 +7087,16 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_nexthop_group_vr_link;
mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
err = mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
if (err)
goto err_fib6_entry_type_set;
fib_entry->fib_node = fib_node;
return fib6_entry;
err_fib6_entry_type_set:
mlxsw_sp_nexthop_group_vr_unlink(fib_entry->nh_group, fib_node->fib);
err_nexthop_group_vr_link:
mlxsw_sp_nexthop6_group_put(mlxsw_sp, fib_entry);
err_nexthop6_group_get:
......@@ -7022,11 +7115,19 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
return ERR_PTR(err);
}
static void
mlxsw_sp_fib6_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib6_entry *fib6_entry)
{
mlxsw_sp_fib_entry_type_unset(mlxsw_sp, &fib6_entry->common);
}
static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib6_entry *fib6_entry)
{
struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
mlxsw_sp_fib6_entry_type_unset(mlxsw_sp, fib6_entry);
mlxsw_sp_nexthop_group_vr_unlink(fib6_entry->common.nh_group,
fib_node->fib);
mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
......@@ -9476,7 +9577,6 @@ static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
{
int err;
mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr;
INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list);
err = mlxsw_sp_ipip_ecn_encap_init(mlxsw_sp);
......@@ -9489,6 +9589,18 @@ static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
return mlxsw_sp_ipip_config_tigcr(mlxsw_sp);
}
static int mlxsw_sp1_ipips_init(struct mlxsw_sp *mlxsw_sp)
{
mlxsw_sp->router->ipip_ops_arr = mlxsw_sp1_ipip_ops_arr;
return mlxsw_sp_ipips_init(mlxsw_sp);
}
static int mlxsw_sp2_ipips_init(struct mlxsw_sp *mlxsw_sp)
{
mlxsw_sp->router->ipip_ops_arr = mlxsw_sp2_ipip_ops_arr;
return mlxsw_sp_ipips_init(mlxsw_sp);
}
static void mlxsw_sp_ipips_fini(struct mlxsw_sp *mlxsw_sp)
{
WARN_ON(!list_empty(&mlxsw_sp->router->ipip_list));
......@@ -9903,6 +10015,7 @@ static int mlxsw_sp1_router_init(struct mlxsw_sp *mlxsw_sp)
const struct mlxsw_sp_router_ops mlxsw_sp1_router_ops = {
.init = mlxsw_sp1_router_init,
.ipips_init = mlxsw_sp1_ipips_init,
};
static int mlxsw_sp2_router_init(struct mlxsw_sp *mlxsw_sp)
......@@ -9918,6 +10031,7 @@ static int mlxsw_sp2_router_init(struct mlxsw_sp *mlxsw_sp)
const struct mlxsw_sp_router_ops mlxsw_sp2_router_ops = {
.init = mlxsw_sp2_router_init,
.ipips_init = mlxsw_sp2_ipips_init,
};
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
......@@ -9963,7 +10077,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_rifs_init;
err = mlxsw_sp_ipips_init(mlxsw_sp);
err = mlxsw_sp->router_ops->ipips_init(mlxsw_sp);
if (err)
goto err_ipips_init;
......
......@@ -226,6 +226,8 @@ static inline bool mlxsw_sp_l3addr_eq(const union mlxsw_sp_l3addr *addr1,
int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp);
struct net_device *
mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev);
extern const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_xm_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment