Removed redundant references to Intel(R) DPDK in Programmers Guide. Signed-off-by: Siobhan Butler <siobhan.a.butler@intel.com> Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>
436 lines
15 KiB
ReStructuredText
436 lines
15 KiB
ReStructuredText
.. BSD LICENSE
|
|
Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the
|
|
distribution.
|
|
* Neither the name of Intel Corporation nor the names of its
|
|
contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
Packet Classification and Access Control
|
|
========================================
|
|
|
|
The DPDK provides an Access Control library that gives the ability
|
|
to classify an input packet based on a set of classification rules.
|
|
|
|
The ACL library is used to perform an N-tuple search over a set of rules with multiple categories
|
|
and find the best match (highest priority) for each category.
|
|
The library API provides the following basic operations:
|
|
|
|
* Create a new Access Control (AC) context.
|
|
|
|
* Add rules into the context.
|
|
|
|
* For all rules in the context, build the runtime structures necessary to perform packet classification.
|
|
|
|
* Perform input packet classifications.
|
|
|
|
* Destroy an AC context and its runtime structures and free the associated memory.
|
|
|
|
Overview
|
|
--------
|
|
|
|
The current implementation allows the user for each AC context to specify its own rule (set of fields)
|
|
over which packet classification will be performed.
|
|
To define each field inside an AC rule, the following structure is used:
|
|
|
|
.. code-block:: c
|
|
|
|
struct rte_acl_field_def {
|
|
uint8_t type; /*< type - ACL_FIELD_TYPE. */
|
|
uint8_t size; /*< size of field 1,2,4, or 8. */
|
|
uint8_t field_index; /*< index of field inside the rule. */
|
|
uint8_t input_index; /*< 0-N input index. */
|
|
uint32_t offset; /*< offset to start of field. */
|
|
};
|
|
|
|
* type
|
|
The field type is one of three choices:
|
|
|
|
* _MASK - for fields such as IP addresses that have a value and a mask defining the number of relevant bits.
|
|
|
|
* _RANGE - for fields such as ports that have a lower and upper value for the field.
|
|
|
|
* _BITMASK - for fields such as protocol identifiers that have a value and a bit mask.
|
|
|
|
* size
|
|
The size parameter defines the length of the field in bytes. Allowable values are 1, 2, 4, or 8 bytes.
|
|
Note that due to the grouping of input bytes, 1 or 2 byte fields must be defined as consecutive fields
|
|
that make up 4 consecutive input bytes.
|
|
Also, it is best to define fields of 8 or more bytes as 4 byte fields so that
|
|
the build processes can eliminate fields that are all wild.
|
|
|
|
* field_index
|
|
A zero-based value that represents the position of the field inside the rule; 0 to N-1 for N fields.
|
|
|
|
* input_index
|
|
For performance reasons, the inner loop of the search function is unrolled to process four input bytes at a time.
|
|
This requires the input to be grouped into sets of 4 consecutive bytes.
|
|
The loop processes the first input byte as part of the setup and then
|
|
subsequent bytes must be in groups of 4 consecutive bytes.
|
|
The input index specifies to which input group that field belongs to.
|
|
|
|
* offset
|
|
The offset field defines the offset for the field.
|
|
This is the offset from the beginning of the buffer parameter for the search.
|
|
|
|
For example, to define classification for the following IPv4 5-tuple structure:
|
|
|
|
.. code-block:: c
|
|
|
|
struct ipv4_5tuple {
|
|
uint8_t proto;
|
|
uint32_t ip_src;
|
|
uint32_t ip_dst;
|
|
uint16_t port_src;
|
|
uint16_t port_dst;
|
|
};
|
|
|
|
The following array of field definitions can be used:
|
|
|
|
.. code-block:: c
|
|
|
|
struct rte_acl_field_def ipv4_defs[5] = {
|
|
/* first input field - always one byte long. */
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof (uint8_t),
|
|
.field_index = 0,
|
|
.input_index = 0,
|
|
.offset = offsetof (struct ipv4_5tuple, proto),
|
|
},
|
|
|
|
/* next input field (IPv4 source address) - 4 consecutive bytes. */
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 1,
|
|
.input_index = 1,
|
|
.offset = offsetof (struct ipv4_5tuple, ip_src),
|
|
},
|
|
|
|
/* next input field (IPv4 destination address) - 4 consecutive bytes. */
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 2,
|
|
.input_index = 2,
|
|
.offset = offsetof (struct ipv4_5tuple, ip_dst),
|
|
},
|
|
|
|
/*
|
|
* Next 2 fields (src & dst ports) form 4 consecutive bytes.
|
|
* They share the same input index.
|
|
*/
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof (uint16_t),
|
|
.field_index = 3,
|
|
.input_index = 3,
|
|
.offset = offsetof (struct ipv4_5tuple, port_src),
|
|
},
|
|
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof (uint16_t),
|
|
.field_index = 4,
|
|
.input_index = 3,
|
|
.offset = offsetof (struct ipv4_5tuple, port_dst),
|
|
},
|
|
};
|
|
|
|
A typical example of such an IPv4 5-tuple rule is a follows:
|
|
|
|
::
|
|
|
|
source addr/mask destination addr/mask source ports dest ports protocol/mask
|
|
192.168.1.0/24 192.168.2.31/32 0:65535 1234:1234 17/0xff
|
|
|
|
Any IPv4 packets with protocol ID 17 (UDP), source address 192.168.1.[0-255], destination address 192.168.2.31,
|
|
source port [0-65535] and destination port 1234 matches the above rule.
|
|
|
|
To define classification for the IPv6 2-tuple: <protocol, IPv6 source address> over the following IPv6 header structure:
|
|
|
|
.. code-block:: c
|
|
|
|
struct struct ipv6_hdr {
|
|
uint32_t vtc_flow; /* IP version, traffic class & flow label. */
|
|
uint16_t payload_len; /* IP packet length - includes sizeof(ip_header). */
|
|
uint8_t proto; /* Protocol, next header. */
|
|
uint8_t hop_limits; /* Hop limits. */
|
|
uint8_t src_addr[16]; /* IP address of source host. */
|
|
uint8_t dst_addr[16]; /* IP address of destination host(s). */
|
|
} __attribute__((__packed__));
|
|
|
|
The following array of field definitions can be used:
|
|
|
|
.. code-block:: c
|
|
|
|
struct struct rte_acl_field_def ipv6_2tuple_defs[5] = {
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof (uint8_t),
|
|
.field_index = 0,
|
|
.input_index = 0,
|
|
.offset = offsetof (struct ipv6_hdr, proto),
|
|
},
|
|
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 1,
|
|
.input_index = 1,
|
|
.offset = offsetof (struct ipv6_hdr, src_addr[0]),
|
|
},
|
|
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 2,
|
|
.input_index = 2,
|
|
.offset = offsetof (struct ipv6_hdr, src_addr[4]),
|
|
},
|
|
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 3,
|
|
.input_index = 3,
|
|
.offset = offsetof (struct ipv6_hdr, src_addr[8]),
|
|
},
|
|
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof (uint32_t),
|
|
.field_index = 4,
|
|
.input_index = 4,
|
|
.offset = offsetof (struct ipv6_hdr, src_addr[12]),
|
|
},
|
|
};
|
|
|
|
A typical example of such an IPv6 2-tuple rule is a follows:
|
|
|
|
::
|
|
|
|
source addr/mask protocol/mask
|
|
2001:db8:1234:0000:0000:0000:0000:0000/48 6/0xff
|
|
|
|
Any IPv6 packets with protocol ID 6 (TCP), and source address inside the range
|
|
[2001:db8:1234:0000:0000:0000:0000:0000 - 2001:db8:1234:ffff:ffff:ffff:ffff:ffff] matches the above rule.
|
|
|
|
When creating a set of rules, for each rule, additional information must be supplied also:
|
|
|
|
* **priority**: A weight to measure the priority of the rules (higher is better).
|
|
If the input tuple matches more than one rule, then the rule with the higher priority is returned.
|
|
Note that if the input tuple matches more than one rule and these rules have equal priority,
|
|
it is undefined which rule is returned as a match.
|
|
It is recommended to assign a unique priority for each rule.
|
|
|
|
* **category_mask**: Each rule uses a bit mask value to select the relevant category(s) for the rule.
|
|
When a lookup is performed, the result for each category is returned.
|
|
This effectively provides a "parallel lookup" by enabling a single search to return multiple results if,
|
|
for example, there were four different sets of ACL rules, one for access control, one for routing, and so on.
|
|
Each set could be assigned its own category and by combining them into a single database,
|
|
one lookup returns a result for each of the four sets.
|
|
|
|
* **userdata**: A user-defined field that could be any value except zero.
|
|
For each category, a successful match returns the userdata field of the highest priority matched rule.
|
|
|
|
.. note::
|
|
|
|
When adding new rules into an ACL context, all fields must be in host byte order (LSB).
|
|
When the search is performed for an input tuple, all fields in that tuple must be in network byte order (MSB).
|
|
|
|
Application Programming Interface (API) Usage
|
|
---------------------------------------------
|
|
|
|
.. note::
|
|
|
|
For more details about the Access Control API, please refer to the *DPDK API Reference*.
|
|
|
|
The following example demonstrates IPv4, 5-tuple classification for rules defined above
|
|
with multiple categories in more detail.
|
|
|
|
Classify with Multiple Categories
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: c
|
|
|
|
struct rte_acl_ctx * acx;
|
|
struct rte_acl_config cfg;
|
|
int ret;
|
|
|
|
/* define a structure for the rule with up to 5 fields. */
|
|
|
|
RTE_ACL_RULE_DEF(acl_ipv4_rule, RTE_DIM(ipv4_defs));
|
|
|
|
/* AC context creation parameters. */
|
|
|
|
struct rte_acl_param prm = {
|
|
.name = "ACL_example",
|
|
.socket_id = SOCKET_ID_ANY,
|
|
.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ipv4_defs)),
|
|
|
|
/* number of fields per rule. */
|
|
|
|
.max_rule_num = 8, /* maximum number of rules in the AC context. */
|
|
};
|
|
|
|
struct acl_ipv4_rule acl_rules[] = {
|
|
|
|
/* matches all packets traveling to 192.168.0.0/16, applies for categories: 0,1 */
|
|
{
|
|
.data = {.userdata = 1, .category_mask = 3, .priority = 1},
|
|
|
|
/* destination IPv4 */
|
|
.field[2] = {.value.u32 = IPv4(192,168,0,0),. mask_range.u32 = 16,},
|
|
|
|
/* source port */
|
|
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
|
|
/* destination port */
|
|
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
},
|
|
|
|
/* matches all packets traveling to 192.168.1.0/24, applies for categories: 0 */
|
|
{
|
|
.data = {.userdata = 2, .category_mask = 1, .priority = 2},
|
|
|
|
/* destination IPv4 */
|
|
.field[2] = {.value.u32 = IPv4(192,168,1,0),. mask_range.u32 = 24,},
|
|
|
|
/* source port */
|
|
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
|
|
/* destination port */
|
|
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
},
|
|
|
|
/* matches all packets traveling from 10.1.1.1, applies for categories: 1 */
|
|
{
|
|
.data = {.userdata = 3, .category_mask = 2, .priority = 3},
|
|
|
|
/* source IPv4 */
|
|
.field[1] = {.value.u32 = IPv4(10,1,1,1),. mask_range.u32 = 32,},
|
|
|
|
/* source port */
|
|
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
|
|
/* destination port */
|
|
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
|
|
},
|
|
|
|
};
|
|
|
|
|
|
/* create an empty AC context */
|
|
|
|
if ((acx = rte_acl_create(&prm)) == NULL) {
|
|
|
|
/* handle context create failure. */
|
|
|
|
}
|
|
|
|
/* add rules to the context */
|
|
|
|
ret = rte_acl_add_rules(acx, acl_rules, RTE_DIM(acl_rules));
|
|
if (ret != 0) {
|
|
/* handle error at adding ACL rules. */
|
|
}
|
|
|
|
/* prepare AC build config. */
|
|
|
|
cfg.num_categories = 2;
|
|
cfg.num_fields = RTE_DIM(ipv4_defs);
|
|
|
|
memcpy(cfg.defs, ipv4_defs, sizeof (ipv4_defs));
|
|
|
|
/* build the runtime structures for added rules, with 2 categories. */
|
|
|
|
ret = rte_acl_build(acx, &cfg);
|
|
if (ret != 0) {
|
|
/* handle error at build runtime structures for ACL context. */
|
|
}
|
|
|
|
For a tuple with source IP address: 10.1.1.1 and destination IP address: 192.168.1.15,
|
|
once the following lines are executed:
|
|
|
|
.. code-block:: c
|
|
|
|
uint32_t results[4]; /* make classify for 4 categories. */
|
|
|
|
rte_acl_classify(acx, data, results, 1, 4);
|
|
|
|
then the results[] array contains:
|
|
|
|
.. code-block:: c
|
|
|
|
results[4] = {2, 3, 0, 0};
|
|
|
|
* For category 0, both rules 1 and 2 match, but rule 2 has higher priority,
|
|
therefore results[0] contains the userdata for rule 2.
|
|
|
|
* For category 1, both rules 1 and 3 match, but rule 3 has higher priority,
|
|
therefore results[1] contains the userdata for rule 3.
|
|
|
|
* For categories 2 and 3, there are no matches, so results[2] and results[3] contain zero,
|
|
which indicates that no matches were found for those categories.
|
|
|
|
For a tuple with source IP address: 192.168.1.1 and destination IP address: 192.168.2.11,
|
|
once the following lines are executed:
|
|
|
|
.. code-block:: c
|
|
|
|
uint32_t results[4]; /* make classify by 4 categories. */
|
|
|
|
rte_acl_classify(acx, data, results, 1, 4);
|
|
|
|
the results[] array contains:
|
|
|
|
.. code-block:: c
|
|
|
|
results[4] = {1, 1, 0, 0};
|
|
|
|
* For categories 0 and 1, only rule 1 matches.
|
|
|
|
* For categories 2 and 3, there are no matches.
|
|
|
|
For a tuple with source IP address: 10.1.1.1 and destination IP address: 201.212.111.12,
|
|
once the following lines are executed:
|
|
|
|
.. code-block:: c
|
|
|
|
uint32_t results[4]; /* make classify by 4 categories. */
|
|
rte_acl_classify(acx, data, results, 1, 4);
|
|
|
|
the results[] array contains:
|
|
|
|
.. code-block:: c
|
|
|
|
results[4] = {0, 3, 0, 0};
|
|
|
|
* For category 1, only rule 3 matches.
|
|
|
|
* For categories 0, 2 and 3, there are no matches.
|