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 11 struct ip_tunnel_parm 12 mlxsw_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 19 struct __ip6_tnl_parm 20 mlxsw_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 27 static bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms) 28 { 29 return !!(parms.i_flags & TUNNEL_KEY); 30 } 31 32 static bool mlxsw_sp_ipip_parms4_has_okey(struct ip_tunnel_parm parms) 33 { 34 return !!(parms.o_flags & TUNNEL_KEY); 35 } 36 37 static u32 mlxsw_sp_ipip_parms4_ikey(struct ip_tunnel_parm parms) 38 { 39 return mlxsw_sp_ipip_parms4_has_ikey(parms) ? 40 be32_to_cpu(parms.i_key) : 0; 41 } 42 43 static u32 mlxsw_sp_ipip_parms4_okey(struct ip_tunnel_parm parms) 44 { 45 return mlxsw_sp_ipip_parms4_has_okey(parms) ? 46 be32_to_cpu(parms.o_key) : 0; 47 } 48 49 static union mlxsw_sp_l3addr 50 mlxsw_sp_ipip_parms4_saddr(struct ip_tunnel_parm parms) 51 { 52 return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.saddr }; 53 } 54 55 static union mlxsw_sp_l3addr 56 mlxsw_sp_ipip_parms6_saddr(struct __ip6_tnl_parm parms) 57 { 58 return (union mlxsw_sp_l3addr) { .addr6 = parms.laddr }; 59 } 60 61 static union mlxsw_sp_l3addr 62 mlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms) 63 { 64 return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr }; 65 } 66 67 static union mlxsw_sp_l3addr 68 mlxsw_sp_ipip_parms6_daddr(struct __ip6_tnl_parm parms) 69 { 70 return (union mlxsw_sp_l3addr) { .addr6 = parms.raddr }; 71 } 72 73 union mlxsw_sp_l3addr 74 mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 75 const struct net_device *ol_dev) 76 { 77 struct ip_tunnel_parm parms4; 78 struct __ip6_tnl_parm parms6; 79 80 switch (proto) { 81 case MLXSW_SP_L3_PROTO_IPV4: 82 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 83 return mlxsw_sp_ipip_parms4_saddr(parms4); 84 case MLXSW_SP_L3_PROTO_IPV6: 85 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 86 return mlxsw_sp_ipip_parms6_saddr(parms6); 87 } 88 89 WARN_ON(1); 90 return (union mlxsw_sp_l3addr) {0}; 91 } 92 93 static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev) 94 { 95 96 struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 97 98 return mlxsw_sp_ipip_parms4_daddr(parms4).addr4; 99 } 100 101 static union mlxsw_sp_l3addr 102 mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto, 103 const struct net_device *ol_dev) 104 { 105 struct ip_tunnel_parm parms4; 106 struct __ip6_tnl_parm parms6; 107 108 switch (proto) { 109 case MLXSW_SP_L3_PROTO_IPV4: 110 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 111 return mlxsw_sp_ipip_parms4_daddr(parms4); 112 case MLXSW_SP_L3_PROTO_IPV6: 113 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 114 return mlxsw_sp_ipip_parms6_daddr(parms6); 115 } 116 117 WARN_ON(1); 118 return (union mlxsw_sp_l3addr) {0}; 119 } 120 121 bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr) 122 { 123 union mlxsw_sp_l3addr naddr = {0}; 124 125 return !memcmp(&addr, &naddr, sizeof(naddr)); 126 } 127 128 static int 129 mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 130 struct mlxsw_sp_ipip_entry *ipip_entry) 131 { 132 u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 133 __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev); 134 char ratr_pl[MLXSW_REG_RATR_LEN]; 135 136 mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, 137 true, MLXSW_REG_RATR_TYPE_IPIP, 138 adj_index, rif_index); 139 mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4)); 140 141 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); 142 } 143 144 static int 145 mlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp, 146 struct mlxsw_sp_ipip_entry *ipip_entry, 147 u32 tunnel_index) 148 { 149 u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 150 u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb); 151 char rtdp_pl[MLXSW_REG_RTDP_LEN]; 152 struct ip_tunnel_parm parms; 153 unsigned int type_check; 154 bool has_ikey; 155 u32 daddr4; 156 u32 ikey; 157 158 parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev); 159 has_ikey = mlxsw_sp_ipip_parms4_has_ikey(parms); 160 ikey = mlxsw_sp_ipip_parms4_ikey(parms); 161 162 mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); 163 mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id); 164 165 type_check = has_ikey ? 166 MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : 167 MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; 168 169 /* Linux demuxes tunnels based on packet SIP (which must match tunnel 170 * remote IP). Thus configure decap so that it filters out packets that 171 * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is 172 * generated for packets that fail this criterion. Linux then handles 173 * such packets in slow path and generates ICMP destination unreachable. 174 */ 175 daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev)); 176 mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index, 177 MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, 178 type_check, has_ikey, daddr4, ikey); 179 180 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); 181 } 182 183 static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, 184 const struct net_device *ol_dev) 185 { 186 union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); 187 union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); 188 189 /* Tunnels with unset local or remote address are valid in Linux and 190 * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access 191 * (NBMA) tunnels. In principle these can be offloaded, but the driver 192 * currently doesn't support this. So punt. 193 */ 194 return !mlxsw_sp_l3addr_is_zero(saddr) && 195 !mlxsw_sp_l3addr_is_zero(daddr); 196 } 197 198 static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, 199 const struct net_device *ol_dev) 200 { 201 struct ip_tunnel *tunnel = netdev_priv(ol_dev); 202 __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ 203 bool inherit_ttl = tunnel->parms.iph.ttl == 0; 204 bool inherit_tos = tunnel->parms.iph.tos & 0x1; 205 206 return (tunnel->parms.i_flags & ~okflags) == 0 && 207 (tunnel->parms.o_flags & ~okflags) == 0 && 208 inherit_ttl && inherit_tos && 209 mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev); 210 } 211 212 static struct mlxsw_sp_rif_ipip_lb_config 213 mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp, 214 const struct net_device *ol_dev) 215 { 216 struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); 217 enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; 218 219 lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(parms) ? 220 MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : 221 MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; 222 return (struct mlxsw_sp_rif_ipip_lb_config){ 223 .lb_ipipt = lb_ipipt, 224 .okey = mlxsw_sp_ipip_parms4_okey(parms), 225 .ul_protocol = MLXSW_SP_L3_PROTO_IPV4, 226 .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 227 ol_dev), 228 }; 229 } 230 231 static int 232 mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp, 233 struct mlxsw_sp_ipip_entry *ipip_entry, 234 struct netlink_ext_ack *extack) 235 { 236 union mlxsw_sp_l3addr old_saddr, new_saddr; 237 union mlxsw_sp_l3addr old_daddr, new_daddr; 238 struct ip_tunnel_parm new_parms; 239 bool update_tunnel = false; 240 bool update_decap = false; 241 bool update_nhs = false; 242 int err = 0; 243 244 new_parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev); 245 246 new_saddr = mlxsw_sp_ipip_parms4_saddr(new_parms); 247 old_saddr = mlxsw_sp_ipip_parms4_saddr(ipip_entry->parms4); 248 new_daddr = mlxsw_sp_ipip_parms4_daddr(new_parms); 249 old_daddr = mlxsw_sp_ipip_parms4_daddr(ipip_entry->parms4); 250 251 if (!mlxsw_sp_l3addr_eq(&new_saddr, &old_saddr)) { 252 u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev); 253 254 /* Since the local address has changed, if there is another 255 * tunnel with a matching saddr, both need to be demoted. 256 */ 257 if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, 258 MLXSW_SP_L3_PROTO_IPV4, 259 new_saddr, ul_tb_id, 260 ipip_entry)) { 261 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); 262 return 0; 263 } 264 265 update_tunnel = true; 266 } else if ((mlxsw_sp_ipip_parms4_okey(ipip_entry->parms4) != 267 mlxsw_sp_ipip_parms4_okey(new_parms)) || 268 ipip_entry->parms4.link != new_parms.link) { 269 update_tunnel = true; 270 } else if (!mlxsw_sp_l3addr_eq(&new_daddr, &old_daddr)) { 271 update_nhs = true; 272 } else if (mlxsw_sp_ipip_parms4_ikey(ipip_entry->parms4) != 273 mlxsw_sp_ipip_parms4_ikey(new_parms)) { 274 update_decap = true; 275 } 276 277 if (update_tunnel) 278 err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 279 true, true, true, 280 extack); 281 else if (update_nhs) 282 err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 283 false, false, true, 284 extack); 285 else if (update_decap) 286 err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 287 false, false, false, 288 extack); 289 290 ipip_entry->parms4 = new_parms; 291 return err; 292 } 293 294 static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = { 295 .dev_type = ARPHRD_IPGRE, 296 .ul_proto = MLXSW_SP_L3_PROTO_IPV4, 297 .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4, 298 .decap_config = mlxsw_sp_ipip_decap_config_gre4, 299 .can_offload = mlxsw_sp_ipip_can_offload_gre4, 300 .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4, 301 .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4, 302 }; 303 304 const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[] = { 305 [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, 306 }; 307 308 static int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp, 309 u8 inner_ecn, u8 outer_ecn) 310 { 311 char tieem_pl[MLXSW_REG_TIEEM_LEN]; 312 313 mlxsw_reg_tieem_pack(tieem_pl, inner_ecn, outer_ecn); 314 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), tieem_pl); 315 } 316 317 int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp) 318 { 319 int i; 320 321 /* Iterate over inner ECN values */ 322 for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 323 u8 outer_ecn = INET_ECN_encapsulate(0, i); 324 int err; 325 326 err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, i, outer_ecn); 327 if (err) 328 return err; 329 } 330 331 return 0; 332 } 333 334 static int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp, 335 u8 inner_ecn, u8 outer_ecn) 336 { 337 char tidem_pl[MLXSW_REG_TIDEM_LEN]; 338 u8 new_inner_ecn; 339 bool trap_en; 340 341 new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn, 342 &trap_en); 343 mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn, 344 trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0); 345 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), tidem_pl); 346 } 347 348 int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp) 349 { 350 int i, j, err; 351 352 /* Iterate over inner ECN values */ 353 for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 354 /* Iterate over outer ECN values */ 355 for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) { 356 err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, i, j); 357 if (err) 358 return err; 359 } 360 } 361 362 return 0; 363 } 364