Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
0003 
0004 #include <net/ip_tunnels.h>
0005 #include <net/ip6_tunnel.h>
0006 #include <net/inet_ecn.h>
0007 
0008 #include "spectrum_ipip.h"
0009 #include "reg.h"
0010 
0011 struct ip_tunnel_parm
0012 mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev)
0013 {
0014     struct ip_tunnel *tun = netdev_priv(ol_dev);
0015 
0016     return tun->parms;
0017 }
0018 
0019 struct __ip6_tnl_parm
0020 mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev)
0021 {
0022     struct ip6_tnl *tun = netdev_priv(ol_dev);
0023 
0024     return tun->parms;
0025 }
0026 
0027 static bool mlxsw_sp_ipip_parms4_has_ikey(const struct ip_tunnel_parm *parms)
0028 {
0029     return !!(parms->i_flags & TUNNEL_KEY);
0030 }
0031 
0032 static bool mlxsw_sp_ipip_parms6_has_ikey(const struct __ip6_tnl_parm *parms)
0033 {
0034     return !!(parms->i_flags & TUNNEL_KEY);
0035 }
0036 
0037 static bool mlxsw_sp_ipip_parms4_has_okey(const struct ip_tunnel_parm *parms)
0038 {
0039     return !!(parms->o_flags & TUNNEL_KEY);
0040 }
0041 
0042 static bool mlxsw_sp_ipip_parms6_has_okey(const struct __ip6_tnl_parm *parms)
0043 {
0044     return !!(parms->o_flags & TUNNEL_KEY);
0045 }
0046 
0047 static u32 mlxsw_sp_ipip_parms4_ikey(const struct ip_tunnel_parm *parms)
0048 {
0049     return mlxsw_sp_ipip_parms4_has_ikey(parms) ?
0050         be32_to_cpu(parms->i_key) : 0;
0051 }
0052 
0053 static u32 mlxsw_sp_ipip_parms6_ikey(const struct __ip6_tnl_parm *parms)
0054 {
0055     return mlxsw_sp_ipip_parms6_has_ikey(parms) ?
0056         be32_to_cpu(parms->i_key) : 0;
0057 }
0058 
0059 static u32 mlxsw_sp_ipip_parms4_okey(const struct ip_tunnel_parm *parms)
0060 {
0061     return mlxsw_sp_ipip_parms4_has_okey(parms) ?
0062         be32_to_cpu(parms->o_key) : 0;
0063 }
0064 
0065 static u32 mlxsw_sp_ipip_parms6_okey(const struct __ip6_tnl_parm *parms)
0066 {
0067     return mlxsw_sp_ipip_parms6_has_okey(parms) ?
0068         be32_to_cpu(parms->o_key) : 0;
0069 }
0070 
0071 static union mlxsw_sp_l3addr
0072 mlxsw_sp_ipip_parms4_saddr(const struct ip_tunnel_parm *parms)
0073 {
0074     return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.saddr };
0075 }
0076 
0077 static union mlxsw_sp_l3addr
0078 mlxsw_sp_ipip_parms6_saddr(const struct __ip6_tnl_parm *parms)
0079 {
0080     return (union mlxsw_sp_l3addr) { .addr6 = parms->laddr };
0081 }
0082 
0083 static union mlxsw_sp_l3addr
0084 mlxsw_sp_ipip_parms4_daddr(const struct ip_tunnel_parm *parms)
0085 {
0086     return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.daddr };
0087 }
0088 
0089 static union mlxsw_sp_l3addr
0090 mlxsw_sp_ipip_parms6_daddr(const struct __ip6_tnl_parm *parms)
0091 {
0092     return (union mlxsw_sp_l3addr) { .addr6 = parms->raddr };
0093 }
0094 
0095 union mlxsw_sp_l3addr
0096 mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
0097                const struct net_device *ol_dev)
0098 {
0099     struct ip_tunnel_parm parms4;
0100     struct __ip6_tnl_parm parms6;
0101 
0102     switch (proto) {
0103     case MLXSW_SP_L3_PROTO_IPV4:
0104         parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
0105         return mlxsw_sp_ipip_parms4_saddr(&parms4);
0106     case MLXSW_SP_L3_PROTO_IPV6:
0107         parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
0108         return mlxsw_sp_ipip_parms6_saddr(&parms6);
0109     }
0110 
0111     WARN_ON(1);
0112     return (union mlxsw_sp_l3addr) {0};
0113 }
0114 
0115 static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
0116 {
0117 
0118     struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
0119 
0120     return mlxsw_sp_ipip_parms4_daddr(&parms4).addr4;
0121 }
0122 
0123 static union mlxsw_sp_l3addr
0124 mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
0125                const struct net_device *ol_dev)
0126 {
0127     struct ip_tunnel_parm parms4;
0128     struct __ip6_tnl_parm parms6;
0129 
0130     switch (proto) {
0131     case MLXSW_SP_L3_PROTO_IPV4:
0132         parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
0133         return mlxsw_sp_ipip_parms4_daddr(&parms4);
0134     case MLXSW_SP_L3_PROTO_IPV6:
0135         parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
0136         return mlxsw_sp_ipip_parms6_daddr(&parms6);
0137     }
0138 
0139     WARN_ON(1);
0140     return (union mlxsw_sp_l3addr) {0};
0141 }
0142 
0143 bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr)
0144 {
0145     union mlxsw_sp_l3addr naddr = {0};
0146 
0147     return !memcmp(&addr, &naddr, sizeof(naddr));
0148 }
0149 
0150 static struct mlxsw_sp_ipip_parms
0151 mlxsw_sp_ipip_netdev_parms_init_gre4(const struct net_device *ol_dev)
0152 {
0153     struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
0154 
0155     return (struct mlxsw_sp_ipip_parms) {
0156         .proto = MLXSW_SP_L3_PROTO_IPV4,
0157         .saddr = mlxsw_sp_ipip_parms4_saddr(&parms),
0158         .daddr = mlxsw_sp_ipip_parms4_daddr(&parms),
0159         .link = parms.link,
0160         .ikey = mlxsw_sp_ipip_parms4_ikey(&parms),
0161         .okey = mlxsw_sp_ipip_parms4_okey(&parms),
0162     };
0163 }
0164 
0165 static int
0166 mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
0167                   struct mlxsw_sp_ipip_entry *ipip_entry,
0168                   bool force, char *ratr_pl)
0169 {
0170     u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
0171     __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev);
0172     enum mlxsw_reg_ratr_op op;
0173 
0174     op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
0175              MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
0176     mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
0177                 adj_index, rif_index);
0178     mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4));
0179 
0180     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
0181 }
0182 
0183 static int
0184 mlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp,
0185                 struct mlxsw_sp_ipip_entry *ipip_entry,
0186                 u32 tunnel_index)
0187 {
0188     u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
0189     u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb);
0190     char rtdp_pl[MLXSW_REG_RTDP_LEN];
0191     struct ip_tunnel_parm parms;
0192     unsigned int type_check;
0193     bool has_ikey;
0194     u32 daddr4;
0195     u32 ikey;
0196 
0197     parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
0198     has_ikey = mlxsw_sp_ipip_parms4_has_ikey(&parms);
0199     ikey = mlxsw_sp_ipip_parms4_ikey(&parms);
0200 
0201     mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
0202     mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
0203 
0204     type_check = has_ikey ?
0205         MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
0206         MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
0207 
0208     /* Linux demuxes tunnels based on packet SIP (which must match tunnel
0209      * remote IP). Thus configure decap so that it filters out packets that
0210      * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is
0211      * generated for packets that fail this criterion. Linux then handles
0212      * such packets in slow path and generates ICMP destination unreachable.
0213      */
0214     daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev));
0215     mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index,
0216                   MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,
0217                   type_check, has_ikey, daddr4, ikey);
0218 
0219     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
0220 }
0221 
0222 static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto,
0223                       const struct net_device *ol_dev)
0224 {
0225     union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev);
0226     union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev);
0227 
0228     /* Tunnels with unset local or remote address are valid in Linux and
0229      * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access
0230      * (NBMA) tunnels. In principle these can be offloaded, but the driver
0231      * currently doesn't support this. So punt.
0232      */
0233     return !mlxsw_sp_l3addr_is_zero(saddr) &&
0234            !mlxsw_sp_l3addr_is_zero(daddr);
0235 }
0236 
0237 static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp,
0238                        const struct net_device *ol_dev)
0239 {
0240     struct ip_tunnel *tunnel = netdev_priv(ol_dev);
0241     __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
0242     bool inherit_ttl = tunnel->parms.iph.ttl == 0;
0243     bool inherit_tos = tunnel->parms.iph.tos & 0x1;
0244 
0245     return (tunnel->parms.i_flags & ~okflags) == 0 &&
0246            (tunnel->parms.o_flags & ~okflags) == 0 &&
0247            inherit_ttl && inherit_tos &&
0248            mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev);
0249 }
0250 
0251 static struct mlxsw_sp_rif_ipip_lb_config
0252 mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
0253                       const struct net_device *ol_dev)
0254 {
0255     struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
0256     enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
0257 
0258     lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(&parms) ?
0259         MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
0260         MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
0261     return (struct mlxsw_sp_rif_ipip_lb_config){
0262         .lb_ipipt = lb_ipipt,
0263         .okey = mlxsw_sp_ipip_parms4_okey(&parms),
0264         .ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
0265         .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
0266                             ol_dev),
0267     };
0268 }
0269 
0270 static int
0271 mlxsw_sp_ipip_ol_netdev_change_gre(struct mlxsw_sp *mlxsw_sp,
0272                    struct mlxsw_sp_ipip_entry *ipip_entry,
0273                    const struct mlxsw_sp_ipip_parms *new_parms,
0274                    struct netlink_ext_ack *extack)
0275 {
0276     const struct mlxsw_sp_ipip_parms *old_parms = &ipip_entry->parms;
0277     bool update_tunnel = false;
0278     bool update_decap = false;
0279     bool update_nhs = false;
0280     int err = 0;
0281 
0282     if (!mlxsw_sp_l3addr_eq(&new_parms->saddr, &old_parms->saddr)) {
0283         u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
0284 
0285         /* Since the local address has changed, if there is another
0286          * tunnel with a matching saddr, both need to be demoted.
0287          */
0288         if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp,
0289                              new_parms->proto,
0290                              new_parms->saddr,
0291                              ul_tb_id,
0292                              ipip_entry)) {
0293             mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
0294             return 0;
0295         }
0296 
0297         update_tunnel = true;
0298     } else if (old_parms->okey != new_parms->okey ||
0299            old_parms->link != new_parms->link) {
0300         update_tunnel = true;
0301     } else if (!mlxsw_sp_l3addr_eq(&new_parms->daddr, &old_parms->daddr)) {
0302         update_nhs = true;
0303     } else if (old_parms->ikey != new_parms->ikey) {
0304         update_decap = true;
0305     }
0306 
0307     if (update_tunnel)
0308         err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
0309                               true, true, true,
0310                               extack);
0311     else if (update_nhs)
0312         err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
0313                               false, false, true,
0314                               extack);
0315     else if (update_decap)
0316         err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
0317                               false, false, false,
0318                               extack);
0319     if (err)
0320         return err;
0321 
0322     ipip_entry->parms = *new_parms;
0323     return 0;
0324 }
0325 
0326 static int
0327 mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
0328                     struct mlxsw_sp_ipip_entry *ipip_entry,
0329                     struct netlink_ext_ack *extack)
0330 {
0331     struct mlxsw_sp_ipip_parms new_parms;
0332 
0333     new_parms = mlxsw_sp_ipip_netdev_parms_init_gre4(ipip_entry->ol_dev);
0334     return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
0335                           &new_parms, extack);
0336 }
0337 
0338 static int
0339 mlxsw_sp_ipip_rem_addr_set_gre4(struct mlxsw_sp *mlxsw_sp,
0340                 struct mlxsw_sp_ipip_entry *ipip_entry)
0341 {
0342     return 0;
0343 }
0344 
0345 static void
0346 mlxsw_sp_ipip_rem_addr_unset_gre4(struct mlxsw_sp *mlxsw_sp,
0347                   const struct mlxsw_sp_ipip_entry *ipip_entry)
0348 {
0349 }
0350 
0351 static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = {
0352     .dev_type = ARPHRD_IPGRE,
0353     .ul_proto = MLXSW_SP_L3_PROTO_IPV4,
0354     .inc_parsing_depth = false,
0355     .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre4,
0356     .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4,
0357     .decap_config = mlxsw_sp_ipip_decap_config_gre4,
0358     .can_offload = mlxsw_sp_ipip_can_offload_gre4,
0359     .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4,
0360     .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4,
0361     .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre4,
0362     .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre4,
0363 };
0364 
0365 static struct mlxsw_sp_ipip_parms
0366 mlxsw_sp1_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
0367 {
0368     struct mlxsw_sp_ipip_parms parms = {0};
0369 
0370     WARN_ON_ONCE(1);
0371     return parms;
0372 }
0373 
0374 static int
0375 mlxsw_sp1_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
0376                    struct mlxsw_sp_ipip_entry *ipip_entry,
0377                    bool force, char *ratr_pl)
0378 {
0379     WARN_ON_ONCE(1);
0380     return -EINVAL;
0381 }
0382 
0383 static int
0384 mlxsw_sp1_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
0385                  struct mlxsw_sp_ipip_entry *ipip_entry,
0386                  u32 tunnel_index)
0387 {
0388     WARN_ON_ONCE(1);
0389     return -EINVAL;
0390 }
0391 
0392 static bool mlxsw_sp1_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
0393                         const struct net_device *ol_dev)
0394 {
0395     return false;
0396 }
0397 
0398 static struct mlxsw_sp_rif_ipip_lb_config
0399 mlxsw_sp1_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
0400                        const struct net_device *ol_dev)
0401 {
0402     struct mlxsw_sp_rif_ipip_lb_config config = {0};
0403 
0404     WARN_ON_ONCE(1);
0405     return config;
0406 }
0407 
0408 static int
0409 mlxsw_sp1_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
0410                      struct mlxsw_sp_ipip_entry *ipip_entry,
0411                      struct netlink_ext_ack *extack)
0412 {
0413     WARN_ON_ONCE(1);
0414     return -EINVAL;
0415 }
0416 
0417 static int
0418 mlxsw_sp1_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
0419                  struct mlxsw_sp_ipip_entry *ipip_entry)
0420 {
0421     WARN_ON_ONCE(1);
0422     return -EINVAL;
0423 }
0424 
0425 static void
0426 mlxsw_sp1_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
0427                    const struct mlxsw_sp_ipip_entry *ipip_entry)
0428 {
0429     WARN_ON_ONCE(1);
0430 }
0431 
0432 static const struct mlxsw_sp_ipip_ops mlxsw_sp1_ipip_gre6_ops = {
0433     .dev_type = ARPHRD_IP6GRE,
0434     .ul_proto = MLXSW_SP_L3_PROTO_IPV6,
0435     .inc_parsing_depth = true,
0436     .parms_init = mlxsw_sp1_ipip_netdev_parms_init_gre6,
0437     .nexthop_update = mlxsw_sp1_ipip_nexthop_update_gre6,
0438     .decap_config = mlxsw_sp1_ipip_decap_config_gre6,
0439     .can_offload = mlxsw_sp1_ipip_can_offload_gre6,
0440     .ol_loopback_config = mlxsw_sp1_ipip_ol_loopback_config_gre6,
0441     .ol_netdev_change = mlxsw_sp1_ipip_ol_netdev_change_gre6,
0442     .rem_ip_addr_set = mlxsw_sp1_ipip_rem_addr_set_gre6,
0443     .rem_ip_addr_unset = mlxsw_sp1_ipip_rem_addr_unset_gre6,
0444 };
0445 
0446 const struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[] = {
0447     [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
0448     [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp1_ipip_gre6_ops,
0449 };
0450 
0451 static struct mlxsw_sp_ipip_parms
0452 mlxsw_sp2_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
0453 {
0454     struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
0455 
0456     return (struct mlxsw_sp_ipip_parms) {
0457         .proto = MLXSW_SP_L3_PROTO_IPV6,
0458         .saddr = mlxsw_sp_ipip_parms6_saddr(&parms),
0459         .daddr = mlxsw_sp_ipip_parms6_daddr(&parms),
0460         .link = parms.link,
0461         .ikey = mlxsw_sp_ipip_parms6_ikey(&parms),
0462         .okey = mlxsw_sp_ipip_parms6_okey(&parms),
0463     };
0464 }
0465 
0466 static int
0467 mlxsw_sp2_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
0468                    struct mlxsw_sp_ipip_entry *ipip_entry,
0469                    bool force, char *ratr_pl)
0470 {
0471     u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
0472     enum mlxsw_reg_ratr_op op;
0473 
0474     op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
0475              MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
0476     mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
0477                 adj_index, rif_index);
0478     mlxsw_reg_ratr_ipip6_entry_pack(ratr_pl,
0479                     ipip_entry->dip_kvdl_index);
0480 
0481     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
0482 }
0483 
0484 static int
0485 mlxsw_sp2_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
0486                  struct mlxsw_sp_ipip_entry *ipip_entry,
0487                  u32 tunnel_index)
0488 {
0489     u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
0490     u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb);
0491     char rtdp_pl[MLXSW_REG_RTDP_LEN];
0492     struct __ip6_tnl_parm parms;
0493     unsigned int type_check;
0494     bool has_ikey;
0495     u32 ikey;
0496 
0497     parms = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
0498     has_ikey = mlxsw_sp_ipip_parms6_has_ikey(&parms);
0499     ikey = mlxsw_sp_ipip_parms6_ikey(&parms);
0500 
0501     mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
0502     mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
0503 
0504     type_check = has_ikey ?
0505         MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
0506         MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
0507 
0508     /* Linux demuxes tunnels based on packet SIP (which must match tunnel
0509      * remote IP). Thus configure decap so that it filters out packets that
0510      * are not IPv6 or have the wrong SIP. IPIP_DECAP_ERROR trap is
0511      * generated for packets that fail this criterion. Linux then handles
0512      * such packets in slow path and generates ICMP destination unreachable.
0513      */
0514     mlxsw_reg_rtdp_ipip6_pack(rtdp_pl, rif_index,
0515                   MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6,
0516                   type_check, has_ikey,
0517                   ipip_entry->dip_kvdl_index, ikey);
0518 
0519     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
0520 }
0521 
0522 static bool mlxsw_sp2_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
0523                         const struct net_device *ol_dev)
0524 {
0525     struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(ol_dev);
0526     bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS;
0527     bool inherit_ttl = tparm.hop_limit == 0;
0528     __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
0529 
0530     return (tparm.i_flags & ~okflags) == 0 &&
0531            (tparm.o_flags & ~okflags) == 0 &&
0532            inherit_ttl && inherit_tos &&
0533            mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV6, ol_dev);
0534 }
0535 
0536 static struct mlxsw_sp_rif_ipip_lb_config
0537 mlxsw_sp2_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
0538                        const struct net_device *ol_dev)
0539 {
0540     struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
0541     enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
0542 
0543     lb_ipipt = mlxsw_sp_ipip_parms6_has_okey(&parms) ?
0544         MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
0545         MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
0546     return (struct mlxsw_sp_rif_ipip_lb_config){
0547         .lb_ipipt = lb_ipipt,
0548         .okey = mlxsw_sp_ipip_parms6_okey(&parms),
0549         .ul_protocol = MLXSW_SP_L3_PROTO_IPV6,
0550         .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV6,
0551                             ol_dev),
0552     };
0553 }
0554 
0555 static int
0556 mlxsw_sp2_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
0557                      struct mlxsw_sp_ipip_entry *ipip_entry,
0558                      struct netlink_ext_ack *extack)
0559 {
0560     struct mlxsw_sp_ipip_parms new_parms;
0561 
0562     new_parms = mlxsw_sp2_ipip_netdev_parms_init_gre6(ipip_entry->ol_dev);
0563     return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
0564                           &new_parms, extack);
0565 }
0566 
0567 static int
0568 mlxsw_sp2_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
0569                  struct mlxsw_sp_ipip_entry *ipip_entry)
0570 {
0571     return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp,
0572                          &ipip_entry->parms.daddr.addr6,
0573                          &ipip_entry->dip_kvdl_index);
0574 }
0575 
0576 static void
0577 mlxsw_sp2_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
0578                    const struct mlxsw_sp_ipip_entry *ipip_entry)
0579 {
0580     mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipip_entry->parms.daddr.addr6);
0581 }
0582 
0583 static const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = {
0584     .dev_type = ARPHRD_IP6GRE,
0585     .ul_proto = MLXSW_SP_L3_PROTO_IPV6,
0586     .inc_parsing_depth = true,
0587     .parms_init = mlxsw_sp2_ipip_netdev_parms_init_gre6,
0588     .nexthop_update = mlxsw_sp2_ipip_nexthop_update_gre6,
0589     .decap_config = mlxsw_sp2_ipip_decap_config_gre6,
0590     .can_offload = mlxsw_sp2_ipip_can_offload_gre6,
0591     .ol_loopback_config = mlxsw_sp2_ipip_ol_loopback_config_gre6,
0592     .ol_netdev_change = mlxsw_sp2_ipip_ol_netdev_change_gre6,
0593     .rem_ip_addr_set = mlxsw_sp2_ipip_rem_addr_set_gre6,
0594     .rem_ip_addr_unset = mlxsw_sp2_ipip_rem_addr_unset_gre6,
0595 };
0596 
0597 const struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[] = {
0598     [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
0599     [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp2_ipip_gre6_ops,
0600 };
0601 
0602 static int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp,
0603                         u8 inner_ecn, u8 outer_ecn)
0604 {
0605     char tieem_pl[MLXSW_REG_TIEEM_LEN];
0606 
0607     mlxsw_reg_tieem_pack(tieem_pl, inner_ecn, outer_ecn);
0608     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), tieem_pl);
0609 }
0610 
0611 int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp)
0612 {
0613     int i;
0614 
0615     /* Iterate over inner ECN values */
0616     for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
0617         u8 outer_ecn = INET_ECN_encapsulate(0, i);
0618         int err;
0619 
0620         err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, i, outer_ecn);
0621         if (err)
0622             return err;
0623     }
0624 
0625     return 0;
0626 }
0627 
0628 static int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp,
0629                         u8 inner_ecn, u8 outer_ecn)
0630 {
0631     char tidem_pl[MLXSW_REG_TIDEM_LEN];
0632     u8 new_inner_ecn;
0633     bool trap_en;
0634 
0635     new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn,
0636                           &trap_en);
0637     mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn,
0638                  trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
0639     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), tidem_pl);
0640 }
0641 
0642 int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
0643 {
0644     int i, j, err;
0645 
0646     /* Iterate over inner ECN values */
0647     for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
0648         /* Iterate over outer ECN values */
0649         for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) {
0650             err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, i, j);
0651             if (err)
0652                 return err;
0653         }
0654     }
0655 
0656     return 0;
0657 }
0658 
0659 struct net_device *
0660 mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
0661 {
0662     struct net *net = dev_net(ol_dev);
0663     struct ip_tunnel *tun4;
0664     struct ip6_tnl *tun6;
0665 
0666     switch (ol_dev->type) {
0667     case ARPHRD_IPGRE:
0668         tun4 = netdev_priv(ol_dev);
0669         return dev_get_by_index_rcu(net, tun4->parms.link);
0670     case ARPHRD_IP6GRE:
0671         tun6 = netdev_priv(ol_dev);
0672         return dev_get_by_index_rcu(net, tun6->parms.link);
0673     default:
0674         return NULL;
0675     }
0676 }