2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-17 14:28:02 +00:00

lib: Keep track of usable protocols while parsing.

Keep track of usable protocols while parsing actions and matches,
rather than checking for them afterwards.  This fixes silently discarded
meter and goto table instructions when not explicitly specifying the
protocol to use.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2013-08-20 18:41:45 -07:00
committed by Ben Pfaff
parent 89454bf477
commit db0b6c2913
12 changed files with 341 additions and 315 deletions

View File

@@ -1100,158 +1100,6 @@ ofputil_packet_in_format_from_string(const char *s)
: -1);
}
static bool
regs_fully_wildcarded(const struct flow_wildcards *wc)
{
int i;
for (i = 0; i < FLOW_N_REGS; i++) {
if (wc->masks.regs[i] != 0) {
return false;
}
}
return true;
}
/* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
* to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
* registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
* use OpenFlow 1.0 protocol for backward compatibility. */
enum ofputil_protocol
ofputil_usable_protocols(const struct match *match)
{
const struct flow_wildcards *wc = &match->wc;
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
/* These tunnel params can't be sent in a flow_mod */
if (wc->masks.tunnel.ip_ttl
|| wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
return OFPUTIL_P_NONE;
}
/* skb_priority can't be sent in a flow_mod */
if (wc->masks.skb_priority) {
return OFPUTIL_P_NONE;
}
/* NXM and OXM support pkt_mark */
if (wc->masks.pkt_mark) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
if (!eth_mask_is_exact(wc->masks.dl_src)
&& !eth_addr_is_zero(wc->masks.dl_src)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
if (!eth_mask_is_exact(wc->masks.dl_dst)
&& !eth_addr_is_zero(wc->masks.dl_dst)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM, OXM, and OF1.1+ support matching metadata. */
if (wc->masks.metadata != htonll(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching ARP hardware addresses. */
if (!eth_addr_is_zero(wc->masks.arp_sha) ||
!eth_addr_is_zero(wc->masks.arp_tha)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching L3 and L4 fields within IPv6.
*
* (arp_sha, arp_tha, nw_frag, and nw_ttl are covered elsewhere so they
* don't need to be included in this test too.) */
if (match->flow.dl_type == htons(ETH_TYPE_IPV6)
&& (!ipv6_mask_is_any(&wc->masks.ipv6_src)
|| !ipv6_mask_is_any(&wc->masks.ipv6_dst)
|| !ipv6_mask_is_any(&wc->masks.nd_target)
|| wc->masks.ipv6_label
|| wc->masks.tp_src
|| wc->masks.tp_dst
|| wc->masks.nw_proto
|| wc->masks.nw_tos)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching registers. */
if (!regs_fully_wildcarded(wc)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
if (wc->masks.tunnel.tun_id != htonll(0)
|| wc->masks.tunnel.ip_src != htonl(0)
|| wc->masks.tunnel.ip_dst != htonl(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching fragments. */
if (wc->masks.nw_frag) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IP ECN bits. */
if (wc->masks.nw_tos & IP_ECN_MASK) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IP TTL/hop limit. */
if (wc->masks.nw_ttl) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support non-CIDR IPv4 address masks. */
if (!ip_is_cidr(wc->masks.nw_src) || !ip_is_cidr(wc->masks.nw_dst)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support bitwise matching on transport port. */
if ((wc->masks.tp_src && wc->masks.tp_src != htons(UINT16_MAX)) ||
(wc->masks.tp_dst && wc->masks.tp_dst != htons(UINT16_MAX))) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OF1.1+ support matching MPLS label */
if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OF1.1+ support matching MPLS TC */
if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OF1.3+ support matching MPLS stack flag */
/* Allow for OF1.2 as there doesn't seem to be a
* particularly good reason not to */
if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* Other formats can express this rule. */
return OFPUTIL_P_ANY;
}
void
ofputil_format_version(struct ds *msg, enum ofp_version version)
{
@@ -2268,39 +2116,6 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
return msg;
}
/* Returns a bitmask with a 1-bit for each protocol that could be used to
* send all of the 'n_fm's flow table modification requests in 'fms', and a
* 0-bit for each protocol that is inadequate.
*
* (The return value will have at least one 1-bit.) */
enum ofputil_protocol
ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
size_t n_fms)
{
enum ofputil_protocol usable_protocols;
size_t i;
usable_protocols = OFPUTIL_P_ANY;
for (i = 0; i < n_fms; i++) {
const struct ofputil_flow_mod *fm = &fms[i];
usable_protocols &= ofputil_usable_protocols(&fm->match);
if (fm->table_id != 0xff) {
usable_protocols &= OFPUTIL_P_TID;
}
/* Matching of the cookie is only supported through NXM or OF1.1+. */
if (fm->cookie_mask != htonll(0)) {
usable_protocols &= (OFPUTIL_P_OF10_NXM_ANY
| OFPUTIL_P_OF11_STD
| OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM);
}
}
return usable_protocols;
}
static enum ofperr
ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
const struct ofp10_flow_stats_request *ofsr,
@@ -2476,24 +2291,6 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
return msg;
}
/* Returns a bitmask with a 1-bit for each protocol that could be used to
* accurately encode 'fsr', and a 0-bit for each protocol that is inadequate.
*
* (The return value will have at least one 1-bit.) */
enum ofputil_protocol
ofputil_flow_stats_request_usable_protocols(
const struct ofputil_flow_stats_request *fsr)
{
enum ofputil_protocol usable_protocols;
usable_protocols = ofputil_usable_protocols(&fsr->match);
if (fsr->cookie_mask != htonll(0)) {
usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
return usable_protocols;
}
/* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract
* ofputil_flow_stats in 'fs'.
*