X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-parse.c;h=6f35c12705522d9572e435e20eb21656de9d53ec;hb=620606f63cc56c7541005dc6787106789e2c364e;hp=0d904b1ed02fa8a01f162f33834324bc891b266b;hpb=8706009e555bb9fa04a5679e4be2c7c67506802b;p=sliver-openvswitch.git diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 0d904b1ed..6f35c1270 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -169,7 +169,7 @@ parse_resubmit(char *arg, struct ofpbuf *ofpacts) in_port_s = strsep(&arg, ","); if (in_port_s && in_port_s[0]) { if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) { - resubmit->in_port = str_to_u32(in_port_s); + ovs_fatal(0, "%s: resubmit to unknown port", in_port_s); } } else { resubmit->in_port = OFPP_IN_PORT; @@ -279,22 +279,28 @@ parse_controller(struct ofpbuf *b, char *arg) } static void -parse_dec_ttl(struct ofpbuf *b, char *arg) +parse_noargs_dec_ttl(struct ofpbuf *b) { struct ofpact_cnt_ids *ids; + uint16_t id = 0; ids = ofpact_put_DEC_TTL(b); + ofpbuf_put(b, &id, sizeof id); + ids = b->l2; + ids->n_controllers++; + ofpact_update_len(b, &ids->ofpact); +} +static void +parse_dec_ttl(struct ofpbuf *b, char *arg) +{ if (*arg == '\0') { - uint16_t id = 0; - - ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL; - ofpbuf_put(b, &id, sizeof id); - ids = b->l2; - ids->n_controllers++; + parse_noargs_dec_ttl(b); } else { + struct ofpact_cnt_ids *ids; char *cntr; + ids = ofpact_put_DEC_TTL(b); ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS; for (cntr = strtok_r(arg, ", ", &arg); cntr != NULL; cntr = strtok_r(NULL, ", ", &arg)) { @@ -308,9 +314,68 @@ parse_dec_ttl(struct ofpbuf *b, char *arg) ovs_fatal(0, "dec_ttl_cnt_ids: expected at least one controller " "id."); } + ofpact_update_len(b, &ids->ofpact); + } +} +static void +set_field_parse(const char *arg, struct ofpbuf *ofpacts) +{ + char *orig = xstrdup(arg); + struct ofpact_reg_load *load = ofpact_put_REG_LOAD(ofpacts); + char *value; + char *delim; + char *key; + const struct mf_field *mf; + const char *error; + union mf_value mf_value; + + value = orig; + delim = strstr(orig, "->"); + if (!delim) { + ovs_fatal(0, "%s: missing `->'", orig); } - ofpact_update_len(b, &ids->ofpact); + if (strlen(delim) <= strlen("->")) { + ovs_fatal(0, "%s: missing field name following `->'", orig); + } + + key = delim + strlen("->"); + mf = mf_from_name(key); + if (!mf) { + ovs_fatal(0, "%s is not valid oxm field name", key); + } + if (!mf->writable) { + ovs_fatal(0, "%s is not allowed to set", key); + } + + delim[0] = '\0'; + error = mf_parse_value(mf, value, &mf_value); + if (error) { + ovs_fatal(0, "%s", error); + } + if (!mf_is_value_valid(mf, &mf_value)) { + ovs_fatal(0, "%s is not valid valid for field %s", value, key); + } + ofpact_set_field_init(load, mf, &mf_value); + free(orig); +} + +static void +parse_metadata(struct ofpbuf *b, char *arg) +{ + struct ofpact_metadata *om; + char *mask = strchr(arg, '/'); + + om = ofpact_put_WRITE_METADATA(b); + + if (mask) { + *mask = '\0'; + om->mask = htonll(str_to_u64(mask + 1)); + } else { + om->mask = htonll(UINT64_MAX); + } + + om->metadata = htonll(str_to_u64(arg)); } static void @@ -319,6 +384,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, { struct ofpact_tunnel *tunnel; uint16_t vid; + uint16_t ethertype; ovs_be32 ip; uint8_t pcp; uint8_t tos; @@ -350,10 +416,29 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp; break; + case OFPUTIL_OFPAT12_SET_FIELD: + set_field_parse(arg, ofpacts); + break; + case OFPUTIL_OFPAT10_STRIP_VLAN: + case OFPUTIL_OFPAT11_POP_VLAN: ofpact_put_STRIP_VLAN(ofpacts); break; + case OFPUTIL_OFPAT11_PUSH_VLAN: + ethertype = str_to_u16(arg, "ethertype"); + if (ethertype != ETH_TYPE_VLAN_8021Q) { + /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */ + ovs_fatal(0, "%s: not a valid VLAN ethertype", arg); + } + ofpact_put_PUSH_VLAN(ofpacts); + break; + + case OFPUTIL_OFPAT11_SET_QUEUE: + ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); + break; + + case OFPUTIL_OFPAT10_SET_DL_SRC: case OFPUTIL_OFPAT11_SET_DL_SRC: str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac); @@ -385,6 +470,9 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos; break; + case OFPUTIL_OFPAT11_DEC_NW_TTL: + NOT_REACHED(); + case OFPUTIL_OFPAT10_SET_TP_SRC: case OFPUTIL_OFPAT11_SET_TP_SRC: ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg); @@ -410,6 +498,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, tunnel->tun_id = str_to_u64(arg); break; + case OFPUTIL_NXAST_WRITE_METADATA: + parse_metadata(ofpacts, arg); + break; + case OFPUTIL_NXAST_SET_QUEUE: ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); break; @@ -473,35 +565,141 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, } } +static bool +str_to_ofpact__(const struct flow *flow, char *pos, char *act, char *arg, + struct ofpbuf *ofpacts, int n_actions) +{ + int code = ofputil_action_code_from_name(act); + if (code >= 0) { + parse_named_action(code, flow, arg, ofpacts); + } else if (!strcasecmp(act, "drop")) { + if (n_actions) { + ovs_fatal(0, "Drop actions must not be preceded by other " + "actions"); + } else if (ofputil_parse_key_value(&pos, &act, &arg)) { + ovs_fatal(0, "Drop actions must not be followed by other " + "actions"); + } + return false; + } else { + uint16_t port; + if (ofputil_port_from_string(act, &port)) { + ofpact_put_OUTPUT(ofpacts)->port = port; + } else { + ovs_fatal(0, "Unknown action: %s", act); + } + } + + return true; +} + static void str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) { char *pos, *act, *arg; + enum ofperr error; int n_actions; pos = str; n_actions = 0; while (ofputil_parse_key_value(&pos, &act, &arg)) { - uint16_t port; - int code; - - code = ofputil_action_code_from_name(act); - if (code >= 0) { - parse_named_action(code, flow, arg, ofpacts); - } else if (!strcasecmp(act, "drop")) { - if (n_actions) { - ovs_fatal(0, "Drop actions must not be preceded by other " - "actions"); - } else if (ofputil_parse_key_value(&pos, &act, &arg)) { - ovs_fatal(0, "Drop actions must not be followed by other " - "actions"); - } + if (!str_to_ofpact__(flow, pos, act, arg, ofpacts, n_actions)) { break; - } else if (ofputil_port_from_string(act, &port)) { - ofpact_put_OUTPUT(ofpacts)->port = port; + } + n_actions++; + } + + error = ofpacts_verify(ofpacts->data, ofpacts->size); + if (error) { + ovs_fatal(0, "Incorrect action ordering"); + } + + ofpact_pad(ofpacts); +} + +static void +parse_named_instruction(enum ovs_instruction_type type, + char *arg, struct ofpbuf *ofpacts) +{ + enum ofperr error; + + switch (type) { + case OVSINST_OFPIT11_APPLY_ACTIONS: + NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */ + break; + + case OVSINST_OFPIT11_WRITE_ACTIONS: + /* XXX */ + ovs_fatal(0, "instruction write-actions is not supported yet"); + break; + + case OVSINST_OFPIT11_CLEAR_ACTIONS: + ofpact_put_CLEAR_ACTIONS(ofpacts); + break; + + case OVSINST_OFPIT11_WRITE_METADATA: + parse_metadata(ofpacts, arg); + break; + + case OVSINST_OFPIT11_GOTO_TABLE: { + struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(ofpacts); + char *table_s = strsep(&arg, ","); + if (!table_s || !table_s[0]) { + ovs_fatal(0, "instruction goto-table needs table id"); + } + ogt->table_id = str_to_table_id(table_s); + break; + } + } + + /* If write_metadata is specified as an action AND an instruction, ofpacts + could be invalid. */ + error = ofpacts_verify(ofpacts->data, ofpacts->size); + if (error) { + ovs_fatal(0, "Incorrect instruction ordering"); + } +} + +static void +str_to_inst_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) +{ + char *pos, *inst, *arg; + int type; + const char *prev_inst = NULL; + int prev_type = -1; + int n_actions = 0; + + pos = str; + while (ofputil_parse_key_value(&pos, &inst, &arg)) { + type = ofpact_instruction_type_from_name(inst); + if (type < 0) { + if (!str_to_ofpact__(flow, pos, inst, arg, ofpacts, n_actions)) { + break; + } + + type = OVSINST_OFPIT11_APPLY_ACTIONS; + if (prev_type == type) { + n_actions++; + continue; + } + } else if (type == OVSINST_OFPIT11_APPLY_ACTIONS) { + ovs_fatal(0, "%s isn't supported. Just write actions then " + "it is interpreted as apply_actions", inst); } else { - ovs_fatal(0, "Unknown action: %s", act); + parse_named_instruction(type, arg, ofpacts); + } + + if (type == prev_type) { + ovs_fatal(0, "instruction can be specified at most once: %s", + inst); } + if (type <= prev_type) { + ovs_fatal(0, "Instruction %s must be specified before %s", + inst, prev_inst); + } + + prev_inst = inst; + prev_type = type; n_actions++; } ofpact_pad(ofpacts); @@ -527,7 +725,8 @@ parse_protocol(const char *name, const struct protocol **p_out) { "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 }, { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP }, { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP }, - }; + { "rarp", ETH_TYPE_RARP, 0}, +}; const struct protocol *p; for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) { @@ -554,7 +753,7 @@ ofp_fatal(const char *flow, bool verbose, const char *format, ...) } static void -parse_field(const struct mf_field *mf, const char *s, struct cls_rule *rule) +parse_field(const struct mf_field *mf, const char *s, struct match *match) { union mf_value value, mask; char *error; @@ -564,7 +763,7 @@ parse_field(const struct mf_field *mf, const char *s, struct cls_rule *rule) ovs_fatal(0, "%s", error); } - mf_set(mf, &value, &mask, rule); + mf_set(mf, &value, &mask, match); } /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man @@ -620,7 +819,8 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, NOT_REACHED(); } - cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY); + match_init_catchall(&fm->match); + fm->priority = OFP_DEFAULT_PRIORITY; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) { @@ -634,7 +834,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; - fm->out_port = OFPP_NONE; + fm->out_port = OFPP_ANY; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); @@ -655,14 +855,20 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, const struct protocol *p; if (parse_protocol(name, &p)) { - cls_rule_set_dl_type(&fm->cr, htons(p->dl_type)); + match_set_dl_type(&fm->match, htons(p->dl_type)); if (p->nw_proto) { - cls_rule_set_nw_proto(&fm->cr, p->nw_proto); + match_set_nw_proto(&fm->match, p->nw_proto); } } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) { fm->flags |= OFPFF_SEND_FLOW_REM; } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) { fm->flags |= OFPFF_CHECK_OVERLAP; + } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) { + fm->flags |= OFPFF12_RESET_COUNTS; + } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) { + fm->flags |= OFPFF13_NO_PKT_COUNTS; + } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) { + fm->flags |= OFPFF13_NO_BYT_COUNTS; } else { char *value; @@ -674,9 +880,12 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, if (!strcmp(name, "table")) { fm->table_id = str_to_table_id(value); } else if (!strcmp(name, "out_port")) { - fm->out_port = atoi(value); + if (!ofputil_port_from_string(name, &fm->out_port)) { + ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", + name); + } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { - fm->cr.priority = str_to_u16(value, name); + fm->priority = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) { fm->idle_timeout = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) { @@ -702,7 +911,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, fm->new_cookie = htonll(str_to_u64(value)); } } else if (mf_from_name(name)) { - parse_field(mf_from_name(name), value, &fm->cr); + parse_field(mf_from_name(name), value, &fm->match); } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") || !strcmp(name, "n_bytes")) { @@ -725,7 +934,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 32); - str_to_ofpacts(&fm->cr.flow, act_str, &ofpacts); + str_to_inst_ofpacts(&fm->match.flow, act_str, &ofpacts); fm->ofpacts_len = ofpacts.size; fm->ofpacts = ofpbuf_steal_data(&ofpacts); } else { @@ -753,7 +962,7 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, | NXFMF_OWN | NXFMF_ACTIONS); fmr->out_port = OFPP_NONE; fmr->table_id = 0xff; - cls_rule_init_catchall(&fmr->match, 0); + match_init_catchall(&fmr->match); for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { @@ -772,9 +981,9 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, } else if (!strcmp(name, "!own")) { fmr->flags &= ~NXFMF_OWN; } else if (parse_protocol(name, &p)) { - cls_rule_set_dl_type(&fmr->match, htons(p->dl_type)); + match_set_dl_type(&fmr->match, htons(p->dl_type)); if (p->nw_proto) { - cls_rule_set_nw_proto(&fmr->match, p->nw_proto); + match_set_nw_proto(&fmr->match, p->nw_proto); } } else { char *value; @@ -817,15 +1026,15 @@ void parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string, uint16_t command, bool verbose) { - struct cls_rule rule_copy; + struct match match_copy; parse_ofp_str(fm, command, string, verbose); - /* Normalize a copy of the rule. This ensures that non-normalized flows + /* Normalize a copy of the match. This ensures that non-normalized flows * get logged but doesn't affect what gets sent to the switch, so that the * switch can do whatever it likes with the flow. */ - rule_copy = fm->cr; - ofputil_normalize_rule(&rule_copy); + match_copy = fm->match; + ofputil_normalize_match(&match_copy); } void @@ -867,7 +1076,7 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr, fsr->aggregate = aggregate; fsr->cookie = fm.cookie; fsr->cookie_mask = fm.cookie_mask; - fsr->match = fm.cr; + fsr->match = fm.match; fsr->out_port = fm.out_port; fsr->table_id = fm.table_id; } @@ -940,6 +1149,10 @@ parse_ofp_exact_flow(struct flow *flow, const char *s) } } + if (!flow->in_port) { + flow->in_port = OFPP_NONE; + } + exit: free(copy);