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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -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 @@ ip_proto_again:
|
||||
__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) &&
|
||||
|
||||
Reference in New Issue
Block a user