X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=ffdccda43ef1f0d5f7de19dbbe0fc6641137ae34;hb=541bc79f73add327072470c9bc3febb4195cdb3c;hp=2565ec7fffa06c671d21bb043a4e7f922b59f89b;hpb=816fd533f85923c03cf8d9d6450bd9a0845d5160;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 2565ec7f..ffdccda4 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -78,9 +78,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) WC_INVARIANT_BIT(DL_SRC) \ WC_INVARIANT_BIT(DL_DST) \ WC_INVARIANT_BIT(DL_TYPE) \ - WC_INVARIANT_BIT(NW_PROTO) \ - WC_INVARIANT_BIT(TP_SRC) \ - WC_INVARIANT_BIT(TP_DST) + WC_INVARIANT_BIT(NW_PROTO) /* Verify that all of the invariant bits (as defined on WC_INVARIANT_LIST) * actually have the same names and values. */ @@ -102,7 +100,7 @@ static const flow_wildcards_t WC_INVARIANTS = 0 void ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); /* Initialize most of rule->wc. */ flow_wildcards_init_catchall(wc); @@ -121,6 +119,13 @@ ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc) wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_SRC_SHIFT); wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT); + if (!(ofpfw & OFPFW_TP_SRC)) { + wc->tp_src_mask = htons(UINT16_MAX); + } + if (!(ofpfw & OFPFW_TP_DST)) { + wc->tp_dst_mask = htons(UINT16_MAX); + } + if (ofpfw & OFPFW_DL_DST) { /* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but * Open vSwitch breaks the Ethernet destination into bits as FWW_DL_DST @@ -200,6 +205,12 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, struct ofp_match *match) if (wc->wildcards & FWW_NW_DSCP) { ofpfw |= OFPFW_NW_TOS; } + if (!wc->tp_src_mask) { + ofpfw |= OFPFW_TP_SRC; + } + if (!wc->tp_dst_mask) { + ofpfw |= OFPFW_TP_DST; + } /* Translate VLANs. */ match->dl_vlan = htons(0); @@ -385,6 +396,14 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length, { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION, NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID", sizeof(struct nx_flow_mod_table_id), 0 }, + + { OFPUTIL_NXT_FLOW_AGE, OFP10_VERSION, + NXT_FLOW_AGE, "NXT_FLOW_AGE", + sizeof(struct nicira_header), 0 }, + + { OFPUTIL_NXT_SET_ASYNC_CONFIG, OFP10_VERSION, + NXT_SET_ASYNC_CONFIG, "NXT_SET_ASYNC_CONFIG", + sizeof(struct nx_async_config), 0 }, }; static const struct ofputil_msg_category nxt_category = { @@ -905,7 +924,7 @@ ofputil_min_flow_format(const struct cls_rule *rule) { const struct flow_wildcards *wc = &rule->wc; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); /* Only NXM supports separately wildcards the Ethernet multicast bit. */ if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) { @@ -953,6 +972,12 @@ ofputil_min_flow_format(const struct cls_rule *rule) return NXFF_NXM; } + /* Only NXM supports bitwise matching on transport port. */ + if ((wc->tp_src_mask && wc->tp_src_mask != htons(UINT16_MAX)) || + (wc->tp_dst_mask && wc->tp_dst_mask != htons(UINT16_MAX))) { + return NXFF_NXM; + } + /* Other formats can express this rule. */ return NXFF_OPENFLOW10; } @@ -1290,11 +1315,18 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, * iterates through the replies. The caller must initially leave 'msg''s layer * pointers null and not modify them between calls. * + * Most switches don't send the values needed to populate fs->idle_age and + * fs->hard_age, so those members will usually be set to 0. If the switch from + * which 'msg' originated is known to implement NXT_FLOW_AGE, then pass + * 'flow_age_extension' as true so that the contents of 'msg' determine the + * 'idle_age' and 'hard_age' members in 'fs'. + * * Returns 0 if successful, EOF if no replies were left in this 'msg', * otherwise a positive errno value. */ int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, - struct ofpbuf *msg) + struct ofpbuf *msg, + bool flow_age_extension) { const struct ofputil_msg_type *type; int code; @@ -1345,6 +1377,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, fs->duration_nsec = ntohl(ofs->duration_nsec); fs->idle_timeout = ntohs(ofs->idle_timeout); fs->hard_timeout = ntohs(ofs->hard_timeout); + fs->idle_age = -1; + fs->hard_age = -1; fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count)); fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count)); } else if (code == OFPUTIL_NXST_FLOW_REPLY) { @@ -1382,6 +1416,16 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, fs->duration_nsec = ntohl(nfs->duration_nsec); fs->idle_timeout = ntohs(nfs->idle_timeout); fs->hard_timeout = ntohs(nfs->hard_timeout); + fs->idle_age = -1; + fs->hard_age = -1; + if (flow_age_extension) { + if (nfs->idle_age) { + fs->idle_age = ntohs(nfs->idle_age) - 1; + } + if (nfs->hard_age) { + fs->hard_age = ntohs(nfs->hard_age) - 1; + } + } fs->packet_count = ntohll(nfs->packet_count); fs->byte_count = ntohll(nfs->byte_count); } else { @@ -1450,8 +1494,13 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, nfs->priority = htons(fs->rule.priority); nfs->idle_timeout = htons(fs->idle_timeout); nfs->hard_timeout = htons(fs->hard_timeout); + nfs->idle_age = htons(fs->idle_age < 0 ? 0 + : fs->idle_age < UINT16_MAX ? fs->idle_age + 1 + : UINT16_MAX); + nfs->hard_age = htons(fs->hard_age < 0 ? 0 + : fs->hard_age < UINT16_MAX ? fs->hard_age + 1 + : UINT16_MAX); nfs->match_len = htons(nx_put_match(msg, &fs->rule, 0, 0)); - memset(nfs->pad2, 0, sizeof nfs->pad2); nfs->cookie = fs->cookie; nfs->packet_count = htonll(fs->packet_count); nfs->byte_count = htonll(fs->byte_count); @@ -1735,6 +1784,70 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, return packet; } +enum ofperr +ofputil_decode_packet_out(struct ofputil_packet_out *po, + const struct ofp_packet_out *opo) +{ + enum ofperr error; + struct ofpbuf b; + + po->buffer_id = ntohl(opo->buffer_id); + po->in_port = ntohs(opo->in_port); + if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL + && po->in_port != OFPP_NONE) { + VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out has bad input port %#"PRIx16, + po->in_port); + return OFPERR_NXBRC_BAD_IN_PORT; + } + + ofpbuf_use_const(&b, opo, ntohs(opo->header.length)); + ofpbuf_pull(&b, sizeof *opo); + + error = ofputil_pull_actions(&b, ntohs(opo->actions_len), + &po->actions, &po->n_actions); + if (error) { + return error; + } + + if (po->buffer_id == UINT32_MAX) { + po->packet = b.data; + po->packet_len = b.size; + } else { + po->packet = NULL; + po->packet_len = 0; + } + + return 0; +} + +struct ofpbuf * +ofputil_encode_packet_out(const struct ofputil_packet_out *po) +{ + struct ofp_packet_out *opo; + size_t actions_len; + struct ofpbuf *msg; + size_t size; + + actions_len = po->n_actions * sizeof *po->actions; + size = sizeof *opo + actions_len; + if (po->buffer_id == UINT32_MAX) { + size += po->packet_len; + } + + msg = ofpbuf_new(size); + opo = put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg); + opo->buffer_id = htonl(po->buffer_id); + opo->in_port = htons(po->in_port); + opo->actions_len = htons(actions_len); + ofpbuf_put(msg, po->actions, actions_len); + if (po->buffer_id == UINT32_MAX) { + ofpbuf_put(msg, po->packet, po->packet_len); + } + update_openflow_length(msg); + + return msg; +} + /* Returns a string representing the message type of 'type'. The string is the * enumeration constant for the type, e.g. "OFPT_HELLO". For statistics * messages, the constant is followed by "request" or "reply", @@ -2113,59 +2226,6 @@ make_packet_in(uint32_t buffer_id, uint16_t in_port, uint8_t reason, return buf; } -struct ofpbuf * -make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, - uint16_t in_port, - const struct ofp_action_header *actions, size_t n_actions) -{ - size_t actions_len = n_actions * sizeof *actions; - struct ofp_packet_out *opo; - size_t size = sizeof *opo + actions_len + (packet ? packet->size : 0); - struct ofpbuf *out = ofpbuf_new(size); - - opo = ofpbuf_put_uninit(out, sizeof *opo); - opo->header.version = OFP_VERSION; - opo->header.type = OFPT_PACKET_OUT; - opo->header.length = htons(size); - opo->header.xid = htonl(0); - opo->buffer_id = htonl(buffer_id); - opo->in_port = htons(in_port); - opo->actions_len = htons(actions_len); - ofpbuf_put(out, actions, actions_len); - if (packet) { - ofpbuf_put(out, packet->data, packet->size); - } - return out; -} - -struct ofpbuf * -make_unbuffered_packet_out(const struct ofpbuf *packet, - uint16_t in_port, uint16_t out_port) -{ - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htons(out_port); - return make_packet_out(packet, UINT32_MAX, in_port, - (struct ofp_action_header *) &action, 1); -} - -struct ofpbuf * -make_buffered_packet_out(uint32_t buffer_id, - uint16_t in_port, uint16_t out_port) -{ - if (out_port != OFPP_NONE) { - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htons(out_port); - return make_packet_out(NULL, buffer_id, in_port, - (struct ofp_action_header *) &action, 1); - } else { - return make_packet_out(NULL, buffer_id, in_port, NULL, 0); - } -} - /* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */ struct ofpbuf * make_echo_request(void) @@ -2192,6 +2252,15 @@ make_echo_reply(const struct ofp_header *rq) return out; } +struct ofpbuf * +ofputil_encode_barrier_request(void) +{ + struct ofpbuf *msg; + + make_openflow(sizeof(struct ofp_header), OFPT_BARRIER_REQUEST, &msg); + return msg; +} + const char * ofputil_frag_handling_to_string(enum ofp_config_flags flags) { @@ -2439,6 +2508,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions, case OFPUTIL_NXAST_SET_TUNNEL64: case OFPUTIL_NXAST_EXIT: case OFPUTIL_NXAST_DEC_TTL: + case OFPUTIL_NXAST_FIN_TIMEOUT: break; } @@ -2735,7 +2805,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format) wc.nw_src_mask = wc.nw_dst_mask = htonl(0); } if (!(may_match & MAY_TP_ADDR)) { - wc.wildcards |= FWW_TP_SRC | FWW_TP_DST; + wc.tp_src_mask = wc.tp_dst_mask = htons(0); } if (!(may_match & MAY_NW_PROTO)) { wc.wildcards |= FWW_NW_PROTO;