- Ensure OpenFlow messages fit in 16-bit length field.
#define BRIDGE_PORT_NO_FLOOD 0x00000001
#define UINT32_MAX 4294967295U
+#define UINT16_MAX 65535
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
struct net_bridge_port {
struct sk_buff *skb;
int max_openflow_len;
+ if ((openflow_len + sizeof(struct ofp_header)) > UINT16_MAX) {
+ if (net_ratelimit())
+ printk("alloc_openflow_skb: openflow message too large: %d\n",
+ openflow_len);
+ return NULL;
+ }
+
genl_len = nlmsg_total_size(GENL_HDRLEN + dp_genl_family.hdrsize);
genl_len += nla_total_size(sizeof(uint32_t)); /* DP_GENL_A_DP_IDX */
genl_len += nla_total_size(openflow_len); /* DP_GENL_A_OPENFLOW */
return send_openflow_skb(skb, NULL);
}
+int
+dp_send_error_msg(struct datapath *dp, const struct sender *sender,
+ uint16_t type, uint16_t code, const uint8_t *data, size_t len)
+{
+ struct sk_buff *skb;
+ struct ofp_error_msg *oem;
+
+
+ oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR_MSG,
+ sender, &skb);
+ if (!oem)
+ return -ENOMEM;
+
+ oem->type = htons(type);
+ oem->code = htons(code);
+ memcpy(oem->data, data, len);
+
+ return send_openflow_skb(skb, sender);
+}
+
static void
fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
int table_idx)
};
int dp_output_port(struct datapath *, struct sk_buff *, int out_port);
-int dp_output_control(struct datapath *, struct sk_buff *,
- uint32_t buffer_id, size_t max_len, int reason);
+int dp_output_control(struct datapath *, struct sk_buff *, uint32_t,
+ size_t, int);
int dp_set_origin(struct datapath *, uint16_t, struct sk_buff *);
int dp_send_features_reply(struct datapath *, const struct sender *);
int dp_send_config_reply(struct datapath *, const struct sender *);
int dp_send_flow_expired(struct datapath *, struct sw_flow *);
int dp_send_flow_stats(struct datapath *, const struct sender *,
- const struct ofp_match *);
+ const struct ofp_match *);
int dp_send_table_stats(struct datapath *, const struct sender *);
int dp_send_port_stats(struct datapath *, const struct sender *);
+int dp_send_error_msg(struct datapath *, const struct sender *,
+ uint16_t, uint16_t, const uint8_t *, size_t);
int dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp);
/* Should hold at least RCU read lock when calling */
OFPT_TABLE, /* 9 Controller/switch message */
OFPT_PORT_MOD, /* 10 Controller/switch message */
OFPT_PORT_STATUS, /* 11 Async message */
- OFPT_FLOW_STATS_REQUEST, /* 12 Controller/switch message */
- OFPT_FLOW_STATS_REPLY, /* 13 Controller/switch message */
- OFPT_TABLE_STATS_REQUEST, /* 14 Controller/switch message */
- OFPT_TABLE_STATS_REPLY, /* 15 Controller/switch message */
- OFPT_PORT_STATS_REQUEST, /* 16 Controller/switch message */
- OFPT_PORT_STATS_REPLY /* 17 Controller/switch message */
+ OFPT_ERROR_MSG, /* 12 Async message */
+ OFPT_FLOW_STATS_REQUEST, /* 13 Controller/switch message */
+ OFPT_FLOW_STATS_REPLY, /* 14 Controller/switch message */
+ OFPT_TABLE_STATS_REQUEST, /* 15 Controller/switch message */
+ OFPT_TABLE_STATS_REPLY, /* 16 Controller/switch message */
+ OFPT_PORT_STATS_REQUEST, /* 17 Controller/switch message */
+ OFPT_PORT_STATS_REPLY /* 18 Controller/switch message */
};
/* Header on all OpenFlow packets. */
uint64_t byte_count;
};
+/* Error message (datapath -> controller). */
+struct ofp_error_msg {
+ struct ofp_header header;
+
+ uint16_t type;
+ uint16_t code;
+ uint8_t data[0]; /* Variable-length data. Interpreted based
+ on the type and code. */
+};
+
/* Statistics about flows that match the "match" field */
struct ofp_flow_stats {
struct ofp_match match; /* Description of fields */
ntohll(ofe->packet_count), ntohll(ofe->byte_count));
}
+/* Pretty-print the OFPT_ERROR_MSG packet of 'len' bytes at 'oh' to 'string'
+ * at the given 'verbosity' level. */
+static void
+ofp_print_error_msg(struct ds *string, const void *oh, size_t len,
+ int verbosity)
+{
+ const struct ofp_error_msg *oem = oh;
+
+ ds_put_format(string,
+ " type%d code%d\n", ntohs(oem->type), ntohs(oem->code));
+}
+
/* Pretty-print the OFPT_PORT_STATUS packet of 'len' bytes at 'oh' to 'string'
* at the given 'verbosity' level. */
static void
sizeof (struct ofp_port_status),
ofp_print_port_status
},
+ [OFPT_ERROR_MSG] = {
+ "error_msg",
+ sizeof (struct ofp_error_msg),
+ ofp_print_error_msg,
+ },
[OFPT_FLOW_STATS_REQUEST] = {
"flow_stats_request",
sizeof (struct ofp_flow_stats_request),
send_openflow_buffer(dp, buffer, NULL);
}
+void
+dp_send_error_msg(struct datapath *dp, const struct sender *sender,
+ uint16_t type, uint16_t code, const uint8_t *data, size_t len)
+{
+ struct buffer *buffer;
+ struct ofp_error_msg *oem;
+ oem = alloc_openflow_buffer(dp, sizeof(*oem)+len, OFPT_ERROR_MSG,
+ sender, &buffer);
+ oem->type = htons(type);
+ oem->code = htons(code);
+ memcpy(oem->data, data, len);
+ send_openflow_buffer(dp, buffer, sender);
+}
+
static void
fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
int table_idx, time_t now)