-
-static uint32_t
-str_to_u32(const char *str)
-{
- char *tail;
- uint32_t value;
-
- errno = 0;
- value = strtoul(str, &tail, 0);
- if (errno == EINVAL || errno == ERANGE || *tail) {
- ovs_fatal(0, "invalid numeric format %s", str);
- }
- return value;
-}
-
-static void
-str_to_mac(const char *str, uint8_t mac[6])
-{
- if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
- != ETH_ADDR_SCAN_COUNT) {
- ovs_fatal(0, "invalid mac address %s", str);
- }
-}
-
-static uint32_t
-str_to_ip(const char *str_, uint32_t *ip)
-{
- char *str = xstrdup(str_);
- char *save_ptr = NULL;
- const char *name, *netmask;
- struct in_addr in_addr;
- int n_wild, retval;
-
- name = strtok_r(str, "/", &save_ptr);
- retval = name ? lookup_ip(name, &in_addr) : EINVAL;
- if (retval) {
- ovs_fatal(0, "%s: could not convert to IP address", str);
- }
- *ip = in_addr.s_addr;
-
- netmask = strtok_r(NULL, "/", &save_ptr);
- if (netmask) {
- uint8_t o[4];
- if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
- &o[0], &o[1], &o[2], &o[3]) == 4) {
- uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
- int i;
-
- /* Find first 1-bit. */
- for (i = 0; i < 32; i++) {
- if (nm & (1u << i)) {
- break;
- }
- }
- n_wild = i;
-
- /* Verify that the rest of the bits are 1-bits. */
- for (; i < 32; i++) {
- if (!(nm & (1u << i))) {
- ovs_fatal(0, "%s: %s is not a valid netmask",
- str, netmask);
- }
- }
- } else {
- int prefix = atoi(netmask);
- if (prefix <= 0 || prefix > 32) {
- ovs_fatal(0, "%s: network prefix bits not between 1 and 32",
- str);
- }
- n_wild = 32 - prefix;
- }
- } else {
- n_wild = 0;
- }
-
- free(str);
- return n_wild;
-}
-
-static void *
-put_action(struct ofpbuf *b, size_t size, uint16_t type)
-{
- struct ofp_action_header *ah = ofpbuf_put_zeros(b, size);
- ah->type = htons(type);
- ah->len = htons(size);
- return ah;
-}
-
-static struct ofp_action_output *
-put_output_action(struct ofpbuf *b, uint16_t port)
-{
- struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT);
- oao->port = htons(port);
- return oao;
-}
-
-static void
-put_dl_addr_action(struct ofpbuf *b, uint16_t type, const char *addr)
-{
- struct ofp_action_dl_addr *oada = put_action(b, sizeof *oada, type);
- str_to_mac(addr, oada->dl_addr);
-}
-
-
-static bool
-parse_port_name(const char *name, uint16_t *port)
-{
- struct pair {
- const char *name;
- uint16_t value;
- };
- static const struct pair pairs[] = {
-#define DEF_PAIR(NAME) {#NAME, OFPP_##NAME}
- DEF_PAIR(IN_PORT),
- DEF_PAIR(TABLE),
- DEF_PAIR(NORMAL),
- DEF_PAIR(FLOOD),
- DEF_PAIR(ALL),
- DEF_PAIR(CONTROLLER),
- DEF_PAIR(LOCAL),
- DEF_PAIR(NONE),
-#undef DEF_PAIR
- };
- static const int n_pairs = ARRAY_SIZE(pairs);
- size_t i;
-
- for (i = 0; i < n_pairs; i++) {
- if (!strcasecmp(name, pairs[i].name)) {
- *port = pairs[i].value;
- return true;
- }
- }
- return false;
-}
-
-static void
-str_to_action(char *str, struct ofpbuf *b)
-{
- char *act, *arg;
- char *saveptr = NULL;
- bool drop = false;
- int n_actions;
-
- for (act = strtok_r(str, ", \t\r\n", &saveptr), n_actions = 0; act;
- act = strtok_r(NULL, ", \t\r\n", &saveptr), n_actions++)
- {
- uint16_t port;
-
- if (drop) {
- ovs_fatal(0, "Drop actions must not be followed by other actions");
- }
-
- /* Arguments are separated by colons */
- arg = strchr(act, ':');
- if (arg) {
- *arg = '\0';
- arg++;
- }
-
- if (!strcasecmp(act, "mod_vlan_vid")) {
- struct ofp_action_vlan_vid *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID);
- va->vlan_vid = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "mod_vlan_pcp")) {
- struct ofp_action_vlan_pcp *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP);
- va->vlan_pcp = str_to_u32(arg);
- } else if (!strcasecmp(act, "strip_vlan")) {
- struct ofp_action_header *ah;
- ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN);
- ah->type = htons(OFPAT_STRIP_VLAN);
- } else if (!strcasecmp(act, "mod_dl_src")) {
- put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
- } else if (!strcasecmp(act, "mod_dl_dst")) {
- put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
- } else if (!strcasecmp(act, "mod_nw_src")) {
- struct ofp_action_nw_addr *na;
- na = put_action(b, sizeof *na, OFPAT_SET_NW_SRC);
- str_to_ip(arg, &na->nw_addr);
- } else if (!strcasecmp(act, "mod_nw_dst")) {
- struct ofp_action_nw_addr *na;
- na = put_action(b, sizeof *na, OFPAT_SET_NW_DST);
- str_to_ip(arg, &na->nw_addr);
- } else if (!strcasecmp(act, "mod_tp_src")) {
- struct ofp_action_tp_port *ta;
- ta = put_action(b, sizeof *ta, OFPAT_SET_TP_SRC);
- ta->tp_port = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "mod_tp_dst")) {
- struct ofp_action_tp_port *ta;
- ta = put_action(b, sizeof *ta, OFPAT_SET_TP_DST);
- ta->tp_port = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "output")) {
- put_output_action(b, str_to_u32(arg));
- } else if (!strcasecmp(act, "drop")) {
- /* A drop action in OpenFlow occurs by just not setting
- * an action. */
- drop = true;
- if (n_actions) {
- ovs_fatal(0, "Drop actions must not be preceded by other "
- "actions");
- }
- } 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 && (strspn(arg, "0123456789") == strlen(arg))) {
- oao->max_len = htons(str_to_u32(arg));
- } else {
- oao->max_len = htons(UINT16_MAX);
- }
- } else if (parse_port_name(act, &port)) {
- put_output_action(b, port);
- } else if (strspn(act, "0123456789") == strlen(act)) {
- put_output_action(b, str_to_u32(act));
- } else {
- ovs_fatal(0, "Unknown action: %s", act);
- }
- }
-}
-
-struct protocol {
- const char *name;
- uint16_t dl_type;
- uint8_t nw_proto;
-};
-
-static bool
-parse_protocol(const char *name, const struct protocol **p_out)