Commit ed8f2b52 authored by Pieter Jansen van Vuuren's avatar Pieter Jansen van Vuuren Committed by David S. Miller

nfp: flower: ignore checksum actions when performing pedit actions

Hardware will automatically update csum in headers when a set action has
been performed. This means we could in the driver ignore the explicit
checksum action when performing a set action.
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5d4b0b40
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.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_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_pedit.h> #include <net/tc_act/tc_pedit.h>
...@@ -398,8 +399,27 @@ nfp_fl_set_tport(const struct tc_action *action, int idx, u32 off, ...@@ -398,8 +399,27 @@ nfp_fl_set_tport(const struct tc_action *action, int idx, u32 off,
return 0; return 0;
} }
static u32 nfp_fl_csum_l4_to_flag(u8 ip_proto)
{
switch (ip_proto) {
case 0:
/* Filter doesn't force proto match,
* both TCP and UDP will be updated if encountered
*/
return TCA_CSUM_UPDATE_FLAG_TCP | TCA_CSUM_UPDATE_FLAG_UDP;
case IPPROTO_TCP:
return TCA_CSUM_UPDATE_FLAG_TCP;
case IPPROTO_UDP:
return TCA_CSUM_UPDATE_FLAG_UDP;
default:
/* All other protocols will be ignored by FW */
return 0;
}
}
static int static int
nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
char *nfp_action, int *a_len, u32 *csum_updated)
{ {
struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src; struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src;
struct nfp_fl_set_ip4_addrs set_ip_addr; struct nfp_fl_set_ip4_addrs set_ip_addr;
...@@ -409,6 +429,7 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) ...@@ -409,6 +429,7 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
int idx, nkeys, err; int idx, nkeys, err;
size_t act_size; size_t act_size;
u32 offset, cmd; u32 offset, cmd;
u8 ip_proto = 0;
memset(&set_ip6_dst, 0, sizeof(set_ip6_dst)); memset(&set_ip6_dst, 0, sizeof(set_ip6_dst));
memset(&set_ip6_src, 0, sizeof(set_ip6_src)); memset(&set_ip6_src, 0, sizeof(set_ip6_src));
...@@ -451,6 +472,15 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) ...@@ -451,6 +472,15 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
return err; return err;
} }
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *basic;
basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->key);
ip_proto = basic->ip_proto;
}
if (set_eth.head.len_lw) { if (set_eth.head.len_lw) {
act_size = sizeof(set_eth); act_size = sizeof(set_eth);
memcpy(nfp_action, &set_eth, act_size); memcpy(nfp_action, &set_eth, act_size);
...@@ -459,6 +489,10 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) ...@@ -459,6 +489,10 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
act_size = sizeof(set_ip_addr); act_size = sizeof(set_ip_addr);
memcpy(nfp_action, &set_ip_addr, act_size); memcpy(nfp_action, &set_ip_addr, act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix IPv4 and TCP/UDP checksum. */
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) { } else if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) {
/* TC compiles set src and dst IPv6 address as a single action, /* TC compiles set src and dst IPv6 address as a single action,
* the hardware requires this to be 2 separate actions. * the hardware requires this to be 2 separate actions.
...@@ -471,18 +505,30 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) ...@@ -471,18 +505,30 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
memcpy(&nfp_action[sizeof(set_ip6_src)], &set_ip6_dst, memcpy(&nfp_action[sizeof(set_ip6_src)], &set_ip6_dst,
act_size); act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_dst.head.len_lw) { } else if (set_ip6_dst.head.len_lw) {
act_size = sizeof(set_ip6_dst); act_size = sizeof(set_ip6_dst);
memcpy(nfp_action, &set_ip6_dst, act_size); memcpy(nfp_action, &set_ip6_dst, act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_src.head.len_lw) { } else if (set_ip6_src.head.len_lw) {
act_size = sizeof(set_ip6_src); act_size = sizeof(set_ip6_src);
memcpy(nfp_action, &set_ip6_src, act_size); memcpy(nfp_action, &set_ip6_src, act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_tport.head.len_lw) { } else if (set_tport.head.len_lw) {
act_size = sizeof(set_tport); act_size = sizeof(set_tport);
memcpy(nfp_action, &set_tport, act_size); memcpy(nfp_action, &set_tport, act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} }
return 0; return 0;
...@@ -493,12 +539,18 @@ nfp_flower_output_action(struct nfp_app *app, const struct tc_action *a, ...@@ -493,12 +539,18 @@ nfp_flower_output_action(struct nfp_app *app, 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, bool last, struct net_device *netdev, bool last,
enum nfp_flower_tun_type *tun_type, int *tun_out_cnt, enum nfp_flower_tun_type *tun_type, int *tun_out_cnt,
int *out_cnt) int *out_cnt, u32 *csum_updated)
{ {
struct nfp_flower_priv *priv = app->priv; struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_output *output; struct nfp_fl_output *output;
int err, prelag_size; int err, prelag_size;
/* If csum_updated has not been reset by now, it means HW will
* incorrectly update csums when they are not requested.
*/
if (*csum_updated)
return -EOPNOTSUPP;
if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -529,10 +581,11 @@ nfp_flower_output_action(struct nfp_app *app, const struct tc_action *a, ...@@ -529,10 +581,11 @@ nfp_flower_output_action(struct nfp_app *app, const struct tc_action *a,
static int static int
nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a, nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a,
struct tc_cls_flower_offload *flow,
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, enum nfp_flower_tun_type *tun_type, int *tun_out_cnt,
int *out_cnt) int *out_cnt, u32 *csum_updated)
{ {
struct nfp_fl_set_ipv4_udp_tun *set_tun; struct nfp_fl_set_ipv4_udp_tun *set_tun;
struct nfp_fl_pre_tunnel *pre_tun; struct nfp_fl_pre_tunnel *pre_tun;
...@@ -545,14 +598,14 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a, ...@@ -545,14 +598,14 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a,
} else if (is_tcf_mirred_egress_redirect(a)) { } else if (is_tcf_mirred_egress_redirect(a)) {
err = nfp_flower_output_action(app, a, nfp_fl, a_len, netdev, err = nfp_flower_output_action(app, a, nfp_fl, a_len, netdev,
true, tun_type, tun_out_cnt, true, tun_type, tun_out_cnt,
out_cnt); out_cnt, csum_updated);
if (err) if (err)
return err; return err;
} else if (is_tcf_mirred_egress_mirror(a)) { } else if (is_tcf_mirred_egress_mirror(a)) {
err = nfp_flower_output_action(app, a, nfp_fl, a_len, netdev, err = nfp_flower_output_action(app, a, nfp_fl, a_len, netdev,
false, tun_type, tun_out_cnt, false, tun_type, tun_out_cnt,
out_cnt); out_cnt, csum_updated);
if (err) if (err)
return err; return err;
...@@ -602,8 +655,17 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a, ...@@ -602,8 +655,17 @@ nfp_flower_loop_action(struct nfp_app *app, const struct tc_action *a,
/* Tunnel decap is handled by default so accept action. */ /* Tunnel decap is handled by default so accept action. */
return 0; return 0;
} else if (is_tcf_pedit(a)) { } else if (is_tcf_pedit(a)) {
if (nfp_fl_pedit(a, &nfp_fl->action_data[*a_len], a_len)) if (nfp_fl_pedit(a, flow, &nfp_fl->action_data[*a_len],
a_len, csum_updated))
return -EOPNOTSUPP; return -EOPNOTSUPP;
} else if (is_tcf_csum(a)) {
/* csum action requests recalc of something we have not fixed */
if (tcf_csum_update_flags(a) & ~*csum_updated)
return -EOPNOTSUPP;
/* If we will correctly fix the csum we can remove it from the
* csum update list. Which will later be used to check support.
*/
*csum_updated &= ~tcf_csum_update_flags(a);
} else { } else {
/* Currently we do not handle any other actions. */ /* Currently we do not handle any other actions. */
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -620,6 +682,7 @@ int nfp_flower_compile_action(struct nfp_app *app, ...@@ -620,6 +682,7 @@ int nfp_flower_compile_action(struct nfp_app *app,
int act_len, act_cnt, err, tun_out_cnt, out_cnt; int act_len, act_cnt, err, tun_out_cnt, out_cnt;
enum nfp_flower_tun_type tun_type; enum nfp_flower_tun_type tun_type;
const struct tc_action *a; const struct tc_action *a;
u32 csum_updated = 0;
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);
...@@ -632,8 +695,9 @@ int nfp_flower_compile_action(struct nfp_app *app, ...@@ -632,8 +695,9 @@ int nfp_flower_compile_action(struct nfp_app *app,
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(app, a, nfp_flow, &act_len, netdev, err = nfp_flower_loop_action(app, a, flow, nfp_flow, &act_len,
&tun_type, &tun_out_cnt, &out_cnt); netdev, &tun_type, &tun_out_cnt,
&out_cnt, &csum_updated);
if (err) if (err)
return err; return err;
act_cnt++; act_cnt++;
......
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