mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-11 00:44:01 +00:00
nfp: compile flower vxlan tunnel set actions
Compile set tunnel actions for tc flower. Only support VXLAN and ensure a tunnel destination port of 4789 is used. Signed-off-by: John Hurley <john.hurley@netronome.com> Signed-off-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
611aec101a
commit
b27d6a95a7
2 changed files with 180 additions and 22 deletions
|
@ -37,6 +37,7 @@
|
||||||
#include <net/tc_act/tc_gact.h>
|
#include <net/tc_act/tc_gact.h>
|
||||||
#include <net/tc_act/tc_mirred.h>
|
#include <net/tc_act/tc_mirred.h>
|
||||||
#include <net/tc_act/tc_vlan.h>
|
#include <net/tc_act/tc_vlan.h>
|
||||||
|
#include <net/tc_act/tc_tunnel_key.h>
|
||||||
|
|
||||||
#include "cmsg.h"
|
#include "cmsg.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -80,14 +81,27 @@ nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan,
|
||||||
push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci);
|
push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfp_fl_netdev_is_tunnel_type(struct net_device *out_dev,
|
||||||
|
enum nfp_flower_tun_type tun_type)
|
||||||
|
{
|
||||||
|
if (!out_dev->rtnl_link_ops)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!strcmp(out_dev->rtnl_link_ops->kind, "vxlan"))
|
||||||
|
return tun_type == NFP_FL_TUNNEL_VXLAN;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
|
nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
|
||||||
struct nfp_fl_payload *nfp_flow, bool last,
|
struct nfp_fl_payload *nfp_flow, bool last,
|
||||||
struct net_device *in_dev)
|
struct net_device *in_dev, enum nfp_flower_tun_type tun_type,
|
||||||
|
int *tun_out_cnt)
|
||||||
{
|
{
|
||||||
size_t act_size = sizeof(struct nfp_fl_output);
|
size_t act_size = sizeof(struct nfp_fl_output);
|
||||||
|
u16 tmp_output_op, tmp_flags;
|
||||||
struct net_device *out_dev;
|
struct net_device *out_dev;
|
||||||
u16 tmp_output_op;
|
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
|
||||||
/* Set action opcode to output action. */
|
/* Set action opcode to output action. */
|
||||||
|
@ -97,34 +111,126 @@ nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
|
||||||
|
|
||||||
output->a_op = cpu_to_be16(tmp_output_op);
|
output->a_op = cpu_to_be16(tmp_output_op);
|
||||||
|
|
||||||
/* Set action output parameters. */
|
|
||||||
output->flags = cpu_to_be16(last ? NFP_FL_OUT_FLAGS_LAST : 0);
|
|
||||||
|
|
||||||
ifindex = tcf_mirred_ifindex(action);
|
ifindex = tcf_mirred_ifindex(action);
|
||||||
out_dev = __dev_get_by_index(dev_net(in_dev), ifindex);
|
out_dev = __dev_get_by_index(dev_net(in_dev), ifindex);
|
||||||
if (!out_dev)
|
if (!out_dev)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
/* Only offload egress ports are on the same device as the ingress
|
tmp_flags = last ? NFP_FL_OUT_FLAGS_LAST : 0;
|
||||||
* port.
|
|
||||||
*/
|
|
||||||
if (!switchdev_port_same_parent_id(in_dev, out_dev))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev));
|
if (tun_type) {
|
||||||
if (!output->port)
|
/* Verify the egress netdev matches the tunnel type. */
|
||||||
return -EOPNOTSUPP;
|
if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (*tun_out_cnt)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
(*tun_out_cnt)++;
|
||||||
|
|
||||||
|
output->flags = cpu_to_be16(tmp_flags |
|
||||||
|
NFP_FL_OUT_FLAGS_USE_TUN);
|
||||||
|
output->port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
|
||||||
|
} else {
|
||||||
|
/* Set action output parameters. */
|
||||||
|
output->flags = cpu_to_be16(tmp_flags);
|
||||||
|
|
||||||
|
/* Only offload if egress ports are on the same device as the
|
||||||
|
* ingress port.
|
||||||
|
*/
|
||||||
|
if (!switchdev_port_same_parent_id(in_dev, out_dev))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev));
|
||||||
|
if (!output->port)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
nfp_flow->meta.shortcut = output->port;
|
nfp_flow->meta.shortcut = output->port;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool nfp_fl_supported_tun_port(const struct tc_action *action)
|
||||||
|
{
|
||||||
|
struct ip_tunnel_info *tun = tcf_tunnel_info(action);
|
||||||
|
|
||||||
|
return tun->key.tp_dst == htons(NFP_FL_VXLAN_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
|
||||||
|
{
|
||||||
|
size_t act_size = sizeof(struct nfp_fl_pre_tunnel);
|
||||||
|
struct nfp_fl_pre_tunnel *pre_tun_act;
|
||||||
|
u16 tmp_pre_tun_op;
|
||||||
|
|
||||||
|
/* Pre_tunnel action must be first on action list.
|
||||||
|
* If other actions already exist they need pushed forward.
|
||||||
|
*/
|
||||||
|
if (act_len)
|
||||||
|
memmove(act_data + act_size, act_data, act_len);
|
||||||
|
|
||||||
|
pre_tun_act = (struct nfp_fl_pre_tunnel *)act_data;
|
||||||
|
|
||||||
|
memset(pre_tun_act, 0, act_size);
|
||||||
|
|
||||||
|
tmp_pre_tun_op =
|
||||||
|
FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
|
||||||
|
FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PRE_TUNNEL);
|
||||||
|
|
||||||
|
pre_tun_act->a_op = cpu_to_be16(tmp_pre_tun_op);
|
||||||
|
|
||||||
|
return pre_tun_act;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan,
|
||||||
|
const struct tc_action *action,
|
||||||
|
struct nfp_fl_pre_tunnel *pre_tun)
|
||||||
|
{
|
||||||
|
struct ip_tunnel_info *vxlan = tcf_tunnel_info(action);
|
||||||
|
size_t act_size = sizeof(struct nfp_fl_set_vxlan);
|
||||||
|
u32 tmp_set_vxlan_type_index = 0;
|
||||||
|
u16 tmp_set_vxlan_op;
|
||||||
|
/* Currently support one pre-tunnel so index is always 0. */
|
||||||
|
int pretun_idx = 0;
|
||||||
|
|
||||||
|
if (vxlan->options_len) {
|
||||||
|
/* Do not support options e.g. vxlan gpe. */
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_set_vxlan_op =
|
||||||
|
FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
|
||||||
|
FIELD_PREP(NFP_FL_ACT_JMP_ID,
|
||||||
|
NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL);
|
||||||
|
|
||||||
|
set_vxlan->a_op = cpu_to_be16(tmp_set_vxlan_op);
|
||||||
|
|
||||||
|
/* Set tunnel type and pre-tunnel index. */
|
||||||
|
tmp_set_vxlan_type_index |=
|
||||||
|
FIELD_PREP(NFP_FL_IPV4_TUNNEL_TYPE, NFP_FL_TUNNEL_VXLAN) |
|
||||||
|
FIELD_PREP(NFP_FL_IPV4_PRE_TUN_INDEX, pretun_idx);
|
||||||
|
|
||||||
|
set_vxlan->tun_type_index = cpu_to_be32(tmp_set_vxlan_type_index);
|
||||||
|
|
||||||
|
set_vxlan->tun_id = vxlan->key.tun_id;
|
||||||
|
set_vxlan->tun_flags = vxlan->key.tun_flags;
|
||||||
|
set_vxlan->ipv4_ttl = vxlan->key.ttl;
|
||||||
|
set_vxlan->ipv4_tos = vxlan->key.tos;
|
||||||
|
|
||||||
|
/* Complete pre_tunnel action. */
|
||||||
|
pre_tun->ipv4_dst = vxlan->key.u.ipv4.dst;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nfp_flower_loop_action(const struct tc_action *a,
|
nfp_flower_loop_action(const struct tc_action *a,
|
||||||
struct nfp_fl_payload *nfp_fl, int *a_len,
|
struct nfp_fl_payload *nfp_fl, int *a_len,
|
||||||
struct net_device *netdev)
|
struct net_device *netdev,
|
||||||
|
enum nfp_flower_tun_type *tun_type, int *tun_out_cnt)
|
||||||
{
|
{
|
||||||
|
struct nfp_fl_pre_tunnel *pre_tun;
|
||||||
|
struct nfp_fl_set_vxlan *s_vxl;
|
||||||
struct nfp_fl_push_vlan *psh_v;
|
struct nfp_fl_push_vlan *psh_v;
|
||||||
struct nfp_fl_pop_vlan *pop_v;
|
struct nfp_fl_pop_vlan *pop_v;
|
||||||
struct nfp_fl_output *output;
|
struct nfp_fl_output *output;
|
||||||
|
@ -137,7 +243,8 @@ nfp_flower_loop_action(const struct tc_action *a,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
|
output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
|
||||||
err = nfp_fl_output(output, a, nfp_fl, true, netdev);
|
err = nfp_fl_output(output, a, nfp_fl, true, netdev, *tun_type,
|
||||||
|
tun_out_cnt);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -147,7 +254,8 @@ nfp_flower_loop_action(const struct tc_action *a,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
|
output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
|
||||||
err = nfp_fl_output(output, a, nfp_fl, false, netdev);
|
err = nfp_fl_output(output, a, nfp_fl, false, netdev, *tun_type,
|
||||||
|
tun_out_cnt);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -170,6 +278,29 @@ nfp_flower_loop_action(const struct tc_action *a,
|
||||||
|
|
||||||
nfp_fl_push_vlan(psh_v, a);
|
nfp_fl_push_vlan(psh_v, a);
|
||||||
*a_len += sizeof(struct nfp_fl_push_vlan);
|
*a_len += sizeof(struct nfp_fl_push_vlan);
|
||||||
|
} else if (is_tcf_tunnel_set(a) && nfp_fl_supported_tun_port(a)) {
|
||||||
|
/* Pre-tunnel action is required for tunnel encap.
|
||||||
|
* This checks for next hop entries on NFP.
|
||||||
|
* If none, the packet falls back before applying other actions.
|
||||||
|
*/
|
||||||
|
if (*a_len + sizeof(struct nfp_fl_pre_tunnel) +
|
||||||
|
sizeof(struct nfp_fl_set_vxlan) > NFP_FL_MAX_A_SIZ)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
*tun_type = NFP_FL_TUNNEL_VXLAN;
|
||||||
|
pre_tun = nfp_fl_pre_tunnel(nfp_fl->action_data, *a_len);
|
||||||
|
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
|
||||||
|
*a_len += sizeof(struct nfp_fl_pre_tunnel);
|
||||||
|
|
||||||
|
s_vxl = (struct nfp_fl_set_vxlan *)&nfp_fl->action_data[*a_len];
|
||||||
|
err = nfp_fl_set_vxlan(s_vxl, a, pre_tun);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
*a_len += sizeof(struct nfp_fl_set_vxlan);
|
||||||
|
} else if (is_tcf_tunnel_release(a)) {
|
||||||
|
/* Tunnel decap is handled by default so accept action. */
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
/* Currently we do not handle any other actions. */
|
/* Currently we do not handle any other actions. */
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -182,18 +313,22 @@ int nfp_flower_compile_action(struct tc_cls_flower_offload *flow,
|
||||||
struct net_device *netdev,
|
struct net_device *netdev,
|
||||||
struct nfp_fl_payload *nfp_flow)
|
struct nfp_fl_payload *nfp_flow)
|
||||||
{
|
{
|
||||||
int act_len, act_cnt, err;
|
int act_len, act_cnt, err, tun_out_cnt;
|
||||||
|
enum nfp_flower_tun_type tun_type;
|
||||||
const struct tc_action *a;
|
const struct tc_action *a;
|
||||||
LIST_HEAD(actions);
|
LIST_HEAD(actions);
|
||||||
|
|
||||||
memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
|
memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
|
||||||
nfp_flow->meta.act_len = 0;
|
nfp_flow->meta.act_len = 0;
|
||||||
|
tun_type = NFP_FL_TUNNEL_NONE;
|
||||||
act_len = 0;
|
act_len = 0;
|
||||||
act_cnt = 0;
|
act_cnt = 0;
|
||||||
|
tun_out_cnt = 0;
|
||||||
|
|
||||||
tcf_exts_to_list(flow->exts, &actions);
|
tcf_exts_to_list(flow->exts, &actions);
|
||||||
list_for_each_entry(a, &actions, list) {
|
list_for_each_entry(a, &actions, list) {
|
||||||
err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev);
|
err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev,
|
||||||
|
&tun_type, &tun_out_cnt);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
act_cnt++;
|
act_cnt++;
|
||||||
|
|
|
@ -67,10 +67,12 @@
|
||||||
#define NFP_FL_LW_SIZ 2
|
#define NFP_FL_LW_SIZ 2
|
||||||
|
|
||||||
/* Action opcodes */
|
/* Action opcodes */
|
||||||
#define NFP_FL_ACTION_OPCODE_OUTPUT 0
|
#define NFP_FL_ACTION_OPCODE_OUTPUT 0
|
||||||
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN 1
|
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN 1
|
||||||
#define NFP_FL_ACTION_OPCODE_POP_VLAN 2
|
#define NFP_FL_ACTION_OPCODE_POP_VLAN 2
|
||||||
#define NFP_FL_ACTION_OPCODE_NUM 32
|
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6
|
||||||
|
#define NFP_FL_ACTION_OPCODE_PRE_TUNNEL 17
|
||||||
|
#define NFP_FL_ACTION_OPCODE_NUM 32
|
||||||
|
|
||||||
#define NFP_FL_ACT_JMP_ID GENMASK(15, 8)
|
#define NFP_FL_ACT_JMP_ID GENMASK(15, 8)
|
||||||
#define NFP_FL_ACT_LEN_LW GENMASK(7, 0)
|
#define NFP_FL_ACT_LEN_LW GENMASK(7, 0)
|
||||||
|
@ -85,6 +87,8 @@
|
||||||
|
|
||||||
/* Tunnel ports */
|
/* Tunnel ports */
|
||||||
#define NFP_FL_PORT_TYPE_TUN 0x50000000
|
#define NFP_FL_PORT_TYPE_TUN 0x50000000
|
||||||
|
#define NFP_FL_IPV4_TUNNEL_TYPE GENMASK(7, 4)
|
||||||
|
#define NFP_FL_IPV4_PRE_TUN_INDEX GENMASK(2, 0)
|
||||||
|
|
||||||
enum nfp_flower_tun_type {
|
enum nfp_flower_tun_type {
|
||||||
NFP_FL_TUNNEL_NONE = 0,
|
NFP_FL_TUNNEL_NONE = 0,
|
||||||
|
@ -123,6 +127,25 @@ struct nfp_flower_meta_one {
|
||||||
u16 reserved;
|
u16 reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nfp_fl_pre_tunnel {
|
||||||
|
__be16 a_op;
|
||||||
|
__be16 reserved;
|
||||||
|
__be32 ipv4_dst;
|
||||||
|
/* reserved for use with IPv6 addresses */
|
||||||
|
__be32 extra[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfp_fl_set_vxlan {
|
||||||
|
__be16 a_op;
|
||||||
|
__be16 reserved;
|
||||||
|
__be64 tun_id;
|
||||||
|
__be32 tun_type_index;
|
||||||
|
__be16 tun_flags;
|
||||||
|
u8 ipv4_ttl;
|
||||||
|
u8 ipv4_tos;
|
||||||
|
__be32 extra[2];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* Metadata with L2 (1W/4B)
|
/* Metadata with L2 (1W/4B)
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
* 3 2 1
|
* 3 2 1
|
||||||
|
|
Loading…
Add table
Reference in a new issue