mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 18:07:40 +00:00
Support userdata in NXT_PACKET_IN2.
Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Jarno Rajahalme <jarno@ovn.org>
This commit is contained in:
parent
4adaf1828a
commit
bdcad671e0
3
NEWS
3
NEWS
@ -5,7 +5,8 @@ Post-v2.5.0
|
|||||||
- OpenFlow:
|
- OpenFlow:
|
||||||
* OpenFlow 1.1+ OFPT_QUEUE_GET_CONFIG_REQUEST now supports OFPP_ANY.
|
* OpenFlow 1.1+ OFPT_QUEUE_GET_CONFIG_REQUEST now supports OFPP_ANY.
|
||||||
* OpenFlow 1.4+ OFPMP_QUEUE_DESC is now supported.
|
* OpenFlow 1.4+ OFPMP_QUEUE_DESC is now supported.
|
||||||
* New property-based packet-in message format NXT_PACKET_IN2.
|
* New property-based packet-in message format NXT_PACKET_IN2 with support
|
||||||
|
for arbitrary user-provided data.
|
||||||
- ovs-ofctl:
|
- ovs-ofctl:
|
||||||
* queue-get-config command now allows a queue ID to be specified.
|
* queue-get-config command now allows a queue ID to be specified.
|
||||||
- DPDK:
|
- DPDK:
|
||||||
|
@ -254,6 +254,7 @@ enum nx_packet_in2_prop_type {
|
|||||||
/* Other. */
|
/* Other. */
|
||||||
NXPINT_REASON, /* uint8_t, one of OFPR_*. */
|
NXPINT_REASON, /* uint8_t, one of OFPR_*. */
|
||||||
NXPINT_METADATA, /* NXM or OXM for metadata fields. */
|
NXPINT_METADATA, /* NXM or OXM for metadata fields. */
|
||||||
|
NXPINT_USERDATA, /* From NXAST_CONTROLLER2 userdata. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Configures the "role" of the sending controller. The default role is:
|
/* Configures the "role" of the sending controller. The default role is:
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "nx-match.h"
|
#include "nx-match.h"
|
||||||
#include "odp-netlink.h"
|
#include "odp-netlink.h"
|
||||||
#include "ofp-parse.h"
|
#include "ofp-parse.h"
|
||||||
|
#include "ofp-prop.h"
|
||||||
#include "ofp-util.h"
|
#include "ofp-util.h"
|
||||||
#include "ofpbuf.h"
|
#include "ofpbuf.h"
|
||||||
#include "unaligned.h"
|
#include "unaligned.h"
|
||||||
@ -273,6 +274,8 @@ enum ofp_raw_action_type {
|
|||||||
|
|
||||||
/* NX1.0+(20): struct nx_action_controller. */
|
/* NX1.0+(20): struct nx_action_controller. */
|
||||||
NXAST_RAW_CONTROLLER,
|
NXAST_RAW_CONTROLLER,
|
||||||
|
/* NX1.0+(37): struct nx_action_controller2, ... */
|
||||||
|
NXAST_RAW_CONTROLLER2,
|
||||||
|
|
||||||
/* NX1.0+(22): struct nx_action_write_metadata. */
|
/* NX1.0+(22): struct nx_action_write_metadata. */
|
||||||
NXAST_RAW_WRITE_METADATA,
|
NXAST_RAW_WRITE_METADATA,
|
||||||
@ -625,6 +628,27 @@ struct nx_action_controller {
|
|||||||
};
|
};
|
||||||
OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
|
OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
|
||||||
|
|
||||||
|
/* Properties for NXAST_CONTROLLER2. */
|
||||||
|
enum nx_action_controller2_prop_type {
|
||||||
|
NXAC2PT_MAX_LEN, /* ovs_be16 max bytes to send (default all). */
|
||||||
|
NXAC2PT_CONTROLLER_ID, /* ovs_be16 dest controller ID (default 0). */
|
||||||
|
NXAC2PT_REASON, /* uint8_t reason (OFPR_*), default 0. */
|
||||||
|
NXAC2PT_USERDATA, /* Data to copy into NXPINT_USERDATA. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Action structure for NXAST_CONTROLLER2.
|
||||||
|
*
|
||||||
|
* This replacement for NXAST_CONTROLLER makes it extensible via properties. */
|
||||||
|
struct nx_action_controller2 {
|
||||||
|
ovs_be16 type; /* OFPAT_VENDOR. */
|
||||||
|
ovs_be16 len; /* Length is 16 or more. */
|
||||||
|
ovs_be32 vendor; /* NX_VENDOR_ID. */
|
||||||
|
ovs_be16 subtype; /* NXAST_CONTROLLER2. */
|
||||||
|
uint8_t zeros[6]; /* Must be zero. */
|
||||||
|
/* Followed by NXAC2PT_* properties. */
|
||||||
|
};
|
||||||
|
OFP_ASSERT(sizeof(struct nx_action_controller2) == 16);
|
||||||
|
|
||||||
static enum ofperr
|
static enum ofperr
|
||||||
decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
|
decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
|
||||||
enum ofp_version ofp_version OVS_UNUSED,
|
enum ofp_version ofp_version OVS_UNUSED,
|
||||||
@ -633,9 +657,77 @@ decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
|
|||||||
struct ofpact_controller *oc;
|
struct ofpact_controller *oc;
|
||||||
|
|
||||||
oc = ofpact_put_CONTROLLER(out);
|
oc = ofpact_put_CONTROLLER(out);
|
||||||
|
oc->ofpact.raw = NXAST_RAW_CONTROLLER;
|
||||||
oc->max_len = ntohs(nac->max_len);
|
oc->max_len = ntohs(nac->max_len);
|
||||||
oc->controller_id = ntohs(nac->controller_id);
|
oc->controller_id = ntohs(nac->controller_id);
|
||||||
oc->reason = nac->reason;
|
oc->reason = nac->reason;
|
||||||
|
ofpact_finish(out, &oc->ofpact);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ofperr
|
||||||
|
decode_NXAST_RAW_CONTROLLER2(const struct nx_action_controller2 *nac2,
|
||||||
|
enum ofp_version ofp_version OVS_UNUSED,
|
||||||
|
struct ofpbuf *out)
|
||||||
|
{
|
||||||
|
if (!is_all_zeros(nac2->zeros, sizeof nac2->zeros)) {
|
||||||
|
return OFPERR_NXBRC_MUST_BE_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t start_ofs = out->size;
|
||||||
|
struct ofpact_controller *oc = ofpact_put_CONTROLLER(out);
|
||||||
|
oc->ofpact.raw = NXAST_RAW_CONTROLLER2;
|
||||||
|
oc->max_len = UINT16_MAX;
|
||||||
|
oc->reason = OFPR_ACTION;
|
||||||
|
|
||||||
|
struct ofpbuf properties;
|
||||||
|
ofpbuf_use_const(&properties, nac2, ntohs(nac2->len));
|
||||||
|
ofpbuf_pull(&properties, sizeof *nac2);
|
||||||
|
|
||||||
|
while (properties.size > 0) {
|
||||||
|
struct ofpbuf payload;
|
||||||
|
uint64_t type;
|
||||||
|
|
||||||
|
enum ofperr error = ofpprop_pull(&properties, &payload, &type);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NXAC2PT_MAX_LEN:
|
||||||
|
error = ofpprop_parse_u16(&payload, &oc->max_len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NXAC2PT_CONTROLLER_ID:
|
||||||
|
error = ofpprop_parse_u16(&payload, &oc->controller_id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NXAC2PT_REASON: {
|
||||||
|
uint8_t u8;
|
||||||
|
error = ofpprop_parse_u8(&payload, &u8);
|
||||||
|
oc->reason = u8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NXAC2PT_USERDATA:
|
||||||
|
out->size = start_ofs + OFPACT_CONTROLLER_SIZE;
|
||||||
|
ofpbuf_put(out, payload.msg, ofpbuf_msgsize(&payload));
|
||||||
|
oc = ofpbuf_at_assert(out, start_ofs, sizeof *oc);
|
||||||
|
oc->userdata_len = ofpbuf_msgsize(&payload);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = OFPPROP_UNKNOWN(false, "NXAST_RAW_CONTROLLER2", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofpact_finish(out, &oc->ofpact);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,6 +736,26 @@ encode_CONTROLLER(const struct ofpact_controller *controller,
|
|||||||
enum ofp_version ofp_version OVS_UNUSED,
|
enum ofp_version ofp_version OVS_UNUSED,
|
||||||
struct ofpbuf *out)
|
struct ofpbuf *out)
|
||||||
{
|
{
|
||||||
|
if (controller->userdata_len
|
||||||
|
|| controller->ofpact.raw == NXAST_RAW_CONTROLLER2) {
|
||||||
|
size_t start_ofs = out->size;
|
||||||
|
put_NXAST_CONTROLLER2(out);
|
||||||
|
if (controller->max_len != UINT16_MAX) {
|
||||||
|
ofpprop_put_u16(out, NXAC2PT_MAX_LEN, controller->max_len);
|
||||||
|
}
|
||||||
|
if (controller->controller_id != 0) {
|
||||||
|
ofpprop_put_u16(out, NXAC2PT_CONTROLLER_ID,
|
||||||
|
controller->controller_id);
|
||||||
|
}
|
||||||
|
if (controller->reason != OFPR_ACTION) {
|
||||||
|
ofpprop_put_u8(out, NXAC2PT_REASON, controller->reason);
|
||||||
|
}
|
||||||
|
if (controller->userdata_len != 0) {
|
||||||
|
ofpprop_put(out, NXAC2PT_USERDATA, controller->userdata,
|
||||||
|
controller->userdata_len);
|
||||||
|
}
|
||||||
|
pad_ofpat(out, start_ofs);
|
||||||
|
} else {
|
||||||
struct nx_action_controller *nac;
|
struct nx_action_controller *nac;
|
||||||
|
|
||||||
nac = put_NXAST_CONTROLLER(out);
|
nac = put_NXAST_CONTROLLER(out);
|
||||||
@ -651,6 +763,7 @@ encode_CONTROLLER(const struct ofpact_controller *controller,
|
|||||||
nac->controller_id = htons(controller->controller_id);
|
nac->controller_id = htons(controller->controller_id);
|
||||||
nac->reason = controller->reason;
|
nac->reason = controller->reason;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char * OVS_WARN_UNUSED_RESULT
|
static char * OVS_WARN_UNUSED_RESULT
|
||||||
parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
||||||
@ -659,6 +772,7 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
|||||||
enum ofp_packet_in_reason reason = OFPR_ACTION;
|
enum ofp_packet_in_reason reason = OFPR_ACTION;
|
||||||
uint16_t controller_id = 0;
|
uint16_t controller_id = 0;
|
||||||
uint16_t max_len = UINT16_MAX;
|
uint16_t max_len = UINT16_MAX;
|
||||||
|
const char *userdata = NULL;
|
||||||
|
|
||||||
if (!arg[0]) {
|
if (!arg[0]) {
|
||||||
/* Use defaults. */
|
/* Use defaults. */
|
||||||
@ -685,6 +799,8 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
|||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(name, "userdata")) {
|
||||||
|
userdata = value;
|
||||||
} else {
|
} else {
|
||||||
return xasprintf("unknown key \"%s\" parsing controller "
|
return xasprintf("unknown key \"%s\" parsing controller "
|
||||||
"action", name);
|
"action", name);
|
||||||
@ -692,7 +808,7 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason == OFPR_ACTION && controller_id == 0) {
|
if (reason == OFPR_ACTION && controller_id == 0 && !userdata) {
|
||||||
struct ofpact_output *output;
|
struct ofpact_output *output;
|
||||||
|
|
||||||
output = ofpact_put_OUTPUT(ofpacts);
|
output = ofpact_put_OUTPUT(ofpacts);
|
||||||
@ -705,15 +821,39 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
|
|||||||
controller->max_len = max_len;
|
controller->max_len = max_len;
|
||||||
controller->reason = reason;
|
controller->reason = reason;
|
||||||
controller->controller_id = controller_id;
|
controller->controller_id = controller_id;
|
||||||
|
|
||||||
|
if (userdata) {
|
||||||
|
size_t start_ofs = ofpacts->size;
|
||||||
|
const char *end = ofpbuf_put_hex(ofpacts, userdata, NULL);
|
||||||
|
if (*end) {
|
||||||
|
return xstrdup("bad hex digit in `controller' "
|
||||||
|
"action `userdata'");
|
||||||
|
}
|
||||||
|
size_t userdata_len = ofpacts->size - start_ofs;
|
||||||
|
controller = ofpacts->header;
|
||||||
|
controller->userdata_len = userdata_len;
|
||||||
|
}
|
||||||
|
ofpact_finish(ofpacts, &controller->ofpact);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
if (i) {
|
||||||
|
ds_put_char(s, '.');
|
||||||
|
}
|
||||||
|
ds_put_format(s, "%02"PRIx8, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
|
format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
|
||||||
{
|
{
|
||||||
if (a->reason == OFPR_ACTION && a->controller_id == 0) {
|
if (a->reason == OFPR_ACTION && !a->controller_id && !a->userdata_len) {
|
||||||
ds_put_format(s, "CONTROLLER:%"PRIu16, a->max_len);
|
ds_put_format(s, "CONTROLLER:%"PRIu16, a->max_len);
|
||||||
} else {
|
} else {
|
||||||
enum ofp_packet_in_reason reason = a->reason;
|
enum ofp_packet_in_reason reason = a->reason;
|
||||||
@ -732,6 +872,11 @@ format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
|
|||||||
if (a->controller_id != 0) {
|
if (a->controller_id != 0) {
|
||||||
ds_put_format(s, "id=%"PRIu16",", a->controller_id);
|
ds_put_format(s, "id=%"PRIu16",", a->controller_id);
|
||||||
}
|
}
|
||||||
|
if (a->userdata_len) {
|
||||||
|
ds_put_cstr(s, "userdata=");
|
||||||
|
format_hex_arg(s, a->userdata, a->userdata_len);
|
||||||
|
ds_put_char(s, ',');
|
||||||
|
}
|
||||||
ds_chomp(s, ',');
|
ds_chomp(s, ',');
|
||||||
ds_put_char(s, ')');
|
ds_put_char(s, ')');
|
||||||
}
|
}
|
||||||
@ -4400,15 +4545,8 @@ parse_NOTE(const char *arg, struct ofpbuf *ofpacts,
|
|||||||
static void
|
static void
|
||||||
format_NOTE(const struct ofpact_note *a, struct ds *s)
|
format_NOTE(const struct ofpact_note *a, struct ds *s)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
|
|
||||||
ds_put_cstr(s, "note:");
|
ds_put_cstr(s, "note:");
|
||||||
for (i = 0; i < a->length; i++) {
|
format_hex_arg(s, a->data, a->length);
|
||||||
if (i) {
|
|
||||||
ds_put_char(s, '.');
|
|
||||||
}
|
|
||||||
ds_put_format(s, "%02"PRIx8, a->data[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit action. */
|
/* Exit action. */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015 Nicira, Inc.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -56,7 +56,7 @@
|
|||||||
/* Output. */ \
|
/* Output. */ \
|
||||||
OFPACT(OUTPUT, ofpact_output, ofpact, "output") \
|
OFPACT(OUTPUT, ofpact_output, ofpact, "output") \
|
||||||
OFPACT(GROUP, ofpact_group, ofpact, "group") \
|
OFPACT(GROUP, ofpact_group, ofpact, "group") \
|
||||||
OFPACT(CONTROLLER, ofpact_controller, ofpact, "controller") \
|
OFPACT(CONTROLLER, ofpact_controller, userdata, "controller") \
|
||||||
OFPACT(ENQUEUE, ofpact_enqueue, ofpact, "enqueue") \
|
OFPACT(ENQUEUE, ofpact_enqueue, ofpact, "enqueue") \
|
||||||
OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact, "output_reg") \
|
OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact, "output_reg") \
|
||||||
OFPACT(BUNDLE, ofpact_bundle, slaves, "bundle") \
|
OFPACT(BUNDLE, ofpact_bundle, slaves, "bundle") \
|
||||||
@ -245,6 +245,11 @@ struct ofpact_controller {
|
|||||||
uint16_t max_len; /* Maximum length to send to controller. */
|
uint16_t max_len; /* Maximum length to send to controller. */
|
||||||
uint16_t controller_id; /* Controller ID to send packet-in. */
|
uint16_t controller_id; /* Controller ID to send packet-in. */
|
||||||
enum ofp_packet_in_reason reason; /* Reason to put in packet-in. */
|
enum ofp_packet_in_reason reason; /* Reason to put in packet-in. */
|
||||||
|
|
||||||
|
/* Arbitrary data to include in the packet-in message (currently, only in
|
||||||
|
* NXT_PACKET_IN2). */
|
||||||
|
uint16_t userdata_len;
|
||||||
|
uint8_t userdata[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* OFPACT_ENQUEUE.
|
/* OFPACT_ENQUEUE.
|
||||||
|
@ -94,6 +94,17 @@ ofp_packet_to_string(const void *data, size_t len)
|
|||||||
return ds_cstr(&ds);
|
return ds_cstr(&ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
if (i) {
|
||||||
|
ds_put_char(s, '.');
|
||||||
|
}
|
||||||
|
ds_put_format(s, "%02"PRIx8, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
|
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
|
||||||
int verbosity)
|
int verbosity)
|
||||||
@ -141,6 +152,12 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
|
|||||||
}
|
}
|
||||||
ds_put_char(string, '\n');
|
ds_put_char(string, '\n');
|
||||||
|
|
||||||
|
if (pin.userdata_len) {
|
||||||
|
ds_put_cstr(string, " userdata=");
|
||||||
|
format_hex_arg(string, pin.userdata, pin.userdata_len);
|
||||||
|
ds_put_char(string, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
if (verbosity > 0) {
|
if (verbosity > 0) {
|
||||||
char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
|
char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
|
||||||
ds_put_cstr(string, packet);
|
ds_put_cstr(string, packet);
|
||||||
|
@ -3361,6 +3361,11 @@ decode_nx_packet_in2(const struct ofp_header *oh,
|
|||||||
&pin->flow_metadata);
|
&pin->flow_metadata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NXPINT_USERDATA:
|
||||||
|
pin->userdata = payload.msg;
|
||||||
|
pin->userdata_len = ofpbuf_msgsize(&payload);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = OFPPROP_UNKNOWN(true, "NX_PACKET_IN2", type);
|
error = OFPPROP_UNKNOWN(true, "NX_PACKET_IN2", type);
|
||||||
break;
|
break;
|
||||||
@ -3596,6 +3601,10 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in *pin,
|
|||||||
oxm_put_raw(msg, &pin->flow_metadata, version);
|
oxm_put_raw(msg, &pin->flow_metadata, version);
|
||||||
ofpprop_end(msg, start);
|
ofpprop_end(msg, start);
|
||||||
|
|
||||||
|
if (pin->userdata_len) {
|
||||||
|
ofpprop_put(msg, NXPINT_USERDATA, pin->userdata, pin->userdata_len);
|
||||||
|
}
|
||||||
|
|
||||||
ofpmsg_update_length(msg);
|
ofpmsg_update_length(msg);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
@ -441,6 +441,10 @@ struct ofputil_packet_in {
|
|||||||
* that case, 'cookie' is UINT64_MAX. */
|
* that case, 'cookie' is UINT64_MAX. */
|
||||||
uint8_t table_id; /* OpenFlow table ID. */
|
uint8_t table_id; /* OpenFlow table ID. */
|
||||||
ovs_be64 cookie; /* Flow's cookie. */
|
ovs_be64 cookie; /* Flow's cookie. */
|
||||||
|
|
||||||
|
/* Arbitrary user-provided data. */
|
||||||
|
uint8_t *userdata;
|
||||||
|
size_t userdata_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *,
|
struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *,
|
||||||
|
@ -2248,5 +2248,6 @@ void
|
|||||||
ofproto_async_msg_free(struct ofproto_async_msg *am)
|
ofproto_async_msg_free(struct ofproto_async_msg *am)
|
||||||
{
|
{
|
||||||
free(am->pin.up.packet);
|
free(am->pin.up.packet);
|
||||||
|
free(am->pin.up.userdata);
|
||||||
free(am);
|
free(am);
|
||||||
}
|
}
|
||||||
|
@ -3602,7 +3602,8 @@ flood_packets(struct xlate_ctx *ctx, bool all)
|
|||||||
static void
|
static void
|
||||||
execute_controller_action(struct xlate_ctx *ctx, int len,
|
execute_controller_action(struct xlate_ctx *ctx, int len,
|
||||||
enum ofp_packet_in_reason reason,
|
enum ofp_packet_in_reason reason,
|
||||||
uint16_t controller_id)
|
uint16_t controller_id,
|
||||||
|
const uint8_t *userdata, size_t userdata_len)
|
||||||
{
|
{
|
||||||
struct dp_packet *packet;
|
struct dp_packet *packet;
|
||||||
|
|
||||||
@ -3638,6 +3639,10 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
|
|||||||
.reason = reason,
|
.reason = reason,
|
||||||
.table_id = ctx->table_id,
|
.table_id = ctx->table_id,
|
||||||
.cookie = ctx->rule_cookie,
|
.cookie = ctx->rule_cookie,
|
||||||
|
.userdata = (userdata_len
|
||||||
|
? xmemdup(userdata, userdata_len)
|
||||||
|
: NULL),
|
||||||
|
.userdata_len = userdata_len,
|
||||||
},
|
},
|
||||||
.max_len = len,
|
.max_len = len,
|
||||||
},
|
},
|
||||||
@ -3775,7 +3780,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
|
|||||||
|
|
||||||
for (i = 0; i < ids->n_controllers; i++) {
|
for (i = 0; i < ids->n_controllers; i++) {
|
||||||
execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
|
execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
|
||||||
ids->cnt_ids[i]);
|
ids->cnt_ids[i], NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop processing for current table. */
|
/* Stop processing for current table. */
|
||||||
@ -3824,7 +3829,8 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx)
|
|||||||
set_mpls_lse_ttl(&flow->mpls_lse[0], ttl);
|
set_mpls_lse_ttl(&flow->mpls_lse[0], ttl);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
|
execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0,
|
||||||
|
NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3862,7 +3868,7 @@ xlate_output_action(struct xlate_ctx *ctx,
|
|||||||
(ctx->in_group ? OFPR_GROUP
|
(ctx->in_group ? OFPR_GROUP
|
||||||
: ctx->in_action_set ? OFPR_ACTION_SET
|
: ctx->in_action_set ? OFPR_ACTION_SET
|
||||||
: OFPR_ACTION),
|
: OFPR_ACTION),
|
||||||
0);
|
0, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case OFPP_NONE:
|
case OFPP_NONE:
|
||||||
break;
|
break;
|
||||||
@ -4473,7 +4479,9 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
|
|||||||
controller = ofpact_get_CONTROLLER(a);
|
controller = ofpact_get_CONTROLLER(a);
|
||||||
execute_controller_action(ctx, controller->max_len,
|
execute_controller_action(ctx, controller->max_len,
|
||||||
controller->reason,
|
controller->reason,
|
||||||
controller->controller_id);
|
controller->controller_id,
|
||||||
|
controller->userdata,
|
||||||
|
controller->userdata_len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OFPACT_ENQUEUE:
|
case OFPACT_ENQUEUE:
|
||||||
|
@ -1411,6 +1411,7 @@ add_internal_flows(struct ofproto_dpif *ofproto)
|
|||||||
controller->max_len = UINT16_MAX;
|
controller->max_len = UINT16_MAX;
|
||||||
controller->controller_id = 0;
|
controller->controller_id = 0;
|
||||||
controller->reason = OFPR_IMPLICIT_MISS;
|
controller->reason = OFPR_IMPLICIT_MISS;
|
||||||
|
ofpact_finish(&ofpacts, &controller->ofpact);
|
||||||
|
|
||||||
error = add_internal_miss_flow(ofproto, id++, &ofpacts,
|
error = add_internal_miss_flow(ofproto, id++, &ofpacts,
|
||||||
&ofproto->miss_rule);
|
&ofproto->miss_rule);
|
||||||
|
@ -113,6 +113,13 @@ ffff 0010 00002320 0013 000a 0014 0000
|
|||||||
# actions=controller(reason=invalid_ttl,max_len=1234,id=5678)
|
# actions=controller(reason=invalid_ttl,max_len=1234,id=5678)
|
||||||
ffff 0010 00002320 0014 04d2 162e 02 00
|
ffff 0010 00002320 0014 04d2 162e 02 00
|
||||||
|
|
||||||
|
# actions=controller(reason=invalid_ttl,max_len=1234,id=5678,userdata=01.02.03.04.05)
|
||||||
|
ffff 0038 00002320 0025 000000000000 dnl
|
||||||
|
0000 0008 04d2 0000 dnl
|
||||||
|
0001 0008 162e 0000 dnl
|
||||||
|
0002 0005 02 000000 dnl
|
||||||
|
0003 0009 0102030405 00000000000000
|
||||||
|
|
||||||
# actions=dec_ttl(32768,12345,90,765,1024)
|
# actions=dec_ttl(32768,12345,90,765,1024)
|
||||||
ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
|
ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
|
||||||
|
|
||||||
|
@ -2849,7 +2849,7 @@ AT_CLEANUP
|
|||||||
AT_SETUP([NX_PACKET_IN2])
|
AT_SETUP([NX_PACKET_IN2])
|
||||||
AT_KEYWORDS([ofp-print])
|
AT_KEYWORDS([ofp-print])
|
||||||
AT_CHECK([ovs-ofctl ofp-print "
|
AT_CHECK([ovs-ofctl ofp-print "
|
||||||
01 04 0088 00000000 00002320 0000001e
|
01 04 0098 00000000 00002320 0000001e
|
||||||
0000 0034
|
0000 0034
|
||||||
82 82 82 82 82 82 80 81 81 81 81 81 81 00 00 50
|
82 82 82 82 82 82 80 81 81 81 81 81 81 00 00 50
|
||||||
08 00 45 00 00 28 00 00 00 00 00 06 32 05 53 53
|
08 00 45 00 00 28 00 00 00 00 00 06 32 05 53 53
|
||||||
@ -2859,9 +2859,12 @@ AT_CHECK([ovs-ofctl ofp-print "
|
|||||||
0003 0005 07 000000
|
0003 0005 07 000000
|
||||||
0004 0010 00000000 fedcba9876543210
|
0004 0010 00000000 fedcba9876543210
|
||||||
0005 0005 01 000000
|
0005 0005 01 000000
|
||||||
0006 0010 80000408 5a5a5a5a5a5a5a5a"
|
0006 0010 80000408 5a5a5a5a5a5a5a5a
|
||||||
|
0007 0009 0102030405 00000000000000
|
||||||
|
"
|
||||||
], [0], [dnl
|
], [0], [dnl
|
||||||
NXT_PACKET_IN2 (xid=0x0): table_id=7 cookie=0xfedcba9876543210 total_len=64 metadata=0x5a5a5a5a5a5a5a5a (via action) data_len=48 buffer=0x00000114
|
NXT_PACKET_IN2 (xid=0x0): table_id=7 cookie=0xfedcba9876543210 total_len=64 metadata=0x5a5a5a5a5a5a5a5a (via action) data_len=48 buffer=0x00000114
|
||||||
|
userdata=01.02.03.04.05
|
||||||
ip,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=0.0.0.0,nw_dst=0.0.0.0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
|
ip,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=0.0.0.0,nw_dst=0.0.0.0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
|
||||||
])
|
])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
@ -3353,8 +3353,8 @@ OFPT_BARRIER_REPLY (OF1.1):
|
|||||||
OVS_VSWITCHD_STOP
|
OVS_VSWITCHD_STOP
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
dnl This test checks that metadata is encoded in NXT_PACKET_IN2.
|
dnl This test checks that metadata and userdata are encoded in NXT_PACKET_IN2.
|
||||||
AT_SETUP([ofproto - packet-out with metadata (NXT_PACKET_IN2)])
|
AT_SETUP([ofproto - packet-out with metadata and userdata (NXT_PACKET_IN2)])
|
||||||
OVS_VSWITCHD_START
|
OVS_VSWITCHD_START
|
||||||
|
|
||||||
# Start a monitor listening for packet-ins.
|
# Start a monitor listening for packet-ins.
|
||||||
@ -3365,7 +3365,7 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
|
|||||||
AT_CAPTURE_FILE([monitor.log])
|
AT_CAPTURE_FILE([monitor.log])
|
||||||
|
|
||||||
# Send a packet-out with a load action to set some metadata, and forward to controller
|
# Send a packet-out with a load action to set some metadata, and forward to controller
|
||||||
AT_CHECK([ovs-ofctl packet-out br0 controller 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), load(0xaa->NXM_NX_PKT_MARK[[]]), controller' '0001020304050010203040501234'])
|
AT_CHECK([ovs-ofctl packet-out br0 controller 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), load(0xaa->NXM_NX_PKT_MARK[[]]), controller(userdata=01.02.03.04.05)' '0001020304050010203040501234'])
|
||||||
|
|
||||||
# Stop the monitor and check its output.
|
# Stop the monitor and check its output.
|
||||||
ovs-appctl -t ovs-ofctl ofctl/barrier
|
ovs-appctl -t ovs-ofctl ofctl/barrier
|
||||||
@ -3373,6 +3373,7 @@ ovs-appctl -t ovs-ofctl exit
|
|||||||
|
|
||||||
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
|
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
|
||||||
NXT_PACKET_IN2: total_len=14 pkt_mark=0xaa,metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
|
NXT_PACKET_IN2: total_len=14 pkt_mark=0xaa,metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
|
||||||
|
userdata=01.02.03.04.05
|
||||||
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
|
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
|
||||||
OFPT_BARRIER_REPLY:
|
OFPT_BARRIER_REPLY:
|
||||||
])
|
])
|
||||||
|
@ -1523,12 +1523,18 @@ default connection ID for each controller connection, and a given
|
|||||||
controller connection will only have a nonzero connection ID if its
|
controller connection will only have a nonzero connection ID if its
|
||||||
controller uses the \fBNXT_SET_CONTROLLER_ID\fR Nicira extension to
|
controller uses the \fBNXT_SET_CONTROLLER_ID\fR Nicira extension to
|
||||||
OpenFlow.
|
OpenFlow.
|
||||||
|
.IP "\fBuserdata=\fIhh\fR...\fR"
|
||||||
|
Supplies the bytes represented as hex digits \fIhh\fR as additional
|
||||||
|
data to the controller in the packet-in message. Pairs of hex digits
|
||||||
|
may be separated by periods for readability.
|
||||||
|
.
|
||||||
.RE
|
.RE
|
||||||
.IP
|
.IP
|
||||||
Any \fIreason\fR other than \fBaction\fR and any nonzero
|
If any \fIreason\fR other than \fBaction\fR or any nonzero
|
||||||
\fIcontroller-id\fR uses a Nicira vendor extension that, as of this
|
\fIcontroller-id\fR is supplied, Open vSwitch extension
|
||||||
writing, is only known to be implemented by Open vSwitch (version 1.6
|
\fBNXAST_CONTROLLER\fR, supported by Open vSwitch 1.6 and later, is
|
||||||
or later).
|
used. If \fBuserdata\fR is supplied, then \fBNXAST_CONTROLLER2\fR,
|
||||||
|
supported by Open vSwitch 2.6 and later, is used.
|
||||||
.
|
.
|
||||||
.IP \fBcontroller\fR
|
.IP \fBcontroller\fR
|
||||||
.IQ \fBcontroller\fR[\fB:\fInbytes\fR]
|
.IQ \fBcontroller\fR[\fB:\fInbytes\fR]
|
||||||
@ -2868,8 +2874,10 @@ little reason to use it with those versions of OpenFlow).
|
|||||||
.
|
.
|
||||||
.IP "\fBnxt_packet_in2\fR"
|
.IP "\fBnxt_packet_in2\fR"
|
||||||
This uses the \fBNXT_PACKET_IN2\fR message, which is extensible and
|
This uses the \fBNXT_PACKET_IN2\fR message, which is extensible and
|
||||||
should avoid the need to define new formats later. Open vSwitch 2.6
|
should avoid the need to define new formats later. In particular,
|
||||||
and later support this format.
|
this format supports passing arbitrary user-provided data to a
|
||||||
|
controller using the \fBuserdata\fB option on the \fBcontroller\fR
|
||||||
|
action. Open vSwitch 2.6 and later support this format.
|
||||||
.
|
.
|
||||||
.RE
|
.RE
|
||||||
.IP
|
.IP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user