mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
netdev-offload-dpdk: Refactor flow patterns.
Refactor the flow patterns code to a helper function for better readability and towards supporting more matches. Signed-off-by: Eli Britstein <elibr@mellanox.com> Reviewed-by: Oz Shlomo <ozsh@mellanox.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
committed by
Ilya Maximets
parent
81e89d5c26
commit
7c5b722a41
@@ -410,6 +410,165 @@ add_flow_rss_action(struct flow_actions *actions,
|
||||
return rss_data;
|
||||
}
|
||||
|
||||
struct flow_items {
|
||||
struct rte_flow_item_eth eth;
|
||||
struct rte_flow_item_vlan vlan;
|
||||
struct rte_flow_item_ipv4 ipv4;
|
||||
union {
|
||||
struct rte_flow_item_tcp tcp;
|
||||
struct rte_flow_item_udp udp;
|
||||
struct rte_flow_item_sctp sctp;
|
||||
struct rte_flow_item_icmp icmp;
|
||||
};
|
||||
};
|
||||
|
||||
static int
|
||||
parse_flow_match(struct flow_patterns *patterns,
|
||||
struct flow_items *spec,
|
||||
struct flow_items *mask,
|
||||
const struct match *match)
|
||||
{
|
||||
uint8_t proto = 0;
|
||||
|
||||
/* Eth */
|
||||
if (!eth_addr_is_zero(match->wc.masks.dl_src) ||
|
||||
!eth_addr_is_zero(match->wc.masks.dl_dst)) {
|
||||
memcpy(&spec->eth.dst, &match->flow.dl_dst, sizeof spec->eth.dst);
|
||||
memcpy(&spec->eth.src, &match->flow.dl_src, sizeof spec->eth.src);
|
||||
spec->eth.type = match->flow.dl_type;
|
||||
|
||||
memcpy(&mask->eth.dst, &match->wc.masks.dl_dst, sizeof mask->eth.dst);
|
||||
memcpy(&mask->eth.src, &match->wc.masks.dl_src, sizeof mask->eth.src);
|
||||
mask->eth.type = match->wc.masks.dl_type;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH,
|
||||
&spec->eth, &mask->eth);
|
||||
} else {
|
||||
/*
|
||||
* If user specifies a flow (like UDP flow) without L2 patterns,
|
||||
* OVS will at least set the dl_type. Normally, it's enough to
|
||||
* create an eth pattern just with it. Unluckily, some Intel's
|
||||
* NIC (such as XL710) doesn't support that. Below is a workaround,
|
||||
* which simply matches any L2 pkts.
|
||||
*/
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
|
||||
}
|
||||
|
||||
/* VLAN */
|
||||
if (match->wc.masks.vlans[0].tci && match->flow.vlans[0].tci) {
|
||||
spec->vlan.tci = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
|
||||
mask->vlan.tci = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
|
||||
|
||||
/* Match any protocols. */
|
||||
mask->vlan.inner_type = 0;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_VLAN,
|
||||
&spec->vlan, &mask->vlan);
|
||||
}
|
||||
|
||||
/* IP v4 */
|
||||
if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
|
||||
spec->ipv4.hdr.type_of_service = match->flow.nw_tos;
|
||||
spec->ipv4.hdr.time_to_live = match->flow.nw_ttl;
|
||||
spec->ipv4.hdr.next_proto_id = match->flow.nw_proto;
|
||||
spec->ipv4.hdr.src_addr = match->flow.nw_src;
|
||||
spec->ipv4.hdr.dst_addr = match->flow.nw_dst;
|
||||
|
||||
mask->ipv4.hdr.type_of_service = match->wc.masks.nw_tos;
|
||||
mask->ipv4.hdr.time_to_live = match->wc.masks.nw_ttl;
|
||||
mask->ipv4.hdr.next_proto_id = match->wc.masks.nw_proto;
|
||||
mask->ipv4.hdr.src_addr = match->wc.masks.nw_src;
|
||||
mask->ipv4.hdr.dst_addr = match->wc.masks.nw_dst;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_IPV4,
|
||||
&spec->ipv4, &mask->ipv4);
|
||||
|
||||
/* Save proto for L4 protocol setup. */
|
||||
proto = spec->ipv4.hdr.next_proto_id &
|
||||
mask->ipv4.hdr.next_proto_id;
|
||||
}
|
||||
|
||||
if (proto != IPPROTO_ICMP && proto != IPPROTO_UDP &&
|
||||
proto != IPPROTO_SCTP && proto != IPPROTO_TCP &&
|
||||
(match->wc.masks.tp_src ||
|
||||
match->wc.masks.tp_dst ||
|
||||
match->wc.masks.tcp_flags)) {
|
||||
VLOG_DBG("L4 Protocol (%u) not supported", proto);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((match->wc.masks.tp_src && match->wc.masks.tp_src != OVS_BE16_MAX) ||
|
||||
(match->wc.masks.tp_dst && match->wc.masks.tp_dst != OVS_BE16_MAX)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
spec->tcp.hdr.src_port = match->flow.tp_src;
|
||||
spec->tcp.hdr.dst_port = match->flow.tp_dst;
|
||||
spec->tcp.hdr.data_off = ntohs(match->flow.tcp_flags) >> 8;
|
||||
spec->tcp.hdr.tcp_flags = ntohs(match->flow.tcp_flags) & 0xff;
|
||||
|
||||
mask->tcp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask->tcp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
mask->tcp.hdr.data_off = ntohs(match->wc.masks.tcp_flags) >> 8;
|
||||
mask->tcp.hdr.tcp_flags = ntohs(match->wc.masks.tcp_flags) & 0xff;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_TCP,
|
||||
&spec->tcp, &mask->tcp);
|
||||
|
||||
/* proto == TCP and ITEM_TYPE_TCP, thus no need for proto match. */
|
||||
mask->ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
spec->udp.hdr.src_port = match->flow.tp_src;
|
||||
spec->udp.hdr.dst_port = match->flow.tp_dst;
|
||||
|
||||
mask->udp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask->udp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_UDP,
|
||||
&spec->udp, &mask->udp);
|
||||
|
||||
/* proto == UDP and ITEM_TYPE_UDP, thus no need for proto match. */
|
||||
mask->ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_SCTP:
|
||||
spec->sctp.hdr.src_port = match->flow.tp_src;
|
||||
spec->sctp.hdr.dst_port = match->flow.tp_dst;
|
||||
|
||||
mask->sctp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask->sctp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_SCTP,
|
||||
&spec->sctp, &mask->sctp);
|
||||
|
||||
/* proto == SCTP and ITEM_TYPE_SCTP, thus no need for proto match. */
|
||||
mask->ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
spec->icmp.hdr.icmp_type = (uint8_t) ntohs(match->flow.tp_src);
|
||||
spec->icmp.hdr.icmp_code = (uint8_t) ntohs(match->flow.tp_dst);
|
||||
|
||||
mask->icmp.hdr.icmp_type = (uint8_t) ntohs(match->wc.masks.tp_src);
|
||||
mask->icmp.hdr.icmp_code = (uint8_t) ntohs(match->wc.masks.tp_dst);
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ICMP,
|
||||
&spec->icmp, &mask->icmp);
|
||||
|
||||
/* proto == ICMP and ITEM_TYPE_ICMP, thus no need for proto match. */
|
||||
mask->ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_END, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
netdev_offload_dpdk_add_flow(struct netdev *netdev,
|
||||
const struct match *match,
|
||||
@@ -428,161 +587,17 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
|
||||
struct flow_actions actions = { .actions = NULL, .cnt = 0 };
|
||||
struct rte_flow *flow;
|
||||
struct rte_flow_error error;
|
||||
uint8_t proto = 0;
|
||||
int ret = 0;
|
||||
struct flow_items {
|
||||
struct rte_flow_item_eth eth;
|
||||
struct rte_flow_item_vlan vlan;
|
||||
struct rte_flow_item_ipv4 ipv4;
|
||||
union {
|
||||
struct rte_flow_item_tcp tcp;
|
||||
struct rte_flow_item_udp udp;
|
||||
struct rte_flow_item_sctp sctp;
|
||||
struct rte_flow_item_icmp icmp;
|
||||
};
|
||||
} spec, mask;
|
||||
struct flow_items spec, mask;
|
||||
|
||||
memset(&spec, 0, sizeof spec);
|
||||
memset(&mask, 0, sizeof mask);
|
||||
|
||||
/* Eth */
|
||||
if (!eth_addr_is_zero(match->wc.masks.dl_src) ||
|
||||
!eth_addr_is_zero(match->wc.masks.dl_dst)) {
|
||||
memcpy(&spec.eth.dst, &match->flow.dl_dst, sizeof spec.eth.dst);
|
||||
memcpy(&spec.eth.src, &match->flow.dl_src, sizeof spec.eth.src);
|
||||
spec.eth.type = match->flow.dl_type;
|
||||
|
||||
memcpy(&mask.eth.dst, &match->wc.masks.dl_dst, sizeof mask.eth.dst);
|
||||
memcpy(&mask.eth.src, &match->wc.masks.dl_src, sizeof mask.eth.src);
|
||||
mask.eth.type = match->wc.masks.dl_type;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
|
||||
&spec.eth, &mask.eth);
|
||||
} else {
|
||||
/*
|
||||
* If user specifies a flow (like UDP flow) without L2 patterns,
|
||||
* OVS will at least set the dl_type. Normally, it's enough to
|
||||
* create an eth pattern just with it. Unluckily, some Intel's
|
||||
* NIC (such as XL710) doesn't support that. Below is a workaround,
|
||||
* which simply matches any L2 pkts.
|
||||
*/
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
|
||||
}
|
||||
|
||||
/* VLAN */
|
||||
if (match->wc.masks.vlans[0].tci && match->flow.vlans[0].tci) {
|
||||
spec.vlan.tci = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
|
||||
mask.vlan.tci = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
|
||||
|
||||
/* Match any protocols. */
|
||||
mask.vlan.inner_type = 0;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_VLAN,
|
||||
&spec.vlan, &mask.vlan);
|
||||
}
|
||||
|
||||
/* IP v4 */
|
||||
if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
|
||||
spec.ipv4.hdr.type_of_service = match->flow.nw_tos;
|
||||
spec.ipv4.hdr.time_to_live = match->flow.nw_ttl;
|
||||
spec.ipv4.hdr.next_proto_id = match->flow.nw_proto;
|
||||
spec.ipv4.hdr.src_addr = match->flow.nw_src;
|
||||
spec.ipv4.hdr.dst_addr = match->flow.nw_dst;
|
||||
|
||||
mask.ipv4.hdr.type_of_service = match->wc.masks.nw_tos;
|
||||
mask.ipv4.hdr.time_to_live = match->wc.masks.nw_ttl;
|
||||
mask.ipv4.hdr.next_proto_id = match->wc.masks.nw_proto;
|
||||
mask.ipv4.hdr.src_addr = match->wc.masks.nw_src;
|
||||
mask.ipv4.hdr.dst_addr = match->wc.masks.nw_dst;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_IPV4,
|
||||
&spec.ipv4, &mask.ipv4);
|
||||
|
||||
/* Save proto for L4 protocol setup. */
|
||||
proto = spec.ipv4.hdr.next_proto_id &
|
||||
mask.ipv4.hdr.next_proto_id;
|
||||
}
|
||||
|
||||
if (proto != IPPROTO_ICMP && proto != IPPROTO_UDP &&
|
||||
proto != IPPROTO_SCTP && proto != IPPROTO_TCP &&
|
||||
(match->wc.masks.tp_src ||
|
||||
match->wc.masks.tp_dst ||
|
||||
match->wc.masks.tcp_flags)) {
|
||||
VLOG_DBG("L4 Protocol (%u) not supported", proto);
|
||||
ret = -1;
|
||||
ret = parse_flow_match(&patterns, &spec, &mask, match);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((match->wc.masks.tp_src && match->wc.masks.tp_src != OVS_BE16_MAX) ||
|
||||
(match->wc.masks.tp_dst && match->wc.masks.tp_dst != OVS_BE16_MAX)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
spec.tcp.hdr.src_port = match->flow.tp_src;
|
||||
spec.tcp.hdr.dst_port = match->flow.tp_dst;
|
||||
spec.tcp.hdr.data_off = ntohs(match->flow.tcp_flags) >> 8;
|
||||
spec.tcp.hdr.tcp_flags = ntohs(match->flow.tcp_flags) & 0xff;
|
||||
|
||||
mask.tcp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask.tcp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
mask.tcp.hdr.data_off = ntohs(match->wc.masks.tcp_flags) >> 8;
|
||||
mask.tcp.hdr.tcp_flags = ntohs(match->wc.masks.tcp_flags) & 0xff;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_TCP,
|
||||
&spec.tcp, &mask.tcp);
|
||||
|
||||
/* proto == TCP and ITEM_TYPE_TCP, thus no need for proto match. */
|
||||
mask.ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
spec.udp.hdr.src_port = match->flow.tp_src;
|
||||
spec.udp.hdr.dst_port = match->flow.tp_dst;
|
||||
|
||||
mask.udp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask.udp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_UDP,
|
||||
&spec.udp, &mask.udp);
|
||||
|
||||
/* proto == UDP and ITEM_TYPE_UDP, thus no need for proto match. */
|
||||
mask.ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_SCTP:
|
||||
spec.sctp.hdr.src_port = match->flow.tp_src;
|
||||
spec.sctp.hdr.dst_port = match->flow.tp_dst;
|
||||
|
||||
mask.sctp.hdr.src_port = match->wc.masks.tp_src;
|
||||
mask.sctp.hdr.dst_port = match->wc.masks.tp_dst;
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_SCTP,
|
||||
&spec.sctp, &mask.sctp);
|
||||
|
||||
/* proto == SCTP and ITEM_TYPE_SCTP, thus no need for proto match. */
|
||||
mask.ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
spec.icmp.hdr.icmp_type = (uint8_t) ntohs(match->flow.tp_src);
|
||||
spec.icmp.hdr.icmp_code = (uint8_t) ntohs(match->flow.tp_dst);
|
||||
|
||||
mask.icmp.hdr.icmp_type = (uint8_t) ntohs(match->wc.masks.tp_src);
|
||||
mask.icmp.hdr.icmp_code = (uint8_t) ntohs(match->wc.masks.tp_dst);
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ICMP,
|
||||
&spec.icmp, &mask.icmp);
|
||||
|
||||
/* proto == ICMP and ITEM_TYPE_ICMP, thus no need for proto match. */
|
||||
mask.ipv4.hdr.next_proto_id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_END, NULL, NULL);
|
||||
|
||||
struct rte_flow_action_mark mark;
|
||||
struct action_rss_data *rss;
|
||||
|
||||
|
Reference in New Issue
Block a user