X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fofp-parse.c;h=fdc30d9b7c0eed67343cf98caec3e3b4869d66f2;hb=4e548ad9e60f8248090a467fefcc58da5f298c96;hp=a18bd9cbd0bda8a367f9743dacc8d0a3cf28ec27;hpb=bc78455bdbabd5f16abde1d0b4d63d488286f2e3;p=cascardo%2Fovs.git diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index a18bd9cbd..fdc30d9b7 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "byte-order.h" #include "dynamic-string.h" @@ -168,6 +169,20 @@ str_to_ip(const char *str, ovs_be32 *ip) return NULL; } +/* Parses 'str' as a conntrack helper into 'alg'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * OVS_WARN_UNUSED_RESULT +str_to_connhelper(const char *str, uint16_t *alg) +{ + if (!strcmp(str, "ftp")) { + *alg = IPPORT_FTP; + return NULL; + } + return xasprintf("invalid conntrack helper \"%s\"", str); +} + struct protocol { const char *name; uint16_t dl_type; @@ -221,9 +236,15 @@ parse_field(const struct mf_field *mf, const char *s, struct match *match, union mf_value value, mask; char *error; + if (!*s) { + /* If there's no string, we're just trying to match on the + * existence of the field, so use a no-op value. */ + s = "0/0"; + } + error = mf_parse(mf, s, &value, &mask); if (!error) { - *usable_protocols &= mf_set(mf, &value, &mask, match); + *usable_protocols &= mf_set(mf, &value, &mask, match, &error); } return error; } @@ -330,7 +351,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, fm->out_port = OFPP_ANY; fm->flags = 0; fm->importance = 0; - fm->out_group = OFPG11_ANY; + fm->out_group = OFPG_ANY; fm->delete_reason = OFPRR_DELETE; if (fields & F_ACTIONS) { act_str = extract_actions(string); @@ -365,11 +386,6 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, || !strcmp(name, "allow_hidden_fields")) { /* ignore these fields. */ } else if (mf_from_name(name)) { - if (!*value) { - /* If there's no value, we're just trying to match on the - * existence of the field, so use a no-op value. */ - value = "0/0"; - } error = parse_field(mf_from_name(name), value, &fm->match, usable_protocols); } else { @@ -387,6 +403,12 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, error = xasprintf("%s is not a valid OpenFlow port", value); } + } else if (fields & F_OUT_PORT && !strcmp(name, "out_group")) { + *usable_protocols &= OFPUTIL_P_OF11_UP; + if (!ofputil_group_from_string(value, &fm->out_group)) { + error = xasprintf("%s is not a valid OpenFlow group", + value); + } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { uint16_t priority = 0; @@ -777,6 +799,7 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr, while (ofputil_parse_key_value(&string, &name, &value)) { const struct protocol *p; + char *error = NULL; if (!strcmp(name, "!initial")) { fmr->flags &= ~NXFMF_INITIAL; @@ -795,30 +818,26 @@ parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr, if (p->nw_proto) { match_set_nw_proto(&fmr->match, p->nw_proto); } + } else if (mf_from_name(name)) { + error = parse_field(mf_from_name(name), value, &fmr->match, + usable_protocols); } else { if (!*value) { return xasprintf("%s: field %s missing value", str_, name); } if (!strcmp(name, "table")) { - char *error = str_to_u8(value, "table", &fmr->table_id); - if (error) { - return error; - } + error = str_to_u8(value, "table", &fmr->table_id); } else if (!strcmp(name, "out_port")) { fmr->out_port = u16_to_ofp(atoi(value)); - } else if (mf_from_name(name)) { - char *error; - - error = parse_field(mf_from_name(name), value, &fmr->match, - usable_protocols); - if (error) { - return error; - } } else { return xasprintf("%s: unknown keyword %s", str_, name); } } + + if (error) { + return error; + } } return NULL; } @@ -867,6 +886,49 @@ parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string, return error; } +/* Convert 'setting' (as described for the "mod-table" command + * in ovs-ofctl man page) into 'tm->table_vacancy->vacancy_up' and + * 'tm->table_vacancy->vacancy_down' threshold values. + * For the two threshold values, value of vacancy_up is always greater + * than value of vacancy_down. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * OVS_WARN_UNUSED_RESULT +parse_ofp_table_vacancy(struct ofputil_table_mod *tm, const char *setting) +{ + char *save_ptr = NULL; + char *vac_up, *vac_down; + char *value = strdup(setting); + int vacancy_up, vacancy_down; + + strtok_r(value, ":", &save_ptr); + vac_down = strtok_r(NULL, ",", &save_ptr); + if (!vac_down) { + return xasprintf("Vacancy down value missing"); + } + if (!str_to_int(vac_down, 0, &vacancy_down) || + vacancy_down < 0 || vacancy_down > 100) { + return xasprintf("Invalid vacancy down value \"%s\"", vac_down); + } + vac_up = strtok_r(NULL, ",", &save_ptr); + if (!vac_up) { + return xasprintf("Vacancy up value missing"); + } + if (!str_to_int(vac_up, 0, &vacancy_up) || + vacancy_up < 0 || vacancy_up > 100) { + return xasprintf("Invalid vacancy up value \"%s\"", vac_up); + } + if (vacancy_down > vacancy_up) { + return xasprintf("Invalid vacancy range, vacancy up should be greater" + " than vacancy down ""(%s)", + ofperr_to_string(OFPERR_OFPBPC_BAD_VALUE)); + } + tm->table_vacancy.vacancy_down = vacancy_down; + tm->table_vacancy.vacancy_up = vacancy_up; + return NULL; +} + /* Convert 'table_id' and 'setting' (as described for the "mod-table" command * in the ovs-ofctl man page) into 'tm' for sending a table_mod command to a * switch. @@ -893,13 +955,13 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id, tm->miss = OFPUTIL_TABLE_MISS_DEFAULT; tm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT; tm->eviction_flags = UINT32_MAX; - + tm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT; + tm->table_vacancy.vacancy_down = 0; + tm->table_vacancy.vacancy_up = 0; + tm->table_vacancy.vacancy = 0; /* Only OpenFlow 1.1 and 1.2 can configure table-miss via table_mod. - * Only OpenFlow 1.4+ can configure eviction via table_mod. - * - * (OpenFlow 1.4+ can also configure vacancy events via table_mod, but OVS - * doesn't support those yet and they're also logically a per-OpenFlow - * session setting so it wouldn't make sense to support them here anyway.) + * Only OpenFlow 1.4+ can configure eviction and vacancy events + * via table_mod. */ if (!strcmp(setting, "controller")) { tm->miss = OFPUTIL_TABLE_MISS_CONTROLLER; @@ -916,6 +978,16 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id, } else if (!strcmp(setting, "noevict")) { tm->eviction = OFPUTIL_TABLE_EVICTION_OFF; *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION); + } else if (!strncmp(setting, "vacancy", strcspn(setting, ":"))) { + tm->vacancy = OFPUTIL_TABLE_VACANCY_ON; + *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION); + char *error = parse_ofp_table_vacancy(tm, setting); + if (error) { + return error; + } + } else if (!strcmp(setting, "novacancy")) { + tm->vacancy = OFPUTIL_TABLE_VACANCY_OFF; + *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION); } else { return xasprintf("invalid table_mod setting %s", setting); } @@ -1152,7 +1224,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_, uint8_t group_type, bucket->weight = group_type == OFPGT11_SELECT ? 1 : 0; bucket->bucket_id = OFPG15_BUCKET_ALL; bucket->watch_port = OFPP_ANY; - bucket->watch_group = OFPG11_ANY; + bucket->watch_group = OFPG_ANY; ds_init(&actions); @@ -1215,24 +1287,20 @@ static char * OVS_WARN_UNUSED_RESULT parse_select_group_field(char *s, struct field_array *fa, enum ofputil_protocol *usable_protocols) { - char *save_ptr = NULL; - char *name; + char *name, *value_str; - for (name = strtok_r(s, "=, \t\r\n", &save_ptr); name; - name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + while (ofputil_parse_key_value(&s, &name, &value_str)) { const struct mf_field *mf = mf_from_name(name); if (mf) { char *error; - const char *value_str; union mf_value value; if (bitmap_is_set(fa->used.bm, mf->id)) { return xasprintf("%s: duplicate field", name); } - value_str = strtok_r(NULL, ", \t\r\n", &save_ptr); - if (value_str) { + if (*value_str) { error = mf_parse_value(mf, value_str, &value); if (error) { return error; @@ -1284,10 +1352,8 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command, F_COMMAND_BUCKET_ID = 1 << 2, F_COMMAND_BUCKET_ID_ALL = 1 << 3, } fields; - char *save_ptr = NULL; bool had_type = false; bool had_command_bucket_id = false; - char *name; struct ofputil_bucket *bucket; char *error = NULL; @@ -1345,16 +1411,9 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command, } /* Parse everything before the buckets. */ - for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; - name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { - char *value; - - value = strtok_r(NULL, ", \t\r\n", &save_ptr); - if (!value) { - error = xasprintf("field %s missing value", name); - goto out; - } - + char *pos = string; + char *name, *value; + while (ofputil_parse_key_value(&pos, &name, &value)) { if (!strcmp(name, "command_bucket_id")) { if (!(fields & F_COMMAND_BUCKET_ID)) { error = xstrdup("command bucket id is not needed"); @@ -1605,30 +1664,30 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command, } char * OVS_WARN_UNUSED_RESULT -parse_ofp_geneve_table_mod_str(struct ofputil_geneve_table_mod *gtm, +parse_ofp_tlv_table_mod_str(struct ofputil_tlv_table_mod *ttm, uint16_t command, const char *s, enum ofputil_protocol *usable_protocols) { *usable_protocols = OFPUTIL_P_NXM_OXM_ANY; - gtm->command = command; - list_init(>m->mappings); + ttm->command = command; + list_init(&ttm->mappings); while (*s) { - struct ofputil_geneve_map *map = xmalloc(sizeof *map); + struct ofputil_tlv_map *map = xmalloc(sizeof *map); int n; if (*s == ',') { s++; } - list_push_back(>m->mappings, &map->list_node); + list_push_back(&ttm->mappings, &map->list_node); if (!ovs_scan(s, "{class=%"SCNi16",type=%"SCNi8",len=%"SCNi8"}->tun_metadata%"SCNi16"%n", &map->option_class, &map->option_type, &map->option_len, &map->index, &n)) { - ofputil_uninit_geneve_table(>m->mappings); - return xstrdup("invalid geneve mapping"); + ofputil_uninit_tlv_table(&ttm->mappings); + return xstrdup("invalid tlv mapping"); } s += n;