/* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err("'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "#"); if (!token) { log_err("Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr4(token, &addr_out->l3); if (error) return error; token = strtok(NULL, "#"); if (!token) { log_err("'%s' does not seem to contain a port (format: %s).", str, FORMAT); return -EINVAL; } return str_to_u16(token, &addr_out->l4, 0, MAX_PORT); /* Error msg already printed. */ } #undef STR_MAX_LEN #define STR_MAX_LEN (INET6_ADDRSTRLEN + 1 + 5) /* [addr + null chara] + # + port */ int str_to_addr6_port(const char *str, struct ipv6_transport_addr *addr_out) { const char *FORMAT = "<IPv6 address>#<port> (eg. 2001:db8::1#96)"; /* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err("'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "#"); if (!token) { log_err("Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr6(token, &addr_out->l3); if (error) return error; token = strtok(NULL, "#"); if (!token) { log_err("'%s' does not seem to contain a port (format: %s).", str, FORMAT); return -EINVAL; } return str_to_u16(token, &addr_out->l4, 0, MAX_PORT); /* Error msg already printed. */ }
static void parse_sample(struct ofpbuf *b, char *arg) { struct ofpact_sample *os = ofpact_put_SAMPLE(b); char *key, *value; while (ofputil_parse_key_value(&arg, &key, &value)) { if (!strcmp(key, "probability")) { os->probability = str_to_u16(value, "probability"); if (os->probability == 0) { ovs_fatal(0, "invalid probability value \"%s\"", value); } } else if (!strcmp(key, "collector_set_id")) { os->collector_set_id = str_to_u32(value); } else if (!strcmp(key, "obs_domain_id")) { os->obs_domain_id = str_to_u32(value); } else if (!strcmp(key, "obs_point_id")) { os->obs_point_id = str_to_u32(value); } else { ovs_fatal(0, "invalid key \"%s\" in \"sample\" argument", key); } } if (os->probability == 0) { ovs_fatal(0, "non-zero \"probability\" must be specified on sample"); } }
static void parse_fin_timeout(struct ofpbuf *b, char *arg) { struct ofpact_fin_timeout *oft = ofpact_put_FIN_TIMEOUT(b); char *key, *value; while (ofputil_parse_key_value(&arg, &key, &value)) { if (!strcmp(key, "idle_timeout")) { oft->fin_idle_timeout = str_to_u16(value, key); } else if (!strcmp(key, "hard_timeout")) { oft->fin_hard_timeout = str_to_u16(value, key); } else { ovs_fatal(0, "invalid key '%s' in 'fin_timeout' argument", key); } } }
bool str_to_addr6_port(const char *str, struct ipv6_tuple_address *addr_out) { const char *FORMAT = "<IPv6 address>#<port> (eg. 64:ff9b::#96)"; const int STR_MAX_LEN = INET6_ADDRSTRLEN + 1 + 5; // [addr + null chara] + # + port char str_copy[STR_MAX_LEN]; // strtok corrupts the string, so we'll be using this copy instead. char *token; if (strlen(str) + 1 > STR_MAX_LEN) { printf("Error: '%s' is too long for this poor, limited parser...\n", str); return false; } strcpy(str_copy, str); token = strtok(str_copy, "#"); if (!token || !str_to_addr6(token, &addr_out->address)) { printf("Error: Cannot parse '%s' as a %s.\n", str, FORMAT); return false; } token = strtok(NULL, "#"); if (!token) { printf("Error: '%s' does not seem to contain a port (format: %s).\n", str, FORMAT); return false; } if (!str_to_u16(token, &addr_out->l4_id, 0, MAX_PORT)) return false; // Error msg already printed. return true; }
bool str_to_u8(const char *str, __u8 *u8_out, __u8 min, __u8 max) { __u16 result; if (!str_to_u16(str, &result, min, max)) return false; // Error msg already printed. *u8_out = result; return true; }
int str_to_u16_array(const char *str, __u16 **array_out, __u16 *array_len_out) { const unsigned int str_max_len = 2048; /* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[str_max_len]; char *token; __u16 *array; __u16 array_len; /* Validate str and copy it to the temp buffer. */ if (strlen(str) + 1 > str_max_len) { log_err(ERR_PARSE_INTARRAY, "'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); /* Count the number of ints in the string. */ array_len = 0; token = strtok(str_copy, ","); while (token) { array_len++; token = strtok(NULL, ","); } if (array_len == 0) { log_err(ERR_PARSE_INTARRAY, "'%s' seems to be an empty list, which is not supported.", str); return -EINVAL; } /* Build the result. */ array = malloc(array_len * sizeof(__u16)); if (!array) { log_err(ERR_ALLOC_FAILED, "Memory allocation failed. Cannot parse the input..."); return -ENOMEM; } strcpy(str_copy, str); array_len = 0; token = strtok(str_copy, ","); while (token) { int error; error = str_to_u16(token, &array[array_len], 0, 0xFFFF); if (error) { free(array); return error; /* Error msg already printed. */ } array_len++; token = strtok(NULL, ","); } /* Finish. */ *array_out = array; *array_len_out = array_len; return 0; }
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) { struct ofpact_output *output; output = ofpact_put_OUTPUT(b); output->port = OFPP_CONTROLLER; output->max_len = max_len; } else { struct ofpact_controller *controller; controller = ofpact_put_CONTROLLER(b); controller->max_len = max_len; controller->reason = reason; controller->controller_id = controller_id; } }
int str_to_plateaus_array(const char *str, __u16 *plateaus, __u16 *count) { /* strtok corrupts the string, so we'll be using this copy instead. */ char *str_copy; char *token; unsigned int len; int error = 0; /* Validate str and copy it to the temp buffer. */ str_copy = malloc(strlen(str) + 1); if (!str_copy) { log_err("I ran out of memory."); return -ENOMEM; } strcpy(str_copy, str); /* Count the number of elements in the string. */ len = 0; token = strtok(str_copy, ","); while (token) { len++; token = strtok(NULL, ","); } if (len == 0) { log_err("The plateaus string seems to be an empty list, which is not supported."); error = -EINVAL; goto end; } if (len > PLATEAUS_MAX) { log_err("Too many plateaus. The current max is %u.", PLATEAUS_MAX); error = -EINVAL; goto end; } /* Build the result. */ *count = len; len = 0; strcpy(str_copy, str); token = strtok(str_copy, ","); while (token) { error = str_to_u16(token, &plateaus[len], 0, 0xFFFF); if (error) goto end; /* Error msg already printed. */ len++; token = strtok(NULL, ","); } /* Fall through */ end: free(str_copy); return error; }
bool str_to_u16_array(const char *str, __u16 **array_out, __u16 *array_len_out) { const int str_max_len = 2048; char str_copy[str_max_len]; // strtok corrupts the string, so we'll be using this copy instead. char *token; __u16 *array; __u16 array_len; // Validate str and copy it to the temp buffer. if (strlen(str) + 1 > str_max_len) { printf("Error: '%s' is too long for this poor, limited parser...\n", str); return false; } strcpy(str_copy, str); // Count the number of ints in the string. array_len = 0; token = strtok(str_copy, ","); while (token) { array_len++; token = strtok(NULL, ","); } if (array_len == 0) { printf("Error: '%s' seems to be an empty list, which is not supported.\n", str); return false; } // Build the result. array = malloc(array_len * sizeof(__u16)); if (!array) { printf("Error: Memory allocation failed. Cannot parse...\n"); return false; } strcpy(str_copy, str); array_len = 0; token = strtok(str_copy, ","); while (token) { if (!str_to_u16(token, &array[array_len], 0, 0xFFFF)) { free(array); return false; // Error msg already printed. } array_len++; token = strtok(NULL, ","); } // Finish. *array_out = array; *array_len_out = array_len; return true; }
static int set_general_u16(struct arguments *args, enum general_module module, __u8 type, char *value, __u16 min, __u16 max) { __u16 tmp; int error; error = str_to_u16(value, &tmp, min, max); if (error) return error; return set_general_arg(args, module, type, sizeof(tmp), &tmp); }
int str_to_u8(const char *str, __u8 *u8_out, __u8 min, __u8 max) { __u16 result; int error; error = str_to_u16(str, &result, min, max); if (error) return error; /* Error msg already printed. */ *u8_out = result; return 0; }
int str_to_addr4_port(const char *str, struct ipv4_tuple_address *addr_out) { const char *FORMAT = "<IPv4 address>#<port> (eg. 10.20.30.40#50)"; /* [addr + null chara] + # + port */ const unsigned int STR_MAX_LEN = INET_ADDRSTRLEN + 1 + 5; /* strtok corrupts the string, so we'll be using this copy instead. */ char str_copy[STR_MAX_LEN]; char *token; int error; if (strlen(str) + 1 > STR_MAX_LEN) { log_err(ERR_PARSE_ADDR4_PORT, "'%s' is too long for this poor, limited parser...", str); return -EINVAL; } strcpy(str_copy, str); token = strtok(str_copy, "#"); if (!token) { log_err(ERR_PARSE_ADDR4_PORT, "Cannot parse '%s' as a %s.", str, FORMAT); return -EINVAL; } error = str_to_addr4(token, &addr_out->address); if (error) return error; token = strtok(NULL, "#"); if (!token) { log_err(ERR_PARSE_ADDR4_PORT, "'%s' does not seem to contain a port (format: %s).", str, FORMAT); return -EINVAL; } error = str_to_u16(token, &addr_out->l4_id, 0, MAX_PORT); if (error) return error; /* Error msg already printed. */ return 0; }
/*! * \brief Parse NSEC3 parameters and fill structure with NSEC3 parameters. */ static bool parse_nsec3_params(dnssec_nsec3_params_t *params, const char *salt_str, const char *algorithm_str, const char *iterations_str) { uint8_t algorithm = 0; int r = str_to_u8(algorithm_str, &algorithm); if (r != DNSSEC_EOK) { error("Invalid algorithm number."); return false; } uint16_t iterations = 0; r = str_to_u16(iterations_str, &iterations); if (r != DNSSEC_EOK) { error("Invalid iteration count, %s.", dnssec_strerror(r)); return false; } dnssec_binary_t salt = { 0 }; r = str_to_salt(salt_str, &salt); if (r != DNSSEC_EOK) { error("Invalid salt, %s.", dnssec_strerror(r)); return false; } if (salt.size > UINT8_MAX) { error("Invalid salt, maximum length is %d bytes.", UINT8_MAX); dnssec_binary_free(&salt); return false; } params->algorithm = algorithm; params->iterations = iterations; params->salt = salt; params->flags = 0; return true; }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man * page) into 'fm' for sending the specified flow_mod 'command' to a switch. * If 'actions' is specified, an action must be in 'string' and may be expanded * or reallocated. * * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_* * constant for 'command'. To parse syntax for an OFPST_FLOW or * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */ void parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, bool verbose) { enum { F_OUT_PORT = 1 << 0, F_ACTIONS = 1 << 1, F_TIMEOUT = 1 << 3, 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) { case -1: fields = F_OUT_PORT; break; case OFPFC_ADD: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_DELETE: fields = F_OUT_PORT; break; case OFPFC_DELETE_STRICT: fields = F_OUT_PORT | F_PRIORITY; break; case OFPFC_MODIFY: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_MODIFY_STRICT: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; default: NOT_REACHED(); } 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) { /* For modify, by default, don't update the cookie. */ fm->new_cookie = htonll(UINT64_MAX); } else{ fm->new_cookie = htonll(0); } fm->table_id = 0xff; fm->command = command; fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_ANY; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } act_str++; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (parse_protocol(name, &p)) { match_set_dl_type(&fm->match, htons(p->dl_type)); if (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; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "table")) { fm->table_id = str_to_u8(value, name); } else if (!strcmp(name, "out_port")) { if (!ofputil_port_from_string(value, &fm->out_port)) { ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", name); } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { 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")) { fm->hard_timeout = str_to_u16(value, name); } else if (!strcmp(name, "cookie")) { char *mask = strchr(value, '/'); if (mask) { /* A mask means we're searching for a cookie. */ if (command == OFPFC_ADD) { ofp_fatal(str_, verbose, "flow additions cannot use " "a cookie mask"); } *mask = '\0'; fm->cookie = htonll(str_to_u64(value)); fm->cookie_mask = htonll(str_to_u64(mask+1)); } else { /* No mask means that the cookie is being set. */ if (command != OFPFC_ADD && command != OFPFC_MODIFY && command != OFPFC_MODIFY_STRICT) { ofp_fatal(str_, verbose, "cannot set cookie"); } fm->new_cookie = htonll(str_to_u64(value)); } } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fm->match); } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") || !strcmp(name, "n_bytes") || !strcmp(name, "idle_age") || !strcmp(name, "hard_age")) { /* Ignore these, so that users can feed the output of * "ovs-ofctl dump-flows" back into commands that parse * flows. */ } else { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX) && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) { /* On modifies without a mask, we are supposed to add a flow if * one does not exist. If a cookie wasn't been specified, use a * default of zero. */ fm->new_cookie = htonll(0); } if (fields & F_ACTIONS) { struct ofpbuf ofpacts; enum ofperr err; ofpbuf_init(&ofpacts, 32); str_to_inst_ofpacts(act_str, &ofpacts); fm->ofpacts_len = ofpacts.size; fm->ofpacts = ofpbuf_steal_data(&ofpacts); err = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow, OFPP_MAX, 0); if (err) { exit(EXIT_FAILURE); } } else { fm->ofpacts_len = 0; fm->ofpacts = NULL; } free(string); }
static void parse_named_action(enum ofputil_action_code code, char *arg, struct ofpbuf *ofpacts) { struct ofpact_tunnel *tunnel; uint16_t vid; uint16_t ethertype; ovs_be32 ip; uint8_t pcp; uint8_t tos; switch (code) { case OFPUTIL_ACTION_INVALID: NOT_REACHED(); case OFPUTIL_OFPAT10_OUTPUT: case OFPUTIL_OFPAT11_OUTPUT: parse_output(arg, ofpacts); break; case OFPUTIL_OFPAT10_SET_VLAN_VID: case OFPUTIL_OFPAT11_SET_VLAN_VID: vid = str_to_u32(arg); if (vid & ~VLAN_VID_MASK) { ovs_fatal(0, "%s: not a valid VLAN VID", arg); } ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid; break; case OFPUTIL_OFPAT10_SET_VLAN_PCP: case OFPUTIL_OFPAT11_SET_VLAN_PCP: pcp = str_to_u32(arg); if (pcp & ~7) { ovs_fatal(0, "%s: not a valid VLAN PCP", arg); } 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); break; case OFPUTIL_OFPAT10_SET_DL_DST: case OFPUTIL_OFPAT11_SET_DL_DST: str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac); break; case OFPUTIL_OFPAT10_SET_NW_SRC: case OFPUTIL_OFPAT11_SET_NW_SRC: str_to_ip(arg, &ip); ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip; break; case OFPUTIL_OFPAT10_SET_NW_DST: case OFPUTIL_OFPAT11_SET_NW_DST: str_to_ip(arg, &ip); ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip; break; case OFPUTIL_OFPAT10_SET_NW_TOS: case OFPUTIL_OFPAT11_SET_NW_TOS: tos = str_to_u32(arg); if (tos & ~IP_DSCP_MASK) { ovs_fatal(0, "%s: not a valid TOS", arg); } 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); break; case OFPUTIL_OFPAT10_SET_TP_DST: case OFPUTIL_OFPAT11_SET_TP_DST: ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg); break; case OFPUTIL_OFPAT10_ENQUEUE: parse_enqueue(arg, ofpacts); break; case OFPUTIL_NXAST_RESUBMIT: parse_resubmit(arg, ofpacts); break; case OFPUTIL_NXAST_SET_TUNNEL: case OFPUTIL_NXAST_SET_TUNNEL64: tunnel = ofpact_put_SET_TUNNEL(ofpacts); tunnel->ofpact.compat = code; 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; case OFPUTIL_NXAST_POP_QUEUE: ofpact_put_POP_QUEUE(ofpacts); break; case OFPUTIL_NXAST_REG_MOVE: nxm_parse_reg_move(ofpact_put_REG_MOVE(ofpacts), arg); break; case OFPUTIL_NXAST_REG_LOAD: nxm_parse_reg_load(ofpact_put_REG_LOAD(ofpacts), arg); break; case OFPUTIL_NXAST_NOTE: parse_note(arg, ofpacts); break; case OFPUTIL_NXAST_MULTIPATH: multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg); break; case OFPUTIL_NXAST_BUNDLE: bundle_parse(arg, ofpacts); break; case OFPUTIL_NXAST_BUNDLE_LOAD: bundle_parse_load(arg, ofpacts); break; case OFPUTIL_NXAST_RESUBMIT_TABLE: case OFPUTIL_NXAST_OUTPUT_REG: case OFPUTIL_NXAST_DEC_TTL_CNT_IDS: NOT_REACHED(); case OFPUTIL_NXAST_LEARN: learn_parse(arg, ofpacts); break; case OFPUTIL_NXAST_EXIT: ofpact_put_EXIT(ofpacts); break; case OFPUTIL_NXAST_DEC_TTL: parse_dec_ttl(ofpacts, arg); break; case OFPUTIL_NXAST_SET_MPLS_TTL: case OFPUTIL_OFPAT11_SET_MPLS_TTL: parse_set_mpls_ttl(ofpacts, arg); break; case OFPUTIL_OFPAT11_DEC_MPLS_TTL: case OFPUTIL_NXAST_DEC_MPLS_TTL: ofpact_put_DEC_MPLS_TTL(ofpacts); break; case OFPUTIL_NXAST_FIN_TIMEOUT: parse_fin_timeout(ofpacts, arg); break; case OFPUTIL_NXAST_CONTROLLER: parse_controller(ofpacts, arg); break; case OFPUTIL_OFPAT11_PUSH_MPLS: case OFPUTIL_NXAST_PUSH_MPLS: ofpact_put_PUSH_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "push_mpls")); break; case OFPUTIL_OFPAT11_POP_MPLS: case OFPUTIL_NXAST_POP_MPLS: ofpact_put_POP_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "pop_mpls")); break; case OFPUTIL_NXAST_STACK_PUSH: nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg); break; case OFPUTIL_NXAST_STACK_POP: nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg); break; case OFPUTIL_NXAST_SAMPLE: parse_sample(ofpacts, arg); break; } }
int main(int argc, char **argv) { int ch, longindex, ret, port = SD_LISTEN_PORT, io_port = SD_LISTEN_PORT; int rc = 1; const char *dirp = DEFAULT_OBJECT_DIR, *short_options; char *dir, *pid_file = NULL, *bindaddr = NULL, log_path[PATH_MAX], *argp = NULL; bool explicit_addr = false; bool daemonize = true; int32_t nr_vnodes = -1; int64_t zone = -1; struct cluster_driver *cdrv; struct option *long_options; #ifdef HAVE_HTTP const char *http_options = NULL; #endif static struct logger_user_info sheep_info; struct stat logdir_st; enum log_dst_type log_dst_type; sys->cinfo.flags |= SD_CLUSTER_FLAG_AUTO_VNODES; sys->node_status = SD_NODE_STATUS_INITIALIZATION; sys->rthrottling.max_exec_count = 0; sys->rthrottling.queue_work_interval = 0; sys->rthrottling.throttling = false; install_crash_handler(crash_handler); signal(SIGPIPE, SIG_IGN); install_sighandler(SIGHUP, sighup_handler, false); long_options = build_long_options(sheep_options); short_options = build_short_options(sheep_options); while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { case 'p': port = str_to_u16(optarg); if (errno != 0 || port < 1) { sd_err("Invalid port number '%s'", optarg); exit(1); } break; case 'P': pid_file = optarg; break; #ifdef HAVE_HTTP case 'r': http_options = optarg; break; #endif case 'l': if (option_parse(optarg, ",", log_parsers) < 0) exit(1); break; case 'n': sys->nosync = true; break; case 'y': if (!str_to_addr(optarg, sys->this_node.nid.addr)) { sd_err("Invalid address: '%s'", optarg); exit(1); } explicit_addr = true; break; case 'D': sys->backend_dio = true; break; case 'f': daemonize = false; break; case 'g': if (nr_vnodes > 0) { sd_err("Options '-g' and '-V' can not be both specified"); exit(1); } nr_vnodes = 0; break; case 'z': zone = str_to_u32(optarg); if (errno != 0) { sd_err("Invalid zone id '%s': must be " "an integer between 0 and %u", optarg, UINT32_MAX); exit(1); } sys->this_node.zone = zone; break; case 'u': sys->upgrade = true; break; case 'c': sys->cdrv = find_cdrv(optarg); if (!sys->cdrv) { sd_err("Invalid cluster driver '%s'", optarg); fprintf(stderr, "Supported drivers:"); FOR_EACH_CLUSTER_DRIVER(cdrv) { fprintf(stderr, " %s", cdrv->name); } fprintf(stderr, "\n"); exit(1); } sys->cdrv_option = get_cdrv_option(sys->cdrv, optarg); break; case 'i': if (option_parse(optarg, ",", ionic_parsers) < 0) exit(1); if (!str_to_addr(io_addr, sys->this_node.nid.io_addr)) { sd_err("Bad addr: '%s'", io_addr); exit(1); } if (io_pt) if (sscanf(io_pt, "%u", &io_port) != 1) { sd_err("Bad port '%s'", io_pt); exit(1); } sys->this_node.nid.io_port = io_port; #ifdef HAVE_ACCELIO if (!strcmp(io_transport, "tcp")) sys->this_node.nid.io_transport_type = IO_TRANSPORT_TYPE_TCP; else if (!strcmp(io_transport, "rdma")) sys->this_node.nid.io_transport_type = IO_TRANSPORT_TYPE_RDMA; else { sd_err("unknown transport type: %s", io_transport); exit(1); } #endif break; case 'j': uatomic_set_true(&sys->use_journal); if (option_parse(optarg, ",", journal_parsers) < 0) exit(1); if (!jsize) { sd_err("you must specify size for journal"); exit(1); } break; case 'b': if (!inetaddr_is_valid(optarg)) exit(1); bindaddr = optarg; break; case 'h': usage(0); break; case 'R': if (option_parse(optarg, ",", recovery_parsers) < 0) exit(1); sys->rthrottling.max_exec_count = max_exec_count; sys->rthrottling.queue_work_interval = queue_work_interval; if (max_exec_count > 0 && queue_work_interval > 0) sys->rthrottling.throttling = true; break; case 'v': fprintf(stdout, "Sheepdog daemon version %s\n", PACKAGE_VERSION); exit(0); break; case 'V': sys->cinfo.flags &= ~SD_CLUSTER_FLAG_AUTO_VNODES; if (nr_vnodes == 0) { sd_err("Options '-g' and '-V' can not be both specified"); exit(1); } nr_vnodes = str_to_u16(optarg); if (errno != 0 || nr_vnodes < 1) { sd_err("Invalid number of vnodes '%s': must be " "an integer between 1 and %u", optarg, UINT16_MAX); exit(1); } break; case 'W': wildcard_recovery = true; break; case 'w': if (option_parse(optarg, ",", wq_parsers) < 0) exit(1); break; default: usage(1); break; } }
/* * PARSER. Field 2 in ARGP. */ static int parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; int error = 0; __u16 temp; switch (key) { case ARGP_POOL6: arguments->mode = MODE_POOL6; break; case ARGP_POOL4: arguments->mode = MODE_POOL4; break; case ARGP_BIB: arguments->mode = MODE_BIB; break; case ARGP_SESSION: arguments->mode = MODE_SESSION; break; case ARGP_FILTERING: arguments->mode = MODE_FILTERING; break; case ARGP_TRANSLATE: arguments->mode = MODE_TRANSLATE; break; case ARGP_DISPLAY: arguments->operation = OP_DISPLAY; break; case ARGP_ADD: arguments->operation = OP_ADD; break; case ARGP_REMOVE: arguments->operation = OP_REMOVE; break; case ARGP_UDP: arguments->udp = true; break; case ARGP_TCP: arguments->tcp = true; break; case ARGP_ICMP: arguments->icmp = true; break; case ARGP_ADDRESS: error = str_to_addr4(arg, &arguments->pool4_addr); arguments->pool4_addr_set = true; break; case ARGP_PREFIX: error = str_to_prefix(arg, &arguments->pool6_prefix); arguments->pool6_prefix_set = true; break; // case ARGP_STATIC: // arguments->static_entries = true; // break; // case ARGP_DYNAMIC: // arguments->dynamic_entries = true; // break; // // case ARGP_IPV6: // error = str_to_addr6_port(arg, &arguments->bib_addr6); // arguments->bib_addr6_set = true; // break; // case ARGP_IPV4: // error = str_to_addr4_port(arg, &arguments->bib_addr4); // arguments->bib_addr4_set = true; // break; case ARGP_REMOTE6: error = str_to_addr6_port(arg, &arguments->session_pair6.remote); arguments->session_pair6_remote_set = true; break; case ARGP_LOCAL6: error = str_to_addr6_port(arg, &arguments->session_pair6.local); arguments->session_pair6_local_set = true; break; case ARGP_LOCAL4: error = str_to_addr4_port(arg, &arguments->session_pair4.local); arguments->session_pair4_local_set = true; break; case ARGP_REMOTE4: error = str_to_addr4_port(arg, &arguments->session_pair4.remote); arguments->session_pair4_remote_set = true; break; case ARGP_DROP_ADDR: arguments->mode = MODE_FILTERING; arguments->operation |= DROP_BY_ADDR_MASK; error = str_to_bool(arg, &arguments->filtering.drop_by_addr); break; case ARGP_DROP_INFO: arguments->mode = MODE_FILTERING; arguments->operation |= DROP_ICMP6_INFO_MASK; error = str_to_bool(arg, &arguments->filtering.drop_icmp6_info); break; // case ARGP_DROP_TCP: // arguments->mode = MODE_FILTERING; // arguments->operation |= DROP_EXTERNAL_TCP_MASK; // error = str_to_bool(arg, &arguments->filtering.drop_external_tcp); // break; case ARGP_UDP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= UDP_TIMEOUT_MASK; error = str_to_u16(arg, &temp, UDP_MIN, 0xFFFF); arguments->filtering.to.udp = temp; break; case ARGP_ICMP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= ICMP_TIMEOUT_MASK; error = str_to_u16(arg, &temp, 0, 0xFFFF); arguments->filtering.to.icmp = temp; break; case ARGP_TCP_TO: arguments->mode = MODE_FILTERING; arguments->operation |= TCP_EST_TIMEOUT_MASK; error = str_to_u16(arg, &temp, TCP_EST, 0xFFFF); arguments->filtering.to.tcp_est = temp; break; case ARGP_TCP_TRANS_TO: arguments->mode = MODE_FILTERING; arguments->operation |= TCP_TRANS_TIMEOUT_MASK; error = str_to_u16(arg, &temp, TCP_TRANS, 0xFFFF); arguments->filtering.to.tcp_trans = temp; break; case ARGP_HEAD: arguments->mode = MODE_TRANSLATE; arguments->operation |= SKB_HEAD_ROOM_MASK; error = str_to_u16(arg, &arguments->translate.skb_head_room, 0, 0xFFFF); break; case ARGP_TAIL: arguments->mode = MODE_TRANSLATE; arguments->operation |= SKB_TAIL_ROOM_MASK; error = str_to_u16(arg, &arguments->translate.skb_tail_room, 0, 0xFFFF); break; case ARGP_RESET_TCLASS: arguments->mode = MODE_TRANSLATE; arguments->operation |= RESET_TCLASS_MASK; error = str_to_bool(arg, &arguments->translate.reset_traffic_class); break; case ARGP_RESET_TOS: arguments->mode = MODE_TRANSLATE; arguments->operation |= RESET_TOS_MASK; error = str_to_bool(arg, &arguments->translate.reset_tos); break; case ARGP_NEW_TOS: arguments->mode = MODE_TRANSLATE; arguments->operation |= NEW_TOS_MASK; error = str_to_u8(arg, &arguments->translate.new_tos, 0, 0xFF); break; case ARGP_DF: arguments->mode = MODE_TRANSLATE; arguments->operation |= DF_ALWAYS_ON_MASK; error = str_to_bool(arg, &arguments->translate.df_always_on); break; case ARGP_BUILD_ID: arguments->mode = MODE_TRANSLATE; arguments->operation |= BUILD_IPV4_ID_MASK; error = str_to_bool(arg, &arguments->translate.build_ipv4_id); break; case ARGP_LOWER_MTU_FAIL: arguments->mode = MODE_TRANSLATE; arguments->operation |= LOWER_MTU_FAIL_MASK; error = str_to_bool(arg, &arguments->translate.lower_mtu_fail); break; case ARGP_NEXT_MTU6: arguments->mode = MODE_TRANSLATE; arguments->operation |= IPV6_NEXTHOP_MTU_MASK; error = str_to_u16(arg, &arguments->translate.ipv6_nexthop_mtu, 0, 0xFFFF); break; case ARGP_NEXT_MTU4: arguments->mode = MODE_TRANSLATE; arguments->operation |= IPV4_NEXTHOP_MTU_MASK; error = str_to_u16(arg, &arguments->translate.ipv4_nexthop_mtu, 0, 0xFFFF); break; case ARGP_PLATEAUS: arguments->mode = MODE_TRANSLATE; arguments->operation |= MTU_PLATEAUS_MASK; error = str_to_u16_array(arg, &arguments->translate.mtu_plateaus, &arguments->translate.mtu_plateau_count); break; default: return ARGP_ERR_UNKNOWN; } return error; }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man * page) into 'fm' for sending the specified flow_mod 'command' to a switch. * If 'actions' is specified, an action must be in 'string' and may be expanded * or reallocated. * * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_* * constant for 'command'. To parse syntax for an OFPST_FLOW or * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */ void parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, bool verbose) { enum { F_OUT_PORT = 1 << 0, F_ACTIONS = 1 << 1, F_TIMEOUT = 1 << 3, F_PRIORITY = 1 << 4 } fields; char *string = xstrdup(str_); char *save_ptr = NULL; char *act_str = NULL; char *name; switch (command) { case -1: fields = F_OUT_PORT; break; case OFPFC_ADD: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY; break; case OFPFC_DELETE: fields = F_OUT_PORT; break; case OFPFC_DELETE_STRICT: fields = F_OUT_PORT | F_PRIORITY; break; case OFPFC_MODIFY: fields = F_ACTIONS; break; case OFPFC_MODIFY_STRICT: fields = F_ACTIONS | F_PRIORITY; break; default: NOT_REACHED(); } cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY); fm->cookie = htonll(0); fm->cookie_mask = htonll(0); if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) { /* For modify, by default, don't update the cookie. */ fm->new_cookie = htonll(UINT64_MAX); } else{ fm->new_cookie = htonll(0); } fm->table_id = 0xff; fm->command = command; fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } act_str++; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (parse_protocol(name, &p)) { cls_rule_set_dl_type(&fm->cr, htons(p->dl_type)); if (p->nw_proto) { cls_rule_set_nw_proto(&fm->cr, p->nw_proto); } } else { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "table")) { 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 = 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")) { fm->hard_timeout = str_to_u16(value, name); } else if (!strcmp(name, "cookie")) { char *mask = strchr(value, '/'); if (mask) { /* A mask means we're searching for a cookie. */ if (command == OFPFC_ADD) { ofp_fatal(str_, verbose, "flow additions cannot use " "a cookie mask"); } *mask = '\0'; fm->cookie = htonll(str_to_u64(value)); fm->cookie_mask = htonll(str_to_u64(mask+1)); } else { /* No mask means that the cookie is being set. */ if (command != OFPFC_ADD && command != OFPFC_MODIFY && command != OFPFC_MODIFY_STRICT) { ofp_fatal(str_, verbose, "cannot set cookie"); } fm->new_cookie = htonll(str_to_u64(value)); } } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fm->cr); } 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 { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX) && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) { /* On modifies without a mask, we are supposed to add a flow if * one does not exist. If a cookie wasn't been specified, use a * default of zero. */ fm->new_cookie = htonll(0); } 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); }