Commit 996dcfff authored by David S. Miller's avatar David S. Miller

Merge branch 'tc-flower-SPI'

Ratheesh Kannoth says:

====================
Packet classify by matching against SPI

1.  net: flow_dissector: Add IPSEC dissector.
Flow dissector patch reads IPSEC headers (ESP or AH) header
from packet and retrieves the SPI header.

2. tc: flower: support for SPI.
TC control path changes to pass SPI field from userspace to
kernel.

3. tc: flower: Enable offload support IPSEC SPI field.
Next patch enables the HW support for classify offload for ESP/AH.
This patch enables the HW offload control.

4. octeontx2-pf: TC flower offload support for SPI field.
HW offload support for classification in octeontx2 driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d7301c4a 73b4c04e
......@@ -1451,6 +1451,10 @@ struct flow_msg {
__be32 ip4dst;
__be32 ip6dst[4];
};
union {
__be32 spi;
};
u8 tos;
u8 ip_ver;
u8 ip_proto;
......
......@@ -204,6 +204,7 @@ enum key_fields {
NPC_DPORT_UDP,
NPC_SPORT_SCTP,
NPC_DPORT_SCTP,
NPC_IPSEC_SPI,
NPC_HEADER_FIELDS_MAX,
NPC_CHAN = NPC_HEADER_FIELDS_MAX, /* Valid when Rx */
NPC_PF_FUNC, /* Valid when Tx */
......
......@@ -2827,6 +2827,10 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
seq_printf(s, "%d ", ntohs(rule->packet.dport));
seq_printf(s, "mask 0x%x\n", ntohs(rule->mask.dport));
break;
case NPC_IPSEC_SPI:
seq_printf(s, "0x%x ", ntohl(rule->packet.spi));
seq_printf(s, "mask 0x%x\n", ntohl(rule->mask.spi));
break;
default:
seq_puts(s, "\n");
break;
......
......@@ -41,6 +41,7 @@ static const char * const npc_flow_names[] = {
[NPC_SPORT_SCTP] = "sctp source port",
[NPC_DPORT_SCTP] = "sctp destination port",
[NPC_LXMB] = "Mcast/Bcast header ",
[NPC_IPSEC_SPI] = "SPI ",
[NPC_UNKNOWN] = "unknown",
};
......@@ -513,6 +514,10 @@ do { \
NPC_SCAN_HDR(NPC_VLAN_TAG1, NPC_LID_LB, NPC_LT_LB_CTAG, 2, 2);
NPC_SCAN_HDR(NPC_VLAN_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 2, 2);
NPC_SCAN_HDR(NPC_DMAC, NPC_LID_LA, la_ltype, la_start, 6);
NPC_SCAN_HDR(NPC_IPSEC_SPI, NPC_LID_LD, NPC_LT_LD_AH, 4, 4);
NPC_SCAN_HDR(NPC_IPSEC_SPI, NPC_LID_LE, NPC_LT_LE_ESP, 0, 4);
/* SMAC follows the DMAC(which is 6 bytes) */
NPC_SCAN_HDR(NPC_SMAC, NPC_LID_LA, la_ltype, la_start + 6, 6);
/* PF_FUNC is 2 bytes at 0th byte of NPC_LT_LA_IH_NIX_ETHER */
......@@ -564,6 +569,9 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
if (!npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features &= ~BIT_ULL(NPC_OUTER_VID);
if (*features & (BIT_ULL(NPC_IPPROTO_AH) | BIT_ULL(NPC_IPPROTO_ESP)))
*features |= BIT_ULL(NPC_IPSEC_SPI);
/* for vlan ethertypes corresponding layer type should be in the key */
if (npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) |
......@@ -930,6 +938,9 @@ do { \
NPC_WRITE_FLOW(NPC_DPORT_SCTP, dport, ntohs(pkt->dport), 0,
ntohs(mask->dport), 0);
NPC_WRITE_FLOW(NPC_IPSEC_SPI, spi, ntohl(pkt->spi), 0,
ntohl(mask->spi), 0);
NPC_WRITE_FLOW(NPC_OUTER_VID, vlan_tci, ntohs(pkt->vlan_tci), 0,
ntohs(mask->vlan_tci), 0);
......
......@@ -461,6 +461,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
BIT(FLOW_DISSECTOR_KEY_IPSEC) |
BIT_ULL(FLOW_DISSECTOR_KEY_IP)))) {
netdev_info(nic->netdev, "unsupported flow used key 0x%llx",
dissector->used_keys);
......@@ -482,6 +483,8 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
match.key->ip_proto != IPPROTO_UDP &&
match.key->ip_proto != IPPROTO_SCTP &&
match.key->ip_proto != IPPROTO_ICMP &&
match.key->ip_proto != IPPROTO_ESP &&
match.key->ip_proto != IPPROTO_AH &&
match.key->ip_proto != IPPROTO_ICMPV6)) {
netdev_info(nic->netdev,
"ip_proto=0x%x not supported\n",
......@@ -501,6 +504,10 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
else if (ip_proto == IPPROTO_ICMPV6)
req->features |= BIT_ULL(NPC_IPPROTO_ICMP6);
else if (ip_proto == IPPROTO_ESP)
req->features |= BIT_ULL(NPC_IPPROTO_ESP);
else if (ip_proto == IPPROTO_AH)
req->features |= BIT_ULL(NPC_IPPROTO_AH);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
......@@ -545,6 +552,26 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
}
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPSEC)) {
struct flow_match_ipsec match;
flow_rule_match_ipsec(rule, &match);
if (!match.mask->spi) {
NL_SET_ERR_MSG_MOD(extack, "spi index not specified");
return -EOPNOTSUPP;
}
if (ip_proto != IPPROTO_ESP &&
ip_proto != IPPROTO_AH) {
NL_SET_ERR_MSG_MOD(extack,
"SPI index is valid only for ESP/AH proto");
return -EOPNOTSUPP;
}
flow_spec->spi = match.key->spi;
flow_mask->spi = match.mask->spi;
req->features |= BIT_ULL(NPC_IPSEC_SPI);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
struct flow_match_ip match;
......
......@@ -301,6 +301,14 @@ struct flow_dissector_key_l2tpv3 {
__be32 session_id;
};
/**
* struct flow_dissector_key_ipsec:
* @spi: identifier for a ipsec connection
*/
struct flow_dissector_key_ipsec {
__be32 spi;
};
/**
* struct flow_dissector_key_cfm
* @mdl_ver: maintenance domain level (mdl) and cfm protocol version
......@@ -354,6 +362,7 @@ enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_PPPOE, /* struct flow_dissector_key_pppoe */
FLOW_DISSECTOR_KEY_L2TPV3, /* struct flow_dissector_key_l2tpv3 */
FLOW_DISSECTOR_KEY_CFM, /* struct flow_dissector_key_cfm */
FLOW_DISSECTOR_KEY_IPSEC, /* struct flow_dissector_key_ipsec */
FLOW_DISSECTOR_KEY_MAX,
};
......
......@@ -64,6 +64,10 @@ struct flow_match_tcp {
struct flow_dissector_key_tcp *key, *mask;
};
struct flow_match_ipsec {
struct flow_dissector_key_ipsec *key, *mask;
};
struct flow_match_mpls {
struct flow_dissector_key_mpls *key, *mask;
};
......@@ -116,6 +120,8 @@ void flow_rule_match_ports_range(const struct flow_rule *rule,
struct flow_match_ports_range *out);
void flow_rule_match_tcp(const struct flow_rule *rule,
struct flow_match_tcp *out);
void flow_rule_match_ipsec(const struct flow_rule *rule,
struct flow_match_ipsec *out);
void flow_rule_match_icmp(const struct flow_rule *rule,
struct flow_match_icmp *out);
void flow_rule_match_mpls(const struct flow_rule *rule,
......
......@@ -598,6 +598,9 @@ enum {
TCA_FLOWER_KEY_CFM, /* nested */
TCA_FLOWER_KEY_SPI, /* be32 */
TCA_FLOWER_KEY_SPI_MASK, /* be32 */
__TCA_FLOWER_MAX,
};
......
......@@ -205,6 +205,50 @@ static void __skb_flow_dissect_icmp(const struct sk_buff *skb,
skb_flow_get_icmp_tci(skb, key_icmp, data, thoff, hlen);
}
static void __skb_flow_dissect_ah(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
void *target_container, const void *data,
int nhoff, int hlen)
{
struct flow_dissector_key_ipsec *key_ah;
struct ip_auth_hdr _hdr, *hdr;
if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPSEC))
return;
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
if (!hdr)
return;
key_ah = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_IPSEC,
target_container);
key_ah->spi = hdr->spi;
}
static void __skb_flow_dissect_esp(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
void *target_container, const void *data,
int nhoff, int hlen)
{
struct flow_dissector_key_ipsec *key_esp;
struct ip_esp_hdr _hdr, *hdr;
if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPSEC))
return;
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
if (!hdr)
return;
key_esp = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_IPSEC,
target_container);
key_esp->spi = hdr->spi;
}
static void __skb_flow_dissect_l2tpv3(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
void *target_container, const void *data,
......@@ -1571,7 +1615,14 @@ bool __skb_flow_dissect(const struct net *net,
__skb_flow_dissect_l2tpv3(skb, flow_dissector, target_container,
data, nhoff, hlen);
break;
case IPPROTO_ESP:
__skb_flow_dissect_esp(skb, flow_dissector, target_container,
data, nhoff, hlen);
break;
case IPPROTO_AH:
__skb_flow_dissect_ah(skb, flow_dissector, target_container,
data, nhoff, hlen);
break;
default:
break;
}
......
......@@ -146,6 +146,13 @@ void flow_rule_match_tcp(const struct flow_rule *rule,
}
EXPORT_SYMBOL(flow_rule_match_tcp);
void flow_rule_match_ipsec(const struct flow_rule *rule,
struct flow_match_ipsec *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPSEC, out);
}
EXPORT_SYMBOL(flow_rule_match_ipsec);
void flow_rule_match_icmp(const struct flow_rule *rule,
struct flow_match_icmp *out)
{
......
......@@ -72,6 +72,7 @@ struct fl_flow_key {
struct flow_dissector_key_num_of_vlans num_of_vlans;
struct flow_dissector_key_pppoe pppoe;
struct flow_dissector_key_l2tpv3 l2tpv3;
struct flow_dissector_key_ipsec ipsec;
struct flow_dissector_key_cfm cfm;
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
......@@ -726,6 +727,8 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
[TCA_FLOWER_KEY_PPPOE_SID] = { .type = NLA_U16 },
[TCA_FLOWER_KEY_PPP_PROTO] = { .type = NLA_U16 },
[TCA_FLOWER_KEY_L2TPV3_SID] = { .type = NLA_U32 },
[TCA_FLOWER_KEY_SPI] = { .type = NLA_U32 },
[TCA_FLOWER_KEY_SPI_MASK] = { .type = NLA_U32 },
[TCA_FLOWER_L2_MISS] = NLA_POLICY_MAX(NLA_U8, 1),
[TCA_FLOWER_KEY_CFM] = { .type = NLA_NESTED },
};
......@@ -795,6 +798,24 @@ static void fl_set_key_val(struct nlattr **tb,
nla_memcpy(mask, tb[mask_type], len);
}
static int fl_set_key_spi(struct nlattr **tb, struct fl_flow_key *key,
struct fl_flow_key *mask,
struct netlink_ext_ack *extack)
{
if (key->basic.ip_proto != IPPROTO_ESP &&
key->basic.ip_proto != IPPROTO_AH) {
NL_SET_ERR_MSG(extack,
"Protocol must be either ESP or AH");
return -EINVAL;
}
fl_set_key_val(tb, &key->ipsec.spi,
TCA_FLOWER_KEY_SPI,
&mask->ipsec.spi, TCA_FLOWER_KEY_SPI_MASK,
sizeof(key->ipsec.spi));
return 0;
}
static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
struct fl_flow_key *mask,
struct netlink_ext_ack *extack)
......@@ -1894,6 +1915,12 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
return ret;
}
if (tb[TCA_FLOWER_KEY_SPI]) {
ret = fl_set_key_spi(tb, key, mask, extack);
if (ret)
return ret;
}
if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
......@@ -2066,6 +2093,8 @@ static void fl_init_dissector(struct flow_dissector *dissector,
FLOW_DISSECTOR_KEY_PPPOE, pppoe);
FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_L2TPV3, l2tpv3);
FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_IPSEC, ipsec);
FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_CFM, cfm);
......@@ -3364,6 +3393,12 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net,
sizeof(key->l2tpv3.session_id)))
goto nla_put_failure;
if (key->ipsec.spi &&
fl_dump_key_val(skb, &key->ipsec.spi, TCA_FLOWER_KEY_SPI,
&mask->ipsec.spi, TCA_FLOWER_KEY_SPI_MASK,
sizeof(key->ipsec.spi)))
goto nla_put_failure;
if ((key->basic.ip_proto == IPPROTO_TCP ||
key->basic.ip_proto == IPPROTO_UDP ||
key->basic.ip_proto == IPPROTO_SCTP) &&
......
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