X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=6b78f84c2894310e7b9d396b48289b595eb5b6ba;hb=2c57a420432de88b8a6f9ee54642c3841577ad7b;hp=320bfde470795a72b557836c1cc61a906731b9c0;hpb=31a9e63f0f7e771c849f7ef45c9827fcc78abe03;p=sliver-openvswitch.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 320bfde47..6b78f84c2 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ #include #include #include -#include "autopath.h" #include "bundle.h" #include "byte-order.h" #include "classifier.h" @@ -85,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20); /* Initialize most of wc. */ flow_wildcards_init_catchall(wc); @@ -440,8 +439,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch, } } - if (match->flow.dl_type == htons(ETH_TYPE_MPLS) || - match->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) { + if (eth_type_mpls(match->flow.dl_type)) { enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC }; if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) { @@ -807,7 +805,7 @@ ofputil_protocols_to_string(enum ofputil_protocol protocols) { struct ds s; - assert(!(protocols & ~OFPUTIL_P_ANY)); + ovs_assert(!(protocols & ~OFPUTIL_P_ANY)); if (protocols == 0) { return xstrdup("none"); } @@ -1060,13 +1058,18 @@ ofputil_usable_protocols(const struct match *match) { const struct flow_wildcards *wc = &match->wc; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20); /* tunnel params other than tun_id can't be sent in a flow_mod */ if (!tun_parms_fully_wildcarded(wc)) { return OFPUTIL_P_NONE; } + /* skb_mark and skb_priority can't be sent in a flow_mod */ + if (wc->masks.skb_mark || wc->masks.skb_priority) { + return OFPUTIL_P_NONE; + } + /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */ if (!eth_mask_is_exact(wc->masks.dl_src) && !eth_addr_is_zero(wc->masks.dl_src)) { @@ -1147,6 +1150,26 @@ ofputil_usable_protocols(const struct match *match) | OFPUTIL_P_OF13_OXM; } + /* NXM and OF1.1+ support matching MPLS label */ + if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) { + return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM + | OFPUTIL_P_OF13_OXM; + } + + /* NXM and OF1.1+ support matching MPLS TC */ + if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) { + return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM + | OFPUTIL_P_OF13_OXM; + } + + /* NXM and OF1.3+ support matching MPLS stack flag */ + /* Allow for OF1.2 as there doesn't seem to be a + * particularly good reason not to */ + if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) { + return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM + | OFPUTIL_P_OF13_OXM; + } + /* Other formats can express this rule. */ return OFPUTIL_P_ANY; } @@ -1362,7 +1385,7 @@ ofputil_encode_set_protocol(enum ofputil_protocol current, return ofputil_make_flow_mod_table_id(want_tid); } - assert(current == want); + ovs_assert(current == want); *next = current; return NULL; @@ -1376,7 +1399,7 @@ ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff) struct nx_set_flow_format *sff; struct ofpbuf *msg; - assert(ofputil_nx_flow_format_is_valid(nxff)); + ovs_assert(ofputil_nx_flow_format_is_valid(nxff)); msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0); sff = ofpbuf_put_zeros(msg, sizeof *sff); @@ -1590,11 +1613,13 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, if (fm->flags & OFPFF10_EMERG) { /* We do not support the OpenFlow 1.0 emergency flow cache, which * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. - * There is no good error code, so just state that the flow table - * is full. - * Moreover, OFPFF10_EMERG overlaps with OFPFF12_RESET_COUNTS, - * so this check must be here */ - return OFPERR_OFPFMFC_TABLE_FULL; + * + * OpenFlow 1.0 specifies the error code to use when idle_timeout + * or hard_timeout is nonzero. Otherwise, there is no good error + * code, so just state that the flow table is full. */ + return (fm->hard_timeout || fm->idle_timeout + ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT + : OFPERR_OFPFMFC_TABLE_FULL); } if (protocol & OFPUTIL_P_TID) { @@ -2320,7 +2345,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, fr->priority = ntohs(nfr->priority); fr->cookie = nfr->cookie; fr->reason = nfr->reason; - fr->table_id = 255; + fr->table_id = nfr->table_id ? nfr->table_id - 1 : 255; fr->duration_sec = ntohl(nfr->duration_sec); fr->duration_nsec = ntohl(nfr->duration_nsec); fr->idle_timeout = ntohs(nfr->idle_timeout); @@ -2399,6 +2424,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, nfr->cookie = fr->cookie; nfr->priority = htons(fr->priority); nfr->reason = fr->reason; + nfr->table_id = fr->table_id + 1; nfr->duration_sec = htonl(fr->duration_sec); nfr->duration_nsec = htonl(fr->duration_nsec); nfr->idle_timeout = htons(fr->idle_timeout); @@ -3190,7 +3216,9 @@ ofputil_put_switch_features_port(const struct ofputil_phy_port *pp, { const struct ofp_header *oh = b->data; - ofputil_put_phy_port(oh->version, pp, b); + if (oh->version < OFP13_VERSION) { + ofputil_put_phy_port(oh->version, pp, b); + } } /* ofputil_port_status */ @@ -3217,7 +3245,7 @@ ofputil_decode_port_status(const struct ofp_header *oh, ps->reason = ops->reason; retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc); - assert(retval != EOF); + ovs_assert(retval != EOF); return retval; } @@ -3346,6 +3374,103 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, return b; } +/* ofputil_role_request */ + +/* Decodes the OpenFlow "role request" or "role reply" message in '*oh' into + * an abstract form in '*rr'. Returns 0 if successful, otherwise an + * OFPERR_* value. */ +enum ofperr +ofputil_decode_role_message(const struct ofp_header *oh, + struct ofputil_role_request *rr) +{ + struct ofpbuf b; + enum ofpraw raw; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + raw = ofpraw_pull_assert(&b); + + if (raw == OFPRAW_OFPT12_ROLE_REQUEST || + raw == OFPRAW_OFPT12_ROLE_REPLY) { + const struct ofp12_role_request *orr = b.l3; + + if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) && + orr->role != htonl(OFPCR12_ROLE_EQUAL) && + orr->role != htonl(OFPCR12_ROLE_MASTER) && + orr->role != htonl(OFPCR12_ROLE_SLAVE)) { + return OFPERR_OFPRRFC_BAD_ROLE; + } + + rr->role = ntohl(orr->role); + if (raw == OFPRAW_OFPT12_ROLE_REQUEST + ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE) + : orr->generation_id == htonll(UINT64_MAX)) { + rr->have_generation_id = false; + rr->generation_id = 0; + } else { + rr->have_generation_id = true; + rr->generation_id = ntohll(orr->generation_id); + } + } else if (raw == OFPRAW_NXT_ROLE_REQUEST || + raw == OFPRAW_NXT_ROLE_REPLY) { + const struct nx_role_request *nrr = b.l3; + + BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL); + BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER); + BUILD_ASSERT(NX_ROLE_SLAVE + 1 == OFPCR12_ROLE_SLAVE); + + if (nrr->role != htonl(NX_ROLE_OTHER) && + nrr->role != htonl(NX_ROLE_MASTER) && + nrr->role != htonl(NX_ROLE_SLAVE)) { + return OFPERR_OFPRRFC_BAD_ROLE; + } + + rr->role = ntohl(nrr->role) + 1; + rr->have_generation_id = false; + rr->generation_id = 0; + } else { + NOT_REACHED(); + } + + return 0; +} + +/* Returns an encoded form of a role reply suitable for the "request" in a + * buffer owned by the caller. */ +struct ofpbuf * +ofputil_encode_role_reply(const struct ofp_header *request, + const struct ofputil_role_request *rr) +{ + struct ofpbuf *buf; + enum ofpraw raw; + + raw = ofpraw_decode_assert(request); + if (raw == OFPRAW_OFPT12_ROLE_REQUEST) { + struct ofp12_role_request *orr; + + buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0); + orr = ofpbuf_put_zeros(buf, sizeof *orr); + + orr->role = htonl(rr->role); + orr->generation_id = htonll(rr->have_generation_id + ? rr->generation_id + : UINT64_MAX); + } else if (raw == OFPRAW_NXT_ROLE_REQUEST) { + struct nx_role_request *nrr; + + BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1); + BUILD_ASSERT(NX_ROLE_MASTER == OFPCR12_ROLE_MASTER - 1); + BUILD_ASSERT(NX_ROLE_SLAVE == OFPCR12_ROLE_SLAVE - 1); + + buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, request, 0); + nrr = ofpbuf_put_zeros(buf, sizeof *nrr); + nrr->role = htonl(rr->role - 1); + } else { + NOT_REACHED(); + } + + return buf; +} + /* Table stats. */ static void @@ -3375,9 +3500,9 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in, struct ofp10_table_stats *out; const struct wc_map *p; - out = ofpbuf_put_uninit(buf, sizeof *out); + out = ofpbuf_put_zeros(buf, sizeof *out); out->table_id = in->table_id; - strcpy(out->name, in->name); + ovs_strlcpy(out->name, in->name, sizeof out->name); out->wildcards = 0; for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) { if (in->wildcards & htonll(1ULL << p->mf12)) { @@ -3435,9 +3560,9 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in, { struct ofp11_table_stats *out; - out = ofpbuf_put_uninit(buf, sizeof *out); + out = ofpbuf_put_zeros(buf, sizeof *out); out->table_id = in->table_id; - strcpy(out->name, in->name); + ovs_strlcpy(out->name, in->name, sizeof out->name); out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards); out->match = oxm12_to_ofp11_flow_match_fields(in->match); out->instructions = in->instructions; @@ -3681,7 +3806,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update, VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has bad event %"PRIu16, ntohs(nfuh->event)); - return OFPERR_OFPET_BAD_REQUEST; + return OFPERR_NXBRC_FM_BAD_EVENT; } bad_len: @@ -4008,20 +4133,20 @@ ofputil_port_from_string(const char *s, uint16_t *portp) *portp = port32; return true; } else if (port32 <= OFPP_LAST_RESV) { - struct ds s; + struct ds msg; - ds_init(&s); - ofputil_format_port(port32, &s); + ds_init(&msg); + ofputil_format_port(port32, &msg); VLOG_WARN_ONCE("referring to port %s as %u is deprecated for " "compatibility with future versions of OpenFlow", - ds_cstr(&s), port32); - ds_destroy(&s); + ds_cstr(&msg), port32); + ds_destroy(&msg); *portp = port32; return true; } else if (port32 < OFPP11_MAX) { VLOG_WARN("port %u is outside the supported range 0 through " - "%"PRIx16"or 0x%x through 0x%"PRIx32, port32, + "%"PRIx16" or 0x%x through 0x%"PRIx32, port32, UINT16_MAX, (unsigned int) OFPP11_MAX, UINT32_MAX); return false; } else { @@ -4200,7 +4325,8 @@ ofputil_normalize_match__(struct match *match, bool may_log) MAY_ARP_SHA = 1 << 4, /* arp_sha */ MAY_ARP_THA = 1 << 5, /* arp_tha */ MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */ - MAY_ND_TARGET = 1 << 7 /* nd_target */ + MAY_ND_TARGET = 1 << 7, /* nd_target */ + MAY_MPLS = 1 << 8, /* mpls label and tc */ } may_match; struct flow_wildcards wc; @@ -4229,6 +4355,8 @@ ofputil_normalize_match__(struct match *match, bool may_log) } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) || match->flow.dl_type == htons(ETH_TYPE_RARP)) { may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA; + } else if (eth_type_mpls(match->flow.dl_type)) { + may_match = MAY_MPLS; } else { may_match = 0; } @@ -4261,6 +4389,10 @@ ofputil_normalize_match__(struct match *match, bool may_log) if (!(may_match & MAY_ND_TARGET)) { wc.masks.nd_target = in6addr_any; } + if (!(may_match & MAY_MPLS)) { + wc.masks.mpls_lse = htonl(0); + wc.masks.mpls_depth = 0; + } /* Log any changes. */ if (!flow_wildcards_equal(&wc, &match->wc)) {