X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-parse.c;h=3f7a02124c33117f769508772e8c0a90e2fa3df2;hb=33f1ff8464641c392fb713fe4e45be0c18a6b047;hp=a80d45fe62608d12a653856dc8fbf233c6d54b5d;hpb=6a885fd0589fdfa3b5d05ca3ff4af52b085a1816;p=sliver-openvswitch.git diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index a80d45fe6..3f7a02124 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011 Nicira Networks. + * Copyright (c) 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ #include "bundle.h" #include "byte-order.h" #include "dynamic-string.h" +#include "learn.h" #include "meta-flow.h" #include "netdev.h" #include "multipath.h" @@ -40,6 +41,28 @@ VLOG_DEFINE_THIS_MODULE(ofp_parse); +static uint8_t +str_to_table_id(const char *str) +{ + int table_id; + + if (!str_to_int(str, 10, &table_id) || table_id < 0 || table_id > 255) { + ovs_fatal(0, "invalid table \"%s\"", str); + } + return table_id; +} + +static uint16_t +str_to_u16(const char *str, const char *name) +{ + int value; + + if (!str_to_int(str, 0, &value) || value < 0 || value > 65535) { + ovs_fatal(0, "invalid %s \"%s\"", name, str); + } + return value; +} + static uint32_t str_to_u32(const char *str) { @@ -101,7 +124,7 @@ put_output_action(struct ofpbuf *b, uint16_t port) { struct ofp_action_output *oao; - oao = ofputil_put_OFPAT_OUTPUT(b); + oao = ofputil_put_OFPAT10_OUTPUT(b); oao->port = htons(port); return oao; } @@ -118,7 +141,7 @@ parse_enqueue(struct ofpbuf *b, char *arg) ovs_fatal(0, "\"enqueue\" syntax is \"enqueue:PORT:QUEUE\""); } - oae = ofputil_put_OFPAT_ENQUEUE(b); + oae = ofputil_put_OFPAT10_ENQUEUE(b); oae->port = htons(str_to_u32(port)); oae->queue_id = htonl(str_to_u32(queue)); } @@ -128,14 +151,13 @@ parse_output(struct ofpbuf *b, char *arg) { if (strchr(arg, '[')) { struct nx_action_output_reg *naor; - int ofs, n_bits; - uint32_t src; + struct mf_subfield src; - nxm_parse_field_bits(arg, &src, &ofs, &n_bits); + mf_parse_subfield(&src, arg); naor = ofputil_put_NXAST_OUTPUT_REG(b); - naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits); - naor->src = htonl(src); + naor->ofs_nbits = nxm_encode_ofs_nbits(src.ofs, src.n_bits); + naor->src = htonl(src.field->nxm_header); naor->max_len = htons(UINT16_MAX); } else { put_output_action(b, str_to_u32(arg)); @@ -228,7 +250,68 @@ parse_note(struct ofpbuf *b, const char *arg) } static void -parse_named_action(enum ofputil_action_code code, struct ofpbuf *b, char *arg) +parse_fin_timeout(struct ofpbuf *b, char *arg) +{ + struct nx_action_fin_timeout *naft; + char *key, *value; + + naft = ofputil_put_NXAST_FIN_TIMEOUT(b); + while (ofputil_parse_key_value(&arg, &key, &value)) { + if (!strcmp(key, "idle_timeout")) { + naft->fin_idle_timeout = htons(str_to_u16(value, key)); + } else if (!strcmp(key, "hard_timeout")) { + naft->fin_hard_timeout = htons(str_to_u16(value, key)); + } else { + ovs_fatal(0, "invalid key '%s' in 'fin_timeout' argument", key); + } + } +} + +static void +parse_controller(struct ofpbuf *b, char *arg) +{ + enum ofp_packet_in_reason reason = OFPR_ACTION; + uint16_t controller_id = 0; + uint16_t max_len = UINT16_MAX; + + if (!arg[0]) { + /* Use defaults. */ + } else if (strspn(arg, "0123456789") == strlen(arg)) { + max_len = str_to_u16(arg, "max_len"); + } else { + char *name, *value; + + while (ofputil_parse_key_value(&arg, &name, &value)) { + if (!strcmp(name, "reason")) { + if (!ofputil_packet_in_reason_from_string(value, &reason)) { + ovs_fatal(0, "unknown reason \"%s\"", value); + } + } else if (!strcmp(name, "max_len")) { + max_len = str_to_u16(value, "max_len"); + } else if (!strcmp(name, "id")) { + controller_id = str_to_u16(value, "id"); + } else { + ovs_fatal(0, "unknown key \"%s\" parsing controller action", + name); + } + } + } + + if (reason == OFPR_ACTION && controller_id == 0) { + put_output_action(b, OFPP_CONTROLLER)->max_len = htons(max_len); + } else { + struct nx_action_controller *nac; + + nac = ofputil_put_NXAST_CONTROLLER(b); + nac->max_len = htons(max_len); + nac->reason = reason; + nac->controller_id = htons(controller_id); + } +} + +static void +parse_named_action(enum ofputil_action_code code, const struct flow *flow, + struct ofpbuf *b, char *arg) { struct ofp_action_dl_addr *oada; struct ofp_action_vlan_pcp *oavp; @@ -237,47 +320,47 @@ parse_named_action(enum ofputil_action_code code, struct ofpbuf *b, char *arg) struct ofp_action_tp_port *oata; switch (code) { - case OFPUTIL_OFPAT_OUTPUT: + case OFPUTIL_OFPAT10_OUTPUT: parse_output(b, arg); break; - case OFPUTIL_OFPAT_SET_VLAN_VID: - oavv = ofputil_put_OFPAT_SET_VLAN_VID(b); + case OFPUTIL_OFPAT10_SET_VLAN_VID: + oavv = ofputil_put_OFPAT10_SET_VLAN_VID(b); oavv->vlan_vid = htons(str_to_u32(arg)); break; - case OFPUTIL_OFPAT_SET_VLAN_PCP: - oavp = ofputil_put_OFPAT_SET_VLAN_PCP(b); + case OFPUTIL_OFPAT10_SET_VLAN_PCP: + oavp = ofputil_put_OFPAT10_SET_VLAN_PCP(b); oavp->vlan_pcp = str_to_u32(arg); break; - case OFPUTIL_OFPAT_STRIP_VLAN: - ofputil_put_OFPAT_STRIP_VLAN(b); + case OFPUTIL_OFPAT10_STRIP_VLAN: + ofputil_put_OFPAT10_STRIP_VLAN(b); break; - case OFPUTIL_OFPAT_SET_DL_SRC: - case OFPUTIL_OFPAT_SET_DL_DST: + case OFPUTIL_OFPAT10_SET_DL_SRC: + case OFPUTIL_OFPAT10_SET_DL_DST: oada = ofputil_put_action(code, b); str_to_mac(arg, oada->dl_addr); break; - case OFPUTIL_OFPAT_SET_NW_SRC: - case OFPUTIL_OFPAT_SET_NW_DST: + case OFPUTIL_OFPAT10_SET_NW_SRC: + case OFPUTIL_OFPAT10_SET_NW_DST: oana = ofputil_put_action(code, b); str_to_ip(arg, &oana->nw_addr); break; - case OFPUTIL_OFPAT_SET_NW_TOS: - ofputil_put_OFPAT_SET_NW_TOS(b)->nw_tos = str_to_u32(arg); + case OFPUTIL_OFPAT10_SET_NW_TOS: + ofputil_put_OFPAT10_SET_NW_TOS(b)->nw_tos = str_to_u32(arg); break; - case OFPUTIL_OFPAT_SET_TP_SRC: - case OFPUTIL_OFPAT_SET_TP_DST: + case OFPUTIL_OFPAT10_SET_TP_SRC: + case OFPUTIL_OFPAT10_SET_TP_DST: oata = ofputil_put_action(code, b); oata->tp_port = htons(str_to_u32(arg)); break; - case OFPUTIL_OFPAT_ENQUEUE: + case OFPUTIL_OFPAT10_ENQUEUE: parse_enqueue(b, arg); break; @@ -332,11 +415,31 @@ parse_named_action(enum ofputil_action_code code, struct ofpbuf *b, char *arg) case OFPUTIL_NXAST_RESUBMIT_TABLE: case OFPUTIL_NXAST_OUTPUT_REG: NOT_REACHED(); + + case OFPUTIL_NXAST_LEARN: + learn_parse(b, arg, flow); + break; + + case OFPUTIL_NXAST_EXIT: + ofputil_put_NXAST_EXIT(b); + break; + + case OFPUTIL_NXAST_DEC_TTL: + ofputil_put_NXAST_DEC_TTL(b); + break; + + case OFPUTIL_NXAST_FIN_TIMEOUT: + parse_fin_timeout(b, arg); + break; + + case OFPUTIL_NXAST_CONTROLLER: + parse_controller(b, arg); + break; } } static void -str_to_action(char *str, struct ofpbuf *b) +str_to_action(const struct flow *flow, char *str, struct ofpbuf *b) { char *pos, *act, *arg; int n_actions; @@ -349,7 +452,7 @@ str_to_action(char *str, struct ofpbuf *b) code = ofputil_action_code_from_name(act); if (code >= 0) { - parse_named_action(code, b, arg); + parse_named_action(code, flow, b, arg); } else if (!strcasecmp(act, "drop")) { /* A drop action in OpenFlow occurs by just not setting * an action. */ @@ -361,17 +464,6 @@ str_to_action(char *str, struct ofpbuf *b) "actions"); } break; - } else if (!strcasecmp(act, "CONTROLLER")) { - struct ofp_action_output *oao; - oao = put_output_action(b, OFPP_CONTROLLER); - - /* Unless a numeric argument is specified, we send the whole - * packet to the controller. */ - if (arg[0] && (strspn(arg, "0123456789") == strlen(arg))) { - oao->max_len = htons(str_to_u32(arg)); - } else { - oao->max_len = htons(UINT16_MAX); - } } else if (ofputil_port_from_string(act, &port)) { put_output_action(b, port); } else { @@ -456,12 +548,13 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, enum { F_OUT_PORT = 1 << 0, F_ACTIONS = 1 << 1, - F_COOKIE = 1 << 2, F_TIMEOUT = 1 << 3, - F_PRIORITY = 1 << 4 + F_PRIORITY = 1 << 4, + F_FLAGS = 1 << 5, } fields; char *string = xstrdup(str_); char *save_ptr = NULL; + char *act_str = NULL; char *name; switch (command) { @@ -470,7 +563,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, break; case OFPFC_ADD: - fields = F_ACTIONS | F_COOKIE | F_TIMEOUT | F_PRIORITY; + fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_DELETE: @@ -482,11 +575,11 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, break; case OFPFC_MODIFY: - fields = F_ACTIONS | F_COOKIE; + fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_MODIFY_STRICT: - fields = F_ACTIONS | F_COOKIE | F_PRIORITY; + fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; default: @@ -495,6 +588,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY); fm->cookie = htonll(0); + fm->cookie_mask = htonll(0); fm->table_id = 0xff; fm->command = command; fm->idle_timeout = OFP_FLOW_PERMANENT; @@ -503,9 +597,6 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, fm->out_port = OFPP_NONE; fm->flags = 0; if (fields & F_ACTIONS) { - struct ofpbuf actions; - char *act_str; - act_str = strstr(string, "action"); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); @@ -518,14 +609,6 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } act_str++; - - ofpbuf_init(&actions, sizeof(union ofp_action)); - str_to_action(act_str, &actions); - fm->actions = ofpbuf_steal_data(&actions); - fm->n_actions = actions.size / sizeof(union ofp_action); - } else { - fm->actions = NULL; - fm->n_actions = 0; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { @@ -536,6 +619,10 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, if (p->nw_proto) { cls_rule_set_nw_proto(&fm->cr, 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 { char *value; @@ -545,16 +632,27 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } if (!strcmp(name, "table")) { - fm->table_id = atoi(value); + fm->table_id = str_to_table_id(value); } else if (!strcmp(name, "out_port")) { fm->out_port = atoi(value); } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { - fm->cr.priority = atoi(value); + fm->cr.priority = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) { - fm->idle_timeout = atoi(value); + fm->idle_timeout = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) { - fm->hard_timeout = atoi(value); - } else if (fields & F_COOKIE && !strcmp(name, "cookie")) { + fm->hard_timeout = str_to_u16(value, name); + } else if (!strcmp(name, "cookie")) { + char *mask = strchr(value, '/'); + if (mask) { + if (command == OFPFC_ADD) { + ofp_fatal(str_, verbose, "flow additions cannot use " + "a cookie mask"); + } + *mask = '\0'; + fm->cookie_mask = htonll(str_to_u64(mask+1)); + } else { + fm->cookie_mask = htonll(UINT64_MAX); + } fm->cookie = htonll(str_to_u64(value)); } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fm->cr); @@ -569,86 +667,90 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } } } + if (fields & F_ACTIONS) { + struct ofpbuf actions; + + ofpbuf_init(&actions, sizeof(union ofp_action)); + str_to_action(&fm->cr.flow, act_str, &actions); + fm->actions = ofpbuf_steal_data(&actions); + fm->n_actions = actions.size / sizeof(union ofp_action); + } else { + fm->actions = NULL; + fm->n_actions = 0; + } free(string); } +/* Parses 's' as a set of OpenFlow actions and appends the actions to + * 'actions'. + * + * Prints an error on stderr and aborts the program if 's' syntax is + * invalid. */ +void +parse_ofp_actions(const char *s_, struct ofpbuf *actions) +{ + char *s = xstrdup(s_); + str_to_action(NULL, s, actions); + free(s); +} + /* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command' - * (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'. - * '*cur_format' should initially contain the flow format currently configured - * on the connection; this function will add a message to change the flow - * format and update '*cur_format', if this is necessary to add the parsed - * flow. */ + * (one of OFPFC_*) into 'fm'. */ void -parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format, - bool *flow_mod_table_id, char *string, uint16_t command, - bool verbose) +parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string, + uint16_t command, bool verbose) { - enum nx_flow_format min_format, next_format; struct cls_rule rule_copy; - struct ofpbuf actions; - struct ofpbuf *ofm; - struct ofputil_flow_mod fm; - ofpbuf_init(&actions, 64); - parse_ofp_str(&fm, command, string, verbose); - - min_format = ofputil_min_flow_format(&fm.cr); - next_format = MAX(*cur_format, min_format); - if (next_format != *cur_format) { - struct ofpbuf *sff = ofputil_make_set_flow_format(next_format); - list_push_back(packets, &sff->list_node); - *cur_format = next_format; - } + parse_ofp_str(fm, command, string, verbose); /* Normalize a copy of the rule. 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, next_format); - - if (fm.table_id != 0xff && !*flow_mod_table_id) { - struct ofpbuf *sff = ofputil_make_flow_mod_table_id(true); - list_push_back(packets, &sff->list_node); - *flow_mod_table_id = true; - } - - ofm = ofputil_encode_flow_mod(&fm, *cur_format, *flow_mod_table_id); - list_push_back(packets, &ofm->list_node); - - ofpbuf_uninit(&actions); + rule_copy = fm->cr; + ofputil_normalize_rule(&rule_copy); } -/* Similar to parse_ofp_flow_mod_str(), except that the string is read from - * 'stream' and the command is always OFPFC_ADD. Returns false if end-of-file - * is reached before reading a flow, otherwise true. */ -bool -parse_ofp_flow_mod_file(struct list *packets, - enum nx_flow_format *cur, bool *flow_mod_table_id, - FILE *stream, uint16_t command) +void +parse_ofp_flow_mod_file(const char *file_name, uint16_t command, + struct ofputil_flow_mod **fms, size_t *n_fms) { + size_t allocated_fms; + FILE *stream; struct ds s; - bool ok; + stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r"); + if (stream == NULL) { + ovs_fatal(errno, "%s: open", file_name); + } + + allocated_fms = *n_fms; ds_init(&s); - ok = ds_get_preprocessed_line(&s, stream) == 0; - if (ok) { - parse_ofp_flow_mod_str(packets, cur, flow_mod_table_id, - ds_cstr(&s), command, true); + while (!ds_get_preprocessed_line(&s, stream)) { + if (*n_fms >= allocated_fms) { + *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms); + } + parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command, false); + *n_fms += 1; } ds_destroy(&s); - return ok; + if (stream != stdin) { + fclose(stream); + } } void parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr, - bool aggregate, char *string) + bool aggregate, const char *string) { struct ofputil_flow_mod fm; parse_ofp_str(&fm, -1, string, false); fsr->aggregate = aggregate; + fsr->cookie = fm.cookie; + fsr->cookie_mask = fm.cookie_mask; fsr->match = fm.cr; fsr->out_port = fm.out_port; fsr->table_id = fm.table_id;