Skip to content

Commit

Permalink
Support userdata in NXT_PACKET_IN2.
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Pfaff <[email protected]>
Acked-by: Jarno Rajahalme <[email protected]>
  • Loading branch information
blp committed Feb 20, 2016
1 parent 4adaf18 commit bdcad67
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 34 deletions.
3 changes: 2 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Post-v2.5.0
- OpenFlow:
* OpenFlow 1.1+ OFPT_QUEUE_GET_CONFIG_REQUEST now supports OFPP_ANY.
* 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:
* queue-get-config command now allows a queue ID to be specified.
- DPDK:
Expand Down
1 change: 1 addition & 0 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ enum nx_packet_in2_prop_type {
/* Other. */
NXPINT_REASON, /* uint8_t, one of OFPR_*. */
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:
Expand Down
168 changes: 153 additions & 15 deletions lib/ofp-actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "nx-match.h"
#include "odp-netlink.h"
#include "ofp-parse.h"
#include "ofp-prop.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "unaligned.h"
Expand Down Expand Up @@ -273,6 +274,8 @@ enum ofp_raw_action_type {

/* NX1.0+(20): struct nx_action_controller. */
NXAST_RAW_CONTROLLER,
/* NX1.0+(37): struct nx_action_controller2, ... */
NXAST_RAW_CONTROLLER2,

/* NX1.0+(22): struct nx_action_write_metadata. */
NXAST_RAW_WRITE_METADATA,
Expand Down Expand Up @@ -625,6 +628,27 @@ struct nx_action_controller {
};
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
decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
enum ofp_version ofp_version OVS_UNUSED,
Expand All @@ -633,9 +657,77 @@ decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
struct ofpact_controller *oc;

oc = ofpact_put_CONTROLLER(out);
oc->ofpact.raw = NXAST_RAW_CONTROLLER;
oc->max_len = ntohs(nac->max_len);
oc->controller_id = ntohs(nac->controller_id);
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;
}

Expand All @@ -644,12 +736,33 @@ encode_CONTROLLER(const struct ofpact_controller *controller,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct nx_action_controller *nac;
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;

nac = put_NXAST_CONTROLLER(out);
nac->max_len = htons(controller->max_len);
nac->controller_id = htons(controller->controller_id);
nac->reason = controller->reason;
nac = put_NXAST_CONTROLLER(out);
nac->max_len = htons(controller->max_len);
nac->controller_id = htons(controller->controller_id);
nac->reason = controller->reason;
}
}

static char * OVS_WARN_UNUSED_RESULT
Expand All @@ -659,6 +772,7 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
enum ofp_packet_in_reason reason = OFPR_ACTION;
uint16_t controller_id = 0;
uint16_t max_len = UINT16_MAX;
const char *userdata = NULL;

if (!arg[0]) {
/* Use defaults. */
Expand All @@ -685,14 +799,16 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
if (error) {
return error;
}
} else if (!strcmp(name, "userdata")) {
userdata = value;
} else {
return xasprintf("unknown key \"%s\" parsing controller "
"action", name);
}
}
}

if (reason == OFPR_ACTION && controller_id == 0) {
if (reason == OFPR_ACTION && controller_id == 0 && !userdata) {
struct ofpact_output *output;

output = ofpact_put_OUTPUT(ofpacts);
Expand All @@ -705,15 +821,39 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
controller->max_len = max_len;
controller->reason = reason;
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;
}

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
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);
} else {
enum ofp_packet_in_reason reason = a->reason;
Expand All @@ -732,6 +872,11 @@ format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
if (a->controller_id != 0) {
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_put_char(s, ')');
}
Expand Down Expand Up @@ -4400,15 +4545,8 @@ parse_NOTE(const char *arg, struct ofpbuf *ofpacts,
static void
format_NOTE(const struct ofpact_note *a, struct ds *s)
{
size_t i;

ds_put_cstr(s, "note:");
for (i = 0; i < a->length; i++) {
if (i) {
ds_put_char(s, '.');
}
ds_put_format(s, "%02"PRIx8, a->data[i]);
}
format_hex_arg(s, a->data, a->length);
}

/* Exit action. */
Expand Down
9 changes: 7 additions & 2 deletions lib/ofp-actions.h
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -56,7 +56,7 @@
/* Output. */ \
OFPACT(OUTPUT, ofpact_output, ofpact, "output") \
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(OUTPUT_REG, ofpact_output_reg, ofpact, "output_reg") \
OFPACT(BUNDLE, ofpact_bundle, slaves, "bundle") \
Expand Down Expand Up @@ -245,6 +245,11 @@ struct ofpact_controller {
uint16_t max_len; /* Maximum length to send to controller. */
uint16_t controller_id; /* Controller ID to send 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.
Expand Down
17 changes: 17 additions & 0 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ ofp_packet_to_string(const void *data, size_t len)
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
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
int verbosity)
Expand Down Expand Up @@ -141,6 +152,12 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
}
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) {
char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
ds_put_cstr(string, packet);
Expand Down
9 changes: 9 additions & 0 deletions lib/ofp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -3361,6 +3361,11 @@ decode_nx_packet_in2(const struct ofp_header *oh,
&pin->flow_metadata);
break;

case NXPINT_USERDATA:
pin->userdata = payload.msg;
pin->userdata_len = ofpbuf_msgsize(&payload);
break;

default:
error = OFPPROP_UNKNOWN(true, "NX_PACKET_IN2", type);
break;
Expand Down Expand Up @@ -3596,6 +3601,10 @@ ofputil_encode_nx_packet_in2(const struct ofputil_packet_in *pin,
oxm_put_raw(msg, &pin->flow_metadata, version);
ofpprop_end(msg, start);

if (pin->userdata_len) {
ofpprop_put(msg, NXPINT_USERDATA, pin->userdata, pin->userdata_len);
}

ofpmsg_update_length(msg);
return msg;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/ofp-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ struct ofputil_packet_in {
* that case, 'cookie' is UINT64_MAX. */
uint8_t table_id; /* OpenFlow table ID. */
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 *,
Expand Down
1 change: 1 addition & 0 deletions ofproto/connmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2248,5 +2248,6 @@ void
ofproto_async_msg_free(struct ofproto_async_msg *am)
{
free(am->pin.up.packet);
free(am->pin.up.userdata);
free(am);
}
Loading

0 comments on commit bdcad67

Please sign in to comment.