2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <net/ip_tunnels.h>
37 #include "spectrum_ipip.h"
40 mlxsw_sp_ipip_netdev_parms(const struct net_device
*ol_dev
)
42 struct ip_tunnel
*tun
= netdev_priv(ol_dev
);
47 static bool mlxsw_sp_ipip_parms_has_ikey(struct ip_tunnel_parm parms
)
49 return !!(parms
.i_flags
& TUNNEL_KEY
);
52 static bool mlxsw_sp_ipip_parms_has_okey(struct ip_tunnel_parm parms
)
54 return !!(parms
.o_flags
& TUNNEL_KEY
);
57 static u32
mlxsw_sp_ipip_parms_ikey(struct ip_tunnel_parm parms
)
59 return mlxsw_sp_ipip_parms_has_ikey(parms
) ?
60 be32_to_cpu(parms
.i_key
) : 0;
63 static u32
mlxsw_sp_ipip_parms_okey(struct ip_tunnel_parm parms
)
65 return mlxsw_sp_ipip_parms_has_okey(parms
) ?
66 be32_to_cpu(parms
.o_key
) : 0;
69 static __be32
mlxsw_sp_ipip_parms_saddr4(struct ip_tunnel_parm parms
)
71 return parms
.iph
.saddr
;
74 static union mlxsw_sp_l3addr
75 mlxsw_sp_ipip_parms_saddr(enum mlxsw_sp_l3proto proto
,
76 struct ip_tunnel_parm parms
)
79 case MLXSW_SP_L3_PROTO_IPV4
:
80 return (union mlxsw_sp_l3addr
) {
81 .addr4
= mlxsw_sp_ipip_parms_saddr4(parms
),
83 case MLXSW_SP_L3_PROTO_IPV6
:
88 return (union mlxsw_sp_l3addr
) {
93 static __be32
mlxsw_sp_ipip_parms_daddr4(struct ip_tunnel_parm parms
)
95 return parms
.iph
.daddr
;
98 static union mlxsw_sp_l3addr
99 mlxsw_sp_ipip_parms_daddr(enum mlxsw_sp_l3proto proto
,
100 struct ip_tunnel_parm parms
)
103 case MLXSW_SP_L3_PROTO_IPV4
:
104 return (union mlxsw_sp_l3addr
) {
105 .addr4
= mlxsw_sp_ipip_parms_daddr4(parms
),
107 case MLXSW_SP_L3_PROTO_IPV6
:
112 return (union mlxsw_sp_l3addr
) {
117 static bool mlxsw_sp_ipip_netdev_has_ikey(const struct net_device
*ol_dev
)
119 return mlxsw_sp_ipip_parms_has_ikey(mlxsw_sp_ipip_netdev_parms(ol_dev
));
122 static bool mlxsw_sp_ipip_netdev_has_okey(const struct net_device
*ol_dev
)
124 return mlxsw_sp_ipip_parms_has_okey(mlxsw_sp_ipip_netdev_parms(ol_dev
));
127 static u32
mlxsw_sp_ipip_netdev_ikey(const struct net_device
*ol_dev
)
129 return mlxsw_sp_ipip_parms_ikey(mlxsw_sp_ipip_netdev_parms(ol_dev
));
132 static u32
mlxsw_sp_ipip_netdev_okey(const struct net_device
*ol_dev
)
134 return mlxsw_sp_ipip_parms_okey(mlxsw_sp_ipip_netdev_parms(ol_dev
));
137 union mlxsw_sp_l3addr
138 mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto
,
139 const struct net_device
*ol_dev
)
141 return mlxsw_sp_ipip_parms_saddr(proto
,
142 mlxsw_sp_ipip_netdev_parms(ol_dev
));
145 static __be32
mlxsw_sp_ipip_netdev_daddr4(const struct net_device
*ol_dev
)
147 return mlxsw_sp_ipip_parms_daddr4(mlxsw_sp_ipip_netdev_parms(ol_dev
));
150 static union mlxsw_sp_l3addr
151 mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto
,
152 const struct net_device
*ol_dev
)
154 return mlxsw_sp_ipip_parms_daddr(proto
,
155 mlxsw_sp_ipip_netdev_parms(ol_dev
));
159 mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp
*mlxsw_sp
, u32 adj_index
,
160 struct mlxsw_sp_ipip_entry
*ipip_entry
)
162 u16 rif_index
= mlxsw_sp_ipip_lb_rif_index(ipip_entry
->ol_lb
);
163 __be32 daddr4
= mlxsw_sp_ipip_netdev_daddr4(ipip_entry
->ol_dev
);
164 char ratr_pl
[MLXSW_REG_RATR_LEN
];
166 mlxsw_reg_ratr_pack(ratr_pl
, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY
,
167 true, MLXSW_REG_RATR_TYPE_IPIP
,
168 adj_index
, rif_index
);
169 mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl
, be32_to_cpu(daddr4
));
171 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ratr
), ratr_pl
);
175 mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp
*mlxsw_sp
,
177 struct mlxsw_sp_ipip_entry
*ipip_entry
)
179 bool has_ikey
= mlxsw_sp_ipip_netdev_has_ikey(ipip_entry
->ol_dev
);
180 u16 rif_index
= mlxsw_sp_ipip_lb_rif_index(ipip_entry
->ol_lb
);
181 u32 ikey
= mlxsw_sp_ipip_netdev_ikey(ipip_entry
->ol_dev
);
182 char rtdp_pl
[MLXSW_REG_RTDP_LEN
];
183 unsigned int type_check
;
186 mlxsw_reg_rtdp_pack(rtdp_pl
, MLXSW_REG_RTDP_TYPE_IPIP
, tunnel_index
);
188 type_check
= has_ikey
?
189 MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY
:
190 MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE
;
192 /* Linux demuxes tunnels based on packet SIP (which must match tunnel
193 * remote IP). Thus configure decap so that it filters out packets that
194 * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is
195 * generated for packets that fail this criterion. Linux then handles
196 * such packets in slow path and generates ICMP destination unreachable.
198 daddr4
= be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry
->ol_dev
));
199 mlxsw_reg_rtdp_ipip4_pack(rtdp_pl
, rif_index
,
200 MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4
,
201 type_check
, has_ikey
, daddr4
, ikey
);
203 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rtdp
), rtdp_pl
);
207 mlxsw_sp_ipip_fib_entry_op_gre4_ralue(struct mlxsw_sp
*mlxsw_sp
,
208 u32 dip
, u8 prefix_len
, u16 ul_vr_id
,
209 enum mlxsw_reg_ralue_op op
,
212 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
214 mlxsw_reg_ralue_pack4(ralue_pl
, MLXSW_REG_RALXX_PROTOCOL_IPV4
, op
,
215 ul_vr_id
, prefix_len
, dip
);
216 mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl
, tunnel_index
);
217 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
220 static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp
*mlxsw_sp
,
221 struct mlxsw_sp_ipip_entry
*ipip_entry
,
222 enum mlxsw_reg_ralue_op op
,
225 u16 ul_vr_id
= mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry
->ol_lb
);
229 err
= mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(mlxsw_sp
, tunnel_index
,
234 dip
= mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4
,
235 ipip_entry
->ol_dev
).addr4
;
236 return mlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp
, be32_to_cpu(dip
),
241 static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto
,
242 const struct net_device
*ol_dev
)
244 union mlxsw_sp_l3addr saddr
= mlxsw_sp_ipip_netdev_saddr(proto
, ol_dev
);
245 union mlxsw_sp_l3addr daddr
= mlxsw_sp_ipip_netdev_daddr(proto
, ol_dev
);
246 union mlxsw_sp_l3addr naddr
= {0};
248 /* Tunnels with unset local or remote address are valid in Linux and
249 * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access
250 * (NBMA) tunnels. In principle these can be offloaded, but the driver
251 * currently doesn't support this. So punt.
253 return memcmp(&saddr
, &naddr
, sizeof(naddr
)) &&
254 memcmp(&daddr
, &naddr
, sizeof(naddr
));
257 static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp
*mlxsw_sp
,
258 const struct net_device
*ol_dev
,
259 enum mlxsw_sp_l3proto ol_proto
)
261 struct ip_tunnel
*tunnel
= netdev_priv(ol_dev
);
262 __be16 okflags
= TUNNEL_KEY
; /* We can't offload any other features. */
263 bool inherit_ttl
= tunnel
->parms
.iph
.ttl
== 0;
264 bool inherit_tos
= tunnel
->parms
.iph
.tos
& 0x1;
266 return (tunnel
->parms
.i_flags
& ~okflags
) == 0 &&
267 (tunnel
->parms
.o_flags
& ~okflags
) == 0 &&
268 inherit_ttl
&& inherit_tos
&&
269 mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4
, ol_dev
);
272 static struct mlxsw_sp_rif_ipip_lb_config
273 mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp
*mlxsw_sp
,
274 const struct net_device
*ol_dev
)
276 enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt
;
278 lb_ipipt
= mlxsw_sp_ipip_netdev_has_okey(ol_dev
) ?
279 MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP
:
280 MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP
;
281 return (struct mlxsw_sp_rif_ipip_lb_config
){
282 .lb_ipipt
= lb_ipipt
,
283 .okey
= mlxsw_sp_ipip_netdev_okey(ol_dev
),
284 .ul_protocol
= MLXSW_SP_L3_PROTO_IPV4
,
285 .saddr
= mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4
,
291 mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp
*mlxsw_sp
,
292 struct mlxsw_sp_ipip_entry
*ipip_entry
,
293 struct netlink_ext_ack
*extack
)
295 union mlxsw_sp_l3addr old_saddr
, new_saddr
;
296 union mlxsw_sp_l3addr old_daddr
, new_daddr
;
297 struct ip_tunnel_parm new_parms
;
298 bool update_tunnel
= false;
299 bool update_decap
= false;
300 bool update_nhs
= false;
303 new_parms
= mlxsw_sp_ipip_netdev_parms(ipip_entry
->ol_dev
);
305 new_saddr
= mlxsw_sp_ipip_parms_saddr(MLXSW_SP_L3_PROTO_IPV4
,
307 old_saddr
= mlxsw_sp_ipip_parms_saddr(MLXSW_SP_L3_PROTO_IPV4
,
309 new_daddr
= mlxsw_sp_ipip_parms_daddr(MLXSW_SP_L3_PROTO_IPV4
,
311 old_daddr
= mlxsw_sp_ipip_parms_daddr(MLXSW_SP_L3_PROTO_IPV4
,
314 if (!mlxsw_sp_l3addr_eq(&new_saddr
, &old_saddr
)) {
315 u16 ul_tb_id
= mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry
->ol_dev
);
317 /* Since the local address has changed, if there is another
318 * tunnel with a matching saddr, both need to be demoted.
320 if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp
,
321 MLXSW_SP_L3_PROTO_IPV4
,
324 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp
, ipip_entry
);
328 update_tunnel
= true;
329 } else if ((mlxsw_sp_ipip_parms_okey(ipip_entry
->parms
) !=
330 mlxsw_sp_ipip_parms_okey(new_parms
)) ||
331 ipip_entry
->parms
.link
!= new_parms
.link
) {
332 update_tunnel
= true;
333 } else if (!mlxsw_sp_l3addr_eq(&new_daddr
, &old_daddr
)) {
335 } else if (mlxsw_sp_ipip_parms_ikey(ipip_entry
->parms
) !=
336 mlxsw_sp_ipip_parms_ikey(new_parms
)) {
341 err
= __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp
, ipip_entry
,
345 err
= __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp
, ipip_entry
,
348 else if (update_decap
)
349 err
= __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp
, ipip_entry
,
353 ipip_entry
->parms
= new_parms
;
357 static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops
= {
358 .dev_type
= ARPHRD_IPGRE
,
359 .ul_proto
= MLXSW_SP_L3_PROTO_IPV4
,
360 .nexthop_update
= mlxsw_sp_ipip_nexthop_update_gre4
,
361 .fib_entry_op
= mlxsw_sp_ipip_fib_entry_op_gre4
,
362 .can_offload
= mlxsw_sp_ipip_can_offload_gre4
,
363 .ol_loopback_config
= mlxsw_sp_ipip_ol_loopback_config_gre4
,
364 .ol_netdev_change
= mlxsw_sp_ipip_ol_netdev_change_gre4
,
367 const struct mlxsw_sp_ipip_ops
*mlxsw_sp_ipip_ops_arr
[] = {
368 [MLXSW_SP_IPIP_TYPE_GRE4
] = &mlxsw_sp_ipip_gre4_ops
,