Skip to content

Commit ce99f6b

Browse files
ogerlitzSaeed Mahameed
authored andcommitted
net/mlx5e: Support SRIOV TC encapsulation offloads for IPv6 tunnels
Add the missing parts for offloading IPv6 tunnels. This includes route and neigh lookups and construnction of the IPv6 tunnel headers. Signed-off-by: Or Gerlitz <[email protected]> Reviewed-by: Hadar Hen Zion <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 9a94111 commit ce99f6b

File tree

1 file changed

+151
-8
lines changed
  • drivers/net/ethernet/mellanox/mlx5/core

1 file changed

+151
-8
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 151 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,47 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
718718
return 0;
719719
}
720720

721+
static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
722+
struct net_device *mirred_dev,
723+
struct net_device **out_dev,
724+
struct flowi6 *fl6,
725+
struct neighbour **out_n,
726+
int *out_ttl)
727+
{
728+
struct neighbour *n = NULL;
729+
struct dst_entry *dst;
730+
731+
#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
732+
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
733+
int ret;
734+
735+
dst = ip6_route_output(dev_net(mirred_dev), NULL, fl6);
736+
if (dst->error) {
737+
ret = dst->error;
738+
dst_release(dst);
739+
return ret;
740+
}
741+
742+
*out_ttl = ip6_dst_hoplimit(dst);
743+
744+
/* if the egress device isn't on the same HW e-switch, we use the uplink */
745+
if (!switchdev_port_same_parent_id(priv->netdev, dst->dev))
746+
*out_dev = mlx5_eswitch_get_uplink_netdev(esw);
747+
else
748+
*out_dev = dst->dev;
749+
#else
750+
return -EOPNOTSUPP;
751+
#endif
752+
753+
n = dst_neigh_lookup(dst, &fl6->daddr);
754+
dst_release(dst);
755+
if (!n)
756+
return -ENOMEM;
757+
758+
*out_n = n;
759+
return 0;
760+
}
761+
721762
static int gen_vxlan_header_ipv4(struct net_device *out_dev,
722763
char buf[],
723764
unsigned char h_dest[ETH_ALEN],
@@ -754,6 +795,41 @@ static int gen_vxlan_header_ipv4(struct net_device *out_dev,
754795
return encap_size;
755796
}
756797

798+
static int gen_vxlan_header_ipv6(struct net_device *out_dev,
799+
char buf[],
800+
unsigned char h_dest[ETH_ALEN],
801+
int ttl,
802+
struct in6_addr *daddr,
803+
struct in6_addr *saddr,
804+
__be16 udp_dst_port,
805+
__be32 vx_vni)
806+
{
807+
int encap_size = VXLAN_HLEN + sizeof(struct ipv6hdr) + ETH_HLEN;
808+
struct ethhdr *eth = (struct ethhdr *)buf;
809+
struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr));
810+
struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr));
811+
struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
812+
813+
memset(buf, 0, encap_size);
814+
815+
ether_addr_copy(eth->h_dest, h_dest);
816+
ether_addr_copy(eth->h_source, out_dev->dev_addr);
817+
eth->h_proto = htons(ETH_P_IPV6);
818+
819+
ip6_flow_hdr(ip6h, 0, 0);
820+
/* the HW fills up ipv6 payload len */
821+
ip6h->nexthdr = IPPROTO_UDP;
822+
ip6h->hop_limit = ttl;
823+
ip6h->daddr = *daddr;
824+
ip6h->saddr = *saddr;
825+
826+
udp->dest = udp_dst_port;
827+
vxh->vx_flags = VXLAN_HF_VNI;
828+
vxh->vx_vni = vxlan_vni_field(vx_vni);
829+
830+
return encap_size;
831+
}
832+
757833
static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
758834
struct net_device *mirred_dev,
759835
struct mlx5_encap_entry *e,
@@ -821,6 +897,75 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
821897
return err;
822898
}
823899

900+
static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
901+
struct net_device *mirred_dev,
902+
struct mlx5_encap_entry *e,
903+
struct net_device **out_dev)
904+
905+
{
906+
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
907+
struct ip_tunnel_key *tun_key = &e->tun_info.key;
908+
int encap_size, err, ttl = 0;
909+
struct neighbour *n = NULL;
910+
struct flowi6 fl6 = {};
911+
char *encap_header;
912+
913+
encap_header = kzalloc(max_encap_size, GFP_KERNEL);
914+
if (!encap_header)
915+
return -ENOMEM;
916+
917+
switch (e->tunnel_type) {
918+
case MLX5_HEADER_TYPE_VXLAN:
919+
fl6.flowi6_proto = IPPROTO_UDP;
920+
fl6.fl6_dport = tun_key->tp_dst;
921+
break;
922+
default:
923+
err = -EOPNOTSUPP;
924+
goto out;
925+
}
926+
927+
fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label);
928+
fl6.daddr = tun_key->u.ipv6.dst;
929+
fl6.saddr = tun_key->u.ipv6.src;
930+
931+
err = mlx5e_route_lookup_ipv6(priv, mirred_dev, out_dev,
932+
&fl6, &n, &ttl);
933+
if (err)
934+
goto out;
935+
936+
if (!(n->nud_state & NUD_VALID)) {
937+
pr_warn("%s: can't offload, neighbour to %pI6 invalid\n", __func__, &fl6.daddr);
938+
err = -EOPNOTSUPP;
939+
goto out;
940+
}
941+
942+
e->n = n;
943+
e->out_dev = *out_dev;
944+
945+
neigh_ha_snapshot(e->h_dest, n, *out_dev);
946+
947+
switch (e->tunnel_type) {
948+
case MLX5_HEADER_TYPE_VXLAN:
949+
encap_size = gen_vxlan_header_ipv6(*out_dev, encap_header,
950+
e->h_dest, ttl,
951+
&fl6.daddr,
952+
&fl6.saddr, tun_key->tp_dst,
953+
tunnel_id_to_key32(tun_key->tun_id));
954+
break;
955+
default:
956+
err = -EOPNOTSUPP;
957+
goto out;
958+
}
959+
960+
err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
961+
encap_size, encap_header, &e->encap_id);
962+
out:
963+
if (err && n)
964+
neigh_release(n);
965+
kfree(encap_header);
966+
return err;
967+
}
968+
824969
static int mlx5e_attach_encap(struct mlx5e_priv *priv,
825970
struct ip_tunnel_info *tun_info,
826971
struct net_device *mirred_dev,
@@ -831,7 +976,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
831976
struct ip_tunnel_key *key = &tun_info->key;
832977
struct mlx5_encap_entry *e;
833978
struct net_device *out_dev;
834-
int tunnel_type, err;
979+
int tunnel_type, err = -EOPNOTSUPP;
835980
uintptr_t hash_key;
836981
bool found = false;
837982

@@ -856,12 +1001,6 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
8561001
return -EOPNOTSUPP;
8571002
}
8581003

859-
if (family == AF_INET6) {
860-
netdev_warn(priv->netdev,
861-
"IPv6 tunnel encap offload isn't supported\n");
862-
return -EOPNOTSUPP;
863-
}
864-
8651004
hash_key = hash_encap_info(key);
8661005

8671006
hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
@@ -885,7 +1024,11 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
8851024
e->tunnel_type = tunnel_type;
8861025
INIT_LIST_HEAD(&e->flows);
8871026

888-
err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e, &out_dev);
1027+
if (family == AF_INET)
1028+
err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e, &out_dev);
1029+
else if (family == AF_INET6)
1030+
err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e, &out_dev);
1031+
8891032
if (err)
8901033
goto out_err;
8911034

0 commit comments

Comments
 (0)