From: Ben Pfaff Date: Mon, 2 Mar 2009 19:12:06 +0000 (-0800) Subject: vconn: New functions for validating and iterating over OpenFlow actions. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3c0b54cfa0aaea043b9f213bae0ffa357b3bb90;p=openvswitch vconn: New functions for validating and iterating over OpenFlow actions. --- diff --git a/lib/vconn.c b/lib/vconn.c index c7342d24..cf527ddf 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -44,7 +44,9 @@ #include "flow.h" #include "ofp-print.h" #include "ofpbuf.h" +#include "openflow/nicira-ext.h" #include "openflow/openflow.h" +#include "packets.h" #include "poll-loop.h" #include "random.h" #include "util.h" @@ -1177,6 +1179,173 @@ flow_stats_next(struct flow_stats_iterator *iter) return fs; } +/* Alignment of ofp_actions. */ +#define ACTION_ALIGNMENT 8 + +static int +check_action_exact_len(const union ofp_action *a, unsigned int len, + unsigned int required_len) +{ + if (len != required_len) { + VLOG_DBG_RL(&bad_ofmsg_rl, + "action %u has invalid length %"PRIu16" (must be %u)\n", + a->type, ntohs(a->header.len), required_len); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + return 0; +} + +static int +check_action_port(int port) +{ + switch (port) { + case OFPP_IN_PORT: + case OFPP_FLOOD: + case OFPP_ALL: + case OFPP_CONTROLLER: + case OFPP_LOCAL: + return 0; + + case OFPP_TABLE: + case OFPP_NORMAL: + VLOG_WARN_RL(&bad_ofmsg_rl, "port %x not yet implemented", port); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + + default: + if (port >= 0 && port < OFPP_MAX) { + return 0; + } + VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + } +} + +static int +check_nicira_action(const union ofp_action *a, unsigned int len) +{ + const struct nx_action_header *nah; + int error; + + if (len < 16) { + VLOG_DBG_RL(&bad_ofmsg_rl, + "Nicira vendor action only %u bytes", len); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + nah = (const struct nx_action_header *) a; + + switch (ntohs(nah->subtype)) { + case NXAST_SNAT: + error = check_action_exact_len(a, len, 16); + if (error) { + return error; + } + return check_action_port(ntohs(((struct nx_action_snat *) nah)->port)); + default: + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); + } +} + +static int +check_action(const union ofp_action *a, unsigned int len) +{ + int error; + + switch (a->type) { + case OFPAT_OUTPUT: + error = check_action_port(ntohs(a->output.port)); + if (error) { + return error; + } + return check_action_exact_len(a, len, 8); + + case OFPAT_SET_VLAN_VID: + case OFPAT_SET_VLAN_PCP: + case OFPAT_STRIP_VLAN: + case OFPAT_SET_NW_SRC: + case OFPAT_SET_NW_DST: + case OFPAT_SET_TP_SRC: + case OFPAT_SET_TP_DST: + return check_action_exact_len(a, len, 8); + + case OFPAT_SET_DL_SRC: + case OFPAT_SET_DL_DST: + return check_action_exact_len(a, len, 16); + + case OFPAT_VENDOR: + if (a->vendor.vendor == htonl(NX_VENDOR_ID)) { + return check_nicira_action(a, len); + } else { + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR); + } + break; + + default: + VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16, a->type); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); + } + + if (!len) { + VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0"); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + if (len % ACTION_ALIGNMENT) { + VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple of %d", + len, ACTION_ALIGNMENT); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + return 0; +} + +int +validate_actions(const union ofp_action *actions, size_t n_actions) +{ + const union ofp_action *a; + + for (a = actions; a < &actions[n_actions]; ) { + unsigned int len = ntohs(a->header.len); + unsigned int n_slots = len / ACTION_ALIGNMENT; + unsigned int slots_left = &actions[n_actions] - a; + int error; + + if (n_slots > slots_left) { + VLOG_DBG_RL(&bad_ofmsg_rl, + "action requires %u slots but only %td remain", + n_slots, slots_left); + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + } + error = check_action(a, len); + if (error) { + return error; + } + a += n_slots; + } + return 0; +} + +/* The set of actions must either come from a trusted source or have been + * previously validated with validate_actions(). */ +const union ofp_action * +actions_first(struct actions_iterator *iter, + const union ofp_action *oa, size_t n_actions) +{ + iter->pos = oa; + iter->end = oa + n_actions; + return actions_next(iter); +} + +const union ofp_action * +actions_next(struct actions_iterator *iter) +{ + if (iter->pos < iter->end) { + const union ofp_action *a = iter->pos; + unsigned int len = ntohs(a->header.len); + iter->pos += len / ACTION_ALIGNMENT; + return a; + } else { + return NULL; + } +} + void vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status, uint32_t ip, const char *name, bool reconnectable) diff --git a/lib/vconn.h b/lib/vconn.h index d521a8be..3c7a9a4a 100644 --- a/lib/vconn.h +++ b/lib/vconn.h @@ -34,6 +34,7 @@ #ifndef VCONN_H #define VCONN_H 1 +#include #include #include #include @@ -120,4 +121,20 @@ const struct ofp_flow_stats *flow_stats_first(struct flow_stats_iterator *, const struct ofp_stats_reply *); const struct ofp_flow_stats *flow_stats_next(struct flow_stats_iterator *); +struct actions_iterator { + const union ofp_action *pos, *end; +}; +const union ofp_action *actions_first(struct actions_iterator *, + const union ofp_action *, + size_t n_actions); +const union ofp_action *actions_next(struct actions_iterator *); +int validate_actions(const union ofp_action *, size_t n_actions); + +static inline int +ofp_mkerr(uint16_t type, uint16_t code) +{ + assert(type > 0 && type <= 0x7fff); + return (type << 16) | code; +} + #endif /* vconn.h */ diff --git a/udatapath/datapath.c b/udatapath/datapath.c index d46fd128..e5e11d54 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -928,7 +928,7 @@ recv_packet_out(struct datapath *dp, const struct sender *sender, flow_extract(buffer, ntohs(opo->in_port), &key.flow); - v_code = validate_actions(dp, &key, opo->actions, actions_len); + v_code = dp_validate_actions(dp, &key, opo->actions, actions_len); if (v_code != ACT_VALIDATION_OK) { dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, msg, ntohs(opo->header.length)); @@ -971,7 +971,7 @@ add_flow(struct datapath *dp, const struct sender *sender, flow_extract_match(&flow->key, &ofm->match); - v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); + v_code = dp_validate_actions(dp, &flow->key, ofm->actions, actions_len); if (v_code != ACT_VALIDATION_OK) { dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, ofm, ntohs(ofm->header.length)); @@ -1038,7 +1038,7 @@ mod_flow(struct datapath *dp, const struct sender *sender, actions_len = ntohs(ofm->header.length) - sizeof *ofm; - v_code = validate_actions(dp, &key, ofm->actions, actions_len); + v_code = dp_validate_actions(dp, &key, ofm->actions, actions_len); if (v_code != ACT_VALIDATION_OK) { dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, ofm, ntohs(ofm->header.length)); diff --git a/udatapath/dp_act.c b/udatapath/dp_act.c index 8f7f9b63..2b2115eb 100644 --- a/udatapath/dp_act.c +++ b/udatapath/dp_act.c @@ -347,7 +347,7 @@ validate_vendor(struct datapath *dp, const struct sw_flow_key *key, * OFPET_BAD_ACTION error type is returned. If the action list validates, * ACT_VALIDATION_OK is returned. */ uint16_t -validate_actions(struct datapath *dp, const struct sw_flow_key *key, +dp_validate_actions(struct datapath *dp, const struct sw_flow_key *key, const struct ofp_action_header *actions, size_t actions_len) { uint8_t *p = (uint8_t *)actions; diff --git a/udatapath/dp_act.h b/udatapath/dp_act.h index e0181fad..daa8b270 100644 --- a/udatapath/dp_act.h +++ b/udatapath/dp_act.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -40,7 +40,7 @@ #define ACT_VALIDATION_OK ((uint16_t)-1) -uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, +uint16_t dp_validate_actions(struct datapath *, const struct sw_flow_key *, const struct ofp_action_header *, size_t); void execute_actions(struct datapath *, struct ofpbuf *, struct sw_flow_key *, const struct ofp_action_header *,