linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
   3
   4#include <net/ip_tunnels.h>
   5#include <net/ip6_tunnel.h>
   6#include <net/inet_ecn.h>
   7
   8#include "spectrum_ipip.h"
   9#include "reg.h"
  10
  11struct ip_tunnel_parm
  12mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev)
  13{
  14        struct ip_tunnel *tun = netdev_priv(ol_dev);
  15
  16        return tun->parms;
  17}
  18
  19struct __ip6_tnl_parm
  20mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev)
  21{
  22        struct ip6_tnl *tun = netdev_priv(ol_dev);
  23
  24        return tun->parms;
  25}
  26
  27static bool mlxsw_sp_ipip_parms4_has_ikey(const struct ip_tunnel_parm *parms)
  28{
  29        return !!(parms->i_flags & TUNNEL_KEY);
  30}
  31
  32static bool mlxsw_sp_ipip_parms6_has_ikey(const struct __ip6_tnl_parm *parms)
  33{
  34        return !!(parms->i_flags & TUNNEL_KEY);
  35}
  36
  37static bool mlxsw_sp_ipip_parms4_has_okey(const struct ip_tunnel_parm *parms)
  38{
  39        return !!(parms->o_flags & TUNNEL_KEY);
  40}
  41
  42static bool mlxsw_sp_ipip_parms6_has_okey(const struct __ip6_tnl_parm *parms)
  43{
  44        return !!(parms->o_flags & TUNNEL_KEY);
  45}
  46
  47static u32 mlxsw_sp_ipip_parms4_ikey(const struct ip_tunnel_parm *parms)
  48{
  49        return mlxsw_sp_ipip_parms4_has_ikey(parms) ?
  50                be32_to_cpu(parms->i_key) : 0;
  51}
  52
  53static u32 mlxsw_sp_ipip_parms6_ikey(const struct __ip6_tnl_parm *parms)
  54{
  55        return mlxsw_sp_ipip_parms6_has_ikey(parms) ?
  56                be32_to_cpu(parms->i_key) : 0;
  57}
  58
  59static u32 mlxsw_sp_ipip_parms4_okey(const struct ip_tunnel_parm *parms)
  60{
  61        return mlxsw_sp_ipip_parms4_has_okey(parms) ?
  62                be32_to_cpu(parms->o_key) : 0;
  63}
  64
  65static u32 mlxsw_sp_ipip_parms6_okey(const struct __ip6_tnl_parm *parms)
  66{
  67        return mlxsw_sp_ipip_parms6_has_okey(parms) ?
  68                be32_to_cpu(parms->o_key) : 0;
  69}
  70
  71static union mlxsw_sp_l3addr
  72mlxsw_sp_ipip_parms4_saddr(const struct ip_tunnel_parm *parms)
  73{
  74        return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.saddr };
  75}
  76
  77static union mlxsw_sp_l3addr
  78mlxsw_sp_ipip_parms6_saddr(const struct __ip6_tnl_parm *parms)
  79{
  80        return (union mlxsw_sp_l3addr) { .addr6 = parms->laddr };
  81}
  82
  83static union mlxsw_sp_l3addr
  84mlxsw_sp_ipip_parms4_daddr(const struct ip_tunnel_parm *parms)
  85{
  86        return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.daddr };
  87}
  88
  89static union mlxsw_sp_l3addr
  90mlxsw_sp_ipip_parms6_daddr(const struct __ip6_tnl_parm *parms)
  91{
  92        return (union mlxsw_sp_l3addr) { .addr6 = parms->raddr };
  93}
  94
  95union mlxsw_sp_l3addr
  96mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
  97                           const struct net_device *ol_dev)
  98{
  99        struct ip_tunnel_parm parms4;
 100        struct __ip6_tnl_parm parms6;
 101
 102        switch (proto) {
 103        case MLXSW_SP_L3_PROTO_IPV4:
 104                parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 105                return mlxsw_sp_ipip_parms4_saddr(&parms4);
 106        case MLXSW_SP_L3_PROTO_IPV6:
 107                parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
 108                return mlxsw_sp_ipip_parms6_saddr(&parms6);
 109        }
 110
 111        WARN_ON(1);
 112        return (union mlxsw_sp_l3addr) {0};
 113}
 114
 115static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
 116{
 117
 118        struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 119
 120        return mlxsw_sp_ipip_parms4_daddr(&parms4).addr4;
 121}
 122
 123static union mlxsw_sp_l3addr
 124mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
 125                           const struct net_device *ol_dev)
 126{
 127        struct ip_tunnel_parm parms4;
 128        struct __ip6_tnl_parm parms6;
 129
 130        switch (proto) {
 131        case MLXSW_SP_L3_PROTO_IPV4:
 132                parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 133                return mlxsw_sp_ipip_parms4_daddr(&parms4);
 134        case MLXSW_SP_L3_PROTO_IPV6:
 135                parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
 136                return mlxsw_sp_ipip_parms6_daddr(&parms6);
 137        }
 138
 139        WARN_ON(1);
 140        return (union mlxsw_sp_l3addr) {0};
 141}
 142
 143bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr)
 144{
 145        union mlxsw_sp_l3addr naddr = {0};
 146
 147        return !memcmp(&addr, &naddr, sizeof(naddr));
 148}
 149
 150static struct mlxsw_sp_ipip_parms
 151mlxsw_sp_ipip_netdev_parms_init_gre4(const struct net_device *ol_dev)
 152{
 153        struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 154
 155        return (struct mlxsw_sp_ipip_parms) {
 156                .proto = MLXSW_SP_L3_PROTO_IPV4,
 157                .saddr = mlxsw_sp_ipip_parms4_saddr(&parms),
 158                .daddr = mlxsw_sp_ipip_parms4_daddr(&parms),
 159                .link = parms.link,
 160                .ikey = mlxsw_sp_ipip_parms4_ikey(&parms),
 161                .okey = mlxsw_sp_ipip_parms4_okey(&parms),
 162        };
 163}
 164
 165static int
 166mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
 167                                  struct mlxsw_sp_ipip_entry *ipip_entry,
 168                                  bool force, char *ratr_pl)
 169{
 170        u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
 171        __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev);
 172        enum mlxsw_reg_ratr_op op;
 173
 174        op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
 175                     MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
 176        mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
 177                            adj_index, rif_index);
 178        mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4));
 179
 180        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
 181}
 182
 183static int
 184mlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp,
 185                                struct mlxsw_sp_ipip_entry *ipip_entry,
 186                                u32 tunnel_index)
 187{
 188        u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
 189        u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb);
 190        char rtdp_pl[MLXSW_REG_RTDP_LEN];
 191        struct ip_tunnel_parm parms;
 192        unsigned int type_check;
 193        bool has_ikey;
 194        u32 daddr4;
 195        u32 ikey;
 196
 197        parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
 198        has_ikey = mlxsw_sp_ipip_parms4_has_ikey(&parms);
 199        ikey = mlxsw_sp_ipip_parms4_ikey(&parms);
 200
 201        mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
 202        mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
 203
 204        type_check = has_ikey ?
 205                MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
 206                MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
 207
 208        /* Linux demuxes tunnels based on packet SIP (which must match tunnel
 209         * remote IP). Thus configure decap so that it filters out packets that
 210         * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is
 211         * generated for packets that fail this criterion. Linux then handles
 212         * such packets in slow path and generates ICMP destination unreachable.
 213         */
 214        daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev));
 215        mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index,
 216                                  MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,
 217                                  type_check, has_ikey, daddr4, ikey);
 218
 219        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
 220}
 221
 222static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto,
 223                                          const struct net_device *ol_dev)
 224{
 225        union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev);
 226        union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev);
 227
 228        /* Tunnels with unset local or remote address are valid in Linux and
 229         * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access
 230         * (NBMA) tunnels. In principle these can be offloaded, but the driver
 231         * currently doesn't support this. So punt.
 232         */
 233        return !mlxsw_sp_l3addr_is_zero(saddr) &&
 234               !mlxsw_sp_l3addr_is_zero(daddr);
 235}
 236
 237static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp,
 238                                           const struct net_device *ol_dev)
 239{
 240        struct ip_tunnel *tunnel = netdev_priv(ol_dev);
 241        __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
 242        bool inherit_ttl = tunnel->parms.iph.ttl == 0;
 243        bool inherit_tos = tunnel->parms.iph.tos & 0x1;
 244
 245        return (tunnel->parms.i_flags & ~okflags) == 0 &&
 246               (tunnel->parms.o_flags & ~okflags) == 0 &&
 247               inherit_ttl && inherit_tos &&
 248               mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev);
 249}
 250
 251static struct mlxsw_sp_rif_ipip_lb_config
 252mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
 253                                      const struct net_device *ol_dev)
 254{
 255        struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 256        enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
 257
 258        lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(&parms) ?
 259                MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
 260                MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
 261        return (struct mlxsw_sp_rif_ipip_lb_config){
 262                .lb_ipipt = lb_ipipt,
 263                .okey = mlxsw_sp_ipip_parms4_okey(&parms),
 264                .ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
 265                .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
 266                                                    ol_dev),
 267        };
 268}
 269
 270static int
 271mlxsw_sp_ipip_ol_netdev_change_gre(struct mlxsw_sp *mlxsw_sp,
 272                                   struct mlxsw_sp_ipip_entry *ipip_entry,
 273                                   const struct mlxsw_sp_ipip_parms *new_parms,
 274                                   struct netlink_ext_ack *extack)
 275{
 276        const struct mlxsw_sp_ipip_parms *old_parms = &ipip_entry->parms;
 277        bool update_tunnel = false;
 278        bool update_decap = false;
 279        bool update_nhs = false;
 280        int err = 0;
 281
 282        if (!mlxsw_sp_l3addr_eq(&new_parms->saddr, &old_parms->saddr)) {
 283                u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
 284
 285                /* Since the local address has changed, if there is another
 286                 * tunnel with a matching saddr, both need to be demoted.
 287                 */
 288                if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp,
 289                                                         new_parms->proto,
 290                                                         new_parms->saddr,
 291                                                         ul_tb_id,
 292                                                         ipip_entry)) {
 293                        mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
 294                        return 0;
 295                }
 296
 297                update_tunnel = true;
 298        } else if (old_parms->okey != new_parms->okey ||
 299                   old_parms->link != new_parms->link) {
 300                update_tunnel = true;
 301        } else if (!mlxsw_sp_l3addr_eq(&new_parms->daddr, &old_parms->daddr)) {
 302                update_nhs = true;
 303        } else if (old_parms->ikey != new_parms->ikey) {
 304                update_decap = true;
 305        }
 306
 307        if (update_tunnel)
 308                err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
 309                                                          true, true, true,
 310                                                          extack);
 311        else if (update_nhs)
 312                err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
 313                                                          false, false, true,
 314                                                          extack);
 315        else if (update_decap)
 316                err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
 317                                                          false, false, false,
 318                                                          extack);
 319        if (err)
 320                return err;
 321
 322        ipip_entry->parms = *new_parms;
 323        return 0;
 324}
 325
 326static int
 327mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
 328                                    struct mlxsw_sp_ipip_entry *ipip_entry,
 329                                    struct netlink_ext_ack *extack)
 330{
 331        struct mlxsw_sp_ipip_parms new_parms;
 332
 333        new_parms = mlxsw_sp_ipip_netdev_parms_init_gre4(ipip_entry->ol_dev);
 334        return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
 335                                                  &new_parms, extack);
 336}
 337
 338static int
 339mlxsw_sp_ipip_rem_addr_set_gre4(struct mlxsw_sp *mlxsw_sp,
 340                                struct mlxsw_sp_ipip_entry *ipip_entry)
 341{
 342        return 0;
 343}
 344
 345static void
 346mlxsw_sp_ipip_rem_addr_unset_gre4(struct mlxsw_sp *mlxsw_sp,
 347                                  const struct mlxsw_sp_ipip_entry *ipip_entry)
 348{
 349}
 350
 351static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = {
 352        .dev_type = ARPHRD_IPGRE,
 353        .ul_proto = MLXSW_SP_L3_PROTO_IPV4,
 354        .inc_parsing_depth = false,
 355        .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre4,
 356        .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4,
 357        .decap_config = mlxsw_sp_ipip_decap_config_gre4,
 358        .can_offload = mlxsw_sp_ipip_can_offload_gre4,
 359        .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4,
 360        .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4,
 361        .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre4,
 362        .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre4,
 363};
 364
 365static struct mlxsw_sp_ipip_parms
 366mlxsw_sp1_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
 367{
 368        struct mlxsw_sp_ipip_parms parms = {0};
 369
 370        WARN_ON_ONCE(1);
 371        return parms;
 372}
 373
 374static int
 375mlxsw_sp1_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
 376                                   struct mlxsw_sp_ipip_entry *ipip_entry,
 377                                   bool force, char *ratr_pl)
 378{
 379        WARN_ON_ONCE(1);
 380        return -EINVAL;
 381}
 382
 383static int
 384mlxsw_sp1_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
 385                                 struct mlxsw_sp_ipip_entry *ipip_entry,
 386                                 u32 tunnel_index)
 387{
 388        WARN_ON_ONCE(1);
 389        return -EINVAL;
 390}
 391
 392static bool mlxsw_sp1_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
 393                                            const struct net_device *ol_dev)
 394{
 395        return false;
 396}
 397
 398static struct mlxsw_sp_rif_ipip_lb_config
 399mlxsw_sp1_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
 400                                       const struct net_device *ol_dev)
 401{
 402        struct mlxsw_sp_rif_ipip_lb_config config = {0};
 403
 404        WARN_ON_ONCE(1);
 405        return config;
 406}
 407
 408static int
 409mlxsw_sp1_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
 410                                     struct mlxsw_sp_ipip_entry *ipip_entry,
 411                                     struct netlink_ext_ack *extack)
 412{
 413        WARN_ON_ONCE(1);
 414        return -EINVAL;
 415}
 416
 417static int
 418mlxsw_sp1_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
 419                                 struct mlxsw_sp_ipip_entry *ipip_entry)
 420{
 421        WARN_ON_ONCE(1);
 422        return -EINVAL;
 423}
 424
 425static void
 426mlxsw_sp1_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
 427                                   const struct mlxsw_sp_ipip_entry *ipip_entry)
 428{
 429        WARN_ON_ONCE(1);
 430}
 431
 432static const struct mlxsw_sp_ipip_ops mlxsw_sp1_ipip_gre6_ops = {
 433        .dev_type = ARPHRD_IP6GRE,
 434        .ul_proto = MLXSW_SP_L3_PROTO_IPV6,
 435        .inc_parsing_depth = true,
 436        .parms_init = mlxsw_sp1_ipip_netdev_parms_init_gre6,
 437        .nexthop_update = mlxsw_sp1_ipip_nexthop_update_gre6,
 438        .decap_config = mlxsw_sp1_ipip_decap_config_gre6,
 439        .can_offload = mlxsw_sp1_ipip_can_offload_gre6,
 440        .ol_loopback_config = mlxsw_sp1_ipip_ol_loopback_config_gre6,
 441        .ol_netdev_change = mlxsw_sp1_ipip_ol_netdev_change_gre6,
 442        .rem_ip_addr_set = mlxsw_sp1_ipip_rem_addr_set_gre6,
 443        .rem_ip_addr_unset = mlxsw_sp1_ipip_rem_addr_unset_gre6,
 444};
 445
 446const struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[] = {
 447        [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
 448        [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp1_ipip_gre6_ops,
 449};
 450
 451static struct mlxsw_sp_ipip_parms
 452mlxsw_sp2_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev)
 453{
 454        struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
 455
 456        return (struct mlxsw_sp_ipip_parms) {
 457                .proto = MLXSW_SP_L3_PROTO_IPV6,
 458                .saddr = mlxsw_sp_ipip_parms6_saddr(&parms),
 459                .daddr = mlxsw_sp_ipip_parms6_daddr(&parms),
 460                .link = parms.link,
 461                .ikey = mlxsw_sp_ipip_parms6_ikey(&parms),
 462                .okey = mlxsw_sp_ipip_parms6_okey(&parms),
 463        };
 464}
 465
 466static int
 467mlxsw_sp2_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
 468                                   struct mlxsw_sp_ipip_entry *ipip_entry,
 469                                   bool force, char *ratr_pl)
 470{
 471        u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
 472        enum mlxsw_reg_ratr_op op;
 473
 474        op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
 475                     MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
 476        mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
 477                            adj_index, rif_index);
 478        mlxsw_reg_ratr_ipip6_entry_pack(ratr_pl,
 479                                        ipip_entry->dip_kvdl_index);
 480
 481        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
 482}
 483
 484static int
 485mlxsw_sp2_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp,
 486                                 struct mlxsw_sp_ipip_entry *ipip_entry,
 487                                 u32 tunnel_index)
 488{
 489        u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
 490        u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb);
 491        char rtdp_pl[MLXSW_REG_RTDP_LEN];
 492        struct __ip6_tnl_parm parms;
 493        unsigned int type_check;
 494        bool has_ikey;
 495        u32 ikey;
 496
 497        parms = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
 498        has_ikey = mlxsw_sp_ipip_parms6_has_ikey(&parms);
 499        ikey = mlxsw_sp_ipip_parms6_ikey(&parms);
 500
 501        mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
 502        mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id);
 503
 504        type_check = has_ikey ?
 505                MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
 506                MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
 507
 508        /* Linux demuxes tunnels based on packet SIP (which must match tunnel
 509         * remote IP). Thus configure decap so that it filters out packets that
 510         * are not IPv6 or have the wrong SIP. IPIP_DECAP_ERROR trap is
 511         * generated for packets that fail this criterion. Linux then handles
 512         * such packets in slow path and generates ICMP destination unreachable.
 513         */
 514        mlxsw_reg_rtdp_ipip6_pack(rtdp_pl, rif_index,
 515                                  MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6,
 516                                  type_check, has_ikey,
 517                                  ipip_entry->dip_kvdl_index, ikey);
 518
 519        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
 520}
 521
 522static bool mlxsw_sp2_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp,
 523                                            const struct net_device *ol_dev)
 524{
 525        struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(ol_dev);
 526        bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS;
 527        bool inherit_ttl = tparm.hop_limit == 0;
 528        __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
 529
 530        return (tparm.i_flags & ~okflags) == 0 &&
 531               (tparm.o_flags & ~okflags) == 0 &&
 532               inherit_ttl && inherit_tos &&
 533               mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV6, ol_dev);
 534}
 535
 536static struct mlxsw_sp_rif_ipip_lb_config
 537mlxsw_sp2_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp,
 538                                       const struct net_device *ol_dev)
 539{
 540        struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev);
 541        enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
 542
 543        lb_ipipt = mlxsw_sp_ipip_parms6_has_okey(&parms) ?
 544                MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
 545                MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
 546        return (struct mlxsw_sp_rif_ipip_lb_config){
 547                .lb_ipipt = lb_ipipt,
 548                .okey = mlxsw_sp_ipip_parms6_okey(&parms),
 549                .ul_protocol = MLXSW_SP_L3_PROTO_IPV6,
 550                .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV6,
 551                                                    ol_dev),
 552        };
 553}
 554
 555static int
 556mlxsw_sp2_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
 557                                     struct mlxsw_sp_ipip_entry *ipip_entry,
 558                                     struct netlink_ext_ack *extack)
 559{
 560        struct mlxsw_sp_ipip_parms new_parms;
 561
 562        new_parms = mlxsw_sp2_ipip_netdev_parms_init_gre6(ipip_entry->ol_dev);
 563        return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
 564                                                  &new_parms, extack);
 565}
 566
 567static int
 568mlxsw_sp2_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
 569                                 struct mlxsw_sp_ipip_entry *ipip_entry)
 570{
 571        char rips_pl[MLXSW_REG_RIPS_LEN];
 572        struct __ip6_tnl_parm parms6;
 573        int err;
 574
 575        err = mlxsw_sp_kvdl_alloc(mlxsw_sp,
 576                                  MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
 577                                  &ipip_entry->dip_kvdl_index);
 578        if (err)
 579                return err;
 580
 581        parms6 = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
 582        mlxsw_reg_rips_pack(rips_pl, ipip_entry->dip_kvdl_index,
 583                            &parms6.raddr);
 584        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);
 585        if (err)
 586                goto err_rips_write;
 587
 588        return 0;
 589
 590err_rips_write:
 591        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
 592                           ipip_entry->dip_kvdl_index);
 593        return err;
 594}
 595
 596static void
 597mlxsw_sp2_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
 598                                   const struct mlxsw_sp_ipip_entry *ipip_entry)
 599{
 600        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
 601                           ipip_entry->dip_kvdl_index);
 602}
 603
 604static const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = {
 605        .dev_type = ARPHRD_IP6GRE,
 606        .ul_proto = MLXSW_SP_L3_PROTO_IPV6,
 607        .inc_parsing_depth = true,
 608        .parms_init = mlxsw_sp2_ipip_netdev_parms_init_gre6,
 609        .nexthop_update = mlxsw_sp2_ipip_nexthop_update_gre6,
 610        .decap_config = mlxsw_sp2_ipip_decap_config_gre6,
 611        .can_offload = mlxsw_sp2_ipip_can_offload_gre6,
 612        .ol_loopback_config = mlxsw_sp2_ipip_ol_loopback_config_gre6,
 613        .ol_netdev_change = mlxsw_sp2_ipip_ol_netdev_change_gre6,
 614        .rem_ip_addr_set = mlxsw_sp2_ipip_rem_addr_set_gre6,
 615        .rem_ip_addr_unset = mlxsw_sp2_ipip_rem_addr_unset_gre6,
 616};
 617
 618const struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[] = {
 619        [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
 620        [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp2_ipip_gre6_ops,
 621};
 622
 623static int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp,
 624                                            u8 inner_ecn, u8 outer_ecn)
 625{
 626        char tieem_pl[MLXSW_REG_TIEEM_LEN];
 627
 628        mlxsw_reg_tieem_pack(tieem_pl, inner_ecn, outer_ecn);
 629        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), tieem_pl);
 630}
 631
 632int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp)
 633{
 634        int i;
 635
 636        /* Iterate over inner ECN values */
 637        for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
 638                u8 outer_ecn = INET_ECN_encapsulate(0, i);
 639                int err;
 640
 641                err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, i, outer_ecn);
 642                if (err)
 643                        return err;
 644        }
 645
 646        return 0;
 647}
 648
 649static int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp,
 650                                            u8 inner_ecn, u8 outer_ecn)
 651{
 652        char tidem_pl[MLXSW_REG_TIDEM_LEN];
 653        u8 new_inner_ecn;
 654        bool trap_en;
 655
 656        new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn,
 657                                                  &trap_en);
 658        mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn,
 659                             trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
 660        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), tidem_pl);
 661}
 662
 663int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
 664{
 665        int i, j, err;
 666
 667        /* Iterate over inner ECN values */
 668        for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
 669                /* Iterate over outer ECN values */
 670                for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) {
 671                        err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, i, j);
 672                        if (err)
 673                                return err;
 674                }
 675        }
 676
 677        return 0;
 678}
 679
 680struct net_device *
 681mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
 682{
 683        struct net *net = dev_net(ol_dev);
 684        struct ip_tunnel *tun4;
 685        struct ip6_tnl *tun6;
 686
 687        switch (ol_dev->type) {
 688        case ARPHRD_IPGRE:
 689                tun4 = netdev_priv(ol_dev);
 690                return dev_get_by_index_rcu(net, tun4->parms.link);
 691        case ARPHRD_IP6GRE:
 692                tun6 = netdev_priv(ol_dev);
 693                return dev_get_by_index_rcu(net, tun6->parms.link);
 694        default:
 695                return NULL;
 696        }
 697}
 698