1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2018 Mellanox Technologies. */ 3 4#include <net/bareudp.h> 5#include <net/mpls.h> 6#include "en/tc_tun.h" 7 8static bool can_offload(struct mlx5e_priv *priv) 9{ 10 return MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, reformat_l3_tunnel_to_l2); 11} 12 13static int calc_hlen(struct mlx5e_encap_entry *e) 14{ 15 return sizeof(struct udphdr) + MPLS_HLEN; 16} 17 18static int init_encap_attr(struct net_device *tunnel_dev, 19 struct mlx5e_priv *priv, 20 struct mlx5e_encap_entry *e, 21 struct netlink_ext_ack *extack) 22{ 23 e->tunnel = &mplsoudp_tunnel; 24 e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; 25 return 0; 26} 27 28static int generate_ip_tun_hdr(char buf[], 29 __u8 *ip_proto, 30 struct mlx5e_encap_entry *r) 31{ 32 const struct ip_tunnel_key *tun_key = &r->tun_info->key; 33 const struct mlx5e_mpls_info *mpls_info = &r->mpls_info; 34 struct udphdr *udp = (struct udphdr *)(buf); 35 struct mpls_shim_hdr *mpls; 36 37 mpls = (struct mpls_shim_hdr *)(udp + 1); 38 *ip_proto = IPPROTO_UDP; 39 40 udp->dest = tun_key->tp_dst; 41 *mpls = mpls_entry_encode(mpls_info->label, mpls_info->ttl, mpls_info->tc, mpls_info->bos); 42 43 return 0; 44} 45 46static int parse_udp_ports(struct mlx5e_priv *priv, 47 struct mlx5_flow_spec *spec, 48 struct flow_cls_offload *f, 49 void *headers_c, 50 void *headers_v) 51{ 52 return mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v); 53} 54 55static int parse_tunnel(struct mlx5e_priv *priv, 56 struct mlx5_flow_spec *spec, 57 struct flow_cls_offload *f, 58 void *headers_c, 59 void *headers_v) 60{ 61 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 62 struct flow_match_mpls match; 63 void *misc2_c; 64 void *misc2_v; 65 66 if (!MLX5_CAP_ETH(priv->mdev, tunnel_stateless_mpls_over_udp) && 67 !(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_CW_MPLS_UDP)) 68 return -EOPNOTSUPP; 69 70 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) 71 return -EOPNOTSUPP; 72 73 if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS)) 74 return 0; 75 76 flow_rule_match_mpls(rule, &match); 77 78 /* Only support matching the first LSE */ 79 if (match.mask->used_lses != 1) 80 return -EOPNOTSUPP; 81 82 misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 83 misc_parameters_2); 84 misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 85 misc_parameters_2); 86 87 MLX5_SET(fte_match_set_misc2, misc2_c, 88 outer_first_mpls_over_udp.mpls_label, 89 match.mask->ls[0].mpls_label); 90 MLX5_SET(fte_match_set_misc2, misc2_v, 91 outer_first_mpls_over_udp.mpls_label, 92 match.key->ls[0].mpls_label); 93 94 MLX5_SET(fte_match_set_misc2, misc2_c, 95 outer_first_mpls_over_udp.mpls_exp, 96 match.mask->ls[0].mpls_tc); 97 MLX5_SET(fte_match_set_misc2, misc2_v, 98 outer_first_mpls_over_udp.mpls_exp, match.key->ls[0].mpls_tc); 99 100 MLX5_SET(fte_match_set_misc2, misc2_c, 101 outer_first_mpls_over_udp.mpls_s_bos, 102 match.mask->ls[0].mpls_bos); 103 MLX5_SET(fte_match_set_misc2, misc2_v, 104 outer_first_mpls_over_udp.mpls_s_bos, 105 match.key->ls[0].mpls_bos); 106 107 MLX5_SET(fte_match_set_misc2, misc2_c, 108 outer_first_mpls_over_udp.mpls_ttl, 109 match.mask->ls[0].mpls_ttl); 110 MLX5_SET(fte_match_set_misc2, misc2_v, 111 outer_first_mpls_over_udp.mpls_ttl, 112 match.key->ls[0].mpls_ttl); 113 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2; 114 115 return 0; 116} 117 118struct mlx5e_tc_tunnel mplsoudp_tunnel = { 119 .tunnel_type = MLX5E_TC_TUNNEL_TYPE_MPLSOUDP, 120 .match_level = MLX5_MATCH_L4, 121 .can_offload = can_offload, 122 .calc_hlen = calc_hlen, 123 .init_encap_attr = init_encap_attr, 124 .generate_ip_tun_hdr = generate_ip_tun_hdr, 125 .parse_udp_ports = parse_udp_ports, 126 .parse_tunnel = parse_tunnel, 127 .encap_info_equal = mlx5e_tc_tun_encap_info_equal_generic, 128}; 129