X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=faa0687c81461e86611a07de1eb2f2b8d1e8094c;hb=e878338bf1409f0dd6d23cb57822a2c4c1a69e0f;hp=834bb622fb7c0c723660567b1a9c8256f3ecc327;hpb=d01c980ffe0d61497298a9f907ff93fe1751e2bd;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 834bb622..faa0687c 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -104,15 +104,14 @@ static const flow_wildcards_t WC_INVARIANTS = 0 void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 14); /* Initialize most of rule->wc. */ flow_wildcards_init_catchall(wc); wc->wildcards = (OVS_FORCE flow_wildcards_t) ofpfw & WC_INVARIANTS; /* Wildcard fields that aren't defined by ofp10_match or tun_id. */ - wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_NW_ECN | FWW_NW_TTL - | FWW_IPV6_LABEL); + wc->wildcards |= FWW_NW_ECN | FWW_NW_TTL; if (ofpfw & OFPFW10_NW_TOS) { /* OpenFlow 1.0 defines a TOS wildcard, but it's much later in @@ -171,7 +170,8 @@ ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *match, rule->flow.nw_proto = match->nw_proto; /* Translate VLANs. */ - if (!(ofpfw & OFPFW10_DL_VLAN) && match->dl_vlan == htons(OFP_VLAN_NONE)) { + if (!(ofpfw & OFPFW10_DL_VLAN) && + match->dl_vlan == htons(OFP10_VLAN_NONE)) { /* Match only packets without 802.1Q header. * * When OFPFW10_DL_VLAN_PCP is wildcarded, this is obviously correct. @@ -232,7 +232,8 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule, ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP; } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI) && !(rule->flow.vlan_tci & htons(VLAN_CFI))) { - match->dl_vlan = htons(OFP_VLAN_NONE); + match->dl_vlan = htons(OFP10_VLAN_NONE); + ofpfw |= OFPFW10_DL_VLAN_PCP; } else { if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) { ofpfw |= OFPFW10_DL_VLAN; @@ -677,6 +678,18 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length, { OFPUTIL_NXT_SET_CONTROLLER_ID, OFP10_VERSION, NXT_SET_CONTROLLER_ID, "NXT_SET_CONTROLLER_ID", sizeof(struct nx_controller_id), 0 }, + + { OFPUTIL_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, + NXT_FLOW_MONITOR_CANCEL, "NXT_FLOW_MONITOR_CANCEL", + sizeof(struct nx_flow_monitor_cancel), 0 }, + + { OFPUTIL_NXT_FLOW_MONITOR_PAUSED, OFP10_VERSION, + NXT_FLOW_MONITOR_PAUSED, "NXT_FLOW_MONITOR_PAUSED", + sizeof(struct nicira_header), 0 }, + + { OFPUTIL_NXT_FLOW_MONITOR_RESUMED, OFP10_VERSION, + NXT_FLOW_MONITOR_RESUMED, "NXT_FLOW_MONITOR_RESUMED", + sizeof(struct nicira_header), 0 }, }; static const struct ofputil_msg_category nxt_category = { @@ -759,6 +772,10 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length, { OFPUTIL_NXST_AGGREGATE_REQUEST, OFP10_VERSION, NXST_AGGREGATE, "NXST_AGGREGATE request", sizeof(struct nx_aggregate_stats_request), 8 }, + + { OFPUTIL_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, + NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR request", + sizeof(struct nicira_stats_msg), 8 }, }; static const struct ofputil_msg_category nxst_request_category = { @@ -792,6 +809,10 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length, { OFPUTIL_NXST_AGGREGATE_REPLY, OFP10_VERSION, NXST_AGGREGATE, "NXST_AGGREGATE reply", sizeof(struct nx_aggregate_stats_reply), 0 }, + + { OFPUTIL_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION, + NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR reply", + sizeof(struct nicira_stats_msg), 8 }, }; static const struct ofputil_msg_category nxst_reply_category = { @@ -1442,7 +1463,7 @@ ofputil_usable_protocols(const struct cls_rule *rule) { const struct flow_wildcards *wc = &rule->wc; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 14); /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */ if (!eth_mask_is_exact(wc->dl_src_mask) @@ -1460,7 +1481,8 @@ ofputil_usable_protocols(const struct cls_rule *rule) } /* Only NXM supports matching ARP hardware addresses. */ - if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) { + if (!eth_addr_is_zero(wc->arp_sha_mask) || + !eth_addr_is_zero(wc->arp_tha_mask)) { return OFPUTIL_P_NXM_ANY; } @@ -1486,7 +1508,7 @@ ofputil_usable_protocols(const struct cls_rule *rule) } /* Only NXM supports matching IPv6 flow label. */ - if (!(wc->wildcards & FWW_IPV6_LABEL)) { + if (wc->ipv6_label_mask) { return OFPUTIL_P_NXM_ANY; } @@ -2144,7 +2166,11 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, if (osm->type == htons(OFPST_FLOW)) { struct ofp_flow_stats *ofs; - ofs = ofpbuf_put_uninit(reply, sizeof *ofs); + ofpbuf_put_uninit(reply, sizeof *ofs); + ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); + + ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs); + ofs->length = htons(reply->size - start_ofs); ofs->table_id = fs->table_id; ofs->pad = 0; ofputil_cls_rule_to_ofp10_match(&fs->rule, &ofs->match); @@ -2159,14 +2185,16 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, htonll(unknown_to_zero(fs->packet_count))); put_32aligned_be64(&ofs->byte_count, htonll(unknown_to_zero(fs->byte_count))); - ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); - - ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs); - ofs->length = htons(reply->size - start_ofs); } else if (osm->type == htons(OFPST_VENDOR)) { struct nx_flow_stats *nfs; + int match_len; - nfs = ofpbuf_put_uninit(reply, sizeof *nfs); + ofpbuf_put_uninit(reply, sizeof *nfs); + match_len = nx_put_match(reply, false, &fs->rule, 0, 0); + ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); + + nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs); + nfs->length = htons(reply->size - start_ofs); nfs->table_id = fs->table_id; nfs->pad = 0; nfs->duration_sec = htonl(fs->duration_sec); @@ -2180,14 +2208,10 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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(reply, false, &fs->rule, 0, 0)); + nfs->match_len = htons(match_len); nfs->cookie = fs->cookie; nfs->packet_count = htonll(fs->packet_count); nfs->byte_count = htonll(fs->byte_count); - ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); - - nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs); - nfs->length = htons(reply->size - start_ofs); } else { NOT_REACHED(); } @@ -3092,7 +3116,268 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, return b; } + +/* ofputil_flow_monitor_request */ + +/* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract + * ofputil_flow_monitor_request in 'rq'. + * + * Multiple NXST_FLOW_MONITOR requests can be packed into a single OpenFlow + * message. Calling this function multiple times for a single 'msg' iterates + * through the requests. The caller must initially leave 'msg''s layer + * pointers null and not modify them between calls. + * + * Returns 0 if successful, EOF if no requests were left in this 'msg', + * otherwise an OFPERR_* value. */ +int +ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq, + struct ofpbuf *msg) +{ + struct nx_flow_monitor_request *nfmr; + uint16_t flags; + + if (!msg->l2) { + msg->l2 = msg->data; + ofpbuf_pull(msg, sizeof(struct nicira_stats_msg)); + } + if (!msg->size) { + return EOF; + } + + nfmr = ofpbuf_try_pull(msg, sizeof *nfmr); + if (!nfmr) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR request has %zu " + "leftover bytes at end", msg->size); + return OFPERR_OFPBRC_BAD_LEN; + } + + flags = ntohs(nfmr->flags); + if (!(flags & (NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY)) + || flags & ~(NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE + | NXFMF_MODIFY | NXFMF_ACTIONS | NXFMF_OWN)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR has bad flags %#"PRIx16, + flags); + return OFPERR_NXBRC_FM_BAD_FLAGS; + } + + if (!is_all_zeros(nfmr->zeros, sizeof nfmr->zeros)) { + return OFPERR_NXBRC_MUST_BE_ZERO; + } + + rq->id = ntohl(nfmr->id); + rq->flags = flags; + rq->out_port = ntohs(nfmr->out_port); + rq->table_id = nfmr->table_id; + + return nx_pull_match(msg, ntohs(nfmr->match_len), OFP_DEFAULT_PRIORITY, + &rq->match, NULL, NULL); +} + +void +ofputil_append_flow_monitor_request( + const struct ofputil_flow_monitor_request *rq, struct ofpbuf *msg) +{ + struct nx_flow_monitor_request *nfmr; + size_t start_ofs; + int match_len; + + if (!msg->size) { + ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST, + htons(OFPST_VENDOR), + htonl(NXST_FLOW_MONITOR), msg); + } + + start_ofs = msg->size; + ofpbuf_put_zeros(msg, sizeof *nfmr); + match_len = nx_put_match(msg, false, &rq->match, htonll(0), htonll(0)); + + nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr); + nfmr->id = htonl(rq->id); + nfmr->flags = htons(rq->flags); + nfmr->out_port = htons(rq->out_port); + nfmr->match_len = htons(match_len); + nfmr->table_id = rq->table_id; +} + +/* Converts an NXST_FLOW_MONITOR reply (also known as a flow update) in 'msg' + * into an abstract ofputil_flow_update in 'update'. The caller must have + * initialized update->match to point to space allocated for a cls_rule. + * + * Uses 'ofpacts' to store the abstract OFPACT_* version of the update's + * actions (except for NXFME_ABBREV, which never includes actions). The caller + * must initialize 'ofpacts' and retains ownership of it. 'update->ofpacts' + * will point into the 'ofpacts' buffer. + * + * Multiple flow updates can be packed into a single OpenFlow message. Calling + * this function multiple times for a single 'msg' iterates through the + * updates. The caller must initially leave 'msg''s layer pointers null and + * not modify them between calls. + * + * Returns 0 if successful, EOF if no updates were left in this 'msg', + * otherwise an OFPERR_* value. */ +int +ofputil_decode_flow_update(struct ofputil_flow_update *update, + struct ofpbuf *msg, struct ofpbuf *ofpacts) +{ + struct nx_flow_update_header *nfuh; + unsigned int length; + + if (!msg->l2) { + msg->l2 = msg->data; + ofpbuf_pull(msg, sizeof(struct nicira_stats_msg)); + } + + if (!msg->size) { + return EOF; + } + + if (msg->size < sizeof(struct nx_flow_update_header)) { + goto bad_len; + } + + nfuh = msg->data; + update->event = ntohs(nfuh->event); + length = ntohs(nfuh->length); + if (length > msg->size || length % 8) { + goto bad_len; + } + + if (update->event == NXFME_ABBREV) { + struct nx_flow_update_abbrev *nfua; + + if (length != sizeof *nfua) { + goto bad_len; + } + + nfua = ofpbuf_pull(msg, sizeof *nfua); + update->xid = nfua->xid; + return 0; + } else if (update->event == NXFME_ADDED + || update->event == NXFME_DELETED + || update->event == NXFME_MODIFIED) { + struct nx_flow_update_full *nfuf; + unsigned int actions_len; + unsigned int match_len; + enum ofperr error; + + if (length < sizeof *nfuf) { + goto bad_len; + } + + nfuf = ofpbuf_pull(msg, sizeof *nfuf); + match_len = ntohs(nfuf->match_len); + if (sizeof *nfuf + match_len > length) { + goto bad_len; + } + + update->reason = ntohs(nfuf->reason); + update->idle_timeout = ntohs(nfuf->idle_timeout); + update->hard_timeout = ntohs(nfuf->hard_timeout); + update->table_id = nfuf->table_id; + update->cookie = nfuf->cookie; + + error = nx_pull_match(msg, match_len, ntohs(nfuf->priority), + update->match, NULL, NULL); + if (error) { + return error; + } + + actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8); + error = ofpacts_pull_openflow10(msg, actions_len, ofpacts); + if (error) { + return error; + } + + update->ofpacts = ofpacts->data; + update->ofpacts_len = ofpacts->size; + return 0; + } else { + VLOG_WARN_RL(&bad_ofmsg_rl, + "NXST_FLOW_MONITOR reply has bad event %"PRIu16, + ntohs(nfuh->event)); + return OFPERR_OFPET_BAD_REQUEST; + } + +bad_len: + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %zu " + "leftover bytes at end", msg->size); + return OFPERR_OFPBRC_BAD_LEN; +} + +uint32_t +ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh) +{ + return ntohl(((const struct nx_flow_monitor_cancel *) oh)->id); +} + +struct ofpbuf * +ofputil_encode_flow_monitor_cancel(uint32_t id) +{ + struct nx_flow_monitor_cancel *nfmc; + struct ofpbuf *msg; + + nfmc = make_nxmsg(sizeof *nfmc, NXT_FLOW_MONITOR_CANCEL, &msg); + nfmc->id = htonl(id); + return msg; +} + +void +ofputil_start_flow_update(struct list *replies) +{ + struct ofpbuf *msg; + + msg = ofpbuf_new(1024); + ofputil_put_stats_header(htonl(0), OFPT10_STATS_REPLY, + htons(OFPST_VENDOR), + htonl(NXST_FLOW_MONITOR), msg); + + list_init(replies); + list_push_back(replies, &msg->list_node); +} + +void +ofputil_append_flow_update(const struct ofputil_flow_update *update, + struct list *replies) +{ + struct nx_flow_update_header *nfuh; + struct ofpbuf *msg; + size_t start_ofs; + + msg = ofpbuf_from_list(list_back(replies)); + start_ofs = msg->size; + + if (update->event == NXFME_ABBREV) { + struct nx_flow_update_abbrev *nfua; + + nfua = ofpbuf_put_zeros(msg, sizeof *nfua); + nfua->xid = update->xid; + } else { + struct nx_flow_update_full *nfuf; + int match_len; + + ofpbuf_put_zeros(msg, sizeof *nfuf); + match_len = nx_put_match(msg, false, update->match, + htonll(0), htonll(0)); + ofpacts_put_openflow10(update->ofpacts, update->ofpacts_len, msg); + + nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf); + nfuf->reason = htons(update->reason); + nfuf->priority = htons(update->match->priority); + nfuf->idle_timeout = htons(update->idle_timeout); + nfuf->hard_timeout = htons(update->hard_timeout); + nfuf->match_len = htons(match_len); + nfuf->table_id = update->table_id; + nfuf->cookie = update->cookie; + } + + nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh); + nfuh->length = htons(msg->size - start_ofs); + nfuh->event = htons(update->event); + + ofputil_postappend_stats_reply(start_ofs, replies); +} + struct ofpbuf * ofputil_encode_packet_out(const struct ofputil_packet_out *po) { @@ -3265,10 +3550,10 @@ update_openflow_length(struct ofpbuf *buffer) oh->length = htons(buffer->size); } -static void -put_stats__(ovs_be32 xid, uint8_t ofp_type, - ovs_be16 ofpst_type, ovs_be32 nxst_subtype, - struct ofpbuf *msg) +void +ofputil_put_stats_header(ovs_be32 xid, uint8_t ofp_type, + ovs_be16 ofpst_type, ovs_be32 nxst_subtype, + struct ofpbuf *msg) { if (ofpst_type == htons(OFPST_VENDOR)) { struct nicira_stats_msg *nsm; @@ -3301,8 +3586,8 @@ ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type, struct ofpbuf *msg; msg = *bufferp = ofpbuf_new(openflow_len); - put_stats__(alloc_xid(), OFPT10_STATS_REQUEST, - htons(ofpst_type), htonl(nxst_subtype), msg); + ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST, + htons(ofpst_type), htonl(nxst_subtype), msg); ofpbuf_padto(msg, openflow_len); return msg->data; @@ -3311,13 +3596,16 @@ ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type, static void put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg) { + ovs_be32 nxst_subtype; + assert(request->header.type == OFPT10_STATS_REQUEST || request->header.type == OFPT10_STATS_REPLY); - put_stats__(request->header.xid, OFPT10_STATS_REPLY, request->type, - (request->type != htons(OFPST_VENDOR) - ? htonl(0) - : ((const struct nicira_stats_msg *) request)->subtype), - msg); + + nxst_subtype = (request->type != htons(OFPST_VENDOR) + ? htonl(0) + : ((const struct nicira_stats_msg *) request)->subtype); + ofputil_put_stats_header(request->header.xid, OFPT10_STATS_REPLY, + request->type, nxst_subtype, msg); } /* Creates a statistics reply message with total length 'openflow_len' @@ -3391,6 +3679,16 @@ ofputil_append_stats_reply(size_t len, struct list *replies) return ofpbuf_put_uninit(ofputil_reserve_stats_reply(len, replies), len); } +/* Sometimes, when composing stats replies, it's difficult to predict how long + * an individual reply chunk will be before actually encoding it into the reply + * buffer. This function allows easy handling of this case: just encode the + * reply, then use this function to break the message into two pieces if it + * exceeds the OpenFlow message limit. + * + * In detail, if the final stats message in 'replies' is too long for OpenFlow, + * this function breaks it into two separate stats replies, the first one with + * the first 'start_ofs' bytes, the second one containing the bytes from that + * offset onward. */ void ofputil_postappend_stats_reply(size_t start_ofs, struct list *replies) { @@ -3812,14 +4110,14 @@ ofputil_normalize_rule(struct cls_rule *rule) wc.wildcards |= FWW_NW_TTL; } if (!(may_match & MAY_ARP_SHA)) { - wc.wildcards |= FWW_ARP_SHA; + memset(wc.arp_sha_mask, 0, ETH_ADDR_LEN); } if (!(may_match & MAY_ARP_THA)) { - wc.wildcards |= FWW_ARP_THA; + memset(wc.arp_tha_mask, 0, ETH_ADDR_LEN); } if (!(may_match & MAY_IPV6)) { wc.ipv6_src_mask = wc.ipv6_dst_mask = in6addr_any; - wc.wildcards |= FWW_IPV6_LABEL; + wc.ipv6_label_mask = htonl(0); } if (!(may_match & MAY_ND_TARGET)) { wc.nd_target_mask = in6addr_any;