b1a3ac782d
Application ipsec-secgw is not working for IPv4 transport mode and for IPv6 both transport and tunnel mode. IPv6 tunnel mode is not working due to wrongly assigned fields of security association patterns, as it was IPv4, during creation of inline crypto session. IPv6 and IPv4 transport mode is iterating through security capabilities until it reaches tunnel, which causes session to be created as tunnel, instead of transport. Another issue, is that config file does not provide source and destination ip addresses for transport mode, which are required by NIC to perform inline crypto. It uses default addresses stored in security association (all zeroes), which causes dropped packages. To fix that, reorganization of code in create_session() is needed, to behave appropriately to given protocol (IPv6/IPv4). Change in iteration through security capabilities is also required, to check for expected mode (not only tunnel). For lack of addresses issue, some resolving mechanism is needed. Approach is to store addresses in security association, as it is for tunnel mode. Difference is that they are obtained from sp rules, instead of config file. To do that, sp[4/6]_spi_present() function is used to find addresses based on spi value, and then stored in corresponding sa rule. This approach assumes, that every sp rule for inline crypto have valid addresses, as well as range of addresses is not supported. New flags for ipsec_sa structure are required to distinguish between IPv4 and IPv6 transport modes. Because of that, there is need to change all checks done on these flags, so they work as expected. Fixes: ec17993a145a ("examples/ipsec-secgw: support security offload") Fixes: 9a0752f498d2 ("net/ixgbe: enable inline IPsec") Cc: stable@dpdk.org Signed-off-by: Mariusz Drost <mariuszx.drost@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Acked-by: Akhil Goyal <akhil.goyal@nxp.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
727 lines
18 KiB
C
727 lines
18 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2016 Intel Corporation
|
|
*/
|
|
|
|
/*
|
|
* Security Policies
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip6.h>
|
|
|
|
#include <rte_acl.h>
|
|
#include <rte_ip.h>
|
|
|
|
#include "ipsec.h"
|
|
#include "parser.h"
|
|
|
|
#define MAX_ACL_RULE_NUM 1024
|
|
|
|
#define IPV6_FROM_SP(acr, fidx_low, fidx_high) \
|
|
(((uint64_t)(acr).field[(fidx_high)].value.u32 << 32) | \
|
|
(acr).field[(fidx_low)].value.u32)
|
|
|
|
#define IPV6_DST_FROM_SP(addr, acr) do {\
|
|
(addr).ip.ip6.ip6[0] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \
|
|
IP6_DST1, IP6_DST0));\
|
|
(addr).ip.ip6.ip6[1] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \
|
|
IP6_DST3, IP6_DST2));\
|
|
} while (0)
|
|
|
|
#define IPV6_SRC_FROM_SP(addr, acr) do {\
|
|
(addr).ip.ip6.ip6[0] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \
|
|
IP6_SRC1, IP6_SRC0));\
|
|
(addr).ip.ip6.ip6[1] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \
|
|
IP6_SRC3, IP6_SRC2));\
|
|
} while (0)
|
|
|
|
#define IPV6_DST_MASK_FROM_SP(mask, acr) \
|
|
((mask) = (acr).field[IP6_DST0].mask_range.u32 + \
|
|
(acr).field[IP6_DST1].mask_range.u32 + \
|
|
(acr).field[IP6_DST2].mask_range.u32 + \
|
|
(acr).field[IP6_DST3].mask_range.u32)
|
|
|
|
#define IPV6_SRC_MASK_FROM_SP(mask, acr) \
|
|
((mask) = (acr).field[IP6_SRC0].mask_range.u32 + \
|
|
(acr).field[IP6_SRC1].mask_range.u32 + \
|
|
(acr).field[IP6_SRC2].mask_range.u32 + \
|
|
(acr).field[IP6_SRC3].mask_range.u32)
|
|
|
|
enum {
|
|
IP6_PROTO,
|
|
IP6_SRC0,
|
|
IP6_SRC1,
|
|
IP6_SRC2,
|
|
IP6_SRC3,
|
|
IP6_DST0,
|
|
IP6_DST1,
|
|
IP6_DST2,
|
|
IP6_DST3,
|
|
IP6_SRCP,
|
|
IP6_DSTP,
|
|
IP6_NUM
|
|
};
|
|
|
|
#define IP6_ADDR_SIZE 16
|
|
|
|
static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint8_t),
|
|
.field_index = IP6_PROTO,
|
|
.input_index = IP6_PROTO,
|
|
.offset = 0,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_SRC0,
|
|
.input_index = IP6_SRC0,
|
|
.offset = 2
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_SRC1,
|
|
.input_index = IP6_SRC1,
|
|
.offset = 6
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_SRC2,
|
|
.input_index = IP6_SRC2,
|
|
.offset = 10
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_SRC3,
|
|
.input_index = IP6_SRC3,
|
|
.offset = 14
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_DST0,
|
|
.input_index = IP6_DST0,
|
|
.offset = 18
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_DST1,
|
|
.input_index = IP6_DST1,
|
|
.offset = 22
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_DST2,
|
|
.input_index = IP6_DST2,
|
|
.offset = 26
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = 4,
|
|
.field_index = IP6_DST3,
|
|
.input_index = IP6_DST3,
|
|
.offset = 30
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = IP6_SRCP,
|
|
.input_index = IP6_SRCP,
|
|
.offset = 34
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = IP6_DSTP,
|
|
.input_index = IP6_SRCP,
|
|
.offset = 36
|
|
}
|
|
};
|
|
|
|
RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
|
|
|
|
static struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
|
|
static uint32_t nb_acl6_rules_out;
|
|
|
|
static struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
|
|
static uint32_t nb_acl6_rules_in;
|
|
|
|
void
|
|
parse_sp6_tokens(char **tokens, uint32_t n_tokens,
|
|
struct parse_status *status)
|
|
{
|
|
struct acl6_rules *rule_ipv6 = NULL;
|
|
|
|
uint32_t *ri = NULL; /* rule index */
|
|
uint32_t ti = 0; /* token index */
|
|
uint32_t tv;
|
|
|
|
uint32_t esp_p = 0;
|
|
uint32_t protect_p = 0;
|
|
uint32_t bypass_p = 0;
|
|
uint32_t discard_p = 0;
|
|
uint32_t pri_p = 0;
|
|
uint32_t src_p = 0;
|
|
uint32_t dst_p = 0;
|
|
uint32_t proto_p = 0;
|
|
uint32_t sport_p = 0;
|
|
uint32_t dport_p = 0;
|
|
|
|
if (strcmp(tokens[1], "in") == 0) {
|
|
ri = &nb_acl6_rules_in;
|
|
|
|
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
|
|
"many sp rules, abort insertion\n");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6 = &acl6_rules_in[*ri];
|
|
|
|
} else if (strcmp(tokens[1], "out") == 0) {
|
|
ri = &nb_acl6_rules_out;
|
|
|
|
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
|
|
"many sp rules, abort insertion\n");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6 = &acl6_rules_out[*ri];
|
|
|
|
} else {
|
|
APP_CHECK(0, status, "unrecognized input \"%s\", expect"
|
|
" \"in\" or \"out\"\n", tokens[ti]);
|
|
return;
|
|
}
|
|
|
|
rule_ipv6->data.category_mask = 1;
|
|
|
|
|
|
for (ti = 2; ti < n_tokens; ti++) {
|
|
if (strcmp(tokens[ti], "esp") == 0) {
|
|
/* currently do nothing */
|
|
APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
esp_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "protect") == 0) {
|
|
APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(bypass_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"bypass");
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(discard_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"discard");
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
tv = atoi(tokens[ti]);
|
|
APP_CHECK(tv != DISCARD && tv != BYPASS, status,
|
|
"invalid SPI: %s", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
rule_ipv6->data.userdata = tv;
|
|
|
|
protect_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "bypass") == 0) {
|
|
APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(protect_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"protect");
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(discard_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"discard");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->data.userdata = BYPASS;
|
|
|
|
bypass_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "discard") == 0) {
|
|
APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(protect_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"protect");
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(bypass_p == 0, status, "conflict item "
|
|
"between \"%s\" and \"%s\"", tokens[ti],
|
|
"discard");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->data.userdata = DISCARD;
|
|
|
|
discard_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "pri") == 0) {
|
|
APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->data.priority = atoi(tokens[ti]);
|
|
|
|
pri_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "src") == 0) {
|
|
struct in6_addr ip;
|
|
uint32_t depth;
|
|
|
|
APP_CHECK_PRESENCE(src_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
|
|
&depth) == 0, status, "unrecognized "
|
|
"input \"%s\", expect valid ipv6 "
|
|
"addr", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->field[1].value.u32 =
|
|
(uint32_t)ip.s6_addr[0] << 24 |
|
|
(uint32_t)ip.s6_addr[1] << 16 |
|
|
(uint32_t)ip.s6_addr[2] << 8 |
|
|
(uint32_t)ip.s6_addr[3];
|
|
rule_ipv6->field[1].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[2].value.u32 =
|
|
(uint32_t)ip.s6_addr[4] << 24 |
|
|
(uint32_t)ip.s6_addr[5] << 16 |
|
|
(uint32_t)ip.s6_addr[6] << 8 |
|
|
(uint32_t)ip.s6_addr[7];
|
|
rule_ipv6->field[2].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[3].value.u32 =
|
|
(uint32_t)ip.s6_addr[8] << 24 |
|
|
(uint32_t)ip.s6_addr[9] << 16 |
|
|
(uint32_t)ip.s6_addr[10] << 8 |
|
|
(uint32_t)ip.s6_addr[11];
|
|
rule_ipv6->field[3].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[4].value.u32 =
|
|
(uint32_t)ip.s6_addr[12] << 24 |
|
|
(uint32_t)ip.s6_addr[13] << 16 |
|
|
(uint32_t)ip.s6_addr[14] << 8 |
|
|
(uint32_t)ip.s6_addr[15];
|
|
rule_ipv6->field[4].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
|
|
src_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "dst") == 0) {
|
|
struct in6_addr ip;
|
|
uint32_t depth;
|
|
|
|
APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
|
|
&depth) == 0, status, "unrecognized "
|
|
"input \"%s\", expect valid ipv6 "
|
|
"addr", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->field[5].value.u32 =
|
|
(uint32_t)ip.s6_addr[0] << 24 |
|
|
(uint32_t)ip.s6_addr[1] << 16 |
|
|
(uint32_t)ip.s6_addr[2] << 8 |
|
|
(uint32_t)ip.s6_addr[3];
|
|
rule_ipv6->field[5].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[6].value.u32 =
|
|
(uint32_t)ip.s6_addr[4] << 24 |
|
|
(uint32_t)ip.s6_addr[5] << 16 |
|
|
(uint32_t)ip.s6_addr[6] << 8 |
|
|
(uint32_t)ip.s6_addr[7];
|
|
rule_ipv6->field[6].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[7].value.u32 =
|
|
(uint32_t)ip.s6_addr[8] << 24 |
|
|
(uint32_t)ip.s6_addr[9] << 16 |
|
|
(uint32_t)ip.s6_addr[10] << 8 |
|
|
(uint32_t)ip.s6_addr[11];
|
|
rule_ipv6->field[7].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
depth = (depth > 32) ? (depth - 32) : 0;
|
|
rule_ipv6->field[8].value.u32 =
|
|
(uint32_t)ip.s6_addr[12] << 24 |
|
|
(uint32_t)ip.s6_addr[13] << 16 |
|
|
(uint32_t)ip.s6_addr[14] << 8 |
|
|
(uint32_t)ip.s6_addr[15];
|
|
rule_ipv6->field[8].mask_range.u32 =
|
|
(depth > 32) ? 32 : depth;
|
|
|
|
dst_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "proto") == 0) {
|
|
uint16_t low, high;
|
|
|
|
APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(parse_range(tokens[ti], &low, &high)
|
|
== 0, status, "unrecognized input \"%s\""
|
|
", expect \"from:to\"", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(low <= 0xff, status, "proto low "
|
|
"over-limit");
|
|
if (status->status < 0)
|
|
return;
|
|
APP_CHECK(high <= 0xff, status, "proto high "
|
|
"over-limit");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->field[0].value.u8 = (uint8_t)low;
|
|
rule_ipv6->field[0].mask_range.u8 = (uint8_t)high;
|
|
|
|
proto_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "sport") == 0) {
|
|
uint16_t port_low, port_high;
|
|
|
|
APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(parse_range(tokens[ti], &port_low,
|
|
&port_high) == 0, status, "unrecognized "
|
|
"input \"%s\", expect \"port_from:"
|
|
"port_to\"", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->field[9].value.u16 = port_low;
|
|
rule_ipv6->field[9].mask_range.u16 = port_high;
|
|
|
|
sport_p = 1;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(tokens[ti], "dport") == 0) {
|
|
uint16_t port_low, port_high;
|
|
|
|
APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
|
|
if (status->status < 0)
|
|
return;
|
|
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(parse_range(tokens[ti], &port_low,
|
|
&port_high) == 0, status, "unrecognized "
|
|
"input \"%s\", expect \"port_from:"
|
|
"port_to\"", tokens[ti]);
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
rule_ipv6->field[10].value.u16 = port_low;
|
|
rule_ipv6->field[10].mask_range.u16 = port_high;
|
|
|
|
dport_p = 1;
|
|
continue;
|
|
}
|
|
|
|
/* unrecognizeable input */
|
|
APP_CHECK(0, status, "unrecognized input \"%s\"",
|
|
tokens[ti]);
|
|
return;
|
|
}
|
|
|
|
/* check if argument(s) are missing */
|
|
APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
|
|
"argument \"protect\", \"bypass\", or \"discard\"");
|
|
if (status->status < 0)
|
|
return;
|
|
|
|
*ri = *ri + 1;
|
|
}
|
|
|
|
static inline void
|
|
print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
|
|
{
|
|
uint8_t a, b, c, d;
|
|
|
|
uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
|
|
rule->field[IP6_SRC0].mask_range.u32
|
|
+ rule->field[IP6_SRC1].mask_range.u32
|
|
+ rule->field[IP6_SRC2].mask_range.u32
|
|
+ rule->field[IP6_SRC3].mask_range.u32);
|
|
|
|
uint32_t_to_char(rule->field[IP6_DST0].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_DST1].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_DST2].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
|
|
uint32_t_to_char(rule->field[IP6_DST3].value.u32,
|
|
&a, &b, &c, &d);
|
|
printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
|
|
rule->field[IP6_DST0].mask_range.u32
|
|
+ rule->field[IP6_DST1].mask_range.u32
|
|
+ rule->field[IP6_DST2].mask_range.u32
|
|
+ rule->field[IP6_DST3].mask_range.u32);
|
|
|
|
printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
|
|
rule->field[IP6_SRCP].value.u16,
|
|
rule->field[IP6_SRCP].mask_range.u16,
|
|
rule->field[IP6_DSTP].value.u16,
|
|
rule->field[IP6_DSTP].mask_range.u16,
|
|
rule->field[IP6_PROTO].value.u8,
|
|
rule->field[IP6_PROTO].mask_range.u8);
|
|
if (extra)
|
|
printf("0x%x-0x%x-0x%x ",
|
|
rule->data.category_mask,
|
|
rule->data.priority,
|
|
rule->data.userdata);
|
|
}
|
|
|
|
static inline void
|
|
dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
|
|
{
|
|
int32_t i;
|
|
|
|
for (i = 0; i < num; i++, rule++) {
|
|
printf("\t%d:", i + 1);
|
|
print_one_ip6_rule(rule, extra);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
static struct rte_acl_ctx *
|
|
acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
|
|
uint32_t rules_nb)
|
|
{
|
|
char s[PATH_MAX];
|
|
struct rte_acl_param acl_param;
|
|
struct rte_acl_config acl_build_param;
|
|
struct rte_acl_ctx *ctx;
|
|
|
|
printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
|
|
|
|
memset(&acl_param, 0, sizeof(acl_param));
|
|
|
|
/* Create ACL contexts */
|
|
snprintf(s, sizeof(s), "%s_%d", name, socketid);
|
|
|
|
printf("IPv4 %s entries [%u]:\n", s, rules_nb);
|
|
dump_ip6_rules(rules, rules_nb, 1);
|
|
|
|
acl_param.name = s;
|
|
acl_param.socket_id = socketid;
|
|
acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
|
|
acl_param.max_rule_num = MAX_ACL_RULE_NUM;
|
|
|
|
ctx = rte_acl_create(&acl_param);
|
|
if (ctx == NULL)
|
|
rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
|
|
|
|
if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
|
|
rules_nb) < 0)
|
|
rte_exit(EXIT_FAILURE, "add rules failed\n");
|
|
|
|
/* Perform builds */
|
|
memset(&acl_build_param, 0, sizeof(acl_build_param));
|
|
|
|
acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
|
|
acl_build_param.num_fields = RTE_DIM(ip6_defs);
|
|
memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
|
|
|
|
if (rte_acl_build(ctx, &acl_build_param) != 0)
|
|
rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
|
|
|
|
rte_acl_dump(ctx);
|
|
|
|
return ctx;
|
|
}
|
|
|
|
/*
|
|
* check that for each rule it's SPI has a correspondent entry in SAD
|
|
*/
|
|
static int
|
|
check_spi_value(int inbound)
|
|
{
|
|
uint32_t i, num, spi;
|
|
const struct acl6_rules *acr;
|
|
|
|
if (inbound != 0) {
|
|
acr = acl6_rules_in;
|
|
num = nb_acl6_rules_in;
|
|
} else {
|
|
acr = acl6_rules_out;
|
|
num = nb_acl6_rules_out;
|
|
}
|
|
|
|
for (i = 0; i != num; i++) {
|
|
spi = acr[i].data.userdata;
|
|
if (spi != DISCARD && spi != BYPASS &&
|
|
sa_spi_present(spi, inbound) < 0) {
|
|
RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
|
|
spi);
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
sp6_init(struct socket_ctx *ctx, int32_t socket_id)
|
|
{
|
|
const char *name;
|
|
|
|
if (ctx == NULL)
|
|
rte_exit(EXIT_FAILURE, "NULL context.\n");
|
|
|
|
if (ctx->sp_ip6_in != NULL)
|
|
rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
|
|
"already initialized\n", socket_id);
|
|
|
|
if (ctx->sp_ip6_out != NULL)
|
|
rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
|
|
"already initialized\n", socket_id);
|
|
|
|
if (check_spi_value(1) < 0)
|
|
rte_exit(EXIT_FAILURE,
|
|
"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
|
|
|
|
if (check_spi_value(0) < 0)
|
|
rte_exit(EXIT_FAILURE,
|
|
"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
|
|
|
|
if (nb_acl6_rules_in > 0) {
|
|
name = "sp_ip6_in";
|
|
ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
|
|
socket_id, acl6_rules_in, nb_acl6_rules_in);
|
|
} else
|
|
RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
|
|
"specified\n");
|
|
|
|
if (nb_acl6_rules_out > 0) {
|
|
name = "sp_ip6_out";
|
|
ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
|
|
socket_id, acl6_rules_out, nb_acl6_rules_out);
|
|
} else
|
|
RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "
|
|
"specified\n");
|
|
}
|
|
|
|
/*
|
|
* Search though SP rules for given SPI.
|
|
*/
|
|
int
|
|
sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
|
|
uint32_t mask[2])
|
|
{
|
|
uint32_t i, num;
|
|
const struct acl6_rules *acr;
|
|
|
|
if (inbound != 0) {
|
|
acr = acl6_rules_in;
|
|
num = nb_acl6_rules_in;
|
|
} else {
|
|
acr = acl6_rules_out;
|
|
num = nb_acl6_rules_out;
|
|
}
|
|
|
|
for (i = 0; i != num; i++) {
|
|
if (acr[i].data.userdata == spi) {
|
|
if (NULL != ip_addr && NULL != mask) {
|
|
IPV6_SRC_FROM_SP(ip_addr[0], acr[i]);
|
|
IPV6_DST_FROM_SP(ip_addr[1], acr[i]);
|
|
IPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);
|
|
IPV6_DST_MASK_FROM_SP(mask[1], acr[i]);
|
|
}
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|