X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=44e7bbc2ab9d746b448ceecf09ea8552a0c7a257;hb=83b03fe05e7a6734b2096dab86937294769987c6;hp=7b46f0f5ef49006fd2d1328909802babef7a1b56;hpb=c7e4f0b2c36a930e8a0a4a256f848356d730fea7;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7b46f0f5e..44e7bbc2a 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1122,6 +1122,7 @@ check_variable_length_userdata(struct dpif_backer *backer) execute.packet = &packet; execute.needs_help = false; execute.probe = true; + execute.mtu = 0; error = dpif_execute(backer->dpif, &execute); @@ -1220,6 +1221,7 @@ check_masked_set_action(struct dpif_backer *backer) execute.packet = &packet; execute.needs_help = false; execute.probe = true; + execute.mtu = 0; error = dpif_execute(backer->dpif, &execute); @@ -1234,6 +1236,48 @@ check_masked_set_action(struct dpif_backer *backer) return !error; } +#define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE) \ +static bool \ +check_##NAME(struct dpif_backer *backer) \ +{ \ + struct flow flow; \ + struct odputil_keybuf keybuf; \ + struct ofpbuf key; \ + bool enable; \ + struct odp_flow_key_parms odp_parms = { \ + .flow = &flow, \ + .support = { \ + .SUPPORT = true, \ + }, \ + }; \ + \ + memset(&flow, 0, sizeof flow); \ + flow.FIELD = VALUE; \ + \ + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); \ + odp_flow_key_from_flow(&odp_parms, &key); \ + enable = dpif_probe_feature(backer->dpif, #NAME, &key, NULL); \ + \ + if (enable) { \ + VLOG_INFO("%s: Datapath supports "#NAME, dpif_name(backer->dpif)); \ + } else { \ + VLOG_INFO("%s: Datapath does not support "#NAME, \ + dpif_name(backer->dpif)); \ + } \ + \ + return enable; \ +} +#define CHECK_FEATURE(FIELD) CHECK_FEATURE__(FIELD, FIELD, FIELD, 1) + +CHECK_FEATURE(ct_state) +CHECK_FEATURE(ct_zone) +CHECK_FEATURE(ct_mark) +CHECK_FEATURE__(ct_label, ct_label, ct_label.u64.lo, 1) +CHECK_FEATURE__(ct_state_nat, ct_state, ct_state, CS_TRACKED|CS_SRC_NAT) + +#undef CHECK_FEATURE +#undef CHECK_FEATURE__ + static void check_support(struct dpif_backer *backer) { @@ -1245,6 +1289,13 @@ check_support(struct dpif_backer *backer) backer->support.masked_set_action = check_masked_set_action(backer); backer->support.ufid = check_ufid(backer); backer->support.tnl_push_pop = dpif_supports_tnl_push_pop(backer->dpif); + + backer->support.odp.ct_state = check_ct_state(backer); + backer->support.odp.ct_zone = check_ct_zone(backer); + backer->support.odp.ct_mark = check_ct_mark(backer); + backer->support.odp.ct_label = check_ct_label(backer); + + backer->support.odp.ct_state_nat = check_ct_state_nat(backer); } static int @@ -1356,7 +1407,6 @@ add_internal_flows(struct ofproto_dpif *ofproto) controller->max_len = UINT16_MAX; controller->controller_id = 0; controller->reason = OFPR_NO_MATCH; - ofpact_pad(&ofpacts); error = add_internal_miss_flow(ofproto, id++, &ofpacts, &ofproto->miss_rule); @@ -1587,8 +1637,6 @@ wait(struct ofproto *ofproto_) mcast_snooping_wait(ofproto->ms); stp_wait(ofproto); if (ofproto->backer->need_revalidate) { - /* Shouldn't happen, but if it does just go around again. */ - VLOG_DBG_RL(&rl, "need revalidate in ofproto_wait_cb()"); poll_immediate_wake(); } @@ -2543,8 +2591,11 @@ set_rstp_port(struct ofport *ofport_, if (!s || !s->enable) { if (rp) { - rstp_port_unref(rp); + rstp_port_set_aux(rp, NULL); + rstp_port_set_state(rp, RSTP_DISABLED); + rstp_port_set_mac_operational(rp, false); ofport->rstp_port = NULL; + rstp_port_unref(rp); update_rstp_port_state(ofport); } return; @@ -3679,7 +3730,10 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto, xin.resubmit_stats = &stats; xin.recurse = recurse; xin.resubmits = resubmits; - xlate_actions(&xin, &xout); + if (xlate_actions(&xin, &xout) != XLATE_OK) { + error = EINVAL; + goto out; + } execute.actions = odp_actions.data; execute.actions_len = odp_actions.size; @@ -3688,6 +3742,7 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto, execute.packet = packet; execute.needs_help = (xout.slow & SLOW_ACTION) != 0; execute.probe = false; + execute.mtu = 0; /* Fix up in_port. */ in_port = flow->in_port.ofp_port; @@ -3697,7 +3752,7 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto, execute.packet->md.in_port.odp_port = ofp_port_to_odp_port(ofproto, in_port); error = dpif_execute(ofproto->backer->dpif, &execute); - +out: xlate_out_uninit(&xout); ofpbuf_uninit(&odp_actions); @@ -3959,11 +4014,106 @@ rule_dealloc(struct rule *rule_) free(rule); } +static enum ofperr +check_mask(struct ofproto_dpif *ofproto, const struct miniflow *flow) +{ + const struct odp_support *support; + uint16_t ct_state, ct_zone; + ovs_u128 ct_label; + uint32_t ct_mark; + + support = &ofproto_dpif_get_support(ofproto)->odp; + ct_state = MINIFLOW_GET_U16(flow, ct_state); + if (support->ct_state && support->ct_zone && support->ct_mark + && support->ct_label && support->ct_state_nat) { + return ct_state & CS_UNSUPPORTED_MASK ? OFPERR_OFPBMC_BAD_MASK : 0; + } + + ct_zone = MINIFLOW_GET_U16(flow, ct_zone); + ct_mark = MINIFLOW_GET_U32(flow, ct_mark); + ct_label = MINIFLOW_GET_U128(flow, ct_label); + + if ((ct_state && !support->ct_state) + || (ct_state & CS_UNSUPPORTED_MASK) + || ((ct_state & (CS_SRC_NAT | CS_DST_NAT)) && !support->ct_state_nat) + || (ct_zone && !support->ct_zone) + || (ct_mark && !support->ct_mark) + || (!ovs_u128_is_zero(&ct_label) && !support->ct_label)) { + return OFPERR_OFPBMC_BAD_MASK; + } + + return 0; +} + +static enum ofperr +check_actions(const struct ofproto_dpif *ofproto, + const struct rule_actions *const actions) +{ + const struct ofpact *ofpact; + + OFPACT_FOR_EACH (ofpact, actions->ofpacts, actions->ofpacts_len) { + const struct odp_support *support; + const struct ofpact_conntrack *ct; + const struct ofpact *a; + + if (ofpact->type != OFPACT_CT) { + continue; + } + + ct = CONTAINER_OF(ofpact, struct ofpact_conntrack, ofpact); + support = &ofproto_dpif_get_support(ofproto)->odp; + + if (!support->ct_state) { + return OFPERR_OFPBAC_BAD_TYPE; + } + if ((ct->zone_imm || ct->zone_src.field) && !support->ct_zone) { + return OFPERR_OFPBAC_BAD_ARGUMENT; + } + + OFPACT_FOR_EACH(a, ct->actions, ofpact_ct_get_action_len(ct)) { + const struct mf_field *dst = ofpact_get_mf_dst(a); + + if (a->type == OFPACT_NAT && !support->ct_state_nat) { + /* The backer doesn't seem to support the NAT bits in + * 'ct_state': assume that it doesn't support the NAT + * action. */ + return OFPERR_OFPBAC_BAD_TYPE; + } + if (dst && ((dst->id == MFF_CT_MARK && !support->ct_mark) + || (dst->id == MFF_CT_LABEL && !support->ct_label))) { + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; + } + } + } + + return 0; +} + +static enum ofperr +rule_check(struct rule *rule) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->ofproto); + enum ofperr err; + + err = check_mask(ofproto, &rule->cr.match.mask->masks); + if (err) { + return err; + } + return check_actions(ofproto, rule->actions); +} + static enum ofperr rule_construct(struct rule *rule_) OVS_NO_THREAD_SAFETY_ANALYSIS { struct rule_dpif *rule = rule_dpif_cast(rule_); + int error; + + error = rule_check(rule_); + if (error) { + return error; + } + ovs_mutex_init_adaptive(&rule->stats_mutex); rule->stats.n_packets = 0; rule->stats.n_bytes = 0; @@ -4447,7 +4597,7 @@ ofproto_unixctl_mcast_snooping_show(struct unixctl_conn *conn, ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port, name, sizeof name); ds_put_format(&ds, "%5s %4d ", name, grp->vlan); - print_ipv6_mapped(&ds, &grp->addr); + ipv6_format_mapped(&grp->addr, &ds); ds_put_format(&ds, " %3d\n", mcast_bundle_age(ofproto->ms, b)); } @@ -4853,13 +5003,18 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc, goto exit; } if (enforce_consistency) { - retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, - &flow, u16_to_ofp(ofproto->up.max_ports), - 0, 0, usable_protocols); + retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &flow, + u16_to_ofp(ofproto->up.max_ports), + 0, ofproto->up.n_tables, + usable_protocols); } else { retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow, - u16_to_ofp(ofproto->up.max_ports), 0, 0, - &usable_protocols); + u16_to_ofp(ofproto->up.max_ports), 0, + ofproto->up.n_tables, &usable_protocols); + } + if (!retval) { + retval = ofproto_check_ofpacts(&ofproto->up, ofpacts.data, + ofpacts.size); } if (retval) { @@ -4895,6 +5050,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, struct ds *ds) { struct trace_ctx trace; + enum xlate_error error; ds_put_format(ds, "Bridge: %s\n", ofproto->up.name); ds_put_cstr(ds, "Flow: "); @@ -4914,8 +5070,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, trace.xin.resubmit_hook = trace_resubmit; trace.xin.report_hook = trace_report_valist; - xlate_actions(&trace.xin, &trace.xout); - + error = xlate_actions(&trace.xin, &trace.xout); ds_put_char(ds, '\n'); trace_format_flow(ds, 0, "Final flow", &trace); trace_format_megaflow(ds, 0, "Megaflow", &trace); @@ -4923,7 +5078,10 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow, ds_put_cstr(ds, "Datapath actions: "); format_odp_actions(ds, trace.odp_actions.data, trace.odp_actions.size); - if (trace.xout.slow) { + if (error != XLATE_OK) { + ds_put_format(ds, "\nTranslation failed (%s), packet is dropped.\n", + xlate_strerror(error)); + } else if (trace.xout.slow) { enum slow_path_reason slow; ds_put_cstr(ds, "\nThis flow is handled by the userspace " @@ -5169,6 +5327,8 @@ disable_tnl_push_pop(struct unixctl_conn *conn OVS_UNUSED, int argc OVS_UNUSED, ofproto_use_tnl_push_pop = true; unixctl_command_reply(conn, "Tunnel push-pop on"); ofproto_revalidate_all_backers(); + } else { + unixctl_command_reply_error(conn, "Invalid argument"); } } @@ -5499,22 +5659,17 @@ ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto, struct rule_dpif *rule; int error; - ofm.fm.match = *match; - ofm.fm.priority = priority; - ofm.fm.new_cookie = htonll(0); - ofm.fm.cookie = htonll(0); - ofm.fm.cookie_mask = htonll(0); - ofm.fm.modify_cookie = false; - ofm.fm.table_id = TBL_INTERNAL; - ofm.fm.command = OFPFC_ADD; - ofm.fm.idle_timeout = idle_timeout; - ofm.fm.hard_timeout = 0; - ofm.fm.importance = 0; - ofm.fm.buffer_id = 0; - ofm.fm.out_port = 0; - ofm.fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY; - ofm.fm.ofpacts = ofpacts->data; - ofm.fm.ofpacts_len = ofpacts->size; + ofm.fm = (struct ofputil_flow_mod) { + .match = *match, + .priority = priority, + .table_id = TBL_INTERNAL, + .command = OFPFC_ADD, + .idle_timeout = idle_timeout, + .flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY, + .ofpacts = ofpacts->data, + .ofpacts_len = ofpacts->size, + .delete_reason = OVS_OFPRR_NONE, + }; error = ofproto_flow_mod(&ofproto->up, &ofm); if (error) { @@ -5543,15 +5698,13 @@ ofproto_dpif_delete_internal_flow(struct ofproto_dpif *ofproto, struct ofproto_flow_mod ofm; int error; - ofm.fm.match = *match; - ofm.fm.priority = priority; - ofm.fm.new_cookie = htonll(0); - ofm.fm.cookie = htonll(0); - ofm.fm.cookie_mask = htonll(0); - ofm.fm.modify_cookie = false; - ofm.fm.table_id = TBL_INTERNAL; - ofm.fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY; - ofm.fm.command = OFPFC_DELETE_STRICT; + ofm.fm = (struct ofputil_flow_mod) { + .match = *match, + .priority = priority, + .table_id = TBL_INTERNAL, + .flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY, + .command = OFPFC_DELETE_STRICT, + }; error = ofproto_flow_mod(&ofproto->up, &ofm); if (error) {