138ebc0f4SPetr Machata /* 238ebc0f4SPetr Machata * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c 338ebc0f4SPetr Machata * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 438ebc0f4SPetr Machata * Copyright (c) 2017 Petr Machata <petrm@mellanox.com> 538ebc0f4SPetr Machata * 638ebc0f4SPetr Machata * Redistribution and use in source and binary forms, with or without 738ebc0f4SPetr Machata * modification, are permitted provided that the following conditions are met: 838ebc0f4SPetr Machata * 938ebc0f4SPetr Machata * 1. Redistributions of source code must retain the above copyright 1038ebc0f4SPetr Machata * notice, this list of conditions and the following disclaimer. 1138ebc0f4SPetr Machata * 2. Redistributions in binary form must reproduce the above copyright 1238ebc0f4SPetr Machata * notice, this list of conditions and the following disclaimer in the 1338ebc0f4SPetr Machata * documentation and/or other materials provided with the distribution. 1438ebc0f4SPetr Machata * 3. Neither the names of the copyright holders nor the names of its 1538ebc0f4SPetr Machata * contributors may be used to endorse or promote products derived from 1638ebc0f4SPetr Machata * this software without specific prior written permission. 1738ebc0f4SPetr Machata * 1838ebc0f4SPetr Machata * Alternatively, this software may be distributed under the terms of the 1938ebc0f4SPetr Machata * GNU General Public License ("GPL") version 2 as published by the Free 2038ebc0f4SPetr Machata * Software Foundation. 2138ebc0f4SPetr Machata * 2238ebc0f4SPetr Machata * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2338ebc0f4SPetr Machata * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2438ebc0f4SPetr Machata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538ebc0f4SPetr Machata * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2638ebc0f4SPetr Machata * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2738ebc0f4SPetr Machata * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2838ebc0f4SPetr Machata * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2938ebc0f4SPetr Machata * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3038ebc0f4SPetr Machata * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3138ebc0f4SPetr Machata * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3238ebc0f4SPetr Machata * POSSIBILITY OF SUCH DAMAGE. 3338ebc0f4SPetr Machata */ 3438ebc0f4SPetr Machata 35ee954d1aSPetr Machata #include <net/ip_tunnels.h> 36ee954d1aSPetr Machata 3738ebc0f4SPetr Machata #include "spectrum_ipip.h" 3838ebc0f4SPetr Machata 39ee954d1aSPetr Machata static bool 40ee954d1aSPetr Machata mlxsw_sp_ipip_netdev_has_ikey(const struct net_device *ol_dev) 41ee954d1aSPetr Machata { 42ee954d1aSPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 43ee954d1aSPetr Machata 44ee954d1aSPetr Machata return !!(tun->parms.i_flags & TUNNEL_KEY); 45ee954d1aSPetr Machata } 46ee954d1aSPetr Machata 47ee954d1aSPetr Machata static bool 48ee954d1aSPetr Machata mlxsw_sp_ipip_netdev_has_okey(const struct net_device *ol_dev) 49ee954d1aSPetr Machata { 50ee954d1aSPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 51ee954d1aSPetr Machata 52ee954d1aSPetr Machata return !!(tun->parms.o_flags & TUNNEL_KEY); 53ee954d1aSPetr Machata } 54ee954d1aSPetr Machata 55ee954d1aSPetr Machata static u32 mlxsw_sp_ipip_netdev_ikey(const struct net_device *ol_dev) 56ee954d1aSPetr Machata { 57ee954d1aSPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 58ee954d1aSPetr Machata 59ee954d1aSPetr Machata return mlxsw_sp_ipip_netdev_has_ikey(ol_dev) ? 60ee954d1aSPetr Machata be32_to_cpu(tun->parms.i_key) : 0; 61ee954d1aSPetr Machata } 62ee954d1aSPetr Machata 63ee954d1aSPetr Machata static u32 mlxsw_sp_ipip_netdev_okey(const struct net_device *ol_dev) 64ee954d1aSPetr Machata { 65ee954d1aSPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 66ee954d1aSPetr Machata 67ee954d1aSPetr Machata return mlxsw_sp_ipip_netdev_has_okey(ol_dev) ? 68ee954d1aSPetr Machata be32_to_cpu(tun->parms.o_key) : 0; 69ee954d1aSPetr Machata } 70ee954d1aSPetr Machata 71*474f0ff6SPetr Machata static __be32 72*474f0ff6SPetr Machata mlxsw_sp_ipip_netdev_saddr4(const struct net_device *ol_dev) 73*474f0ff6SPetr Machata { 74*474f0ff6SPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 75*474f0ff6SPetr Machata 76*474f0ff6SPetr Machata return tun->parms.iph.saddr; 77*474f0ff6SPetr Machata } 78*474f0ff6SPetr Machata 79*474f0ff6SPetr Machata union mlxsw_sp_l3addr 80*474f0ff6SPetr Machata mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 81*474f0ff6SPetr Machata const struct net_device *ol_dev) 82*474f0ff6SPetr Machata { 83*474f0ff6SPetr Machata switch (proto) { 84*474f0ff6SPetr Machata case MLXSW_SP_L3_PROTO_IPV4: 85*474f0ff6SPetr Machata return (union mlxsw_sp_l3addr) { 86*474f0ff6SPetr Machata .addr4 = mlxsw_sp_ipip_netdev_saddr4(ol_dev), 87*474f0ff6SPetr Machata }; 88*474f0ff6SPetr Machata case MLXSW_SP_L3_PROTO_IPV6: 89*474f0ff6SPetr Machata break; 90*474f0ff6SPetr Machata } 91*474f0ff6SPetr Machata 92*474f0ff6SPetr Machata WARN_ON(1); 93*474f0ff6SPetr Machata return (union mlxsw_sp_l3addr) { 94*474f0ff6SPetr Machata .addr4 = 0, 95*474f0ff6SPetr Machata }; 96*474f0ff6SPetr Machata } 97*474f0ff6SPetr Machata 98*474f0ff6SPetr Machata static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev) 99*474f0ff6SPetr Machata { 100*474f0ff6SPetr Machata struct ip_tunnel *tun = netdev_priv(ol_dev); 101*474f0ff6SPetr Machata 102*474f0ff6SPetr Machata return tun->parms.iph.daddr; 103*474f0ff6SPetr Machata } 104*474f0ff6SPetr Machata 105*474f0ff6SPetr Machata static union mlxsw_sp_l3addr 106*474f0ff6SPetr Machata mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto, 107*474f0ff6SPetr Machata const struct net_device *ol_dev) 108*474f0ff6SPetr Machata { 109*474f0ff6SPetr Machata switch (proto) { 110*474f0ff6SPetr Machata case MLXSW_SP_L3_PROTO_IPV4: 111*474f0ff6SPetr Machata return (union mlxsw_sp_l3addr) { 112*474f0ff6SPetr Machata .addr4 = mlxsw_sp_ipip_netdev_daddr4(ol_dev), 113*474f0ff6SPetr Machata }; 114*474f0ff6SPetr Machata case MLXSW_SP_L3_PROTO_IPV6: 115*474f0ff6SPetr Machata break; 116*474f0ff6SPetr Machata } 117*474f0ff6SPetr Machata 118*474f0ff6SPetr Machata WARN_ON(1); 119*474f0ff6SPetr Machata return (union mlxsw_sp_l3addr) { 120*474f0ff6SPetr Machata .addr4 = 0, 121*474f0ff6SPetr Machata }; 122*474f0ff6SPetr Machata } 123*474f0ff6SPetr Machata 124ee954d1aSPetr Machata static int 125ee954d1aSPetr Machata mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 126ee954d1aSPetr Machata struct mlxsw_sp_ipip_entry *ipip_entry) 127ee954d1aSPetr Machata { 128ee954d1aSPetr Machata u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 129ee954d1aSPetr Machata __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev); 130ee954d1aSPetr Machata char ratr_pl[MLXSW_REG_RATR_LEN]; 131ee954d1aSPetr Machata 132ee954d1aSPetr Machata mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, 133ee954d1aSPetr Machata true, MLXSW_REG_RATR_TYPE_IPIP, 134ee954d1aSPetr Machata adj_index, rif_index); 135ee954d1aSPetr Machata mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4)); 136ee954d1aSPetr Machata 137ee954d1aSPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); 138ee954d1aSPetr Machata } 139ee954d1aSPetr Machata 140ee954d1aSPetr Machata static int 141ee954d1aSPetr Machata mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp, 142ee954d1aSPetr Machata u32 tunnel_index, 143ee954d1aSPetr Machata struct mlxsw_sp_ipip_entry *ipip_entry) 144ee954d1aSPetr Machata { 145ee954d1aSPetr Machata bool has_ikey = mlxsw_sp_ipip_netdev_has_ikey(ipip_entry->ol_dev); 146ee954d1aSPetr Machata u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 147ee954d1aSPetr Machata u32 ikey = mlxsw_sp_ipip_netdev_ikey(ipip_entry->ol_dev); 148ee954d1aSPetr Machata char rtdp_pl[MLXSW_REG_RTDP_LEN]; 149ee954d1aSPetr Machata unsigned int type_check; 150ee954d1aSPetr Machata u32 daddr4; 151ee954d1aSPetr Machata 152ee954d1aSPetr Machata mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); 153ee954d1aSPetr Machata 154ee954d1aSPetr Machata type_check = has_ikey ? 155ee954d1aSPetr Machata MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : 156ee954d1aSPetr Machata MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; 157ee954d1aSPetr Machata 158ee954d1aSPetr Machata /* Linux demuxes tunnels based on packet SIP (which must match tunnel 159ee954d1aSPetr Machata * remote IP). Thus configure decap so that it filters out packets that 160ee954d1aSPetr Machata * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is 161ee954d1aSPetr Machata * generated for packets that fail this criterion. Linux then handles 162ee954d1aSPetr Machata * such packets in slow path and generates ICMP destination unreachable. 163ee954d1aSPetr Machata */ 164ee954d1aSPetr Machata daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev)); 165ee954d1aSPetr Machata mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index, 166ee954d1aSPetr Machata MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, 167ee954d1aSPetr Machata type_check, has_ikey, daddr4, ikey); 168ee954d1aSPetr Machata 169ee954d1aSPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); 170ee954d1aSPetr Machata } 171ee954d1aSPetr Machata 172ee954d1aSPetr Machata static int 173ee954d1aSPetr Machata mlxsw_sp_ipip_fib_entry_op_gre4_ralue(struct mlxsw_sp *mlxsw_sp, 174ee954d1aSPetr Machata u32 dip, u8 prefix_len, u16 ul_vr_id, 175ee954d1aSPetr Machata enum mlxsw_reg_ralue_op op, 176ee954d1aSPetr Machata u32 tunnel_index) 177ee954d1aSPetr Machata { 178ee954d1aSPetr Machata char ralue_pl[MLXSW_REG_RALUE_LEN]; 179ee954d1aSPetr Machata 180ee954d1aSPetr Machata mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_REG_RALXX_PROTOCOL_IPV4, op, 181ee954d1aSPetr Machata ul_vr_id, prefix_len, dip); 182ee954d1aSPetr Machata mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, tunnel_index); 183ee954d1aSPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); 184ee954d1aSPetr Machata } 185ee954d1aSPetr Machata 186ee954d1aSPetr Machata static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp, 187ee954d1aSPetr Machata struct mlxsw_sp_ipip_entry *ipip_entry, 188ee954d1aSPetr Machata enum mlxsw_reg_ralue_op op, 189ee954d1aSPetr Machata u32 tunnel_index) 190ee954d1aSPetr Machata { 191ee954d1aSPetr Machata u16 ul_vr_id = mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb); 192ee954d1aSPetr Machata __be32 dip; 193ee954d1aSPetr Machata int err; 194ee954d1aSPetr Machata 195ee954d1aSPetr Machata err = mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(mlxsw_sp, tunnel_index, 196ee954d1aSPetr Machata ipip_entry); 197ee954d1aSPetr Machata if (err) 198ee954d1aSPetr Machata return err; 199ee954d1aSPetr Machata 200ee954d1aSPetr Machata dip = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 201ee954d1aSPetr Machata ipip_entry->ol_dev).addr4; 202ee954d1aSPetr Machata return mlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp, be32_to_cpu(dip), 203ee954d1aSPetr Machata 32, ul_vr_id, op, 204ee954d1aSPetr Machata tunnel_index); 205ee954d1aSPetr Machata } 206ee954d1aSPetr Machata 207ee954d1aSPetr Machata static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, 208ee954d1aSPetr Machata const struct net_device *ol_dev) 209ee954d1aSPetr Machata { 210ee954d1aSPetr Machata union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); 211ee954d1aSPetr Machata union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); 212ee954d1aSPetr Machata union mlxsw_sp_l3addr naddr = {0}; 213ee954d1aSPetr Machata 214ee954d1aSPetr Machata /* Tunnels with unset local or remote address are valid in Linux and 215ee954d1aSPetr Machata * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access 216ee954d1aSPetr Machata * (NBMA) tunnels. In principle these can be offloaded, but the driver 217ee954d1aSPetr Machata * currently doesn't support this. So punt. 218ee954d1aSPetr Machata */ 219ee954d1aSPetr Machata return memcmp(&saddr, &naddr, sizeof(naddr)) && 220ee954d1aSPetr Machata memcmp(&daddr, &naddr, sizeof(naddr)); 221ee954d1aSPetr Machata } 222ee954d1aSPetr Machata 223ee954d1aSPetr Machata static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, 224ee954d1aSPetr Machata const struct net_device *ol_dev, 225ee954d1aSPetr Machata enum mlxsw_sp_l3proto ol_proto) 226ee954d1aSPetr Machata { 227ee954d1aSPetr Machata struct ip_tunnel *tunnel = netdev_priv(ol_dev); 228ee954d1aSPetr Machata __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ 229ee954d1aSPetr Machata bool inherit_ttl = tunnel->parms.iph.ttl == 0; 230ee954d1aSPetr Machata bool inherit_tos = tunnel->parms.iph.tos & 0x1; 231ee954d1aSPetr Machata 232ee954d1aSPetr Machata return (tunnel->parms.i_flags & ~okflags) == 0 && 233ee954d1aSPetr Machata (tunnel->parms.o_flags & ~okflags) == 0 && 234ee954d1aSPetr Machata inherit_ttl && inherit_tos && 235ee954d1aSPetr Machata mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev); 236ee954d1aSPetr Machata } 237ee954d1aSPetr Machata 238ee954d1aSPetr Machata static struct mlxsw_sp_rif_ipip_lb_config 239ee954d1aSPetr Machata mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp, 240ee954d1aSPetr Machata const struct net_device *ol_dev) 241ee954d1aSPetr Machata { 242ee954d1aSPetr Machata enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; 243ee954d1aSPetr Machata 244ee954d1aSPetr Machata lb_ipipt = mlxsw_sp_ipip_netdev_has_okey(ol_dev) ? 245ee954d1aSPetr Machata MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : 246ee954d1aSPetr Machata MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; 247ee954d1aSPetr Machata return (struct mlxsw_sp_rif_ipip_lb_config){ 248ee954d1aSPetr Machata .lb_ipipt = lb_ipipt, 249ee954d1aSPetr Machata .okey = mlxsw_sp_ipip_netdev_okey(ol_dev), 250ee954d1aSPetr Machata .ul_protocol = MLXSW_SP_L3_PROTO_IPV4, 251ee954d1aSPetr Machata .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 252ee954d1aSPetr Machata ol_dev), 253ee954d1aSPetr Machata }; 254ee954d1aSPetr Machata } 255ee954d1aSPetr Machata 256ee954d1aSPetr Machata static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = { 257ee954d1aSPetr Machata .dev_type = ARPHRD_IPGRE, 258ee954d1aSPetr Machata .ul_proto = MLXSW_SP_L3_PROTO_IPV4, 259ee954d1aSPetr Machata .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4, 260ee954d1aSPetr Machata .fib_entry_op = mlxsw_sp_ipip_fib_entry_op_gre4, 261ee954d1aSPetr Machata .can_offload = mlxsw_sp_ipip_can_offload_gre4, 262ee954d1aSPetr Machata .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4, 263ee954d1aSPetr Machata }; 264ee954d1aSPetr Machata 26538ebc0f4SPetr Machata const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[] = { 266ee954d1aSPetr Machata [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, 26738ebc0f4SPetr Machata }; 268