X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=2ca00771542c5a904c7d3429eade87db89d1c722;hb=8d71683b7632b5b621dd21418bf33ff90865b4e0;hp=9c9aaefc2ed26b4b4b517e22b659cef0ed92700f;hpb=3bdc692b0445b685f0dce52aedc83bd855af28a5;p=sliver-openvswitch.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 9c9aaefc2..2ca007715 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"); } @@ -924,7 +922,7 @@ ofputil_version_from_string(const char *s) } static bool -is_delimiter(char c) +is_delimiter(unsigned char c) { return isspace(c) || c == ','; } @@ -1041,16 +1039,6 @@ regs_fully_wildcarded(const struct flow_wildcards *wc) return true; } -static bool -tun_parms_fully_wildcarded(const struct flow_wildcards *wc) -{ - return (!wc->masks.tunnel.ip_src && - !wc->masks.tunnel.ip_dst && - !wc->masks.tunnel.ip_ttl && - !wc->masks.tunnel.ip_tos && - !wc->masks.tunnel.flags); -} - /* Returns a bit-mask of ofputil_protocols that can be used for sending 'match' * to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs, * registers, or fixing the Ethernet multicast bit. Otherwise, it's better to @@ -1060,10 +1048,11 @@ 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)) { + /* These tunnel params can't be sent in a flow_mod */ + if (wc->masks.tunnel.ip_ttl + || wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) { return OFPUTIL_P_NONE; } @@ -1109,8 +1098,10 @@ ofputil_usable_protocols(const struct match *match) | OFPUTIL_P_OF13_OXM; } - /* NXM and OXM support matching tun_id. */ - if (wc->masks.tunnel.tun_id != htonll(0)) { + /* NXM and OXM support matching tun_id, tun_src, and tun_dst. */ + if (wc->masks.tunnel.tun_id != htonll(0) + || wc->masks.tunnel.ip_src != htonl(0) + || wc->masks.tunnel.ip_dst != htonl(0)) { return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM | OFPUTIL_P_OF13_OXM; } @@ -1152,6 +1143,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; } @@ -1367,7 +1378,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; @@ -1381,7 +1392,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); @@ -2327,7 +2338,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); @@ -2406,6 +2417,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); @@ -2431,6 +2443,8 @@ ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin, pin->fmd.in_port = match->flow.in_port; pin->fmd.tun_id = match->flow.tunnel.tun_id; + pin->fmd.tun_src = match->flow.tunnel.ip_src; + pin->fmd.tun_dst = match->flow.tunnel.ip_dst; pin->fmd.metadata = match->flow.metadata; memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs); } @@ -2531,6 +2545,12 @@ ofputil_packet_in_to_match(const struct ofputil_packet_in *pin, if (pin->fmd.tun_id != htonll(0)) { match_set_tun_id(match, pin->fmd.tun_id); } + if (pin->fmd.tun_src != htonl(0)) { + match_set_tun_src(match, pin->fmd.tun_src); + } + if (pin->fmd.tun_dst != htonl(0)) { + match_set_tun_dst(match, pin->fmd.tun_dst); + } if (pin->fmd.metadata != htonll(0)) { match_set_metadata(match, pin->fmd.metadata); } @@ -3226,7 +3246,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; } @@ -3364,43 +3384,54 @@ enum ofperr ofputil_decode_role_message(const struct ofp_header *oh, struct ofputil_role_request *rr) { - const struct ofp12_role_request *orr = ofpmsg_body(oh); - uint32_t role = ntohl(orr->role); struct ofpbuf b; enum ofpraw raw; - memset(rr, 0, sizeof *rr); - ofpbuf_use_const(&b, oh, ntohs(oh->length)); raw = ofpraw_pull_assert(&b); - if (raw == OFPRAW_OFPT12_ROLE_REQUEST - || raw == OFPRAW_OFPT12_ROLE_REPLY) { + if (raw == OFPRAW_OFPT12_ROLE_REQUEST || + raw == OFPRAW_OFPT12_ROLE_REPLY) { + const struct ofp12_role_request *orr = b.l3; - if (raw == OFPRAW_OFPT12_ROLE_REQUEST) { - if (role == OFPCR12_ROLE_NOCHANGE) { - rr->request_current_role_only = true; - return 0; - } - if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) { - rr->generation_id = ntohll(orr->generation_id); - rr->have_generation_id = true; - } + 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; } - /* Map to enum nx_role */ - role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */ - } else if (raw != OFPRAW_NXT_ROLE_REQUEST - && raw != OFPRAW_NXT_ROLE_REPLY) { - return OFPERR_OFPBRC_BAD_TYPE; - } + 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; + } - if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER - && role != 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(); } - rr->role = role; return 0; } @@ -3408,47 +3439,35 @@ ofputil_decode_role_message(const struct ofp_header *oh, * buffer owned by the caller. */ struct ofpbuf * ofputil_encode_role_reply(const struct ofp_header *request, - enum nx_role role) + const struct ofputil_role_request *rr) { - struct ofp12_role_request *reply; struct ofpbuf *buf; - size_t reply_size; - - struct ofpbuf b; enum ofpraw raw; - ofpbuf_use_const(&b, request, ntohs(request->length)); - raw = ofpraw_pull_assert(&b); + raw = ofpraw_decode_assert(request); if (raw == OFPRAW_OFPT12_ROLE_REQUEST) { - reply_size = sizeof (struct ofp12_role_request); - raw = OFPRAW_OFPT12_ROLE_REPLY; - } - else if (raw == OFPRAW_NXT_ROLE_REQUEST) { - reply_size = sizeof (struct nx_role_request); - raw = OFPRAW_NXT_ROLE_REPLY; - } else { - NOT_REACHED(); - } + struct ofp12_role_request *orr; - buf = ofpraw_alloc_reply(raw, request, 0); - reply = ofpbuf_put_zeros(buf, reply_size); + buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0); + orr = ofpbuf_put_zeros(buf, sizeof *orr); - if (raw == OFPRAW_OFPT12_ROLE_REPLY) { - /* Map to OpenFlow enum ofp12_controller_role */ - role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */ - /* - * OpenFlow specification does not specify use of generation_id field - * on reply messages. Intuitively, it would seem a good idea to return - * the current value. However, the current value is undefined - * initially, and there is no way to insert an undefined value in the - * message. Therefore we leave the generation_id zeroed on reply - * messages. - * - * A request for clarification has been filed with the Open Networking - * Foundation as EXT-272. - */ + 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(); } - reply->role = htonl(role); return buf; } @@ -4115,14 +4134,14 @@ 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; @@ -4217,7 +4236,7 @@ size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b) int ofputil_action_code_from_name(const char *name) { - static const char *names[OFPUTIL_N_ACTIONS] = { + static const char *const names[OFPUTIL_N_ACTIONS] = { NULL, #define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME, #define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME, @@ -4225,7 +4244,7 @@ ofputil_action_code_from_name(const char *name) #include "ofp-util.def" }; - const char **p; + const char *const *p; for (p = names; p < &names[ARRAY_SIZE(names)]; p++) { if (*p && !strcasecmp(name, *p)) { @@ -4307,7 +4326,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; @@ -4336,6 +4356,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; } @@ -4368,6 +4390,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)) { @@ -4495,7 +4521,7 @@ ofputil_parse_key_value(char **stringp, char **keyp, char **valuep) * will be for Open Flow version 'ofp_version'. Returns message * as a struct ofpbuf. Returns encoded message on success, NULL on error */ struct ofpbuf * -ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port) +ofputil_encode_dump_ports_request(enum ofp_version ofp_version, uint16_t port) { struct ofpbuf *request;