- switch (ntohs(a->type)) {
- case OFPAT_OUTPUT:
- {
- uint16_t port = ntohs(a->arg.output.port);
- if (port < OFPP_MAX) {
- ds_put_format(string, "output:%"PRIu16, port);
- } else {
- ofp_print_port_name(string, port);
- if (port == OFPP_CONTROLLER) {
- if (a->arg.output.max_len) {
- ds_put_format(string, ":%"PRIu16,
- ntohs(a->arg.output.max_len));
- } else {
- ds_put_cstr(string, ":all");
- }
+ uint16_t type;
+ size_t len;
+
+ struct openflow_action {
+ size_t min_size;
+ size_t max_size;
+ };
+
+ const struct openflow_action of_actions[] = {
+ [OFPAT_OUTPUT] = {
+ sizeof(struct ofp_action_output),
+ sizeof(struct ofp_action_output),
+ },
+ [OFPAT_SET_VLAN_VID] = {
+ sizeof(struct ofp_action_vlan_vid),
+ sizeof(struct ofp_action_vlan_vid),
+ },
+ [OFPAT_SET_VLAN_PCP] = {
+ sizeof(struct ofp_action_vlan_pcp),
+ sizeof(struct ofp_action_vlan_pcp),
+ },
+ [OFPAT_STRIP_VLAN] = {
+ sizeof(struct ofp_action_header),
+ sizeof(struct ofp_action_header),
+ },
+ [OFPAT_SET_DL_SRC] = {
+ sizeof(struct ofp_action_dl_addr),
+ sizeof(struct ofp_action_dl_addr),
+ },
+ [OFPAT_SET_DL_DST] = {
+ sizeof(struct ofp_action_dl_addr),
+ sizeof(struct ofp_action_dl_addr),
+ },
+ [OFPAT_SET_NW_SRC] = {
+ sizeof(struct ofp_action_nw_addr),
+ sizeof(struct ofp_action_nw_addr),
+ },
+ [OFPAT_SET_NW_DST] = {
+ sizeof(struct ofp_action_nw_addr),
+ sizeof(struct ofp_action_nw_addr),
+ },
+ [OFPAT_SET_TP_SRC] = {
+ sizeof(struct ofp_action_tp_port),
+ sizeof(struct ofp_action_tp_port),
+ },
+ [OFPAT_SET_TP_DST] = {
+ sizeof(struct ofp_action_tp_port),
+ sizeof(struct ofp_action_tp_port),
+ }
+ /* OFPAT_VENDOR is not here, since it would blow up the array size. */
+ };
+
+ if (actions_len < sizeof *ah) {
+ ds_put_format(string, "***action array too short for next action***\n");
+ return -1;
+ }
+
+ type = ntohs(ah->type);
+ len = ntohs(ah->len);
+ if (actions_len < len) {
+ ds_put_format(string, "***truncated action %"PRIu16"***\n", type);
+ return -1;
+ }
+
+ if ((len % 8) != 0) {
+ ds_put_format(string,
+ "***action %"PRIu16" length not a multiple of 8***\n",
+ type);
+ return -1;
+ }
+
+ if (type < ARRAY_SIZE(of_actions)) {
+ const struct openflow_action *act = &of_actions[type];
+ if ((len < act->min_size) || (len > act->max_size)) {
+ ds_put_format(string,
+ "***action %"PRIu16" wrong length: %"PRIu16"***\n",
+ type, len);
+ return -1;
+ }
+ }
+
+ switch (type) {
+ case OFPAT_OUTPUT: {
+ struct ofp_action_output *oa = (struct ofp_action_output *)ah;
+ uint16_t port = ntohs(oa->port);
+ if (port < OFPP_MAX) {
+ ds_put_format(string, "output:%"PRIu16, port);
+ } else {
+ ofp_print_port_name(string, port);
+ if (port == OFPP_CONTROLLER) {
+ if (oa->max_len) {
+ ds_put_format(string, ":%"PRIu16, ntohs(oa->max_len));
+ } else {
+ ds_put_cstr(string, ":all");