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

nfp: flower: add ipv4 set ttl and tos offload

Add ipv4 set ttl and tos action offload. Since pedit sets headers per 4
byte word, we need to ensure that setting either version, ihl, protocol,
total length or checksum does not get offloaded.
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Reviewed-by: default avatarJohn Hurley <john.hurley@netronome.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6a02d1fa
...@@ -384,10 +384,21 @@ nfp_fl_set_eth(const struct tc_action *action, int idx, u32 off, ...@@ -384,10 +384,21 @@ nfp_fl_set_eth(const struct tc_action *action, int idx, u32 off,
return 0; return 0;
} }
struct ipv4_ttl_word {
__u8 ttl;
__u8 protocol;
__sum16 check;
};
static int static int
nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off, nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ip4_addrs *set_ip_addr) struct nfp_fl_set_ip4_addrs *set_ip_addr,
struct nfp_fl_set_ip4_ttl_tos *set_ip_ttl_tos)
{ {
struct ipv4_ttl_word *ttl_word_mask;
struct ipv4_ttl_word *ttl_word;
struct iphdr *tos_word_mask;
struct iphdr *tos_word;
__be32 exact, mask; __be32 exact, mask;
/* We are expecting tcf_pedit to return a big endian value */ /* We are expecting tcf_pedit to return a big endian value */
...@@ -402,20 +413,53 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off, ...@@ -402,20 +413,53 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
set_ip_addr->ipv4_dst_mask |= mask; set_ip_addr->ipv4_dst_mask |= mask;
set_ip_addr->ipv4_dst &= ~mask; set_ip_addr->ipv4_dst &= ~mask;
set_ip_addr->ipv4_dst |= exact & mask; set_ip_addr->ipv4_dst |= exact & mask;
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >>
NFP_FL_LW_SIZ;
break; break;
case offsetof(struct iphdr, saddr): case offsetof(struct iphdr, saddr):
set_ip_addr->ipv4_src_mask |= mask; set_ip_addr->ipv4_src_mask |= mask;
set_ip_addr->ipv4_src &= ~mask; set_ip_addr->ipv4_src &= ~mask;
set_ip_addr->ipv4_src |= exact & mask; set_ip_addr->ipv4_src |= exact & mask;
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >>
NFP_FL_LW_SIZ;
break;
case offsetof(struct iphdr, ttl):
ttl_word_mask = (struct ipv4_ttl_word *)&mask;
ttl_word = (struct ipv4_ttl_word *)&exact;
if (ttl_word_mask->protocol || ttl_word_mask->check)
return -EOPNOTSUPP;
set_ip_ttl_tos->ipv4_ttl_mask |= ttl_word_mask->ttl;
set_ip_ttl_tos->ipv4_ttl &= ~ttl_word_mask->ttl;
set_ip_ttl_tos->ipv4_ttl |= ttl_word->ttl & ttl_word_mask->ttl;
set_ip_ttl_tos->head.jump_id =
NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS;
set_ip_ttl_tos->head.len_lw = sizeof(*set_ip_ttl_tos) >>
NFP_FL_LW_SIZ;
break;
case round_down(offsetof(struct iphdr, tos), 4):
tos_word_mask = (struct iphdr *)&mask;
tos_word = (struct iphdr *)&exact;
if (tos_word_mask->version || tos_word_mask->ihl ||
tos_word_mask->tot_len)
return -EOPNOTSUPP;
set_ip_ttl_tos->ipv4_tos_mask |= tos_word_mask->tos;
set_ip_ttl_tos->ipv4_tos &= ~tos_word_mask->tos;
set_ip_ttl_tos->ipv4_tos |= tos_word->tos & tos_word_mask->tos;
set_ip_ttl_tos->head.jump_id =
NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS;
set_ip_ttl_tos->head.len_lw = sizeof(*set_ip_ttl_tos) >>
NFP_FL_LW_SIZ;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
set_ip_addr->reserved = cpu_to_be16(0);
set_ip_addr->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS;
set_ip_addr->head.len_lw = sizeof(*set_ip_addr) >> NFP_FL_LW_SIZ;
return 0; return 0;
} }
...@@ -513,6 +557,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -513,6 +557,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
char *nfp_action, int *a_len, u32 *csum_updated) 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_ttl_tos set_ip_ttl_tos;
struct nfp_fl_set_ip4_addrs set_ip_addr; struct nfp_fl_set_ip4_addrs set_ip_addr;
struct nfp_fl_set_tport set_tport; struct nfp_fl_set_tport set_tport;
struct nfp_fl_set_eth set_eth; struct nfp_fl_set_eth set_eth;
...@@ -522,6 +567,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -522,6 +567,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
u32 offset, cmd; u32 offset, cmd;
u8 ip_proto = 0; u8 ip_proto = 0;
memset(&set_ip_ttl_tos, 0, sizeof(set_ip_ttl_tos));
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));
memset(&set_ip_addr, 0, sizeof(set_ip_addr)); memset(&set_ip_addr, 0, sizeof(set_ip_addr));
...@@ -542,7 +588,8 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -542,7 +588,8 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
err = nfp_fl_set_eth(action, idx, offset, &set_eth); err = nfp_fl_set_eth(action, idx, offset, &set_eth);
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4: case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr); err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr,
&set_ip_ttl_tos);
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst, err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst,
...@@ -577,6 +624,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -577,6 +624,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
memcpy(nfp_action, &set_eth, act_size); memcpy(nfp_action, &set_eth, act_size);
*a_len += act_size; *a_len += act_size;
} }
if (set_ip_ttl_tos.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip_ttl_tos);
memcpy(nfp_action, &set_ip_ttl_tos, 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);
}
if (set_ip_addr.head.len_lw) { if (set_ip_addr.head.len_lw) {
nfp_action += act_size; nfp_action += act_size;
act_size = sizeof(set_ip_addr); act_size = sizeof(set_ip_addr);
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6 #define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6
#define NFP_FL_ACTION_OPCODE_SET_ETHERNET 7 #define NFP_FL_ACTION_OPCODE_SET_ETHERNET 7
#define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS 9 #define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS 9
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS 10
#define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11 #define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11
#define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12 #define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12
#define NFP_FL_ACTION_OPCODE_SET_UDP 14 #define NFP_FL_ACTION_OPCODE_SET_UDP 14
...@@ -125,6 +126,15 @@ struct nfp_fl_set_ip4_addrs { ...@@ -125,6 +126,15 @@ struct nfp_fl_set_ip4_addrs {
__be32 ipv4_dst; __be32 ipv4_dst;
}; };
struct nfp_fl_set_ip4_ttl_tos {
struct nfp_fl_act_head head;
u8 ipv4_ttl_mask;
u8 ipv4_tos_mask;
u8 ipv4_ttl;
u8 ipv4_tos;
__be16 reserved;
};
struct nfp_fl_set_ipv6_addr { struct nfp_fl_set_ipv6_addr {
struct nfp_fl_act_head head; struct nfp_fl_act_head head;
__be16 reserved; __be16 reserved;
......
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