Commit d5082b27 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-ttl-tos-geneve'

Simon Horman says:

====================
nfp: flower: tunnel TTL & TOS, and Geneve options set & match support

this series contains updates for the TC Flower classifier
and the offload facility for it in the NFP driver.

* Patches 1 & 2: update the NFP driver to allow offload
  of matching and setting tunnel ToS/TTL of flows using the TC Flower
  classifier and tun_key action

* Patches 3 & 4: enhance the flow dissector and TC Flower classifier
  to allow match on Geneve options

* Patch 5 & 6: update the NFP driver to allow offload of
  matching and setting Geneve options of flows using the TC Flower
  classifier and tun_key action
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 50ee42b9 0a22b17a
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <net/geneve.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/switchdev.h> #include <net/switchdev.h>
#include <net/tc_act/tc_csum.h> #include <net/tc_act/tc_csum.h>
...@@ -45,7 +46,15 @@ ...@@ -45,7 +46,15 @@
#include "main.h" #include "main.h"
#include "../nfp_net_repr.h" #include "../nfp_net_repr.h"
#define NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS (TUNNEL_CSUM | TUNNEL_KEY) /* The kernel versions of TUNNEL_* are not ABI and therefore vulnerable
* to change. Such changes will break our FW ABI.
*/
#define NFP_FL_TUNNEL_CSUM cpu_to_be16(0x01)
#define NFP_FL_TUNNEL_KEY cpu_to_be16(0x04)
#define NFP_FL_TUNNEL_GENEVE_OPT cpu_to_be16(0x0800)
#define NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS (NFP_FL_TUNNEL_CSUM | \
NFP_FL_TUNNEL_KEY | \
NFP_FL_TUNNEL_GENEVE_OPT)
static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan) static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan)
{ {
...@@ -229,7 +238,71 @@ static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len) ...@@ -229,7 +238,71 @@ static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
} }
static int static int
nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun, nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
const struct tc_action *action)
{
struct ip_tunnel_info *ip_tun = tcf_tunnel_info(action);
int opt_len, opt_cnt, act_start, tot_push_len;
u8 *src = ip_tunnel_info_opts(ip_tun);
/* We need to populate the options in reverse order for HW.
* Therefore we go through the options, calculating the
* number of options and the total size, then we populate
* them in reverse order in the action list.
*/
opt_cnt = 0;
tot_push_len = 0;
opt_len = ip_tun->options_len;
while (opt_len > 0) {
struct geneve_opt *opt = (struct geneve_opt *)src;
opt_cnt++;
if (opt_cnt > NFP_FL_MAX_GENEVE_OPT_CNT)
return -EOPNOTSUPP;
tot_push_len += sizeof(struct nfp_fl_push_geneve) +
opt->length * 4;
if (tot_push_len > NFP_FL_MAX_GENEVE_OPT_ACT)
return -EOPNOTSUPP;
opt_len -= sizeof(struct geneve_opt) + opt->length * 4;
src += sizeof(struct geneve_opt) + opt->length * 4;
}
if (*list_len + tot_push_len > NFP_FL_MAX_A_SIZ)
return -EOPNOTSUPP;
act_start = *list_len;
*list_len += tot_push_len;
src = ip_tunnel_info_opts(ip_tun);
while (opt_cnt) {
struct geneve_opt *opt = (struct geneve_opt *)src;
struct nfp_fl_push_geneve *push;
size_t act_size, len;
opt_cnt--;
act_size = sizeof(struct nfp_fl_push_geneve) + opt->length * 4;
tot_push_len -= act_size;
len = act_start + tot_push_len;
push = (struct nfp_fl_push_geneve *)&nfp_fl->action_data[len];
push->head.jump_id = NFP_FL_ACTION_OPCODE_PUSH_GENEVE;
push->head.len_lw = act_size >> NFP_FL_LW_SIZ;
push->reserved = 0;
push->class = opt->opt_class;
push->type = opt->type;
push->length = opt->length;
memcpy(&push->opt_data, opt->opt_data, opt->length * 4);
src += sizeof(struct geneve_opt) + opt->length * 4;
}
return 0;
}
static int
nfp_fl_set_ipv4_udp_tun(struct nfp_app *app,
struct nfp_fl_set_ipv4_udp_tun *set_tun,
const struct tc_action *action, const struct tc_action *action,
struct nfp_fl_pre_tunnel *pre_tun, struct nfp_fl_pre_tunnel *pre_tun,
enum nfp_flower_tun_type tun_type, enum nfp_flower_tun_type tun_type,
...@@ -237,19 +310,19 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun, ...@@ -237,19 +310,19 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
{ {
size_t act_size = sizeof(struct nfp_fl_set_ipv4_udp_tun); size_t act_size = sizeof(struct nfp_fl_set_ipv4_udp_tun);
struct ip_tunnel_info *ip_tun = tcf_tunnel_info(action); struct ip_tunnel_info *ip_tun = tcf_tunnel_info(action);
struct nfp_flower_priv *priv = app->priv;
u32 tmp_set_ip_tun_type_index = 0; u32 tmp_set_ip_tun_type_index = 0;
struct flowi4 flow = {};
/* Currently support one pre-tunnel so index is always 0. */ /* Currently support one pre-tunnel so index is always 0. */
int pretun_idx = 0; int pretun_idx = 0;
struct rtable *rt;
struct net *net;
int err;
if (ip_tun->options_len) BUILD_BUG_ON(NFP_FL_TUNNEL_CSUM != TUNNEL_CSUM ||
NFP_FL_TUNNEL_KEY != TUNNEL_KEY ||
NFP_FL_TUNNEL_GENEVE_OPT != TUNNEL_GENEVE_OPT);
if (ip_tun->options_len &&
(tun_type != NFP_FL_TUNNEL_GENEVE ||
!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
net = dev_net(netdev);
set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL; set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL;
set_tun->head.len_lw = act_size >> NFP_FL_LW_SIZ; set_tun->head.len_lw = act_size >> NFP_FL_LW_SIZ;
...@@ -261,28 +334,42 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun, ...@@ -261,28 +334,42 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_fl_set_ipv4_udp_tun *set_tun,
set_tun->tun_type_index = cpu_to_be32(tmp_set_ip_tun_type_index); set_tun->tun_type_index = cpu_to_be32(tmp_set_ip_tun_type_index);
set_tun->tun_id = ip_tun->key.tun_id; set_tun->tun_id = ip_tun->key.tun_id;
/* Do a route lookup to determine ttl - if fails then use default. if (ip_tun->key.ttl) {
* Note that CONFIG_INET is a requirement of CONFIG_NET_SWITCHDEV so set_tun->ttl = ip_tun->key.ttl;
* must be defined here.
*/
flow.daddr = ip_tun->key.u.ipv4.dst;
flow.flowi4_proto = IPPROTO_UDP;
rt = ip_route_output_key(net, &flow);
err = PTR_ERR_OR_ZERO(rt);
if (!err) {
set_tun->ttl = ip4_dst_hoplimit(&rt->dst);
ip_rt_put(rt);
} else { } else {
set_tun->ttl = net->ipv4.sysctl_ip_default_ttl; struct net *net = dev_net(netdev);
struct flowi4 flow = {};
struct rtable *rt;
int err;
/* Do a route lookup to determine ttl - if fails then use
* default. Note that CONFIG_INET is a requirement of
* CONFIG_NET_SWITCHDEV so must be defined here.
*/
flow.daddr = ip_tun->key.u.ipv4.dst;
flow.flowi4_proto = IPPROTO_UDP;
rt = ip_route_output_key(net, &flow);
err = PTR_ERR_OR_ZERO(rt);
if (!err) {
set_tun->ttl = ip4_dst_hoplimit(&rt->dst);
ip_rt_put(rt);
} else {
set_tun->ttl = net->ipv4.sysctl_ip_default_ttl;
}
} }
set_tun->tos = ip_tun->key.tos; set_tun->tos = ip_tun->key.tos;
if (!(ip_tun->key.tun_flags & TUNNEL_KEY) || if (!(ip_tun->key.tun_flags & NFP_FL_TUNNEL_KEY) ||
ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS) ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS)
return -EOPNOTSUPP; return -EOPNOTSUPP;
set_tun->tun_flags = ip_tun->key.tun_flags; set_tun->tun_flags = ip_tun->key.tun_flags;
if (tun_type == NFP_FL_TUNNEL_GENEVE) {
set_tun->tun_proto = htons(ETH_P_TEB);
set_tun->tun_len = ip_tun->options_len / 4;
}
/* Complete pre_tunnel action. */ /* Complete pre_tunnel action. */
pre_tun->ipv4_dst = ip_tun->key.u.ipv4.dst; pre_tun->ipv4_dst = ip_tun->key.u.ipv4.dst;
...@@ -671,9 +758,13 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a, ...@@ -671,9 +758,13 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a,
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
*a_len += sizeof(struct nfp_fl_pre_tunnel); *a_len += sizeof(struct nfp_fl_pre_tunnel);
err = nfp_fl_push_geneve_options(nfp_fl, a_len, a);
if (err)
return err;
set_tun = (void *)&nfp_fl->action_data[*a_len]; set_tun = (void *)&nfp_fl->action_data[*a_len];
err = nfp_fl_set_ipv4_udp_tun(set_tun, a, pre_tun, *tun_type, err = nfp_fl_set_ipv4_udp_tun(app, set_tun, a, pre_tun,
netdev); *tun_type, netdev);
if (err) if (err)
return err; return err;
*a_len += sizeof(struct nfp_fl_set_ipv4_udp_tun); *a_len += sizeof(struct nfp_fl_set_ipv4_udp_tun);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/geneve.h>
#include "../nfp_app.h" #include "../nfp_app.h"
#include "../nfpcore/nfp_cpp.h" #include "../nfpcore/nfp_cpp.h"
...@@ -51,6 +52,7 @@ ...@@ -51,6 +52,7 @@
#define NFP_FLOWER_LAYER_VXLAN BIT(7) #define NFP_FLOWER_LAYER_VXLAN BIT(7)
#define NFP_FLOWER_LAYER2_GENEVE BIT(5) #define NFP_FLOWER_LAYER2_GENEVE BIT(5)
#define NFP_FLOWER_LAYER2_GENEVE_OP BIT(6)
#define NFP_FLOWER_MASK_VLAN_PRIO GENMASK(15, 13) #define NFP_FLOWER_MASK_VLAN_PRIO GENMASK(15, 13)
#define NFP_FLOWER_MASK_VLAN_CFI BIT(12) #define NFP_FLOWER_MASK_VLAN_CFI BIT(12)
...@@ -81,6 +83,11 @@ ...@@ -81,6 +83,11 @@
#define NFP_FL_MAX_A_SIZ 1216 #define NFP_FL_MAX_A_SIZ 1216
#define NFP_FL_LW_SIZ 2 #define NFP_FL_LW_SIZ 2
/* Maximum allowed geneve options */
#define NFP_FL_MAX_GENEVE_OPT_ACT 32
#define NFP_FL_MAX_GENEVE_OPT_CNT 64
#define NFP_FL_MAX_GENEVE_OPT_KEY 32
/* 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
...@@ -94,6 +101,7 @@ ...@@ -94,6 +101,7 @@
#define NFP_FL_ACTION_OPCODE_SET_TCP 15 #define NFP_FL_ACTION_OPCODE_SET_TCP 15
#define NFP_FL_ACTION_OPCODE_PRE_LAG 16 #define NFP_FL_ACTION_OPCODE_PRE_LAG 16
#define NFP_FL_ACTION_OPCODE_PRE_TUNNEL 17 #define NFP_FL_ACTION_OPCODE_PRE_TUNNEL 17
#define NFP_FL_ACTION_OPCODE_PUSH_GENEVE 26
#define NFP_FL_ACTION_OPCODE_NUM 32 #define NFP_FL_ACTION_OPCODE_NUM 32
#define NFP_FL_OUT_FLAGS_LAST BIT(15) #define NFP_FL_OUT_FLAGS_LAST BIT(15)
...@@ -206,7 +214,19 @@ struct nfp_fl_set_ipv4_udp_tun { ...@@ -206,7 +214,19 @@ struct nfp_fl_set_ipv4_udp_tun {
__be16 tun_flags; __be16 tun_flags;
u8 ttl; u8 ttl;
u8 tos; u8 tos;
__be32 extra[2]; __be32 extra;
u8 tun_len;
u8 res2;
__be16 tun_proto;
};
struct nfp_fl_push_geneve {
struct nfp_fl_act_head head;
__be16 reserved;
__be16 class;
u8 type;
u8 length;
u8 opt_data[];
}; };
/* Metadata with L2 (1W/4B) /* Metadata with L2 (1W/4B)
...@@ -346,7 +366,7 @@ struct nfp_flower_ipv6 { ...@@ -346,7 +366,7 @@ struct nfp_flower_ipv6 {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ipv4_addr_dst | * | ipv4_addr_dst |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | * | Reserved | tos | ttl |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | * | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...@@ -356,10 +376,17 @@ struct nfp_flower_ipv6 { ...@@ -356,10 +376,17 @@ struct nfp_flower_ipv6 {
struct nfp_flower_ipv4_udp_tun { struct nfp_flower_ipv4_udp_tun {
__be32 ip_src; __be32 ip_src;
__be32 ip_dst; __be32 ip_dst;
__be32 reserved[2]; __be16 reserved1;
u8 tos;
u8 ttl;
__be32 reserved2;
__be32 tun_id; __be32 tun_id;
}; };
struct nfp_flower_geneve_options {
u8 data[NFP_FL_MAX_GENEVE_OPT_KEY];
};
#define NFP_FL_TUN_VNI_OFFSET 8 #define NFP_FL_TUN_VNI_OFFSET 8
/* The base header for a control message packet. /* The base header for a control message packet.
......
...@@ -69,6 +69,7 @@ struct nfp_app; ...@@ -69,6 +69,7 @@ struct nfp_app;
/* Extra features bitmap. */ /* Extra features bitmap. */
#define NFP_FL_FEATS_GENEVE BIT(0) #define NFP_FL_FEATS_GENEVE BIT(0)
#define NFP_FL_NBI_MTU_SETTING BIT(1) #define NFP_FL_NBI_MTU_SETTING BIT(1)
#define NFP_FL_FEATS_GENEVE_OPT BIT(2)
#define NFP_FL_FEATS_LAG BIT(31) #define NFP_FL_FEATS_LAG BIT(31)
struct nfp_fl_mask_id { struct nfp_fl_mask_id {
......
...@@ -262,6 +262,21 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame, ...@@ -262,6 +262,21 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame,
nfp_flower_compile_ip_ext(&frame->ip_ext, flow, mask_version); nfp_flower_compile_ip_ext(&frame->ip_ext, flow, mask_version);
} }
static int
nfp_flower_compile_geneve_opt(void *key_buf, struct tc_cls_flower_offload *flow,
bool mask_version)
{
struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_enc_opts *opts;
opts = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS,
target);
memcpy(key_buf, opts->data, opts->len);
return 0;
}
static void static void
nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame, nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
struct tc_cls_flower_offload *flow, struct tc_cls_flower_offload *flow,
...@@ -270,6 +285,7 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame, ...@@ -270,6 +285,7 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
struct fl_flow_key *target = mask_version ? flow->mask : flow->key; struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_ipv4_addrs *tun_ips; struct flow_dissector_key_ipv4_addrs *tun_ips;
struct flow_dissector_key_keyid *vni; struct flow_dissector_key_keyid *vni;
struct flow_dissector_key_ip *ip;
memset(frame, 0, sizeof(struct nfp_flower_ipv4_udp_tun)); memset(frame, 0, sizeof(struct nfp_flower_ipv4_udp_tun));
...@@ -293,6 +309,14 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame, ...@@ -293,6 +309,14 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
frame->ip_src = tun_ips->src; frame->ip_src = tun_ips->src;
frame->ip_dst = tun_ips->dst; frame->ip_dst = tun_ips->dst;
} }
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_ENC_IP)) {
ip = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_IP,
target);
frame->tos = ip->tos;
frame->ttl = ip->ttl;
}
} }
int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
...@@ -415,6 +439,16 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, ...@@ -415,6 +439,16 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
nfp_flow->nfp_tun_ipv4_addr = tun_dst; nfp_flow->nfp_tun_ipv4_addr = tun_dst;
nfp_tunnel_add_ipv4_off(netdev_repr->app, tun_dst); nfp_tunnel_add_ipv4_off(netdev_repr->app, tun_dst);
} }
if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE_OP) {
err = nfp_flower_compile_geneve_opt(ext, flow, false);
if (err)
return err;
err = nfp_flower_compile_geneve_opt(msk, flow, true);
if (err)
return err;
}
} }
return 0; return 0;
......
...@@ -66,6 +66,8 @@ ...@@ -66,6 +66,8 @@
BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \ BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \ BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \ BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_IP) | \
BIT(FLOW_DISSECTOR_KEY_MPLS) | \ BIT(FLOW_DISSECTOR_KEY_MPLS) | \
BIT(FLOW_DISSECTOR_KEY_IP)) BIT(FLOW_DISSECTOR_KEY_IP))
...@@ -74,7 +76,9 @@ ...@@ -74,7 +76,9 @@
BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \ BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \ BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \ BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_PORTS)) BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
BIT(FLOW_DISSECTOR_KEY_ENC_IP))
#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \ #define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \
(BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \ (BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
...@@ -138,6 +142,21 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f) ...@@ -138,6 +142,21 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP); dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP);
} }
static int
nfp_flower_calc_opt_layer(struct flow_dissector_key_enc_opts *enc_opts,
u32 *key_layer_two, int *key_size)
{
if (enc_opts->len > NFP_FL_MAX_GENEVE_OPT_KEY)
return -EOPNOTSUPP;
if (enc_opts->len > 0) {
*key_layer_two |= NFP_FLOWER_LAYER2_GENEVE_OP;
*key_size += sizeof(struct nfp_flower_geneve_options);
}
return 0;
}
static int static int
nfp_flower_calculate_key_layers(struct nfp_app *app, nfp_flower_calculate_key_layers(struct nfp_app *app,
struct nfp_fl_key_ls *ret_key_ls, struct nfp_fl_key_ls *ret_key_ls,
...@@ -151,6 +170,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, ...@@ -151,6 +170,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
u32 key_layer_two; u32 key_layer_two;
u8 key_layer; u8 key_layer;
int key_size; int key_size;
int err;
if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR) if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -176,6 +196,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, ...@@ -176,6 +196,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
FLOW_DISSECTOR_KEY_ENC_CONTROL)) { FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
struct flow_dissector_key_ipv4_addrs *mask_ipv4 = NULL; struct flow_dissector_key_ipv4_addrs *mask_ipv4 = NULL;
struct flow_dissector_key_ports *mask_enc_ports = NULL; struct flow_dissector_key_ports *mask_enc_ports = NULL;
struct flow_dissector_key_enc_opts *enc_op = NULL;
struct flow_dissector_key_ports *enc_ports = NULL; struct flow_dissector_key_ports *enc_ports = NULL;
struct flow_dissector_key_control *mask_enc_ctl = struct flow_dissector_key_control *mask_enc_ctl =
skb_flow_dissector_target(flow->dissector, skb_flow_dissector_target(flow->dissector,
...@@ -212,11 +233,21 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, ...@@ -212,11 +233,21 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
if (mask_enc_ports->dst != cpu_to_be16(~0)) if (mask_enc_ports->dst != cpu_to_be16(~0))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS)) {
enc_op = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS,
flow->key);
}
switch (enc_ports->dst) { switch (enc_ports->dst) {
case htons(NFP_FL_VXLAN_PORT): case htons(NFP_FL_VXLAN_PORT):
*tun_type = NFP_FL_TUNNEL_VXLAN; *tun_type = NFP_FL_TUNNEL_VXLAN;
key_layer |= NFP_FLOWER_LAYER_VXLAN; key_layer |= NFP_FLOWER_LAYER_VXLAN;
key_size += sizeof(struct nfp_flower_ipv4_udp_tun); key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
if (enc_op)
return -EOPNOTSUPP;
break; break;
case htons(NFP_FL_GENEVE_PORT): case htons(NFP_FL_GENEVE_PORT):
if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE)) if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
...@@ -226,6 +257,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, ...@@ -226,6 +257,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
key_size += sizeof(struct nfp_flower_ext_meta); key_size += sizeof(struct nfp_flower_ext_meta);
key_layer_two |= NFP_FLOWER_LAYER2_GENEVE; key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
key_size += sizeof(struct nfp_flower_ipv4_udp_tun); key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
if (!enc_op)
break;
if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))
return -EOPNOTSUPP;
err = nfp_flower_calc_opt_layer(enc_op, &key_layer_two,
&key_size);
if (err)
return err;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -57,6 +57,21 @@ struct flow_dissector_key_mpls { ...@@ -57,6 +57,21 @@ struct flow_dissector_key_mpls {
mpls_label:20; mpls_label:20;
}; };
#define FLOW_DIS_TUN_OPTS_MAX 255
/**
* struct flow_dissector_key_enc_opts:
* @data: tunnel option data
* @len: length of tunnel option data
* @dst_opt_type: tunnel option type
*/
struct flow_dissector_key_enc_opts {
u8 data[FLOW_DIS_TUN_OPTS_MAX]; /* Using IP_TUNNEL_OPTS_MAX is desired
* here but seems difficult to #include
*/
u8 len;
__be16 dst_opt_type;
};
struct flow_dissector_key_keyid { struct flow_dissector_key_keyid {
__be32 keyid; __be32 keyid;
}; };
...@@ -208,6 +223,8 @@ enum flow_dissector_key_id { ...@@ -208,6 +223,8 @@ enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_IP, /* struct flow_dissector_key_ip */ FLOW_DISSECTOR_KEY_IP, /* struct flow_dissector_key_ip */
FLOW_DISSECTOR_KEY_CVLAN, /* struct flow_dissector_key_flow_vlan */ FLOW_DISSECTOR_KEY_CVLAN, /* struct flow_dissector_key_flow_vlan */
FLOW_DISSECTOR_KEY_ENC_IP, /* struct flow_dissector_key_ip */ FLOW_DISSECTOR_KEY_ENC_IP, /* struct flow_dissector_key_ip */
FLOW_DISSECTOR_KEY_ENC_OPTS, /* struct flow_dissector_key_enc_opts */
FLOW_DISSECTOR_KEY_MAX, FLOW_DISSECTOR_KEY_MAX,
}; };
......
...@@ -480,11 +480,37 @@ enum { ...@@ -480,11 +480,37 @@ enum {
TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */
TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */
TCA_FLOWER_KEY_ENC_OPTS,
TCA_FLOWER_KEY_ENC_OPTS_MASK,
__TCA_FLOWER_MAX, __TCA_FLOWER_MAX,
}; };
#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
enum {
TCA_FLOWER_KEY_ENC_OPTS_UNSPEC,
TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested
* TCA_FLOWER_KEY_ENC_OPT_GENEVE_
* attributes
*/
__TCA_FLOWER_KEY_ENC_OPTS_MAX,
};
#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1)
enum {
TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC,
TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */
TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */
TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */
__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
};
#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \
(__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
enum { enum {
TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
......
...@@ -154,7 +154,9 @@ skb_flow_dissect_tunnel_info(const struct sk_buff *skb, ...@@ -154,7 +154,9 @@ skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
!dissector_uses_key(flow_dissector, !dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS) && FLOW_DISSECTOR_KEY_ENC_PORTS) &&
!dissector_uses_key(flow_dissector, !dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_ENC_IP)) FLOW_DISSECTOR_KEY_ENC_IP) &&
!dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS))
return; return;
info = skb_tunnel_info(skb); info = skb_tunnel_info(skb);
...@@ -224,6 +226,21 @@ skb_flow_dissect_tunnel_info(const struct sk_buff *skb, ...@@ -224,6 +226,21 @@ skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
ip->tos = key->tos; ip->tos = key->tos;
ip->ttl = key->ttl; ip->ttl = key->ttl;
} }
if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
struct flow_dissector_key_enc_opts *enc_opt;
enc_opt = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS,
target_container);
if (info->options_len) {
enc_opt->len = info->options_len;
ip_tunnel_info_opts_get(enc_opt->data, info);
enc_opt->dst_opt_type = info->key.tun_flags &
TUNNEL_OPTIONS_PRESENT;
}
}
} }
EXPORT_SYMBOL(skb_flow_dissect_tunnel_info); EXPORT_SYMBOL(skb_flow_dissect_tunnel_info);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/flow_dissector.h> #include <net/flow_dissector.h>
#include <net/geneve.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/dst_metadata.h> #include <net/dst_metadata.h>
...@@ -53,6 +54,7 @@ struct fl_flow_key { ...@@ -53,6 +54,7 @@ struct fl_flow_key {
struct flow_dissector_key_tcp tcp; struct flow_dissector_key_tcp tcp;
struct flow_dissector_key_ip ip; struct flow_dissector_key_ip ip;
struct flow_dissector_key_ip enc_ip; struct flow_dissector_key_ip enc_ip;
struct flow_dissector_key_enc_opts enc_opts;
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
struct fl_flow_mask_range { struct fl_flow_mask_range {
...@@ -482,6 +484,21 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { ...@@ -482,6 +484,21 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
[TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 },
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
[TCA_FLOWER_KEY_ENC_OPTS] = { .type = NLA_NESTED },
[TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NLA_NESTED },
};
static const struct nla_policy
enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
[TCA_FLOWER_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED },
};
static const struct nla_policy
geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] = { .type = NLA_U16 },
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 },
[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY,
.len = 128 },
}; };
static void fl_set_key_val(struct nlattr **tb, static void fl_set_key_val(struct nlattr **tb,
...@@ -603,6 +620,145 @@ static void fl_set_key_ip(struct nlattr **tb, bool encap, ...@@ -603,6 +620,145 @@ static void fl_set_key_ip(struct nlattr **tb, bool encap,
fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)); fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
} }
static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
int depth, int option_len,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
struct nlattr *class = NULL, *type = NULL, *data = NULL;
struct geneve_opt *opt;
int err, data_len = 0;
if (option_len > sizeof(struct geneve_opt))
data_len = option_len - sizeof(struct geneve_opt);
opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
memset(opt, 0xff, option_len);
opt->length = data_len / 4;
opt->r1 = 0;
opt->r2 = 0;
opt->r3 = 0;
/* If no mask has been prodived we assume an exact match. */
if (!depth)
return sizeof(struct geneve_opt) + data_len;
if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
return -EINVAL;
}
err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
nla, geneve_opt_policy, extack);
if (err < 0)
return err;
/* We are not allowed to omit any of CLASS, TYPE or DATA
* fields from the key.
*/
if (!option_len &&
(!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
return -EINVAL;
}
/* Omitting any of CLASS, TYPE or DATA fields is allowed
* for the mask.
*/
if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
int new_len = key->enc_opts.len;
data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
data_len = nla_len(data);
if (data_len < 4) {
NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
return -ERANGE;
}
if (data_len % 4) {
NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
return -ERANGE;
}
new_len += sizeof(struct geneve_opt) + data_len;
BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
return -ERANGE;
}
opt->length = data_len / 4;
memcpy(opt->opt_data, nla_data(data), data_len);
}
if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
opt->opt_class = nla_get_be16(class);
}
if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
opt->type = nla_get_u8(type);
}
return sizeof(struct geneve_opt) + data_len;
}
static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
struct fl_flow_key *mask,
struct netlink_ext_ack *extack)
{
const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
int option_len, key_depth, msk_depth = 0;
nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
}
nla_for_each_attr(nla_opt_key, nla_enc_key,
nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
switch (nla_type(nla_opt_key)) {
case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
option_len = 0;
key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
option_len = fl_set_geneve_opt(nla_opt_key, key,
key_depth, option_len,
extack);
if (option_len < 0)
return option_len;
key->enc_opts.len += option_len;
/* At the same time we need to parse through the mask
* in order to verify exact and mask attribute lengths.
*/
mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
option_len = fl_set_geneve_opt(nla_opt_msk, mask,
msk_depth, option_len,
extack);
if (option_len < 0)
return option_len;
mask->enc_opts.len += option_len;
if (key->enc_opts.len != mask->enc_opts.len) {
NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
return -EINVAL;
}
if (msk_depth)
nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
break;
default:
NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
return -EINVAL;
}
}
return 0;
}
static int fl_set_key(struct net *net, struct nlattr **tb, static int fl_set_key(struct net *net, struct nlattr **tb,
struct fl_flow_key *key, struct fl_flow_key *mask, struct fl_flow_key *key, struct fl_flow_key *mask,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -799,6 +955,12 @@ static int fl_set_key(struct net *net, struct nlattr **tb, ...@@ -799,6 +955,12 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip); fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
ret = fl_set_enc_opt(tb, key, mask, extack);
if (ret)
return ret;
}
if (tb[TCA_FLOWER_KEY_FLAGS]) if (tb[TCA_FLOWER_KEY_FLAGS])
ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
...@@ -894,6 +1056,8 @@ static void fl_init_dissector(struct flow_dissector *dissector, ...@@ -894,6 +1056,8 @@ static void fl_init_dissector(struct flow_dissector *dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
FL_KEY_SET_IF_MASKED(mask, keys, cnt, FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
skb_flow_dissector_init(dissector, keys, cnt); skb_flow_dissector_init(dissector, keys, cnt);
} }
...@@ -1414,6 +1578,83 @@ static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) ...@@ -1414,6 +1578,83 @@ static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
} }
static int fl_dump_key_geneve_opt(struct sk_buff *skb,
struct flow_dissector_key_enc_opts *enc_opts)
{
struct geneve_opt *opt;
struct nlattr *nest;
int opt_off = 0;
nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
if (!nest)
goto nla_put_failure;
while (enc_opts->len > opt_off) {
opt = (struct geneve_opt *)&enc_opts->data[opt_off];
if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
opt->opt_class))
goto nla_put_failure;
if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
opt->type))
goto nla_put_failure;
if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
opt->length * 4, opt->opt_data))
goto nla_put_failure;
opt_off += sizeof(struct geneve_opt) + opt->length * 4;
}
nla_nest_end(skb, nest);
return 0;
nla_put_failure:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
struct flow_dissector_key_enc_opts *enc_opts)
{
struct nlattr *nest;
int err;
if (!enc_opts->len)
return 0;
nest = nla_nest_start(skb, enc_opt_type);
if (!nest)
goto nla_put_failure;
switch (enc_opts->dst_opt_type) {
case TUNNEL_GENEVE_OPT:
err = fl_dump_key_geneve_opt(skb, enc_opts);
if (err)
goto nla_put_failure;
break;
default:
goto nla_put_failure;
}
nla_nest_end(skb, nest);
return 0;
nla_put_failure:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static int fl_dump_key_enc_opt(struct sk_buff *skb,
struct flow_dissector_key_enc_opts *key_opts,
struct flow_dissector_key_enc_opts *msk_opts)
{
int err;
err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
if (err)
return err;
return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
}
static int fl_dump_key(struct sk_buff *skb, struct net *net, static int fl_dump_key(struct sk_buff *skb, struct net *net,
struct fl_flow_key *key, struct fl_flow_key *mask) struct fl_flow_key *key, struct fl_flow_key *mask)
{ {
...@@ -1594,7 +1835,8 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net, ...@@ -1594,7 +1835,8 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net,
&mask->enc_tp.dst, &mask->enc_tp.dst,
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
sizeof(key->enc_tp.dst)) || sizeof(key->enc_tp.dst)) ||
fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip)) fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
goto nla_put_failure; goto nla_put_failure;
if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment