Skip to content

Commit ee954d1

Browse files
pmachatadavem330
authored andcommitted
mlxsw: spectrum_router: Support GRE tunnels
This patch introduces callbacks and tunnel type to offload GRE tunnels. Signed-off-by: Petr Machata <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 92107cf commit ee954d1

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,183 @@
3232
* POSSIBILITY OF SUCH DAMAGE.
3333
*/
3434

35+
#include <net/ip_tunnels.h>
36+
3537
#include "spectrum_ipip.h"
3638

39+
static bool
40+
mlxsw_sp_ipip_netdev_has_ikey(const struct net_device *ol_dev)
41+
{
42+
struct ip_tunnel *tun = netdev_priv(ol_dev);
43+
44+
return !!(tun->parms.i_flags & TUNNEL_KEY);
45+
}
46+
47+
static bool
48+
mlxsw_sp_ipip_netdev_has_okey(const struct net_device *ol_dev)
49+
{
50+
struct ip_tunnel *tun = netdev_priv(ol_dev);
51+
52+
return !!(tun->parms.o_flags & TUNNEL_KEY);
53+
}
54+
55+
static u32 mlxsw_sp_ipip_netdev_ikey(const struct net_device *ol_dev)
56+
{
57+
struct ip_tunnel *tun = netdev_priv(ol_dev);
58+
59+
return mlxsw_sp_ipip_netdev_has_ikey(ol_dev) ?
60+
be32_to_cpu(tun->parms.i_key) : 0;
61+
}
62+
63+
static u32 mlxsw_sp_ipip_netdev_okey(const struct net_device *ol_dev)
64+
{
65+
struct ip_tunnel *tun = netdev_priv(ol_dev);
66+
67+
return mlxsw_sp_ipip_netdev_has_okey(ol_dev) ?
68+
be32_to_cpu(tun->parms.o_key) : 0;
69+
}
70+
71+
static int
72+
mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
73+
struct mlxsw_sp_ipip_entry *ipip_entry)
74+
{
75+
u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
76+
__be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev);
77+
char ratr_pl[MLXSW_REG_RATR_LEN];
78+
79+
mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY,
80+
true, MLXSW_REG_RATR_TYPE_IPIP,
81+
adj_index, rif_index);
82+
mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4));
83+
84+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
85+
}
86+
87+
static int
88+
mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp,
89+
u32 tunnel_index,
90+
struct mlxsw_sp_ipip_entry *ipip_entry)
91+
{
92+
bool has_ikey = mlxsw_sp_ipip_netdev_has_ikey(ipip_entry->ol_dev);
93+
u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
94+
u32 ikey = mlxsw_sp_ipip_netdev_ikey(ipip_entry->ol_dev);
95+
char rtdp_pl[MLXSW_REG_RTDP_LEN];
96+
unsigned int type_check;
97+
u32 daddr4;
98+
99+
mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
100+
101+
type_check = has_ikey ?
102+
MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY :
103+
MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;
104+
105+
/* Linux demuxes tunnels based on packet SIP (which must match tunnel
106+
* remote IP). Thus configure decap so that it filters out packets that
107+
* are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is
108+
* generated for packets that fail this criterion. Linux then handles
109+
* such packets in slow path and generates ICMP destination unreachable.
110+
*/
111+
daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev));
112+
mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index,
113+
MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,
114+
type_check, has_ikey, daddr4, ikey);
115+
116+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
117+
}
118+
119+
static int
120+
mlxsw_sp_ipip_fib_entry_op_gre4_ralue(struct mlxsw_sp *mlxsw_sp,
121+
u32 dip, u8 prefix_len, u16 ul_vr_id,
122+
enum mlxsw_reg_ralue_op op,
123+
u32 tunnel_index)
124+
{
125+
char ralue_pl[MLXSW_REG_RALUE_LEN];
126+
127+
mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_REG_RALXX_PROTOCOL_IPV4, op,
128+
ul_vr_id, prefix_len, dip);
129+
mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, tunnel_index);
130+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
131+
}
132+
133+
static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp,
134+
struct mlxsw_sp_ipip_entry *ipip_entry,
135+
enum mlxsw_reg_ralue_op op,
136+
u32 tunnel_index)
137+
{
138+
u16 ul_vr_id = mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb);
139+
__be32 dip;
140+
int err;
141+
142+
err = mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(mlxsw_sp, tunnel_index,
143+
ipip_entry);
144+
if (err)
145+
return err;
146+
147+
dip = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
148+
ipip_entry->ol_dev).addr4;
149+
return mlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp, be32_to_cpu(dip),
150+
32, ul_vr_id, op,
151+
tunnel_index);
152+
}
153+
154+
static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto,
155+
const struct net_device *ol_dev)
156+
{
157+
union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev);
158+
union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev);
159+
union mlxsw_sp_l3addr naddr = {0};
160+
161+
/* Tunnels with unset local or remote address are valid in Linux and
162+
* used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access
163+
* (NBMA) tunnels. In principle these can be offloaded, but the driver
164+
* currently doesn't support this. So punt.
165+
*/
166+
return memcmp(&saddr, &naddr, sizeof(naddr)) &&
167+
memcmp(&daddr, &naddr, sizeof(naddr));
168+
}
169+
170+
static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp,
171+
const struct net_device *ol_dev,
172+
enum mlxsw_sp_l3proto ol_proto)
173+
{
174+
struct ip_tunnel *tunnel = netdev_priv(ol_dev);
175+
__be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */
176+
bool inherit_ttl = tunnel->parms.iph.ttl == 0;
177+
bool inherit_tos = tunnel->parms.iph.tos & 0x1;
178+
179+
return (tunnel->parms.i_flags & ~okflags) == 0 &&
180+
(tunnel->parms.o_flags & ~okflags) == 0 &&
181+
inherit_ttl && inherit_tos &&
182+
mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev);
183+
}
184+
185+
static struct mlxsw_sp_rif_ipip_lb_config
186+
mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
187+
const struct net_device *ol_dev)
188+
{
189+
enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
190+
191+
lb_ipipt = mlxsw_sp_ipip_netdev_has_okey(ol_dev) ?
192+
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
193+
MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
194+
return (struct mlxsw_sp_rif_ipip_lb_config){
195+
.lb_ipipt = lb_ipipt,
196+
.okey = mlxsw_sp_ipip_netdev_okey(ol_dev),
197+
.ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
198+
.saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
199+
ol_dev),
200+
};
201+
}
202+
203+
static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = {
204+
.dev_type = ARPHRD_IPGRE,
205+
.ul_proto = MLXSW_SP_L3_PROTO_IPV4,
206+
.nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4,
207+
.fib_entry_op = mlxsw_sp_ipip_fib_entry_op_gre4,
208+
.can_offload = mlxsw_sp_ipip_can_offload_gre4,
209+
.ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4,
210+
};
211+
37212
const struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[] = {
213+
[MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops,
38214
};

drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <net/ip_fib.h>
4040

4141
enum mlxsw_sp_ipip_type {
42+
MLXSW_SP_IPIP_TYPE_GRE4,
4243
MLXSW_SP_IPIP_TYPE_MAX,
4344
};
4445

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,32 @@ mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
10201020
};
10211021
}
10221022

1023+
__be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
1024+
{
1025+
struct ip_tunnel *tun = netdev_priv(ol_dev);
1026+
1027+
return tun->parms.iph.daddr;
1028+
}
1029+
1030+
union mlxsw_sp_l3addr
1031+
mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
1032+
const struct net_device *ol_dev)
1033+
{
1034+
switch (proto) {
1035+
case MLXSW_SP_L3_PROTO_IPV4:
1036+
return (union mlxsw_sp_l3addr) {
1037+
.addr4 = mlxsw_sp_ipip_netdev_daddr4(ol_dev),
1038+
};
1039+
case MLXSW_SP_L3_PROTO_IPV6:
1040+
break;
1041+
};
1042+
1043+
WARN_ON(1);
1044+
return (union mlxsw_sp_l3addr) {
1045+
.addr4 = 0,
1046+
};
1047+
}
1048+
10231049
static bool mlxsw_sp_l3addr_eq(const union mlxsw_sp_l3addr *addr1,
10241050
const union mlxsw_sp_l3addr *addr2)
10251051
{

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,9 @@ bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry);
103103
union mlxsw_sp_l3addr
104104
mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
105105
const struct net_device *ol_dev);
106+
union mlxsw_sp_l3addr
107+
mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
108+
const struct net_device *ol_dev);
109+
__be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev);
106110

107111
#endif /* _MLXSW_ROUTER_H_*/

0 commit comments

Comments
 (0)