X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=lib%2Fofp-parse.c;h=25fd2b965fecea16c470316e7dd900dad690a43d;hb=e2eed6a7581193da43210a26ad182fb2a697eaf5;hp=5e488a6e21e8cd7896b0036a0b32916db1252082;hpb=009853d87ec9ae26edcaa74687a2908a1692b7a1;p=openvswitch diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 5e488a6e..25fd2b96 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -83,6 +83,27 @@ str_to_mac(const char *str, uint8_t mac[6]) } } +static void +str_to_eth_dst(const char *str, + uint8_t mac[ETH_ADDR_LEN], uint8_t mask[ETH_ADDR_LEN]) +{ + if (sscanf(str, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT, + ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask)) + == ETH_ADDR_SCAN_COUNT * 2) { + if (!flow_wildcards_is_dl_dst_mask_valid(mask)) { + ovs_fatal(0, "%s: invalid Ethernet destination mask (only " + "00:00:00:00:00:00, 01:00:00:00:00:00, " + "fe:ff:ff:ff:ff:ff, and ff:ff:ff:ff:ff:ff are allowed)", + str); + } + } else if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) + == ETH_ADDR_SCAN_COUNT) { + memset(mask, 0xff, ETH_ADDR_LEN); + } else { + ovs_fatal(0, "invalid mac address %s", str); + } +} + static void str_to_ip(const char *str_, ovs_be32 *ip, ovs_be32 *maskp) { @@ -162,6 +183,35 @@ error: ovs_fatal(0, "%s: bad syntax for tunnel id", str); } +static void +str_to_vlan_tci(const char *str, ovs_be16 *vlan_tcip, ovs_be16 *maskp) +{ + uint16_t vlan_tci, mask; + char *tail; + + errno = 0; + vlan_tci = strtol(str, &tail, 0); + if (errno || (*tail != '\0' && *tail != '/')) { + goto error; + } + + if (*tail == '/') { + mask = strtol(tail + 1, &tail, 0); + if (errno || *tail != '\0') { + goto error; + } + } else { + mask = UINT16_MAX; + } + + *vlan_tcip = htons(vlan_tci); + *maskp = htons(mask); + return; + +error: + ovs_fatal(0, "%s: bad syntax for vlan_tci", str); +} + static void str_to_ipv6(const char *str_, struct in6_addr *addrp, struct in6_addr *maskp) { @@ -389,11 +439,6 @@ str_to_action(char *str, struct ofpbuf *b) nast->subtype = htons(NXAST_SET_TUNNEL); nast->tun_id = htonl(tun_id); } - } else if (!strcasecmp(act, "drop_spoofed_arp")) { - struct nx_action_header *nah; - nah = put_action(b, sizeof *nah, OFPAT_VENDOR); - nah->vendor = htonl(NX_VENDOR_ID); - nah->subtype = htons(NXAST_DROP_SPOOFED_ARP); } else if (!strcasecmp(act, "set_queue")) { struct nx_action_set_queue *nasq; nasq = put_action(b, sizeof *nasq, OFPAT_VENDOR); @@ -536,6 +581,7 @@ parse_protocol(const char *name, const struct protocol **p_out) FIELD(F_IN_PORT, "in_port", FWW_IN_PORT) \ FIELD(F_DL_VLAN, "dl_vlan", 0) \ FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", 0) \ + FIELD(F_VLAN_TCI, "vlan_tci", 0) \ FIELD(F_DL_SRC, "dl_src", FWW_DL_SRC) \ FIELD(F_DL_DST, "dl_dst", FWW_DL_DST | FWW_ETH_MCAST) \ FIELD(F_DL_TYPE, "dl_type", FWW_DL_TYPE) \ @@ -568,6 +614,19 @@ struct field { flow_wildcards_t wildcard; /* FWW_* bit. */ }; +static void +ofp_fatal(const char *flow, bool verbose, const char *format, ...) +{ + va_list args; + + if (verbose) { + fprintf(stderr, "%s:\n", flow); + } + + va_start(args, format); + ovs_fatal_valist(0, format, args); +} + static bool parse_field_name(const char *name, const struct field **f_out) { @@ -592,9 +651,10 @@ static void parse_field_value(struct cls_rule *rule, enum field_index index, const char *value) { - uint8_t mac[ETH_ADDR_LEN]; + uint8_t mac[ETH_ADDR_LEN], mac_mask[ETH_ADDR_LEN]; ovs_be64 tun_id, tun_mask; ovs_be32 ip, mask; + ovs_be16 tci, tci_mask; struct in6_addr ipv6, ipv6_mask; uint16_t port_no; @@ -619,14 +679,19 @@ parse_field_value(struct cls_rule *rule, enum field_index index, cls_rule_set_dl_vlan_pcp(rule, str_to_u32(value)); break; + case F_VLAN_TCI: + str_to_vlan_tci(value, &tci, &tci_mask); + cls_rule_set_dl_tci_masked(rule, tci, tci_mask); + break; + case F_DL_SRC: str_to_mac(value, mac); cls_rule_set_dl_src(rule, mac); break; case F_DL_DST: - str_to_mac(value, mac); - cls_rule_set_dl_dst(rule, mac); + str_to_eth_dst(value, mac, mac_mask); + cls_rule_set_dl_dst_masked(rule, mac, mac_mask); break; case F_DL_TYPE: @@ -725,12 +790,14 @@ parse_reg_value(struct cls_rule *rule, int reg_idx, const char *value) } } -/* Convert 'string' (as described in the Flow Syntax section of the ovs-ofctl - * man page) into 'pf'. If 'actions' is specified, an action must be in +/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl + * man page) into 'fm'. If 'actions' is specified, an action must be in * 'string' and may be expanded or reallocated. */ void -parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, char *string) +parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, const char *str_, + bool verbose) { + char *string = xstrdup(str_); char *save_ptr = NULL; char *name; @@ -746,13 +813,13 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, char *string) if (actions) { char *act_str = strstr(string, "action"); if (!act_str) { - ovs_fatal(0, "must specify an action"); + ofp_fatal(str_, verbose, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { - ovs_fatal(0, "must specify an action"); + ofp_fatal(str_, verbose, "must specify an action"); } act_str++; @@ -779,7 +846,7 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, char *string) value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { - ovs_fatal(0, "field %s missing value", name); + ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "table")) { @@ -823,14 +890,25 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, char *string) && isdigit((unsigned char) name[3])) { unsigned int reg_idx = atoi(name + 3); if (reg_idx >= FLOW_N_REGS) { - ovs_fatal(0, "only %d registers supported", FLOW_N_REGS); + if (verbose) { + fprintf(stderr, "%s:\n", str_); + } + ofp_fatal(str_, verbose, "only %d registers supported", FLOW_N_REGS); } parse_reg_value(&fm->cr, reg_idx, value); + } else if (!strcmp(name, "duration") + || !strcmp(name, "n_packets") + || !strcmp(name, "n_bytes")) { + /* Ignore these, so that users can feed the output of + * "ovs-ofctl dump-flows" back into commands that parse + * flows. */ } else { - ovs_fatal(0, "unknown keyword %s", name); + ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } + + free(string); } /* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command' @@ -841,7 +919,8 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, char *string) * flow. */ 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 *flow_mod_table_id, char *string, uint16_t command, + bool verbose) { bool is_del = command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT; enum nx_flow_format min_format, next_format; @@ -851,7 +930,7 @@ parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format, struct flow_mod fm; ofpbuf_init(&actions, 64); - parse_ofp_str(&fm, is_del ? NULL : &actions, string); + parse_ofp_str(&fm, is_del ? NULL : &actions, string, verbose); fm.command = command; min_format = ofputil_min_flow_format(&fm.cr); @@ -895,7 +974,7 @@ parse_ofp_flow_mod_file(struct list *packets, 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); + ds_cstr(&s), command, true); } ds_destroy(&s); @@ -908,7 +987,7 @@ parse_ofp_flow_stats_request_str(struct flow_stats_request *fsr, { struct flow_mod fm; - parse_ofp_str(&fm, NULL, string); + parse_ofp_str(&fm, NULL, string, false); fsr->aggregate = aggregate; fsr->match = fm.cr; fsr->out_port = fm.out_port;