mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
FreeBSD insists that <sys/types.h> be included before <netinet/in.h> and that <netinet/in.h> be included before <arpa/inet.h>. This adds guards to the "sparse" headers to yield a warning if this order is violated. This commit also adjusts the order of many #includes to suit this requirement. Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Justin Pettit <jpettit@ovn.org>
339 lines
10 KiB
C
339 lines
10 KiB
C
/*
|
|
* Copyright (c) 2017 Intel, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include "openvswitch/ofp-ed-props.h"
|
|
#include "openvswitch/ofp-util.h"
|
|
#include "openvswitch/ofpbuf.h"
|
|
#include "openvswitch/ofp-parse.h"
|
|
#include "util.h"
|
|
#include "lib/packets.h"
|
|
|
|
|
|
enum ofperr
|
|
decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
|
|
struct ofpbuf *out OVS_UNUSED,
|
|
size_t *remaining)
|
|
{
|
|
uint16_t prop_class = ntohs((*ofp_prop)->prop_class);
|
|
uint8_t prop_type = (*ofp_prop)->type;
|
|
size_t len = (*ofp_prop)->len;
|
|
size_t pad_len = ROUND_UP(len, 8);
|
|
|
|
if (pad_len > *remaining) {
|
|
return OFPERR_OFPBAC_BAD_LEN;
|
|
}
|
|
|
|
switch (prop_class) {
|
|
case OFPPPC_NSH: {
|
|
switch (prop_type) {
|
|
case OFPPPT_PROP_NSH_MDTYPE: {
|
|
struct ofp_ed_prop_nsh_md_type *opnmt =
|
|
ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type *, *ofp_prop);
|
|
if (len > sizeof(*opnmt) || len > *remaining) {
|
|
return OFPERR_NXBAC_BAD_ED_PROP;
|
|
}
|
|
struct ofpact_ed_prop_nsh_md_type *pnmt =
|
|
ofpbuf_put_uninit(out, sizeof(*pnmt));
|
|
pnmt->header.prop_class = prop_class;
|
|
pnmt->header.type = prop_type;
|
|
pnmt->header.len = len;
|
|
pnmt->md_type = opnmt->md_type;
|
|
break;
|
|
}
|
|
case OFPPPT_PROP_NSH_TLV: {
|
|
struct ofp_ed_prop_nsh_tlv *opnt =
|
|
ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv *, *ofp_prop);
|
|
size_t tlv_pad_len = ROUND_UP(opnt->tlv_len, 8);
|
|
if (len != sizeof(*opnt) + tlv_pad_len || len > *remaining) {
|
|
return OFPERR_NXBAC_BAD_ED_PROP;
|
|
}
|
|
struct ofpact_ed_prop_nsh_tlv *pnt =
|
|
ofpbuf_put_uninit(out, sizeof(*pnt));
|
|
pnt->header.prop_class = prop_class;
|
|
pnt->header.type = prop_type;
|
|
pnt->header.len = len;
|
|
pnt->tlv_class = opnt->tlv_class;
|
|
pnt->tlv_type = opnt->tlv_type;
|
|
pnt->tlv_len = opnt->tlv_len;
|
|
ofpbuf_put(out, opnt->data, tlv_pad_len);
|
|
break;
|
|
}
|
|
default:
|
|
return OFPERR_NXBAC_UNKNOWN_ED_PROP;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return OFPERR_NXBAC_UNKNOWN_ED_PROP;
|
|
}
|
|
|
|
*remaining -= pad_len;
|
|
*ofp_prop = ALIGNED_CAST(const struct ofp_ed_prop_header *,
|
|
((char *)(*ofp_prop) + pad_len));
|
|
return 0;
|
|
}
|
|
|
|
enum ofperr
|
|
encode_ed_prop(const struct ofpact_ed_prop **prop,
|
|
struct ofpbuf *out OVS_UNUSED)
|
|
{
|
|
size_t prop_len;
|
|
|
|
switch ((*prop)->prop_class) {
|
|
case OFPPPC_NSH: {
|
|
switch ((*prop)->type) {
|
|
case OFPPPT_PROP_NSH_MDTYPE: {
|
|
struct ofpact_ed_prop_nsh_md_type *pnmt =
|
|
ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, *prop);
|
|
struct ofp_ed_prop_nsh_md_type *opnmt =
|
|
ofpbuf_put_uninit(out, sizeof(*opnmt));
|
|
opnmt->header.prop_class = htons((*prop)->prop_class);
|
|
opnmt->header.type = (*prop)->type;
|
|
opnmt->header.len =
|
|
offsetof(struct ofp_ed_prop_nsh_md_type, pad);
|
|
opnmt->md_type = pnmt->md_type;
|
|
prop_len = sizeof(*pnmt);
|
|
break;
|
|
}
|
|
case OFPPPT_PROP_NSH_TLV: {
|
|
struct ofpact_ed_prop_nsh_tlv *pnt =
|
|
ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, *prop);
|
|
struct ofp_ed_prop_nsh_tlv *opnt;
|
|
size_t tlv_pad_len = ROUND_UP(pnt->tlv_len, 8);
|
|
size_t len = sizeof(*opnt) + tlv_pad_len;
|
|
opnt = ofpbuf_put_uninit(out, len);
|
|
opnt->header.prop_class = htons((*prop)->prop_class);
|
|
opnt->header.type = (*prop)->type;
|
|
opnt->header.len = len;
|
|
opnt->tlv_class = pnt->tlv_class;
|
|
opnt->tlv_type = pnt->tlv_type;
|
|
opnt->tlv_len = pnt->tlv_len;
|
|
memcpy(opnt->data, pnt->data, tlv_pad_len);
|
|
prop_len = sizeof(*pnt) + tlv_pad_len;
|
|
break;
|
|
}
|
|
default:
|
|
return OFPERR_OFPBAC_BAD_ARGUMENT;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return OFPERR_OFPBAC_BAD_ARGUMENT;
|
|
}
|
|
|
|
*prop = ALIGNED_CAST(const struct ofpact_ed_prop *,
|
|
((char *)(*prop) + prop_len));
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
parse_ed_prop_class(const char *str OVS_UNUSED,
|
|
uint16_t *prop_class)
|
|
{
|
|
if (!strcmp(str,"basic")) {
|
|
*prop_class = OFPPPC_BASIC;
|
|
} else if (!strcmp(str,"ethernet")) {
|
|
*prop_class = OFPPPC_BASIC;
|
|
} else if (!strcmp(str,"mpls")) {
|
|
*prop_class = OFPPPC_MPLS;
|
|
} else if (!strcmp(str,"gre")) {
|
|
*prop_class = OFPPPC_GRE;
|
|
} else if (!strcmp(str,"gtp")) {
|
|
*prop_class = OFPPPC_GTP;
|
|
} else if (!strcmp(str,"nsh")) {
|
|
*prop_class = OFPPPC_NSH;
|
|
} else {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
parse_ed_prop_type(uint16_t prop_class,
|
|
const char *str OVS_UNUSED,
|
|
uint8_t *type OVS_UNUSED)
|
|
{
|
|
switch (prop_class) {
|
|
case OFPPPC_NSH:
|
|
if (!strcmp(str, "md_type")) {
|
|
*type = OFPPPT_PROP_NSH_MDTYPE;
|
|
return true;
|
|
} else if (!strcmp(str, "tlv")) {
|
|
*type = OFPPPT_PROP_NSH_TLV;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Parse the value of an encap/decap property based on property class
|
|
* and type and append the parsed property in internal format to the
|
|
* ofpbuf out.
|
|
* Returns a malloced string in the event of a parse error. The caller
|
|
* must free the string.
|
|
*/
|
|
|
|
char *
|
|
parse_ed_prop_value(uint16_t prop_class, uint8_t prop_type OVS_UNUSED,
|
|
const char *value, struct ofpbuf *out OVS_UNUSED)
|
|
{
|
|
char *error = NULL;
|
|
|
|
if (value == NULL || *value == '\0') {
|
|
return xstrdup("Value missing for encap property");
|
|
}
|
|
|
|
switch (prop_class) {
|
|
case OFPPPC_NSH:
|
|
switch (prop_type) {
|
|
case OFPPPT_PROP_NSH_MDTYPE: {
|
|
/* Format: "<md_type>:uint8_t". */
|
|
uint8_t md_type;
|
|
error = str_to_u8(value, "md_type", &md_type);
|
|
if (error != NULL) {
|
|
return error;
|
|
}
|
|
if (md_type < 1 || md_type > 2) {
|
|
return xstrdup("invalid md_type");
|
|
}
|
|
struct ofpact_ed_prop_nsh_md_type *pnmt =
|
|
ofpbuf_put_uninit(out, sizeof(*pnmt));
|
|
pnmt->header.prop_class = prop_class;
|
|
pnmt->header.type = prop_type;
|
|
pnmt->header.len =
|
|
offsetof(struct ofp_ed_prop_nsh_md_type, pad);
|
|
pnmt->md_type = md_type;
|
|
break;
|
|
}
|
|
case OFPPPT_PROP_NSH_TLV: {
|
|
/* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
|
|
struct ofpact_ed_prop_nsh_tlv *pnt;
|
|
uint16_t tlv_class;
|
|
uint8_t tlv_type;
|
|
char buf[256];
|
|
size_t tlv_value_len, padding;
|
|
size_t start_ofs = out->size;
|
|
|
|
if (!ovs_scan(value, "0x%"SCNx16",%"SCNu8",0x%251[0-9a-fA-F]",
|
|
&tlv_class, &tlv_type, buf)) {
|
|
return xasprintf("Invalid NSH TLV header: %s", value);
|
|
}
|
|
ofpbuf_put_uninit(out, sizeof(*pnt));
|
|
ofpbuf_put_hex(out, buf, &tlv_value_len);
|
|
pnt = ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
|
|
((char *)out->data + start_ofs));
|
|
padding = ROUND_UP(tlv_value_len, 8) - tlv_value_len;
|
|
pnt->header.prop_class = prop_class;
|
|
pnt->header.type = prop_type;
|
|
pnt->header.len = sizeof(*pnt) + tlv_value_len + padding;
|
|
pnt->tlv_class = htons(tlv_class);
|
|
pnt->tlv_type = tlv_type;
|
|
pnt->tlv_len = tlv_value_len;
|
|
if (padding > 0) {
|
|
ofpbuf_put_zeros(out, padding);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
/* Unsupported property types rejected before. */
|
|
OVS_NOT_REACHED();
|
|
}
|
|
break;
|
|
default:
|
|
/* Unsupported property classes rejected before. */
|
|
OVS_NOT_REACHED();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *
|
|
format_ed_prop_class(const struct ofpact_ed_prop *prop)
|
|
{
|
|
switch (prop->prop_class) {
|
|
case OFPPPC_BASIC:
|
|
return "basic";
|
|
case OFPPPC_MPLS:
|
|
return "mpls";
|
|
case OFPPPC_GRE:
|
|
return "gre";
|
|
case OFPPPC_GTP:
|
|
return "gtp";
|
|
case OFPPPC_NSH:
|
|
return "nsh";
|
|
default:
|
|
OVS_NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
char *
|
|
format_ed_prop_type(const struct ofpact_ed_prop *prop)
|
|
{
|
|
switch (prop->prop_class) {
|
|
case OFPPPC_NSH:
|
|
switch (prop->type) {
|
|
case OFPPPT_PROP_NSH_MDTYPE:
|
|
return "md_type";
|
|
case OFPPPT_PROP_NSH_TLV:
|
|
return "tlv";
|
|
default:
|
|
OVS_NOT_REACHED();
|
|
}
|
|
break;
|
|
default:
|
|
OVS_NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
void
|
|
format_ed_prop(struct ds *s OVS_UNUSED,
|
|
const struct ofpact_ed_prop *prop)
|
|
{
|
|
switch (prop->prop_class) {
|
|
case OFPPPC_NSH:
|
|
switch (prop->type) {
|
|
case OFPPPT_PROP_NSH_MDTYPE: {
|
|
struct ofpact_ed_prop_nsh_md_type *pnmt =
|
|
ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, prop);
|
|
ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
|
|
pnmt->md_type);
|
|
return;
|
|
}
|
|
case OFPPPT_PROP_NSH_TLV: {
|
|
struct ofpact_ed_prop_nsh_tlv *pnt =
|
|
ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, prop);
|
|
ds_put_format(s, "%s(0x%04x,%d,",
|
|
format_ed_prop_type(prop),
|
|
ntohs(pnt->tlv_class), pnt->tlv_type);
|
|
ds_put_hex(s, pnt->data, pnt->tlv_len);
|
|
ds_put_cstr(s,")");
|
|
return;
|
|
}
|
|
default:
|
|
OVS_NOT_REACHED();
|
|
}
|
|
default:
|
|
OVS_NOT_REACHED();
|
|
}
|
|
}
|