Ofproto always provides a valid pointer to a mask, but the mask length is zero when megaflows are disabled. Use match_wc_init() to get an appropriate exact match mask when there is no mask.
Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- v5: - Split dpif_netdev_flow_mask_from_nlattrs() to dpif_netdev_flow_from_nlattrs() and dpif_netdev_mask_from_nlattrs() and make the latter to require non-zero mask_key_len. - Make dp_netdev_flow_add() to initialize an exact match mask if no wildcards are given. This reflects the kernel datapath behavior. lib/dpif-netdev.c | 88 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 911cb5d..5899f74 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -787,30 +787,56 @@ get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow, stats->tcp_flags = netdev_flow->tcp_flags; } +/* Should only be called with a non-zero mask_key_len. */ static int -dpif_netdev_flow_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, - const struct nlattr *mask_key, - uint32_t mask_key_len, struct flow *flow, - struct flow *mask) +dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, + const struct nlattr *mask_key, + uint32_t mask_key_len, const struct flow *flow, + struct flow *mask) +{ + if (odp_flow_key_to_mask(mask_key, mask_key_len, mask, flow)) { + /* This should not happen: it indicates that + * odp_flow_key_from_mask() and odp_flow_key_to_mask() + * disagree on the acceptable form of a mask. Log the problem + * as an error, with enough details to enable debugging. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + + if (!VLOG_DROP_ERR(&rl)) { + struct ds s; + + ds_init(&s); + odp_flow_format(key, key_len, mask_key, mask_key_len, NULL, &s, + true); + VLOG_ERR("internal error parsing flow mask %s", ds_cstr(&s)); + ds_destroy(&s); + } + + return EINVAL; + } + /* Force unwildcard the in_port. */ + mask->in_port.odp_port = u32_to_odp(UINT32_MAX); + + return 0; +} + +static int +dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, + struct flow *flow) { odp_port_t in_port; - if (odp_flow_key_to_flow(key, key_len, flow) - || (mask_key - && odp_flow_key_to_mask(mask_key, mask_key_len, mask, flow))) { + if (odp_flow_key_to_flow(key, key_len, flow)) { /* This should not happen: it indicates that odp_flow_key_from_flow() - * and odp_flow_key_to_flow() disagree on the acceptable form of a flow - * or odp_flow_key_from_mask() and odp_flow_key_to_mask() disagree on - * the acceptable form of a mask. Log the problem as an error, with - * enough details to enable debugging. */ + * and odp_flow_key_to_flow() disagree on the acceptable form of a + * flow. Log the problem as an error, with enough details to enable + * debugging. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); if (!VLOG_DROP_ERR(&rl)) { struct ds s; ds_init(&s); - odp_flow_format(key, key_len, mask_key, mask_key_len, NULL, &s, - true); + odp_flow_format(key, key_len, NULL, 0, NULL, &s, true); VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s)); ds_destroy(&s); } @@ -818,11 +844,6 @@ dpif_netdev_flow_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, return EINVAL; } - if (mask_key) { - /* Force unwildcard the in_port. */ - mask->in_port.odp_port = u32_to_odp(UINT32_MAX); - } - in_port = flow->in_port.odp_port; if (!is_valid_port_number(in_port) && in_port != ODPP_NONE) { return EINVAL; @@ -832,14 +853,6 @@ dpif_netdev_flow_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len, } static int -dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, - struct flow *flow) -{ - return dpif_netdev_flow_mask_from_nlattrs(key, key_len, NULL, 0, flow, - NULL); -} - -static int dpif_netdev_flow_get(const struct dpif *dpif, const struct nlattr *nl_key, size_t nl_key_len, struct ofpbuf **actionsp, struct dpif_flow_stats *stats) @@ -882,6 +895,7 @@ set_flow_actions(struct dp_netdev_flow *netdev_flow, return 0; } +/* Will use exact match if 'wc' is NULL. */ static int dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *flow, const struct flow_wildcards *wc, @@ -895,7 +909,11 @@ dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *flow, netdev_flow = xzalloc(sizeof *netdev_flow); netdev_flow->flow = *flow; - match_init(&match, flow, wc); + if (wc) { + match_init(&match, flow, wc); + } else { + match_wc_init(&match, flow); + } cls_rule_init(&netdev_flow->cr, &match, NETDEV_RULE_PRIORITY); ovs_rwlock_wrlock(&dp->cls.rwlock); classifier_insert(&dp->cls, &netdev_flow->cr); @@ -934,11 +952,18 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) struct flow_wildcards wc; int error; - error = dpif_netdev_flow_mask_from_nlattrs(put->key, put->key_len, - put->mask, put->mask_len, &flow, &wc.masks); + error = dpif_netdev_flow_from_nlattrs(put->key, put->key_len, &flow); if (error) { return error; } + if (put->mask_len) { + error = dpif_netdev_mask_from_nlattrs(put->key, put->key_len, + put->mask, put->mask_len, + &flow, &wc.masks); + if (error) { + return error; + } + } ovs_mutex_lock(&dp_netdev_mutex); netdev_flow = dp_netdev_lookup_flow(dp, &flow); @@ -948,8 +973,9 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) if (put->stats) { memset(put->stats, 0, sizeof *put->stats); } - error = dp_netdev_flow_add(dp, &flow, &wc, put->actions, - put->actions_len); + error = dp_netdev_flow_add(dp, &flow, + put->mask_len ? &wc : NULL, + put->actions, put->actions_len); } else { error = EFBIG; } -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev