-# Copyright (c) 2008, 2009 Nicira Networks
+# Copyright (c) 2008, 2009, 2010 Nicira Networks
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# limitations under the License.
AC_PREREQ(2.63)
- AC_INIT(openvswitch, 0.99.1, ovs-bugs@openvswitch.org)
+ AC_INIT(openvswitch, 0.99.2, ovs-bugs@openvswitch.org)
NX_BUILDNR
AC_CONFIG_SRCDIR([datapath/datapath.c])
AC_CONFIG_MACRO_DIR([m4])
AC_C_BIGENDIAN
AC_SYS_LARGEFILE
+AC_SEARCH_LIBS([pow], [m])
+
OVS_CHECK_COVERAGE
OVS_CHECK_NDEBUG
OVS_CHECK_NETLINK
OVS_CHECK_VALGRIND
OVS_CHECK_TTY_LOCK_DIR
OVS_CHECK_SOCKET_LIBS
-OVS_CHECK_FAULT_LIBS
AC_CHECK_FUNCS([strsignal])
datapath/linux-2.6/Makefile.main
tests/atlocal])
+dnl This makes sure that include/openflow gets created in the build directory.
+AC_CONFIG_COMMANDS([include/openflow/openflow.h.stamp])
+
AC_OUTPUT
#include <linux/udp.h>
#include <linux/in6.h>
#include <linux/if_vlan.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/checksum.h>
#include "datapath.h"
mask = VLAN_VID_MASK;
key->dl_vlan = htons(tci & mask);
} else {
- tci = a->vlan_pcp.vlan_pcp << 13;
+ tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
mask = VLAN_PCP_MASK;
}
__be32 from, __be32 to, int pseudohdr)
{
__be32 diff[] = { ~from, to };
- if (skb->ip_summed != CHECKSUM_PARTIAL) {
+
+/* On older kernels, CHECKSUM_PARTIAL and CHECKSUM_COMPLETE are both defined
+ * as CHECKSUM_HW. However, we can make some inferences so that we can update
+ * the checksums appropriately. */
+ enum {
+ CSUM_PARTIAL, /* Partial checksum, skb->csum undefined. */
+ CSUM_PACKET, /* In-packet checksum, skb->csum undefined. */
+ CSUM_COMPLETE, /* In-packet checksum, skb->csum valid. */
+ } csum_type;
+
+ csum_type = CSUM_PACKET;
+#ifndef CHECKSUM_HW
+ /* Newer kernel, just map between kernel types and ours. */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ csum_type = CSUM_PARTIAL;
+ else if (skb->ip_summed == CHECKSUM_COMPLETE)
+ csum_type = CSUM_COMPLETE;
+#else
+ /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
+ * However, we should only get CHECKSUM_PARTIAL packets from Xen, which
+ * uses some special fields to represent this (see below). Since we
+ * can only make one type work, pick the one that actually happens in
+ * practice. */
+ if (skb->ip_summed == CHECKSUM_HW)
+ csum_type = CSUM_COMPLETE;
+#endif
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+ /* Xen has a special way of representing CHECKSUM_PARTIAL on older
+ * kernels. */
+ if (skb->proto_csum_blank)
+ csum_type = CSUM_PARTIAL;
+#endif
+
+ if (csum_type != CSUM_PARTIAL) {
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
~csum_unfold(*sum)));
- if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+ if (csum_type == CSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
~skb->csum);
} else if (pseudohdr)
return skb;
}
+static struct sk_buff *set_nw_tos(struct sk_buff *skb,
+ struct odp_flow_key *key,
+ const struct odp_action_nw_tos *a,
+ gfp_t gfp)
+{
+ if (key->dl_type != htons(ETH_P_IP))
+ return skb;
+
+ skb = make_writable(skb, 0, gfp);
+ if (skb) {
+ struct iphdr *nh = ip_hdr(skb);
+ u8 *f = &nh->tos;
+ u8 old = *f;
+ u8 new;
+
+ /* Set the DSCP bits and preserve the ECN bits. */
+ new = (a->nw_tos & ~INET_ECN_MASK) | (nh->tos & INET_ECN_MASK);
+ update_csum(&nh->check, skb, htons((uint16_t)old),
+ htons((uint16_t)new), 0);
+ *f = new;
+ }
+ return skb;
+}
+
static struct sk_buff *
set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
const struct odp_action_tp_port *a,
u16 old = *f;
u16 new = a->tp_port;
update_csum((u16*)(skb_transport_header(skb) + check_ofs),
- skb, old, new, 1);
+ skb, old, new, 0);
*f = new;
}
return skb;
return -E2BIG;
}
+ forward_ip_summed(skb);
dev_queue_xmit(skb);
return len;
skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
break;
+ case ODPAT_SET_NW_TOS:
+ skb = set_nw_tos(skb, key, &a->nw_tos, gfp);
+ break;
+
case ODPAT_SET_TP_SRC:
case ODPAT_SET_TP_DST:
skb = set_tp_port(skb, key, &a->tp_port, gfp);
#define OFP_ASSERT BOOST_STATIC_ASSERT
#endif /* __cplusplus */
- #ifndef SWIG
- #define OFP_PACKED __attribute__((packed))
- #else
- #define OFP_PACKED /* SWIG doesn't understand __attribute. */
- #endif
-
+/* Version number:
+ * Non-experimental versions released: 0x01
+ * Experimental versions released: 0x81 -- 0x99
+ */
/* The most significant bit being set in the version field indicates an
- * experimental OpenFlow version.
+ * experimental OpenFlow version.
*/
-#define OFP_VERSION 0x97
+#define OFP_VERSION 0x01
#define OFP_MAX_TABLE_NAME_LEN 32
#define OFP_MAX_PORT_NAME_LEN 16
#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */
-/* Port numbering. Physical ports are numbered starting from 0. */
+/* Port numbering. Physical ports are numbered starting from 1. */
enum ofp_port {
/* Maximum number of physical switch ports. */
OFPP_MAX = 0xff00,
/* Fake output "ports". */
- OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This
- virtual port must be explicitly used
- in order to send back out of the input
+ OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This
+ virtual port must be explicitly used
+ in order to send back out of the input
port. */
- OFPP_TABLE = 0xfff9, /* Perform actions in flow table.
+ OFPP_TABLE = 0xfff9, /* Perform actions in flow table.
NB: This can only be the destination
port for packet-out messages. */
OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */
- OFPP_FLOOD = 0xfffb, /* All physical ports except input port and
+ OFPP_FLOOD = 0xfffb, /* All physical ports except input port and
those disabled by STP. */
OFPP_ALL = 0xfffc, /* All physical ports except input port. */
- OFPP_CONTROLLER = 0xfffd, /* Send to controller. */
+ OFPP_CONTROLLER = 0xfffd, /* Send to controller. */
OFPP_LOCAL = 0xfffe, /* Local openflow "port". */
OFPP_NONE = 0xffff /* Not associated with a physical port. */
};
/* Asynchronous messages. */
OFPT_PACKET_IN, /* Async message */
- OFPT_FLOW_EXPIRED, /* Async message */
+ OFPT_FLOW_REMOVED, /* Async message */
OFPT_PORT_STATUS, /* Async message */
/* Controller command messages. */
/* Statistics messages. */
OFPT_STATS_REQUEST, /* Controller/switch message */
- OFPT_STATS_REPLY /* Controller/switch message */
+ OFPT_STATS_REPLY, /* Controller/switch message */
+
+ /* Barrier messages. */
+ OFPT_BARRIER_REQUEST, /* Controller/switch message */
+ OFPT_BARRIER_REPLY, /* Controller/switch message */
+
+ /* Queue Configuration messages. */
+ OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */
+ OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */
};
/* Header on all OpenFlow packets. */
#define OFP_DEFAULT_MISS_SEND_LEN 128
enum ofp_config_flags {
- /* Tells datapath to notify the controller of expired flow entries. */
- OFPC_SEND_FLOW_EXP = 1 << 0,
-
/* Handling of IP fragments. */
- OFPC_FRAG_NORMAL = 0 << 1, /* No special handling for fragments. */
- OFPC_FRAG_DROP = 1 << 1, /* Drop fragments. */
- OFPC_FRAG_REASM = 2 << 1, /* Reassemble (only if OFPC_IP_REASM set). */
- OFPC_FRAG_MASK = 3 << 1
+ OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */
+ OFPC_FRAG_DROP = 1, /* Drop fragments. */
+ OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */
+ OFPC_FRAG_MASK = 3
};
/* Switch configuration. */
OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */
OFPC_PORT_STATS = 1 << 2, /* Port statistics. */
OFPC_STP = 1 << 3, /* 802.1d spanning tree. */
- OFPC_MULTI_PHY_TX = 1 << 4, /* Supports transmitting through multiple
- physical interfaces */
- OFPC_IP_REASM = 1 << 5 /* Can reassemble IP fragments. */
+ OFPC_RESERVED = 1 << 4, /* Reserved, must not be set. */
+ OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */
+ OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */
+ OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP
+ pkts. */
};
/* Flags to indicate behavior of the physical port. These flags are
* used in ofp_phy_port to describe the current configuration. They are
- * used in the ofp_port_mod message to configure the port's behavior.
+ * used in the ofp_port_mod message to configure the port's behavior.
*/
enum ofp_port_config {
OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */
OFPPC_NO_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */
- OFPPC_NO_RECV = 1 << 2, /* Drop most packets received on port. */
+ OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D
+ spanning tree packets. */
OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */
OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */
OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */
/* Switch features. */
struct ofp_switch_features {
struct ofp_header header;
- uint64_t datapath_id; /* Datapath unique ID. Only the lower 48-bits
- are meaningful. */
+ uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for
+ a MAC address, while the upper 16-bits are
+ implementer-defined. */
uint32_t n_buffers; /* Max packets buffered at once. */
struct ofp_port_mod {
struct ofp_header header;
uint16_t port_no;
- uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
- configurable. This is used to
- sanity-check the request, so it must
+ uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
+ configurable. This is used to
+ sanity-check the request, so it must
be the same as returned in an
ofp_phy_port struct. */
uint32_t config; /* Bitmap of OFPPC_* flags. */
uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */
- uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all
+ uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all
bits to prevent any action taking place. */
uint8_t pad[4]; /* Pad to 64-bits. */
};
uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
uint8_t pad;
uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word,
- so the IP header is 32-bit aligned. The
+ so the IP header is 32-bit aligned. The
amount of data is inferred from the length
field in the header. Because of padding,
offsetof(struct ofp_packet_in, data) ==
OFPAT_SET_DL_DST, /* Ethernet destination address. */
OFPAT_SET_NW_SRC, /* IP source address. */
OFPAT_SET_NW_DST, /* IP destination address. */
+ OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */
OFPAT_SET_TP_SRC, /* TCP/UDP source port. */
OFPAT_SET_TP_DST, /* TCP/UDP destination port. */
+ OFPAT_ENQUEUE, /* Output to queue. */
OFPAT_VENDOR = 0xffff
};
-/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
- * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
+/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
+ * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
* number of bytes to send. A 'max_len' of zero means no bytes of the
* packet should be sent. */
struct ofp_action_output {
};
OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
+/* Action structure for OFPAT_SET_NW_TOS. */
+struct ofp_action_nw_tos {
+ uint16_t type; /* OFPAT_SET_TW_TOS. */
+ uint16_t len; /* Length is 8. */
+ uint8_t nw_tos; /* IP TOS (DSCP field, 6 bits). */
+ uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
+
/* Action structure for OFPAT_SET_TP_SRC/DST. */
struct ofp_action_tp_port {
uint16_t type; /* OFPAT_SET_TP_SRC/DST. */
struct ofp_action_vendor_header {
uint16_t type; /* OFPAT_VENDOR. */
uint16_t len; /* Length is a multiple of 8. */
- uint32_t vendor; /* Vendor ID, which takes the same form
- as in "struct ofp_vendor_header". */
+ uint32_t vendor; /* Vendor ID, which takes the same form
+ as in "struct ofp_vendor_header". */
};
OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8);
-/* Action header that is common to all actions. The length includes the
- * header and any padding used to make the action 64-bit aligned.
+/* Action header that is common to all actions. The length includes the
+ * header and any padding used to make the action 64-bit aligned.
* NB: The length of an action *must* always be a multiple of eight. */
struct ofp_action_header {
uint16_t type; /* One of OFPAT_*. */
- uint16_t len; /* Length of action, including this
- header. This is the length of action,
- including any padding to make it
+ uint16_t len; /* Length of action, including this
+ header. This is the length of action,
+ including any padding to make it
64-bit aligned. */
uint8_t pad[4];
};
struct ofp_action_vlan_vid vlan_vid;
struct ofp_action_vlan_pcp vlan_pcp;
struct ofp_action_nw_addr nw_addr;
+ struct ofp_action_nw_tos nw_tos;
struct ofp_action_tp_port tp_port;
};
OFP_ASSERT(sizeof(union ofp_action) == 8);
uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */
uint16_t actions_len; /* Size of action array in bytes. */
struct ofp_action_header actions[0]; /* Actions. */
- /* uint8_t data[0]; */ /* Packet data. The length is inferred
- from the length field in the header.
+ /* uint8_t data[0]; */ /* Packet data. The length is inferred
+ from the length field in the header.
(Only meaningful if buffer_id == -1.) */
};
OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
/* Flow wildcards. */
enum ofp_flow_wildcards {
- OFPFW_IN_PORT = 1 << 0, /* Switch input port. */
- OFPFW_DL_VLAN = 1 << 1, /* VLAN. */
- OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */
- OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */
- OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */
- OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */
- OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */
- OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */
+ OFPFW_IN_PORT = 1 << 0, /* Switch input port. */
+ OFPFW_DL_VLAN = 1 << 1, /* VLAN vid. */
+ OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */
+ OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */
+ OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */
+ OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */
+ OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */
+ OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */
/* IP source address wildcard bit count. 0 is exact match, 1 ignores the
* LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT,
OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT,
+ OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */
+ OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */
+
/* Wildcard all fields. */
- OFPFW_ALL = ((1 << 20) - 1)
+ OFPFW_ALL = ((1 << 22) - 1)
};
-/* The wildcards for ICMP type and code fields use the transport source
+/* The wildcards for ICMP type and code fields use the transport source
* and destination port fields, respectively. */
#define OFPFW_ICMP_TYPE OFPFW_TP_SRC
#define OFPFW_ICMP_CODE OFPFW_TP_DST
uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
uint16_t dl_vlan; /* Input VLAN. */
+ uint8_t dl_vlan_pcp; /* Input VLAN priority. */
+ uint8_t pad1[1]; /* Align to 64-bits. */
uint16_t dl_type; /* Ethernet frame type. */
- uint8_t nw_proto; /* IP protocol. */
- uint8_t pad; /* Align to 32-bits. */
+ uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */
+ uint8_t nw_proto; /* IP protocol or lower 8 bits of
+ ARP opcode. */
+ uint8_t pad2[2]; /* Align to 64-bits. */
uint32_t nw_src; /* IP source address. */
uint32_t nw_dst; /* IP destination address. */
uint16_t tp_src; /* TCP/UDP source port. */
uint16_t tp_dst; /* TCP/UDP destination port. */
};
-OFP_ASSERT(sizeof(struct ofp_match) == 36);
+OFP_ASSERT(sizeof(struct ofp_match) == 40);
-/* The match fields for ICMP type and code use the transport source and
+/* The match fields for ICMP type and code use the transport source and
* destination port fields, respectively. */
#define icmp_type tp_src
#define icmp_code tp_dst
/* By default, choose a priority in the middle. */
#define OFP_DEFAULT_PRIORITY 0x8000
+enum ofp_flow_mod_flags {
+ OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow
+ * expires or is deleted. */
+ OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */
+ OFPFF_EMERG = 1 << 2 /* Ramark this is for emergency. */
+};
+
/* Flow setup and teardown (controller -> datapath). */
struct ofp_flow_mod {
struct ofp_header header;
struct ofp_match match; /* Fields to match */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
/* Flow actions. */
uint16_t command; /* One of OFPFC_*. */
uint16_t idle_timeout; /* Idle time before discarding (seconds). */
uint16_t hard_timeout; /* Max time before discarding (seconds). */
uint16_t priority; /* Priority level of flow entry. */
- uint32_t buffer_id; /* Buffered packet to apply to (or -1).
+ uint32_t buffer_id; /* Buffered packet to apply to (or -1).
Not meaningful for OFPFC_DELETE*. */
- uint16_t out_port; /* For OFPFC_DELETE* commands, require
- matching entries to include this as an
- output port. A value of OFPP_NONE
+ uint16_t out_port; /* For OFPFC_DELETE* commands, require
+ matching entries to include this as an
+ output port. A value of OFPP_NONE
indicates no restriction. */
- uint8_t pad[2]; /* Align to 32-bits. */
- uint32_t reserved; /* Reserved for future use. */
- struct ofp_action_header actions[0]; /* The action length is inferred
- from the length field in the
+ uint16_t flags; /* One of OFPFF_*. */
+ struct ofp_action_header actions[0]; /* The action length is inferred
+ from the length field in the
header. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
+OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
-/* Why did this flow expire? */
-enum ofp_flow_expired_reason {
- OFPER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */
- OFPER_HARD_TIMEOUT /* Time exceeded hard_timeout. */
+/* Why was this flow removed? */
+enum ofp_flow_removed_reason {
+ OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */
+ OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */
+ OFPRR_DELETE /* Evicted by a DELETE flow mod. */
};
-/* Flow expiration (datapath -> controller). */
-struct ofp_flow_expired {
+/* Flow removed (datapath -> controller). */
+struct ofp_flow_removed {
struct ofp_header header;
struct ofp_match match; /* Description of fields. */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
uint16_t priority; /* Priority level of flow entry. */
- uint8_t reason; /* One of OFPER_*. */
+ uint8_t reason; /* One of OFPRR_*. */
uint8_t pad[1]; /* Align to 32-bits. */
- uint32_t duration; /* Time flow was alive in seconds. */
- uint8_t pad2[4]; /* Align to 64-bits. */
- uint64_t packet_count;
+ uint32_t duration_sec; /* Time flow was alive in seconds. */
+ uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond
+ duration_sec. */
+ uint16_t idle_timeout; /* Idle timeout from original flow mod. */
+ uint8_t pad2[2]; /* Align to 64-bits. */
+ uint64_t packet_count;
uint64_t byte_count;
};
-OFP_ASSERT(sizeof(struct ofp_flow_expired) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
/* Values for 'type' in ofp_error_message. These values are immutable: they
* will not change in future versions of the protocol (although new values may
OFPET_BAD_REQUEST, /* Request was not understood. */
OFPET_BAD_ACTION, /* Error in action description. */
OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */
- OFPET_PORT_MOD_FAILED /* OFPT_PORT_MOD failed. */
+ OFPET_PORT_MOD_FAILED, /* OFPT_PORT_MOD failed. */
+ OFPET_QUEUE_OP_FAILED /* Queue operation failed. */
};
/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an
* ASCII text string that may give failure details. */
enum ofp_hello_failed_code {
- OFPHFC_INCOMPATIBLE /* No compatible version. */
+ OFPHFC_INCOMPATIBLE, /* No compatible version. */
+ OFPHFC_EPERM /* Permissions error. */
};
/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least
OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */
OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */
OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */
- OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header
+ OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header
* or ofp_stats_request or ofp_stats_reply). */
OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */
- OFPBRC_BAD_LENGTH, /* Wrong request length for type. */
+ OFPBRC_EPERM, /* Permissions error. */
+ OFPBRC_BAD_LEN, /* Wrong request length for type. */
OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */
- OFPBRC_BAD_COOKIE /* Specified buffer does not exist. */
+ OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */
};
-/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
+/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
* the first 64 bytes of the failed request. */
enum ofp_bad_action_code {
OFPBAC_BAD_TYPE, /* Unknown action type. */
OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */
OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */
OFPBAC_BAD_ARGUMENT, /* Bad action argument. */
- OFPBAC_TOO_MANY /* Can't handle this many actions. */
+ OFPBAC_EPERM, /* Permissions error. */
+ OFPBAC_TOO_MANY, /* Can't handle this many actions. */
+ OFPBAC_BAD_QUEUE /* Problem validating output queue. */
};
-/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
+/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
* at least the first 64 bytes of the failed request. */
enum ofp_flow_mod_failed_code {
OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */
- OFPFMFC_BAD_COMMAND /* Unknown command. */
+ OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with
+ * CHECK_OVERLAP flag set. */
+ OFPFMFC_EPERM, /* Permissions error. */
+ OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard
+ * timeout. */
+ OFPFMFC_BAD_COMMAND, /* Unknown command. */
+ OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in
+ the order specified. */
};
/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains
OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */
};
+/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request */
+enum ofp_queue_op_failed_code {
+ OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */
+ OFPQOFC_BAD_QUEUE, /* Queue does not exist. */
+ OFPQOFC_EPERM /* Permissions error. */
+};
+
/* OFPT_ERROR: 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
+ uint8_t data[0]; /* Variable-length data. Interpreted based
on the type and code. */
};
OFP_ASSERT(sizeof(struct ofp_error_msg) == 12);
enum ofp_stats_types {
- /* Description of this OpenFlow switch.
+ /* Description of this OpenFlow switch.
* The request body is empty.
* The reply body is struct ofp_desc_stats. */
OFPST_DESC,
OFPST_TABLE,
/* Physical port statistics.
- * The request body is empty.
+ * The request body is struct ofp_port_stats_request.
* The reply body is an array of struct ofp_port_stats. */
OFPST_PORT,
+ /* Queue statistics for a port
+ * The request body defines the port
+ * The reply body is an array of struct ofp_queue_stats */
+ OFPST_QUEUE,
+
/* Vendor extension.
* The request and reply bodies begin with a 32-bit vendor ID, which takes
- * the same form as in "struct ofp_vendor_header". The request and reply
+ * the same form as in "struct ofp_vendor_header". The request and reply
* bodies are otherwise vendor-defined. */
OFPST_VENDOR = 0xffff
};
#define DESC_STR_LEN 256
#define SERIAL_NUM_LEN 32
-/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated
+/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated
* ASCII string. */
struct ofp_desc_stats {
char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */
char hw_desc[DESC_STR_LEN]; /* Hardware description. */
char sw_desc[DESC_STR_LEN]; /* Software description. */
char serial_num[SERIAL_NUM_LEN]; /* Serial number. */
+ char dp_desc[DESC_STR_LEN]; /* Human readable description of
+ the datapath. */
};
-OFP_ASSERT(sizeof(struct ofp_desc_stats) == 800);
+OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056);
/* Body for ofp_stats_request of type OFPST_FLOW. */
struct ofp_flow_stats_request {
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
uint8_t pad; /* Align to 32 bits. */
- uint16_t out_port; /* Require matching entries to include this
- as an output port. A value of OFPP_NONE
+ uint16_t out_port; /* Require matching entries to include this
+ as an output port. A value of OFPP_NONE
indicates no restriction. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40);
+OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44);
/* Body of reply to OFPST_FLOW request. */
struct ofp_flow_stats {
uint8_t table_id; /* ID of table flow came from. */
uint8_t pad;
struct ofp_match match; /* Description of fields. */
- uint32_t duration; /* Time flow has been alive in seconds. */
+ uint32_t duration_sec; /* Time flow has been alive in seconds. */
+ uint32_t duration_nsec; /* Time flow has been alive in nanoseconds
+ beyond duration_sec. */
uint16_t priority; /* Priority of the entry. Only meaningful
when this is not an exact-match entry. */
uint16_t idle_timeout; /* Number of seconds idle before expiration. */
uint16_t hard_timeout; /* Number of seconds before expiration. */
- uint16_t pad2[3]; /* Pad to 64 bits. */
+ uint8_t pad2[6]; /* Align to 64 bits. */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
uint64_t packet_count; /* Number of packets in flow. */
uint64_t byte_count; /* Number of bytes in flow. */
struct ofp_action_header actions[0]; /* Actions. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_stats) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88);
/* Body for ofp_stats_request of type OFPST_AGGREGATE. */
struct ofp_aggregate_stats_request {
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
uint8_t pad; /* Align to 32 bits. */
- uint16_t out_port; /* Require matching entries to include this
- as an output port. A value of OFPP_NONE
+ uint16_t out_port; /* Require matching entries to include this
+ as an output port. A value of OFPP_NONE
indicates no restriction. */
};
-OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40);
+OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44);
/* Body of reply to OFPST_AGGREGATE request. */
struct ofp_aggregate_stats_reply {
/* Body of reply to OFPST_TABLE request. */
struct ofp_table_stats {
- uint8_t table_id; /* Identifier of table. Lower numbered tables
+ uint8_t table_id; /* Identifier of table. Lower numbered tables
are consulted first. */
uint8_t pad[3]; /* Align to 32-bits. */
char name[OFP_MAX_TABLE_NAME_LEN];
- uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are
+ uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are
supported by the table. */
uint32_t max_entries; /* Max number of entries supported. */
uint32_t active_count; /* Number of active entries. */
};
OFP_ASSERT(sizeof(struct ofp_table_stats) == 64);
+/* Body for ofp_stats_request of type OFPST_PORT. */
+struct ofp_port_stats_request {
+ uint16_t port_no; /* OFPST_PORT message may request statistics
+ for a single port (specified with port_no)
+ or for all ports (port_no == OFPP_NONE). */
+ uint8_t pad[6];
+};
+OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8);
+
/* Body of reply to OFPST_PORT request. If a counter is unsupported, set
* the field to all ones. */
struct ofp_port_stats {
uint64_t tx_packets; /* Number of transmitted packets. */
uint64_t rx_bytes; /* Number of received bytes. */
uint64_t tx_bytes; /* Number of transmitted bytes. */
- uint64_t rx_dropped; /* Number of packets dropped by RX. */
- uint64_t tx_dropped; /* Number of packets dropped by TX. */
+ uint64_t rx_dropped; /* Number of packets dropped by RX. */
+ uint64_t tx_dropped; /* Number of packets dropped by TX. */
uint64_t rx_errors; /* Number of receive errors. This is a super-set
of receive errors and should be great than or
equal to the sum of all rx_*_err values. */
uint64_t tx_errors; /* Number of transmit errors. This is a super-set
of transmit errors. */
- uint64_t rx_frame_err; /* Number of frame alignment errors. */
- uint64_t rx_over_err; /* Number of packets with RX overrun. */
- uint64_t rx_crc_err; /* Number of CRC errors. */
- uint64_t collisions; /* Number of collisions. */
+ uint64_t rx_frame_err; /* Number of frame alignment errors. */
+ uint64_t rx_over_err; /* Number of packets with RX overrun. */
+ uint64_t rx_crc_err; /* Number of CRC errors. */
+ uint64_t collisions; /* Number of collisions. */
};
OFP_ASSERT(sizeof(struct ofp_port_stats) == 104);
/* Logical ports. */
#define ODPP_LOCAL ((__u16)0)
#define ODPP_NONE ((__u16)-1)
+ #define ODPP_NORMAL ((__u16)-2)
/* Listening channels. */
#define _ODPL_MISS_NR 0 /* Packet missed in flow table. */
__u8 dl_dst[ETH_ALEN]; /* Ethernet destination address. */
__u8 nw_proto; /* IP protocol or lower 8 bits of
ARP opcode. */
- __u8 reserved; /* Pad to 64 bits. */
+ __u8 dl_vlan_pcp; /* Input VLAN priority. */
+ __u8 nw_tos; /* IP ToS (DSCP field, 6 bits). */
+ __u8 reserved[3]; /* Align to 32-bits...must be zeroed. */
};
/* Flags for ODP_FLOW. */
#define ODPAT_SET_DL_DST 7 /* Ethernet destination address. */
#define ODPAT_SET_NW_SRC 8 /* IP source address. */
#define ODPAT_SET_NW_DST 9 /* IP destination address. */
-#define ODPAT_SET_TP_SRC 10 /* TCP/UDP source port. */
-#define ODPAT_SET_TP_DST 11 /* TCP/UDP destination port. */
-#define ODPAT_N_ACTIONS 12
+#define ODPAT_SET_NW_TOS 10 /* IP ToS/DSCP field (6 bits). */
+#define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */
+#define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */
+#define ODPAT_N_ACTIONS 13
struct odp_action_output {
__u16 type; /* ODPAT_OUTPUT. */
__be32 nw_addr; /* IP address. */
};
+struct odp_action_nw_tos {
+ __u16 type; /* ODPAT_SET_NW_TOS. */
+ __u8 nw_tos; /* IP ToS/DSCP field (6 bits). */
+ __u8 reserved1;
+ __u16 reserved2;
+ __u16 reserved3;
+};
+
/* Action structure for ODPAT_SET_TP_SRC/DST. */
struct odp_action_tp_port {
__u16 type; /* ODPAT_SET_TP_SRC/DST. */
struct odp_action_vlan_pcp vlan_pcp;
struct odp_action_dl_addr dl_addr;
struct odp_action_nw_addr nw_addr;
+ struct odp_action_nw_tos nw_tos;
struct odp_action_tp_port tp_port;
};
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
+ #include "dynamic-string.h"
#include "flow.h"
#include "hash.h"
size_t hash, const flow_t *);
static bool rules_match_1wild(const struct cls_rule *fixed,
const struct cls_rule *wild, int field_idx);
+static bool rules_match_2wild(const struct cls_rule *wild1,
+ const struct cls_rule *wild2, int field_idx);
/* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
* 'wildcards' and 'priority'.*/
cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
uint32_t wildcards, unsigned int priority)
{
- assert(flow->reserved == 0);
+ assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
rule->flow = *flow;
flow_wildcards_init(&rule->wc, wildcards);
rule->priority = priority;
rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
}
+ /* Converts 'rule' to a string and returns the string. The caller must free
+ * the string (with free()). */
+ char *
+ cls_rule_to_string(const struct cls_rule *rule)
+ {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_format(&s, "wildcards=%x priority=%u ",
+ rule->wc.wildcards, rule->priority);
+ flow_format(&s, &rule->flow);
+ return ds_cstr(&s);
+ }
+
/* Prints cls_rule 'rule', for debugging.
*
* (The output could be improved and expanded, but this was good enough to
if (new->wc.wildcards) {
list_moved(&new->node.list);
} else {
- hmap_moved(&cls->exact_table, &old->node.hmap, &new->node.hmap);
+ hmap_node_moved(&cls->exact_table,
+ &old->node.hmap, &new->node.hmap);
}
}
}
return NULL;
}
+/* Checks if the flow defined by 'target' with 'wildcards' at 'priority'
+ * overlaps with any other rule at the same priority in the classifier.
+ * Two rules are considered overlapping if a packet could match both. */
+bool
+classifier_rule_overlaps(const struct classifier *cls,
+ const flow_t *target, uint32_t wildcards,
+ unsigned int priority)
+{
+ struct cls_rule target_rule;
+ const struct hmap *tbl;
+
+ if (!wildcards) {
+ return search_exact_table(cls, flow_hash(target, 0), target) ?
+ true : false;
+ }
+
+ cls_rule_from_flow(&target_rule, target, wildcards, priority);
+
+ for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
+ struct cls_bucket *bucket;
+
+ HMAP_FOR_EACH (bucket, struct cls_bucket, hmap_node, tbl) {
+ struct cls_rule *rule;
+
+ LIST_FOR_EACH (rule, struct cls_rule, node.list,
+ &bucket->rules) {
+ if (rule->priority == priority
+ && rules_match_2wild(rule, &target_rule, 0)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
/* Ignores target->priority.
*
* 'callback' is allowed to delete the rule that is passed as its argument, but
{
return rules_match(fixed, wild, wild->wc.wildcards, wild->wc.nw_src_mask,
wild->wc.nw_dst_mask, field_idx);
+}
+
+/* Returns true if 'wild1' and 'wild2' match, that is, if their fields
+ * are equal modulo wildcards in 'wild1' or 'wild2'.
+ *
+ * 'field_idx' is the index of the first field to be compared; fields before
+ * 'field_idx' are assumed to match. Always returns true if 'field_idx' is
+ * CLS_N_FIELDS. */
+static bool
+rules_match_2wild(const struct cls_rule *wild1, const struct cls_rule *wild2,
+ int field_idx)
+{
+ return rules_match(wild1, wild2,
+ wild1->wc.wildcards | wild2->wc.wildcards,
+ wild1->wc.nw_src_mask & wild2->wc.nw_src_mask,
+ wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask,
+ field_idx);
}
/* Searches 'bucket' for a rule that matches 'target'. Returns the
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* ----------------- ----------- -------- */ \
CLS_FIELD(OFPFW_IN_PORT, in_port, IN_PORT) \
CLS_FIELD(OFPFW_DL_VLAN, dl_vlan, DL_VLAN) \
+ CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
CLS_FIELD(OFPFW_DL_SRC, dl_src, DL_SRC) \
CLS_FIELD(OFPFW_DL_DST, dl_dst, DL_DST) \
CLS_FIELD(OFPFW_DL_TYPE, dl_type, DL_TYPE) \
CLS_FIELD(OFPFW_NW_SRC_MASK, nw_src, NW_SRC) \
CLS_FIELD(OFPFW_NW_DST_MASK, nw_dst, NW_DST) \
CLS_FIELD(OFPFW_NW_PROTO, nw_proto, NW_PROTO) \
+ CLS_FIELD(OFPFW_NW_TOS, nw_tos, NW_TOS) \
CLS_FIELD(OFPFW_TP_SRC, tp_src, TP_SRC) \
CLS_FIELD(OFPFW_TP_DST, tp_dst, TP_DST)
unsigned int priority);
void cls_rule_from_match(struct cls_rule *, const struct ofp_match *,
unsigned int priority);
+ char *cls_rule_to_string(const struct cls_rule *);
void cls_rule_print(const struct cls_rule *);
void cls_rule_moved(struct classifier *,
struct cls_rule *old, struct cls_rule *new);
const flow_t *);
struct cls_rule *classifier_lookup_exact(const struct classifier *,
const flow_t *);
+bool classifier_rule_overlaps(const struct classifier *, const flow_t *,
+ uint32_t wildcards, unsigned int priority);
typedef void cls_cb_func(struct cls_rule *, void *aux);
#ifndef COMPILER_H
#define COMPILER_H 1
+ #ifdef __GNUC__
#define NO_RETURN __attribute__((__noreturn__))
#define OVS_UNUSED __attribute__((__unused__))
- #define PACKED __attribute__((__packed__))
#define PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1)))
#define STRFTIME_FORMAT(FMT) __attribute__((__format__(__strftime__, FMT, 0)))
#define MALLOC_LIKE __attribute__((__malloc__))
#define ALWAYS_INLINE __attribute__((always_inline))
- #define likely(x) __builtin_expect((x),1)
- #define unlikely(x) __builtin_expect((x),0)
+#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+ #else
+ #define NO_RETURN
+ #define OVS_UNUSED
+ #define PRINTF_FORMAT(FMT, ARG1)
+ #define STRFTIME_FORMAT(FMT)
+ #define MALLOC_LIKE
+ #define ALWAYS_INLINE
++#define WARN_UNUSED_RESULT
+ #endif
#endif /* compiler.h */
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
- #include <net/if.h>
#include <netinet/in.h>
+ #include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
struct list node;
int dp_idx;
int open_cnt;
- bool deleted;
+ bool destroyed;
bool drop_frags; /* Drop all IP fragments, if true. */
struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */
dp->open_cnt++;
- dpname = xasprintf("netdev:dp%d", dp->dp_idx);
+ dpname = xasprintf("dp%d", dp->dp_idx);
dpif = xmalloc(sizeof *dpif);
dpif_init(&dpif->dpif, &dpif_netdev_class, dpname, dp->dp_idx, dp->dp_idx);
dpif->dp = dp;
}
/* Create datapath. */
- dp_netdevs[dp_idx] = dp = xcalloc(1, sizeof *dp);
+ dp_netdevs[dp_idx] = dp = xzalloc(sizeof *dp);
list_push_back(&dp_netdev_list, &dp->node);
dp->dp_idx = dp_idx;
dp->open_cnt = 0;
error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
if (error) {
dp_netdev_free(dp);
- return error;
+ return ENODEV;
}
*dpifp = create_dpif_netdev(dp);
}
static int
-dpif_netdev_open(const char *name OVS_UNUSED, char *suffix, bool create,
+dpif_netdev_open(const char *name, const char *type OVS_UNUSED, bool create,
struct dpif **dpifp)
{
if (create) {
- if (find_dp_netdev(suffix)) {
+ if (find_dp_netdev(name)) {
return EEXIST;
} else {
- int dp_idx = name_to_dp_idx(suffix);
+ int dp_idx = name_to_dp_idx(name);
if (dp_idx >= 0) {
- return create_dp_netdev(suffix, dp_idx, dpifp);
+ return create_dp_netdev(name, dp_idx, dpifp);
} else {
/* Scan for unused dp_idx number. */
for (dp_idx = 0; dp_idx < N_DP_NETDEVS; dp_idx++) {
- int error = create_dp_netdev(suffix, dp_idx, dpifp);
+ int error = create_dp_netdev(name, dp_idx, dpifp);
if (error != EBUSY) {
return error;
}
}
}
} else {
- struct dp_netdev *dp = find_dp_netdev(suffix);
+ struct dp_netdev *dp = find_dp_netdev(name);
if (dp) {
*dpifp = create_dpif_netdev(dp);
return 0;
{
struct dp_netdev *dp = get_dp_netdev(dpif);
assert(dp->open_cnt > 0);
- if (--dp->open_cnt == 0 && dp->deleted) {
+ if (--dp->open_cnt == 0 && dp->destroyed) {
dp_netdev_free(dp);
}
free(dpif);
}
static int
-dpif_netdev_delete(struct dpif *dpif)
+dpif_netdev_destroy(struct dpif *dpif)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
- dp->deleted = true;
+ dp->destroyed = true;
return 0;
}
{
bool internal = (flags & ODP_PORT_INTERNAL) != 0;
struct dp_netdev_port *port;
+ struct netdev_options netdev_options;
struct netdev *netdev;
int mtu;
int error;
/* XXX reject devices already in some dp_netdev. */
/* Open and validate network device. */
- if (!internal) {
- error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
+ memset(&netdev_options, 0, sizeof netdev_options);
+ netdev_options.name = devname;
+ netdev_options.ethertype = NETDEV_ETH_TYPE_ANY;
+ netdev_options.may_create = true;
+ if (internal) {
+ netdev_options.type = "tap";
} else {
- error = netdev_create(devname, "tap", NULL);
- if (!error) {
- error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
- if (error) {
- netdev_destroy(devname);
- }
- }
+ netdev_options.may_open = true;
}
+
+ error = netdev_open(&netdev_options, &netdev);
if (error) {
return error;
}
name = xstrdup(netdev_get_name(port->netdev));
netdev_close(port->netdev);
- if (port->internal) {
- netdev_destroy(name);
- }
+
free(name);
free(port);
{
struct dp_netdev_flow *flow;
- assert(key->reserved == 0);
+ assert(!key->reserved[0] && !key->reserved[1] && !key->reserved[2]);
HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
flow_hash(key, 0), &dp->flow_table) {
if (flow_equal(&flow->key, key)) {
case ODPAT_SET_VLAN_PCP:
*mutates = true;
- if (a->vlan_pcp.vlan_pcp & ~VLAN_PCP_MASK) {
+ if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
return EINVAL;
}
break;
case ODPAT_SET_DL_DST:
case ODPAT_SET_NW_SRC:
case ODPAT_SET_NW_DST:
+ case ODPAT_SET_NW_TOS:
case ODPAT_SET_TP_SRC:
case ODPAT_SET_TP_DST:
*mutates = true;
struct dp_netdev_flow *flow;
int error;
- flow = xcalloc(1, sizeof *flow);
+ flow = xzalloc(sizeof *flow);
flow->key = odp_flow->key;
- flow->key.reserved = 0;
+ memset(flow->key.reserved, 0, sizeof flow->key.reserved);
error = set_flow_actions(flow, odp_flow);
if (error) {
}
}
+static void
+dp_netdev_set_nw_tos(struct ofpbuf *packet, flow_t *key,
+ const struct odp_action_nw_tos *a)
+{
+ if (key->dl_type == htons(ETH_TYPE_IP)) {
+ struct ip_header *nh = packet->l3;
+ uint8_t *field = &nh->ip_tos;
+
+ /* Set the DSCP bits and preserve the ECN bits. */
+ uint8_t new = (a->nw_tos & IP_DSCP_MASK) | (nh->ip_tos & IP_ECN_MASK);
+
+ nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
+ htons((uint16_t)a->nw_tos));
+ *field = new;
+ }
+}
+
static void
dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
const struct odp_action_tp_port *a)
break;
case ODPAT_SET_VLAN_PCP:
- dp_netdev_modify_vlan_tci(packet, key, a->vlan_pcp.vlan_pcp << 13,
- VLAN_PCP_MASK);
+ dp_netdev_modify_vlan_tci(
+ packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+ VLAN_PCP_MASK);
break;
case ODPAT_STRIP_VLAN:
dp_netdev_set_nw_addr(packet, key, &a->nw_addr);
break;
+ case ODPAT_SET_NW_TOS:
+ dp_netdev_set_nw_tos(packet, key, &a->nw_tos);
+ break;
+
case ODPAT_SET_TP_SRC:
case ODPAT_SET_TP_DST:
dp_netdev_set_tp_port(packet, key, &a->tp_port);
}
const struct dpif_class dpif_netdev_class = {
- "netdev",
"netdev",
dp_netdev_run,
dp_netdev_wait,
dpif_netdev_open,
dpif_netdev_close,
NULL, /* get_all_names */
- dpif_netdev_delete,
+ dpif_netdev_destroy,
dpif_netdev_get_stats,
dpif_netdev_get_drop_frags,
dpif_netdev_set_drop_frags,
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#ifndef DPIF_H
#define DPIF_H 1
-/* Operations for the datapath running in the local kernel. The interface can
- * generalize to multiple types of local datapaths, but the implementation only
- * supports the openflow kernel module. */
-
#include "openvswitch/datapath-protocol.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+
struct dpif;
struct ofpbuf;
struct svec;
+struct dpif_class;
void dp_run(void);
void dp_wait(void);
-int dp_enumerate(struct svec *);
-int dpif_open(const char *name, struct dpif **);
-int dpif_create(const char *name, struct dpif **);
-int dpif_create_and_open(const char *name, struct dpif **);
+int dp_register_provider(const struct dpif_class *);
+int dp_unregister_provider(const char *type);
+void dp_enumerate_types(struct svec *types);
+
+int dp_enumerate_names(const char *type, struct svec *names);
+void dp_parse_name(const char *datapath_name, char **name, char **type);
+
+int dpif_open(const char *name, const char *type, struct dpif **);
+int dpif_create(const char *name, const char *type, struct dpif **);
+int dpif_create_and_open(const char *name, const char *type, struct dpif **);
void dpif_close(struct dpif *);
const char *dpif_name(const struct dpif *);
+const char *dpif_base_name(const struct dpif *);
int dpif_get_all_names(const struct dpif *, struct svec *);
int dpif_delete(struct dpif *);
void dpif_get_netflow_ids(const struct dpif *,
uint8_t *engine_type, uint8_t *engine_id);
+ #ifdef __cplusplus
+ }
+ #endif
+
#endif /* dpif.h */
#ifndef FLOW_H
#define FLOW_H 1
+ #include <sys/types.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet,
struct odp_flow_stats *stats);
void flow_to_match(const flow_t *, uint32_t wildcards, struct ofp_match *);
-void flow_to_ovs_match(const flow_t *, uint32_t wildcards, struct ofp_match *);
void flow_from_match(flow_t *, uint32_t *wildcards, const struct ofp_match *);
char *flow_to_string(const flow_t *);
void flow_format(struct ds *, const flow_t *);
#include <config.h>
#include "ofp-print.h"
- #include "xtoxll.h"
#include <errno.h>
#include <inttypes.h>
+ #include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <stdarg.h>
#include "packets.h"
#include "pcap.h"
#include "util.h"
+ #include "xtoxll.h"
static void ofp_print_port_name(struct ds *string, uint16_t port);
sizeof(struct ofp_action_nw_addr),
sizeof(struct ofp_action_nw_addr),
},
+ [OFPAT_SET_NW_TOS] = {
+ sizeof(struct ofp_action_nw_tos),
+ sizeof(struct ofp_action_nw_tos),
+ },
[OFPAT_SET_TP_SRC] = {
sizeof(struct ofp_action_tp_port),
sizeof(struct ofp_action_tp_port),
break;
}
+ case OFPAT_SET_NW_TOS: {
+ struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
+ ds_put_format(string, "mod_nw_tos:%d", nt->nw_tos);
+ break;
+ }
+
case OFPAT_SET_TP_SRC: {
struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
int n_ports;
int i;
- ds_put_format(string, " ver:0x%x, dpid:%"PRIx64"\n",
+ ds_put_format(string, " ver:0x%x, dpid:%016"PRIx64"\n",
osf->header.version, ntohll(osf->datapath_id));
ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
ntohl(osf->n_buffers));
uint16_t flags;
flags = ntohs(osc->flags);
- if (flags & OFPC_SEND_FLOW_EXP) {
- flags &= ~OFPC_SEND_FLOW_EXP;
- ds_put_format(string, " (sending flow expirations)");
- }
if (flags) {
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
}
"%d", ntohs(om->in_port));
print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
"0x%04x", ntohs(om->dl_vlan));
+ print_wild(&f, "dl_vlan_pcp=", w & OFPFW_DL_VLAN_PCP, verbosity,
+ "%d", om->dl_vlan_pcp);
print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
print_ip_netmask(&f, "nw_dst=", om->nw_dst,
(w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
if (!skip_proto) {
- print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
- "%u", om->nw_proto);
+ if (om->dl_type == htons(ETH_TYPE_ARP)) {
+ print_wild(&f, "opcode=", w & OFPFW_NW_PROTO, verbosity,
+ "%u", om->nw_proto);
+ } else {
+ print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
+ "%u", om->nw_proto);
+ print_wild(&f, "nw_tos=", w & OFPFW_NW_TOS, verbosity,
+ "%u", om->nw_tos);
+ }
}
if (om->nw_proto == IP_TYPE_ICMP) {
print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
default:
ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
}
- ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x",
+ ds_put_format(string, "cookie:%"PRIx64" idle:%d hard:%d pri:%d "
+ "buf:%#x flags:%"PRIx16" ", ntohll(ofm->cookie),
ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
- ntohl(ofm->buffer_id));
+ ntohl(ofm->buffer_id), ntohs(ofm->flags));
ofp_print_actions(string, ofm->actions,
len - offsetof(struct ofp_flow_mod, actions));
ds_put_char(string, '\n');
}
-/* Pretty-print the OFPT_FLOW_EXPIRED packet of 'len' bytes at 'oh' to 'string'
+/* Pretty-print the OFPT_FLOW_REMOVED packet of 'len' bytes at 'oh' to 'string'
* at the given 'verbosity' level. */
static void
-ofp_print_flow_expired(struct ds *string, const void *oh,
+ofp_print_flow_removed(struct ds *string, const void *oh,
size_t len OVS_UNUSED, int verbosity)
{
- const struct ofp_flow_expired *ofe = oh;
+ const struct ofp_flow_removed *ofr = oh;
- ofp_print_match(string, &ofe->match, verbosity);
+ ofp_print_match(string, &ofr->match, verbosity);
ds_put_cstr(string, " reason=");
- switch (ofe->reason) {
- case OFPER_IDLE_TIMEOUT:
+ switch (ofr->reason) {
+ case OFPRR_IDLE_TIMEOUT:
ds_put_cstr(string, "idle");
break;
- case OFPER_HARD_TIMEOUT:
+ case OFPRR_HARD_TIMEOUT:
ds_put_cstr(string, "hard");
break;
+ case OFPRR_DELETE:
+ ds_put_cstr(string, "delete");
+ break;
default:
- ds_put_format(string, "**%"PRIu8"**", ofe->reason);
+ ds_put_format(string, "**%"PRIu8"**", ofr->reason);
break;
}
ds_put_format(string,
- " pri%"PRIu16" secs%"PRIu32" pkts%"PRIu64" bytes%"PRIu64"\n",
- ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1,
- ntohl(ofe->duration), ntohll(ofe->packet_count),
- ntohll(ofe->byte_count));
+ " cookie%"PRIx64" pri%"PRIu16" secs%"PRIu32" nsecs%"PRIu32
+ " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
+ ntohll(ofr->cookie),
+ ofr->match.wildcards ? ntohs(ofr->priority) : (uint16_t)-1,
+ ntohl(ofr->duration_sec), ntohl(ofr->duration_nsec),
+ ntohs(ofr->idle_timeout), ntohll(ofr->packet_count),
+ ntohll(ofr->byte_count));
}
static void
#define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
ERROR_TYPE(OFPET_HELLO_FAILED),
ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
+ ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_EPERM),
ERROR_TYPE(OFPET_BAD_REQUEST),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH),
+ ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_EPERM),
+ ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE),
+ ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN),
ERROR_TYPE(OFPET_BAD_ACTION),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT),
+ ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_EPERM),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_TOO_MANY),
ERROR_TYPE(OFPET_FLOW_MOD_FAILED),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL),
+ ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP),
+ ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EPERM),
+ ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_EMERG_TIMEOUT),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND),
ERROR_TYPE(OFPET_PORT_MOD_FAILED),
{
const struct ofp_desc_stats *ods = body;
- ds_put_format(string, "Manufacturer: %s\n", ods->mfr_desc);
- ds_put_format(string, "Hardware: %s\n", ods->hw_desc);
- ds_put_format(string, "Software: %s\n", ods->sw_desc);
- ds_put_format(string, "Serial Num: %s\n", ods->serial_num);
+ ds_put_format(string, "Manufacturer: %.*s\n",
+ (int) sizeof ods->mfr_desc, ods->mfr_desc);
+ ds_put_format(string, "Hardware: %.*s\n",
+ (int) sizeof ods->hw_desc, ods->hw_desc);
+ ds_put_format(string, "Software: %.*s\n",
+ (int) sizeof ods->sw_desc, ods->sw_desc);
+ ds_put_format(string, "Serial Num: %.*s\n",
+ (int) sizeof ods->serial_num, ods->serial_num);
+ ds_put_format(string, "DP Description: %.*s\n",
+ (int) sizeof ods->dp_desc, ods->dp_desc);
}
static void
break;
}
- ds_put_format(string, " duration=%"PRIu32"s, ", ntohl(fs->duration));
+ ds_put_format(string, " cookie=%"PRIu64"s, ", ntohll(fs->cookie));
+ ds_put_format(string, "duration_sec=%"PRIu32"s, ",
+ ntohl(fs->duration_sec));
+ ds_put_format(string, "duration_nsec=%"PRIu32"s, ",
+ ntohl(fs->duration_nsec));
ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
ds_put_format(string, "priority=%"PRIu16", ",
fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
}
}
+static void
+ofp_port_stats_request(struct ds *string, const void *body_,
+ size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+{
+ const struct ofp_port_stats_request *psr = body_;
+ ds_put_format(string, "port_no=%"PRIu16, ntohs(psr->port_no));
+}
+
static void
ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
int verbosity)
{
OFPST_PORT,
"port",
- { 0, 0, NULL, },
+ { sizeof(struct ofp_port_stats_request),
+ sizeof(struct ofp_port_stats_request),
+ ofp_port_stats_request },
{ 0, SIZE_MAX, ofp_port_stats_reply },
},
{
ofp_print_flow_mod,
},
{
- OFPT_FLOW_EXPIRED,
- "flow_expired",
- sizeof (struct ofp_flow_expired),
- ofp_print_flow_expired,
+ OFPT_FLOW_REMOVED,
+ "flow_removed",
+ sizeof (struct ofp_flow_removed),
+ ofp_print_flow_removed,
},
{
OFPT_PORT_MOD,
sizeof (struct ofp_vendor_header),
NULL,
},
+ {
+ OFPT_BARRIER_REQUEST,
+ "barrier_request",
+ sizeof (struct ofp_header),
+ NULL,
+ },
+ {
+ OFPT_BARRIER_REPLY,
+ "barrier_reply",
+ sizeof (struct ofp_header),
+ NULL,
+ }
};
/* Composes and returns a string representing the OpenFlow packet of 'len'
struct ofpbuf;
+bool dpid_from_string(const char *s, uint64_t *dpidp);
+
#define ETH_ADDR_LEN 6
static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] OVS_UNUSED
return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff;
}
-/* Returns true if 'ea' is an Ethernet address used for virtual interfaces
- * under XenServer. Generally the actual Ethernet address is FE:FF:FF:FF:FF:FF
- * but it can be FE:FE:FE:FE:FE:FE in some cases. */
-static inline bool eth_addr_is_vif(const uint8_t ea[6])
-{
- return ea[0] == 0xfe && (ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) >= 0xfe;
-}
-
static inline bool eth_addr_is_multicast(const uint8_t ea[6])
{
return ea[0] & 1;
}
static inline bool eth_addr_is_local(const uint8_t ea[6])
{
- return ea[0] & 2;
+ /* Local if it is either a locally administered address or a Nicira random
+ * address. */
+ return !!(ea[0] & 2)
+ || (ea[0] == 0x00 && ea[1] == 0x23 && ea[2] == 0x20 && !!(ea[3] & 0x80));
}
static inline bool eth_addr_is_zero(const uint8_t ea[6])
{
random_bytes(ea, ETH_ADDR_LEN);
eth_addr_mark_random(ea);
}
+static inline void eth_addr_nicira_random(uint8_t ea[ETH_ADDR_LEN])
+{
+ eth_addr_random(ea);
+
+ /* Set the OUI to the Nicira one. */
+ ea[0] = 0x00;
+ ea[1] = 0x23;
+ ea[2] = 0x20;
+
+ /* Set the top bit to indicate random Nicira address. */
+ ea[3] |= 0x80;
+}
/* Returns true if 'ea' is a reserved multicast address, that a bridge must
* never forward, false otherwise. */
static inline bool eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
&& (ea[5] & 0xf0) == 0x00);
}
+bool eth_addr_from_string(const char *, uint8_t ea[ETH_ADDR_LEN]);
+
void compose_benign_packet(struct ofpbuf *, const char *tag,
uint16_t snap_type,
const uint8_t eth_src[ETH_ADDR_LEN]);
BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
#define VLAN_VID_MASK 0x0fff
+ #define VLAN_VID_SHIFT 0
+
#define VLAN_PCP_MASK 0xe000
+ #define VLAN_PCP_SHIFT 13
#define VLAN_HEADER_LEN 4
struct vlan_header {
#define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
#define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
+/* TOS fields. */
+#define IP_ECN_MASK 0x03
+#define IP_DSCP_MASK 0xfc
+
#define IP_TYPE_ICMP 1
#define IP_TYPE_TCP 6
#define IP_TYPE_UDP 17
/*
- * Copyright (c) 2008 Nicira Networks.
+ * Copyright (c) 2008, 2009 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <poll.h>
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+
struct poll_waiter;
/* Schedule events to wake up the following poll_block(). */
/* Wait until an event occurs. */
void poll_block(void);
-/* Autonomous function callbacks. */
-typedef void poll_fd_func(int fd, short int revents, void *aux);
-struct poll_waiter *poll_fd_callback(int fd, short int events,
- poll_fd_func *, void *aux);
-
/* Cancel a file descriptor callback or event. */
void poll_cancel(struct poll_waiter *);
+ #ifdef __cplusplus
+ }
+ #endif
+
#endif /* poll-loop.h */
time_t last_connected;
unsigned int packets_sent;
unsigned int seqno;
+ int last_error;
/* In S_ACTIVE and S_IDLE, probably_admitted reports whether we believe
* that the peer has made a (positive) admission control decision on our
static void set_vconn_name(struct rconn *, const char *name);
static int try_send(struct rconn *);
static int reconnect(struct rconn *);
+ static void report_error(struct rconn *, int error);
static void disconnect(struct rconn *, int error);
static void flush_queue(struct rconn *);
static void question_connectivity(struct rconn *);
struct rconn *
rconn_create(int probe_interval, int max_backoff)
{
- struct rconn *rc = xcalloc(1, sizeof *rc);
+ struct rconn *rc = xzalloc(sizeof *rc);
rc->state = S_VOID;
rc->state_entered = time_now();
rconn_reconnect(struct rconn *rc)
{
if (rc->state & (S_ACTIVE | S_IDLE)) {
+ VLOG_INFO("%s: disconnecting", rc->name);
disconnect(rc, 0);
}
}
} else {
VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
- disconnect(rc, 0);
+ disconnect(rc, retval);
}
return retval;
}
} else if (timed_out(rc)) {
VLOG_INFO("%s: connection timed out", rc->name);
rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
- disconnect(rc, 0);
+ disconnect(rc, ETIMEDOUT);
}
}
VLOG_ERR("%s: no response to inactivity probe after %u "
"seconds, disconnecting",
rc->name, elapsed_in_this_state(rc));
- disconnect(rc, 0);
+ disconnect(rc, ETIMEDOUT);
} else {
do_tx_work(rc);
}
rconn_run(struct rconn *rc)
{
int old_state;
+ size_t i;
+
+ if (rc->vconn) {
+ vconn_run(rc->vconn);
+ }
+ for (i = 0; i < rc->n_monitors; i++) {
+ vconn_run(rc->monitors[i]);
+ }
+
do {
old_state = rc->state;
switch (rc->state) {
void
rconn_run_wait(struct rconn *rc)
{
- unsigned int timeo = timeout(rc);
+ unsigned int timeo;
+ size_t i;
+
+ if (rc->vconn) {
+ vconn_run_wait(rc->vconn);
+ }
+ for (i = 0; i < rc->n_monitors; i++) {
+ vconn_run_wait(rc->monitors[i]);
+ }
+
+ timeo = timeout(rc);
if (timeo != UINT_MAX) {
unsigned int expires = sat_add(rc->state_entered, timeo);
unsigned int remaining = sat_sub(expires, time_now());
}
return buffer;
} else if (error != EAGAIN) {
+ report_error(rc, error);
disconnect(rc, error);
}
}
{
return rc->seqno;
}
+
+ /* Returns a value that explains why 'rc' last disconnected:
+ *
+ * - 0 means that the last disconnection was caused by a call to
+ * rconn_disconnect(), or that 'rc' is new and has not yet completed its
+ * initial connection or connection attempt.
+ *
+ * - EOF means that the connection was closed in the normal way by the peer.
+ *
+ * - A positive integer is an errno value that represents the error.
+ */
+ int
+ rconn_get_last_error(const struct rconn *rc)
+ {
+ return rc->last_error;
+ }
\f
struct rconn_packet_counter *
rconn_packet_counter_create(void)
retval = vconn_send(rc->vconn, rc->txq.head);
if (retval) {
if (retval != EAGAIN) {
+ report_error(rc, retval);
disconnect(rc, retval);
}
return retval;
return 0;
}
- /* Disconnects 'rc'. 'error' is used only for logging purposes. If it is
- * nonzero, then it should be EOF to indicate the connection was closed by the
- * peer in a normal fashion or a positive errno value. */
+ /* Reports that 'error' caused 'rc' to disconnect. 'error' may be a positive
+ * errno value, or it may be EOF to indicate that the connection was closed
+ * normally. */
+ static void
+ report_error(struct rconn *rc, int error)
+ {
+ if (error == EOF) {
+ /* If 'rc' isn't reliable, then we don't really expect this connection
+ * to last forever anyway (probably it's a connection that we received
+ * via accept()), so use DBG level to avoid cluttering the logs. */
+ enum vlog_level level = rc->reliable ? VLL_INFO : VLL_DBG;
+ VLOG(level, "%s: connection closed by peer", rc->name);
+ } else {
+ VLOG_WARN("%s: connection dropped (%s)", rc->name, strerror(error));
+ }
+ }
+
+ /* Disconnects 'rc' and records 'error' as the error that caused 'rc''s last
+ * disconnection:
+ *
+ * - 0 means that this disconnection is due to a request by 'rc''s client,
+ * not due to any kind of network error.
+ *
+ * - EOF means that the connection was closed in the normal way by the peer.
+ *
+ * - A positive integer is an errno value that represents the error.
+ */
static void
disconnect(struct rconn *rc, int error)
{
+ rc->last_error = error;
if (rc->reliable) {
time_t now = time_now();
if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) {
- if (error > 0) {
- VLOG_WARN("%s: connection dropped (%s)",
- rc->name, strerror(error));
- } else if (error == EOF) {
- if (rc->reliable) {
- VLOG_INFO("%s: connection closed by peer", rc->name);
- }
- } else {
- VLOG_INFO("%s: connection dropped", rc->name);
- }
vconn_close(rc->vconn);
rc->vconn = NULL;
flush_queue(rc);
* applies to all modifications. */
#include "stp.h"
+ #include <sys/types.h>
+ #include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <inttypes.h>
struct stp *stp;
struct stp_port *p;
- stp = xcalloc(1, sizeof *stp);
+ stp = xzalloc(sizeof *stp);
stp->name = xstrdup(name);
stp->bridge_id = bridge_id;
if (!(stp->bridge_id >> 48)) {
void
stp_destroy(struct stp *stp)
{
- free(stp);
+ if (stp) {
+ free(stp->name);
+ free(stp);
+ }
}
/* Runs 'stp' given that 'ms' milliseconds have passed. */
#endif
#define NOT_REACHED() abort()
- #define NOT_IMPLEMENTED() abort()
- #define NOT_TESTED() ((void) 0) /* XXX should print a message. */
/* Given POINTER, the address of the given MEMBER in a STRUCT object, returns
the STRUCT object. */
void out_of_memory(void) NO_RETURN;
void *xmalloc(size_t) MALLOC_LIKE;
void *xcalloc(size_t, size_t) MALLOC_LIKE;
+void *xzalloc(size_t) MALLOC_LIKE;
void *xrealloc(void *, size_t);
void *xmemdup(const void *, size_t) MALLOC_LIKE;
char *xmemdup0(const char *, size_t) MALLOC_LIKE;
bool str_to_ulong(const char *, int base, unsigned long *);
bool str_to_ullong(const char *, int base, unsigned long long *);
+bool str_to_double(const char *, double *);
+
+int hexit_value(int c);
+
+char *dir_name(const char *file_name);
+
+void ignore(bool x OVS_UNUSED);
+
#ifdef __cplusplus
}
#endif
struct vconn_class *class = vconn_classes[i];
assert(class->name != NULL);
assert(class->open != NULL);
- if (class->close || class->recv || class->send || class->wait) {
+ if (class->close || class->recv || class->send
+ || class->run || class->run_wait || class->wait) {
assert(class->close != NULL);
assert(class->recv != NULL);
assert(class->send != NULL);
#endif
}
+ /* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0. Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+ static int
+ vconn_lookup_class(const char *name, struct vconn_class **classp)
+ {
+ size_t prefix_len;
+
+ prefix_len = strcspn(name, ":");
+ if (name[prefix_len] != '\0') {
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
+ struct vconn_class *class = vconn_classes[i];
+ if (strlen(class->name) == prefix_len
+ && !memcmp(class->name, name, prefix_len)) {
+ *classp = class;
+ return 0;
+ }
+ }
+ }
+
+ *classp = NULL;
+ return EAFNOSUPPORT;
+ }
+
+ /* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT. */
+ int
+ vconn_verify_name(const char *name)
+ {
+ struct vconn_class *class;
+ return vconn_lookup_class(name, &class);
+ }
+
/* Attempts to connect to an OpenFlow device. 'name' is a connection name in
* the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS
* are vconn class-specific.
int
vconn_open(const char *name, int min_version, struct vconn **vconnp)
{
- size_t prefix_len;
- size_t i;
+ struct vconn_class *class;
+ struct vconn *vconn;
+ char *suffix_copy;
+ int error;
COVERAGE_INC(vconn_open);
check_vconn_classes();
- *vconnp = NULL;
- prefix_len = strcspn(name, ":");
- if (prefix_len == strlen(name)) {
- return EAFNOSUPPORT;
+ /* Look up the class. */
+ error = vconn_lookup_class(name, &class);
+ if (!class) {
+ goto error;
}
- for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
- struct vconn_class *class = vconn_classes[i];
- if (strlen(class->name) == prefix_len
- && !memcmp(class->name, name, prefix_len)) {
- struct vconn *vconn;
- char *suffix_copy = xstrdup(name + prefix_len + 1);
- int retval = class->open(name, suffix_copy, &vconn);
- free(suffix_copy);
- if (!retval) {
- assert(vconn->state != VCS_CONNECTING
- || vconn->class->connect);
- vconn->min_version = min_version;
- *vconnp = vconn;
- }
- return retval;
- }
+
+ /* Call class's "open" function. */
+ suffix_copy = xstrdup(strchr(name, ':') + 1);
+ error = class->open(name, suffix_copy, &vconn);
+ free(suffix_copy);
+ if (error) {
+ goto error;
}
- return EAFNOSUPPORT;
+
+ /* Success. */
+ assert(vconn->state != VCS_CONNECTING || vconn->class->connect);
+ vconn->min_version = min_version;
+ *vconnp = vconn;
+ return 0;
+
+ error:
+ *vconnp = NULL;
+ return error;
}
+/* Allows 'vconn' to perform maintenance activities, such as flushing output
+ * buffers. */
+void
+vconn_run(struct vconn *vconn)
+{
+ if (vconn->class->run) {
+ (vconn->class->run)(vconn);
+ }
+}
+
+/* Arranges for the poll loop to wake up when 'vconn' needs to perform
+ * maintenance activities. */
+void
+vconn_run_wait(struct vconn *vconn)
+{
+ if (vconn->class->run_wait) {
+ (vconn->class->run_wait)(vconn);
+ }
+}
+
int
vconn_open_block(const char *name, int min_version, struct vconn **vconnp)
{
error = vconn_open(name, min_version, &vconn);
while (error == EAGAIN) {
+ vconn_run(vconn);
+ vconn_run_wait(vconn);
vconn_connect_wait(vconn);
poll_block();
error = vconn_connect(vconn);
{
int retval;
while ((retval = vconn_send(vconn, msg)) == EAGAIN) {
+ vconn_run(vconn);
+ vconn_run_wait(vconn);
vconn_send_wait(vconn);
poll_block();
}
{
int retval;
while ((retval = vconn_recv(vconn, msgp)) == EAGAIN) {
+ vconn_run(vconn);
+ vconn_run_wait(vconn);
vconn_recv_wait(vconn);
poll_block();
}
vconn_wait(vconn, WAIT_SEND);
}
+ /* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0. Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+ static int
+ pvconn_lookup_class(const char *name, struct pvconn_class **classp)
+ {
+ size_t prefix_len;
+
+ prefix_len = strcspn(name, ":");
+ if (name[prefix_len] != '\0') {
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+ struct pvconn_class *class = pvconn_classes[i];
+ if (strlen(class->name) == prefix_len
+ && !memcmp(class->name, name, prefix_len)) {
+ *classp = class;
+ return 0;
+ }
+ }
+ }
+
+ *classp = NULL;
+ return EAFNOSUPPORT;
+ }
+
+ /* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT. */
+ int
+ pvconn_verify_name(const char *name)
+ {
+ struct pvconn_class *class;
+ return pvconn_lookup_class(name, &class);
+ }
+
/* Attempts to start listening for OpenFlow connections. 'name' is a
* connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
* class's name and ARGS are vconn class-specific.
int
pvconn_open(const char *name, struct pvconn **pvconnp)
{
- size_t prefix_len;
- size_t i;
+ struct pvconn_class *class;
+ struct pvconn *pvconn;
+ char *suffix_copy;
+ int error;
check_vconn_classes();
- *pvconnp = NULL;
- prefix_len = strcspn(name, ":");
- if (prefix_len == strlen(name)) {
- return EAFNOSUPPORT;
+ /* Look up the class. */
+ error = pvconn_lookup_class(name, &class);
+ if (!class) {
+ goto error;
}
- for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
- struct pvconn_class *class = pvconn_classes[i];
- if (strlen(class->name) == prefix_len
- && !memcmp(class->name, name, prefix_len)) {
- char *suffix_copy = xstrdup(name + prefix_len + 1);
- int retval = class->listen(name, suffix_copy, pvconnp);
- free(suffix_copy);
- if (retval) {
- *pvconnp = NULL;
- }
- return retval;
- }
+
+ /* Call class's "open" function. */
+ suffix_copy = xstrdup(strchr(name, ':') + 1);
+ error = class->listen(name, suffix_copy, &pvconn);
+ free(suffix_copy);
+ if (error) {
+ goto error;
}
- return EAFNOSUPPORT;
+
+ /* Success. */
+ *pvconnp = pvconn;
+ return 0;
+
+ error:
+ *pvconnp = NULL;
+ return error;
}
/* Returns the name that was used to open 'pvconn'. The caller must not
ofm->header.version = OFP_VERSION;
ofm->header.type = OFPT_FLOW_MOD;
ofm->header.length = htons(size);
+ ofm->cookie = 0;
ofm->match.wildcards = htonl(0);
ofm->match.in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
: flow->in_port);
memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src);
memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst);
ofm->match.dl_vlan = flow->dl_vlan;
+ ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp;
ofm->match.dl_type = flow->dl_type;
ofm->match.nw_src = flow->nw_src;
ofm->match.nw_dst = flow->nw_dst;
ofm->match.nw_proto = flow->nw_proto;
+ ofm->match.nw_tos = flow->nw_tos;
ofm->match.tp_src = flow->tp_src;
ofm->match.tp_dst = flow->tp_dst;
ofm->command = htons(command);
"received %s message of length %zu (expected %zu)",
type_name, got_size, size);
free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
return 0;
"(expected at least %zu)",
type_name, got_size, min_size);
free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
if ((got_size - min_size) % array_elt_size) {
char *type_name = ofp_message_type_to_string(type);
type_name, got_size, min_size, got_size - min_size,
array_elt_size, (got_size - min_size) % array_elt_size);
free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
if (n_array_elts) {
*n_array_elts = (got_size - min_size) / array_elt_size;
VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions "
"but message has room for only %zu bytes",
actions_len, extra);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
if (actions_len % sizeof(union ofp_action)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions, "
"which is not a multiple of %zu",
actions_len, sizeof(union ofp_action));
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
n_actions = actions_len / sizeof(union ofp_action);
switch (ntohs(a->type)) {
case OFPAT_OUTPUT:
error = check_action_port(ntohs(a->output.port), max_ports);
- if (error) {
- return error;
- }
- return check_action_exact_len(a, len, 8);
+ return error ? error : check_action_exact_len(a, len, 8);
case OFPAT_SET_VLAN_VID:
case OFPAT_SET_VLAN_PCP:
case OFPAT_STRIP_VLAN:
case OFPAT_SET_NW_SRC:
case OFPAT_SET_NW_DST:
+ case OFPAT_SET_NW_TOS:
case OFPAT_SET_TP_SRC:
case OFPAT_SET_TP_DST:
return check_action_exact_len(a, len, 8);
return check_action_exact_len(a, len, 16);
case OFPAT_VENDOR:
- if (a->vendor.vendor == htonl(NX_VENDOR_ID)) {
- return check_nicira_action(a, len);
- } else {
- return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR);
- }
- break;
+ return (a->vendor.vendor == htonl(NX_VENDOR_ID)
+ ? check_nicira_action(a, len)
+ : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
default:
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
ntohs(a->type));
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
}
-
- if (!len) {
- VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
- return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
- }
- if (len % ACTION_ALIGNMENT) {
- VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple of %d",
- len, ACTION_ALIGNMENT);
- return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
- }
- return 0;
}
int
"action requires %u slots but only %u remain",
n_slots, slots_left);
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+ } else if (!len) {
+ VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
+ return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+ } else if (len % ACTION_ALIGNMENT) {
+ VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple "
+ "of %d", len, ACTION_ALIGNMENT);
+ return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
}
+
error = check_action(a, len, max_ports);
if (error) {
return error;
if (wc & OFPFW_NW_DST_MASK) {
m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
}
+ } else if (m->dl_type == htons(ETH_TYPE_ARP)) {
+ if (wc & OFPFW_NW_PROTO) {
+ m->nw_proto = 0;
+ }
+ if (wc & OFPFW_NW_SRC_MASK) {
+ m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT);
+ }
+ if (wc & OFPFW_NW_DST_MASK) {
+ m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
+ }
+ m->tp_src = m->tp_dst = 0;
} else {
/* Network and transport layer fields will always be extracted as
* zeros, so we can do an exact-match on those values. */
vconn->local_ip = 0;
vconn->local_port = 0;
vconn->name = xstrdup(name);
+ assert(vconn->state != VCS_CONNECTING || class->connect);
}
void
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void vconn_usage(bool active, bool passive, bool bootstrap);
/* Active vconns: virtual connections to OpenFlow devices. */
+ int vconn_verify_name(const char *name);
int vconn_open(const char *name, int min_version, struct vconn **);
void vconn_close(struct vconn *);
const char *vconn_get_name(const struct vconn *);
int vconn_recv_xid(struct vconn *, uint32_t xid, struct ofpbuf **);
int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **);
+void vconn_run(struct vconn *);
+void vconn_run_wait(struct vconn *);
+
int vconn_open_block(const char *name, int min_version, struct vconn **);
int vconn_send_block(struct vconn *, struct ofpbuf *);
int vconn_recv_block(struct vconn *, struct ofpbuf **);
void vconn_send_wait(struct vconn *);
/* Passive vconns: virtual listeners for incoming OpenFlow connections. */
+ int pvconn_verify_name(const char *name);
int pvconn_open(const char *name, struct pvconn **);
const char *pvconn_get_name(const struct pvconn *);
void pvconn_close(struct pvconn *);
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#ifndef NETFLOW_H
#define NETFLOW_H 1
+ #include <stdint.h>
#include "flow.h"
#include "svec.h"
+static const int NF_ACTIVE_TIMEOUT_DEFAULT = 600;
+
struct ofexpired;
struct netflow_options {
#include "discovery.h"
#include "dpif.h"
#include "dynamic-string.h"
-#include "executer.h"
#include "fail-open.h"
#include "in-band.h"
#include "mac-learning.h"
#include "ofpbuf.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
-#include "openflow/openflow-mgmt.h"
#include "openvswitch/datapath-protocol.h"
#include "packets.h"
#include "pinsched.h"
#include "shash.h"
#include "status.h"
#include "stp.h"
+#include "stream-ssl.h"
#include "svec.h"
#include "tag.h"
#include "timeval.h"
#include "unixctl.h"
#include "vconn.h"
-#include "vconn-ssl.h"
#include "xtoxll.h"
#define THIS_MODULE VLM_ofproto
struct rule {
struct cls_rule cr;
+ uint64_t flow_cookie; /* Controller-issued identifier.
+ (Kept in network-byte order.) */
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
+ bool send_flow_removed; /* Send a flow removed message? */
long long int used; /* Last-used time (0 if never used). */
long long int created; /* Creation time. */
uint64_t packet_count; /* Number of packets received. */
static struct rule *rule_create(struct ofproto *, struct rule *super,
const union ofp_action *, size_t n_actions,
- uint16_t idle_timeout, uint16_t hard_timeout);
+ uint16_t idle_timeout, uint16_t hard_timeout,
+ uint64_t flow_cookie, bool send_flow_removed);
static void rule_free(struct rule *);
static void rule_destroy(struct ofproto *, struct rule *);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
struct rule *displaced_rule);
static void rule_uninstall(struct ofproto *, struct rule *);
static void rule_post_uninstall(struct ofproto *, struct rule *);
+static void send_flow_removed(struct ofproto *p, struct rule *rule,
+ long long int now, uint8_t reason);
struct ofconn {
struct list node;
struct rconn *rconn;
struct pktbuf *pktbuf;
- bool send_flow_exp;
int miss_send_len;
struct rconn_packet_counter *packet_in_counter;
};
static struct ofconn *ofconn_create(struct ofproto *, struct rconn *);
-static void ofconn_destroy(struct ofconn *, struct ofproto *);
+static void ofconn_destroy(struct ofconn *);
static void ofconn_run(struct ofconn *, struct ofproto *);
static void ofconn_wait(struct ofconn *);
static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
/* Settings. */
uint64_t datapath_id; /* Datapath ID. */
uint64_t fallback_dpid; /* Datapath ID if no better choice found. */
- uint64_t mgmt_id; /* Management channel identifier. */
- char *manufacturer; /* Manufacturer. */
- char *hardware; /* Hardware. */
- char *software; /* Software version. */
- char *serial; /* Serial number. */
+ char *mfr_desc; /* Manufacturer. */
+ char *hw_desc; /* Hardware. */
+ char *sw_desc; /* Software version. */
+ char *serial_desc; /* Serial number. */
+ char *dp_desc; /* Datapath description. */
/* Datapath. */
struct dpif *dpif;
struct discovery *discovery;
struct fail_open *fail_open;
struct pinsched *miss_sched, *action_sched;
- struct executer *executer;
struct netflow *netflow;
struct ofproto_sflow *sflow;
static void reinit_ports(struct ofproto *);
int
-ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
+ofproto_create(const char *datapath, const char *datapath_type,
+ const struct ofhooks *ofhooks, void *aux,
struct ofproto **ofprotop)
{
struct odp_stats stats;
*ofprotop = NULL;
/* Connect to datapath and start listening for messages. */
- error = dpif_open(datapath, &dpif);
+ error = dpif_open(datapath, datapath_type, &dpif);
if (error) {
VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
return error;
dpif_recv_purge(dpif);
/* Initialize settings. */
- p = xcalloc(1, sizeof *p);
+ p = xzalloc(sizeof *p);
p->fallback_dpid = pick_fallback_dpid();
p->datapath_id = p->fallback_dpid;
- p->manufacturer = xstrdup("Nicira Networks, Inc.");
- p->hardware = xstrdup("Reference Implementation");
- p->software = xstrdup(VERSION BUILDNR);
- p->serial = xstrdup("None");
+ p->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
+ p->hw_desc = xstrdup(DEFAULT_HW_DESC);
+ p->sw_desc = xstrdup(DEFAULT_SW_DESC);
+ p->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
+ p->dp_desc = xstrdup(DEFAULT_DP_DESC);
/* Initialize datapath. */
p->dpif = dpif;
p->discovery = NULL;
p->fail_open = NULL;
p->miss_sched = p->action_sched = NULL;
- p->executer = NULL;
p->netflow = NULL;
p->sflow = NULL;
p->ss_cat = switch_status_register(p->switch_status, "remote",
rconn_status_cb, p->controller->rconn);
- /* Almost done... */
- error = init_ports(p);
- if (error) {
- ofproto_destroy(p);
- return error;
- }
-
/* Pick final datapath ID. */
p->datapath_id = pick_datapath_id(p);
- VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id);
+ VLOG_INFO("using datapath ID %016"PRIx64, p->datapath_id);
*ofprotop = p;
return 0;
uint64_t old_dpid = p->datapath_id;
p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p);
if (p->datapath_id != old_dpid) {
- VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id);
+ VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id);
rconn_reconnect(p->controller->rconn);
}
}
-void
-ofproto_set_mgmt_id(struct ofproto *p, uint64_t mgmt_id)
-{
- p->mgmt_id = mgmt_id;
-}
-
void
ofproto_set_probe_interval(struct ofproto *p, int probe_interval)
{
void
ofproto_set_desc(struct ofproto *p,
- const char *manufacturer, const char *hardware,
- const char *software, const char *serial)
+ const char *mfr_desc, const char *hw_desc,
+ const char *sw_desc, const char *serial_desc,
+ const char *dp_desc)
{
- if (manufacturer) {
- free(p->manufacturer);
- p->manufacturer = xstrdup(manufacturer);
+ struct ofp_desc_stats *ods;
+
+ if (mfr_desc) {
+ if (strlen(mfr_desc) >= sizeof ods->mfr_desc) {
+ VLOG_WARN("truncating mfr_desc, must be less than %zu characters",
+ sizeof ods->mfr_desc);
+ }
+ free(p->mfr_desc);
+ p->mfr_desc = xstrdup(mfr_desc);
}
- if (hardware) {
- free(p->hardware);
- p->hardware = xstrdup(hardware);
+ if (hw_desc) {
+ if (strlen(hw_desc) >= sizeof ods->hw_desc) {
+ VLOG_WARN("truncating hw_desc, must be less than %zu characters",
+ sizeof ods->hw_desc);
+ }
+ free(p->hw_desc);
+ p->hw_desc = xstrdup(hw_desc);
}
- if (software) {
- free(p->software);
- p->software = xstrdup(software);
+ if (sw_desc) {
+ if (strlen(sw_desc) >= sizeof ods->sw_desc) {
+ VLOG_WARN("truncating sw_desc, must be less than %zu characters",
+ sizeof ods->sw_desc);
+ }
+ free(p->sw_desc);
+ p->sw_desc = xstrdup(sw_desc);
+ }
+ if (serial_desc) {
+ if (strlen(serial_desc) >= sizeof ods->serial_num) {
+ VLOG_WARN("truncating serial_desc, must be less than %zu "
+ "characters",
+ sizeof ods->serial_num);
+ }
+ free(p->serial_desc);
+ p->serial_desc = xstrdup(serial_desc);
}
- if (serial) {
- free(p->serial);
- p->serial = xstrdup(serial);
+ if (dp_desc) {
+ if (strlen(dp_desc) >= sizeof ods->dp_desc) {
+ VLOG_WARN("truncating dp_desc, must be less than %zu characters",
+ sizeof ods->dp_desc);
+ }
+ free(p->dp_desc);
+ p->dp_desc = xstrdup(dp_desc);
}
}
ofproto_set_netflow(struct ofproto *ofproto,
const struct netflow_options *nf_options)
{
- if (nf_options->collectors.n) {
+ if (nf_options && nf_options->collectors.n) {
if (!ofproto->netflow) {
ofproto->netflow = netflow_create();
}
}
}
-int
-ofproto_set_remote_execution(struct ofproto *ofproto, const char *command_acl,
- const char *command_dir)
-{
- if (command_acl) {
- if (!ofproto->executer) {
- return executer_create(command_acl, command_dir,
- &ofproto->executer);
- } else {
- executer_set_acl(ofproto->executer, command_acl, command_dir);
- }
- } else {
- executer_destroy(ofproto->executer);
- ofproto->executer = NULL;
- }
- return 0;
-}
-
uint64_t
ofproto_get_datapath_id(const struct ofproto *ofproto)
{
return ofproto->datapath_id;
}
-uint64_t
-ofproto_get_mgmt_id(const struct ofproto *ofproto)
-{
- return ofproto->mgmt_id;
-}
-
int
ofproto_get_probe_interval(const struct ofproto *ofproto)
{
return;
}
+ /* Destroy fail-open early, because it touches the classifier. */
+ ofproto_set_failure(p, false);
+
ofproto_flush_flows(p);
classifier_destroy(&p->cls);
LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
&p->all_conns) {
- ofconn_destroy(ofconn, p);
+ ofconn_destroy(ofconn);
}
dpif_close(p->dpif);
switch_status_destroy(p->switch_status);
in_band_destroy(p->in_band);
discovery_destroy(p->discovery);
- fail_open_destroy(p->fail_open);
pinsched_destroy(p->miss_sched);
pinsched_destroy(p->action_sched);
- executer_destroy(p->executer);
netflow_destroy(p->netflow);
ofproto_sflow_destroy(p->sflow);
mac_learning_destroy(p->ml);
+ free(p->mfr_desc);
+ free(p->hw_desc);
+ free(p->sw_desc);
+ free(p->serial_desc);
+ free(p->dp_desc);
+
+ port_array_destroy(&p->ports);
+
free(p);
}
int error;
int i;
+ if (shash_is_empty(&p->port_by_name)) {
+ init_ports(p);
+ }
+
for (i = 0; i < 50; i++) {
struct ofpbuf *buf;
int error;
}
pinsched_run(p->miss_sched, send_packet_in_miss, p);
pinsched_run(p->action_sched, send_packet_in_action, p);
- if (p->executer) {
- executer_run(p->executer);
- }
LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
&p->all_conns) {
}
pinsched_wait(p->miss_sched);
pinsched_wait(p->action_sched);
- if (p->executer) {
- executer_wait(p->executer);
- }
if (p->sflow) {
ofproto_sflow_wait(p->sflow);
}
{
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
- idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0);
+ idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
+ 0, 0, false);
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
rule_insert(p, rule, NULL, 0);
}
static struct ofport *
make_ofport(const struct odp_port *odp_port)
{
+ struct netdev_options netdev_options;
enum netdev_flags flags;
struct ofport *ofport;
struct netdev *netdev;
bool carrier;
int error;
- error = netdev_open(odp_port->devname, NETDEV_ETH_TYPE_NONE, &netdev);
+ memset(&netdev_options, 0, sizeof netdev_options);
+ netdev_options.name = odp_port->devname;
+ netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
+ netdev_options.may_open = true;
+
+ error = netdev_open(&netdev_options, &netdev);
if (error) {
VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
"cannot be opened (%s)",
list_push_back(&p->all_conns, &ofconn->node);
ofconn->rconn = rconn;
ofconn->pktbuf = NULL;
- ofconn->send_flow_exp = false;
ofconn->miss_send_len = 0;
ofconn->packet_in_counter = rconn_packet_counter_create ();
ofconn->reply_counter = rconn_packet_counter_create ();
}
static void
-ofconn_destroy(struct ofconn *ofconn, struct ofproto *p)
+ofconn_destroy(struct ofconn *ofconn)
{
- if (p->executer) {
- executer_rconn_closing(p->executer, ofconn->rconn);
- }
-
list_remove(&ofconn->node);
rconn_destroy(ofconn->rconn);
rconn_packet_counter_destroy(ofconn->packet_in_counter);
}
if (ofconn != p->controller && !rconn_is_alive(ofconn->rconn)) {
- ofconn_destroy(ofconn, p);
+ ofconn_destroy(ofconn);
}
}
static struct rule *
rule_create(struct ofproto *ofproto, struct rule *super,
const union ofp_action *actions, size_t n_actions,
- uint16_t idle_timeout, uint16_t hard_timeout)
+ uint16_t idle_timeout, uint16_t hard_timeout,
+ uint64_t flow_cookie, bool send_flow_removed)
{
- struct rule *rule = xcalloc(1, sizeof *rule);
+ struct rule *rule = xzalloc(sizeof *rule);
rule->idle_timeout = idle_timeout;
rule->hard_timeout = hard_timeout;
+ rule->flow_cookie = flow_cookie;
rule->used = rule->created = time_msec();
+ rule->send_flow_removed = send_flow_removed;
rule->super = super;
if (super) {
list_push_back(&super->list, &rule->list);
const flow_t *flow)
{
struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
- rule->idle_timeout, rule->hard_timeout);
+ rule->idle_timeout, rule->hard_timeout,
+ 0, false);
COVERAGE_INC(ofproto_subrule_create);
cls_rule_from_flow(&subrule->cr, flow, 0,
(rule->cr.priority <= UINT16_MAX ? UINT16_MAX
osf->n_buffers = htonl(pktbuf_capacity());
osf->n_tables = 2;
osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
- OFPC_PORT_STATS | OFPC_MULTI_PHY_TX);
+ OFPC_PORT_STATS | OFPC_ARP_MATCH_IP);
osf->actions = htonl((1u << OFPAT_OUTPUT) |
(1u << OFPAT_SET_VLAN_VID) |
(1u << OFPAT_SET_VLAN_PCP) |
(1u << OFPAT_SET_DL_DST) |
(1u << OFPAT_SET_NW_SRC) |
(1u << OFPAT_SET_NW_DST) |
+ (1u << OFPAT_SET_NW_TOS) |
(1u << OFPAT_SET_TP_SRC) |
(1u << OFPAT_SET_TP_DST));
/* Figure out flags. */
dpif_get_drop_frags(p->dpif, &drop_frags);
flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
- if (ofconn->send_flow_exp) {
- flags |= OFPC_SEND_FLOW_EXP;
- }
/* Send reply. */
osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
}
flags = ntohs(osc->flags);
- ofconn->send_flow_exp = (flags & OFPC_SEND_FLOW_EXP) != 0;
-
if (ofconn == p->controller) {
switch (flags & OFPC_FRAG_MASK) {
case OFPC_FRAG_NORMAL:
oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
break;
+ case OFPAT_SET_NW_TOS:
+ oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
+ oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
+ break;
+
case OFPAT_SET_TP_SRC:
oa = odp_actions_add(ctx->out, ODPAT_SET_TP_SRC);
oa->tp_port.tp_port = ia->tp_port.tp_port;
msg = start_stats_reply(request, sizeof *ods);
ods = append_stats_reply(sizeof *ods, ofconn, &msg);
- strncpy(ods->mfr_desc, p->manufacturer, sizeof ods->mfr_desc);
- strncpy(ods->hw_desc, p->hardware, sizeof ods->hw_desc);
- strncpy(ods->sw_desc, p->software, sizeof ods->sw_desc);
- strncpy(ods->serial_num, p->serial, sizeof ods->serial_num);
+ memset(ods, 0, sizeof *ods);
+ ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
+ ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
+ ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
+ ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
+ ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc);
queue_tx(msg, ofconn, ofconn->reply_counter);
return 0;
return 0;
}
+static void
+append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
+ struct ofpbuf *msg)
+{
+ struct netdev_stats stats;
+ struct ofp_port_stats *ops;
+
+ /* Intentionally ignore return value, since errors will set
+ * 'stats' to all-1s, which is correct for OpenFlow, and
+ * netdev_get_stats() will log errors. */
+ netdev_get_stats(port->netdev, &stats);
+
+ ops = append_stats_reply(sizeof *ops, ofconn, &msg);
+ ops->port_no = htons(odp_port_to_ofp_port(port_no));
+ memset(ops->pad, 0, sizeof ops->pad);
+ ops->rx_packets = htonll(stats.rx_packets);
+ ops->tx_packets = htonll(stats.tx_packets);
+ ops->rx_bytes = htonll(stats.rx_bytes);
+ ops->tx_bytes = htonll(stats.tx_bytes);
+ ops->rx_dropped = htonll(stats.rx_dropped);
+ ops->tx_dropped = htonll(stats.tx_dropped);
+ ops->rx_errors = htonll(stats.rx_errors);
+ ops->tx_errors = htonll(stats.tx_errors);
+ ops->rx_frame_err = htonll(stats.rx_frame_errors);
+ ops->rx_over_err = htonll(stats.rx_over_errors);
+ ops->rx_crc_err = htonll(stats.rx_crc_errors);
+ ops->collisions = htonll(stats.collisions);
+}
+
static int
handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
- struct ofp_stats_request *request)
+ struct ofp_stats_request *osr,
+ size_t arg_size)
{
+ struct ofp_port_stats_request *psr;
struct ofp_port_stats *ops;
struct ofpbuf *msg;
struct ofport *port;
unsigned int port_no;
- msg = start_stats_reply(request, sizeof *ops * 16);
- PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
- struct netdev_stats stats;
-
- /* Intentionally ignore return value, since errors will set 'stats' to
- * all-1s, which is correct for OpenFlow, and netdev_get_stats() will
- * log errors. */
- netdev_get_stats(port->netdev, &stats);
-
- ops = append_stats_reply(sizeof *ops, ofconn, &msg);
- ops->port_no = htons(odp_port_to_ofp_port(port_no));
- memset(ops->pad, 0, sizeof ops->pad);
- ops->rx_packets = htonll(stats.rx_packets);
- ops->tx_packets = htonll(stats.tx_packets);
- ops->rx_bytes = htonll(stats.rx_bytes);
- ops->tx_bytes = htonll(stats.tx_bytes);
- ops->rx_dropped = htonll(stats.rx_dropped);
- ops->tx_dropped = htonll(stats.tx_dropped);
- ops->rx_errors = htonll(stats.rx_errors);
- ops->tx_errors = htonll(stats.tx_errors);
- ops->rx_frame_err = htonll(stats.rx_frame_errors);
- ops->rx_over_err = htonll(stats.rx_over_errors);
- ops->rx_crc_err = htonll(stats.rx_crc_errors);
- ops->collisions = htonll(stats.collisions);
+ if (arg_size != sizeof *psr) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+ psr = (struct ofp_port_stats_request *) osr->body;
+
+ msg = start_stats_reply(osr, sizeof *ops * 16);
+ if (psr->port_no != htons(OFPP_NONE)) {
+ port = port_array_get(&p->ports,
+ ofp_port_to_odp_port(ntohs(psr->port_no)));
+ if (port) {
+ append_port_stat(port, ntohs(psr->port_no), ofconn, msg);
+ }
+ } else {
+ PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
+ append_port_stat(port, port_no, ofconn, msg);
+ }
}
queue_tx(msg, ofconn, ofconn->reply_counter);
byte_count = rule->byte_count;
n_odp_flows = rule->cr.wc.wildcards ? list_size(&rule->list) : 1;
- odp_flows = xcalloc(1, n_odp_flows * sizeof *odp_flows);
+ odp_flows = xzalloc(n_odp_flows * sizeof *odp_flows);
if (rule->cr.wc.wildcards) {
size_t i = 0;
LIST_FOR_EACH (subrule, struct rule, list, &rule->list) {
struct ofp_flow_stats *ofs;
uint64_t packet_count, byte_count;
size_t act_len, len;
+ long long int tdiff = time_msec() - rule->created;
+ uint32_t sec = tdiff / 1000;
+ uint32_t msec = tdiff - (sec * 1000);
if (rule_is_hidden(rule) || !rule_has_out_port(rule, cbdata->out_port)) {
return;
ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
ofs->pad = 0;
flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match);
- ofs->duration = htonl((time_msec() - rule->created) / 1000);
+ ofs->duration_sec = htonl(sec);
+ ofs->duration_nsec = htonl(msec * 1000000);
+ ofs->cookie = rule->flow_cookie;
ofs->priority = htons(rule->cr.priority);
ofs->idle_timeout = htons(rule->idle_timeout);
ofs->hard_timeout = htons(rule->hard_timeout);
struct cls_rule target;
if (arg_size != sizeof *fsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
fsr = (struct ofp_flow_stats_request *) osr->body;
}
query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
- flow_to_ovs_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
+ flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
ds_put_format(results, "duration=%llds, ",
(time_msec() - rule->created) / 1000);
struct ofpbuf *msg;
if (arg_size != sizeof *asr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
asr = (struct ofp_aggregate_stats_request *) osr->body;
return handle_table_stats_request(p, ofconn, osr);
case OFPST_PORT:
- return handle_port_stats_request(p, ofconn, osr);
+ return handle_port_stats_request(p, ofconn, osr, arg_size);
case OFPST_VENDOR:
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
uint16_t in_port;
int error;
+ if (ofm->flags & htons(OFPFF_CHECK_OVERLAP)) {
+ flow_t flow;
+ uint32_t wildcards;
+
+ flow_from_match(&flow, &wildcards, &ofm->match);
+ if (classifier_rule_overlaps(&p->cls, &flow, wildcards,
+ ntohs(ofm->priority))) {
+ return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
+ }
+ }
+
rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions,
n_actions, ntohs(ofm->idle_timeout),
- ntohs(ofm->hard_timeout));
+ ntohs(ofm->hard_timeout), ofm->cookie,
+ ofm->flags & htons(OFPFF_SEND_FLOW_REM));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
- packet = NULL;
error = 0;
if (ofm->buffer_id != htonl(UINT32_MAX)) {
error = pktbuf_retrieve(ofconn->pktbuf, ntohl(ofm->buffer_id),
&packet, &in_port);
+ } else {
+ packet = NULL;
+ in_port = UINT16_MAX;
}
rule_insert(p, rule, packet, in_port);
}
if (command == OFPFC_DELETE) {
+ long long int now = time_msec();
+ send_flow_removed(p, rule, now, OFPRR_DELETE);
rule_remove(p, rule);
} else {
size_t actions_len = n_actions * sizeof *rule->actions;
free(rule->actions);
rule->actions = xmemdup(ofm->actions, actions_len);
rule->n_actions = n_actions;
+ rule->flow_cookie = ofm->cookie;
if (rule->cr.wc.wildcards) {
COVERAGE_INC(ofproto_mod_wc_flow);
return error;
}
+ /* We do not support the emergency flow cache. It will hopefully
+ * get dropped from OpenFlow in the near future. */
+ if (ofm->flags & htons(OFPFF_EMERG)) {
+ /* There isn't a good fit for an error code, so just state that the
+ * flow table is full. */
+ return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
+ }
+
normalize_match(&ofm->match);
if (!ofm->match.wildcards) {
ofm->priority = htons(UINT16_MAX);
}
}
-static void
-send_capability_reply(struct ofproto *p, struct ofconn *ofconn, uint32_t xid)
-{
- struct ofmp_capability_reply *ocr;
- struct ofpbuf *b;
- char capabilities[] = "com.nicira.mgmt.manager=false\n";
-
- ocr = make_openflow_xid(sizeof(*ocr), OFPT_VENDOR, xid, &b);
- ocr->header.header.vendor = htonl(NX_VENDOR_ID);
- ocr->header.header.subtype = htonl(NXT_MGMT);
- ocr->header.type = htons(OFMPT_CAPABILITY_REPLY);
-
- ocr->format = htonl(OFMPCOF_SIMPLE);
- ocr->mgmt_id = htonll(p->mgmt_id);
-
- ofpbuf_put(b, capabilities, strlen(capabilities));
-
- queue_tx(b, ofconn, ofconn->reply_counter);
-}
-
-static int
-handle_ofmp(struct ofproto *p, struct ofconn *ofconn,
- struct ofmp_header *ofmph)
-{
- size_t msg_len = ntohs(ofmph->header.header.length);
- if (msg_len < sizeof(*ofmph)) {
- VLOG_WARN_RL(&rl, "dropping short managment message: %zu\n", msg_len);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
- }
-
- if (ofmph->type == htons(OFMPT_CAPABILITY_REQUEST)) {
- struct ofmp_capability_request *ofmpcr;
-
- if (msg_len < sizeof(struct ofmp_capability_request)) {
- VLOG_WARN_RL(&rl, "dropping short capability request: %zu\n",
- msg_len);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
- }
-
- ofmpcr = (struct ofmp_capability_request *)ofmph;
- if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
- /* xxx Find a better type than bad subtype */
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-
- send_capability_reply(p, ofconn, ofmph->header.header.xid);
- return 0;
- } else {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-}
-
static int
handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
{
struct nicira_header *nh;
if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
if (ovh->vendor != htonl(NX_VENDOR_ID)) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
}
if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
nh = msg;
case NXT_STATUS_REQUEST:
return switch_status_handle_request(p->switch_status, ofconn->rconn,
msg);
-
- case NXT_ACT_SET_CONFIG:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
-
- case NXT_ACT_GET_CONFIG:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
-
- case NXT_COMMAND_REQUEST:
- if (p->executer) {
- return executer_handle_request(p->executer, ofconn->rconn, msg);
- }
- break;
-
- case NXT_MGMT:
- return handle_ofmp(p, ofconn, msg);
}
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
}
+static int
+handle_barrier_request(struct ofconn *ofconn, struct ofp_header *oh)
+{
+ struct ofp_header *ob;
+ struct ofpbuf *buf;
+
+ /* Currently, everything executes synchronously, so we can just
+ * immediately send the barrier reply. */
+ ob = make_openflow_xid(sizeof *ob, OFPT_BARRIER_REPLY, oh->xid, &buf);
+ queue_tx(buf, ofconn, ofconn->reply_counter);
+ return 0;
+}
+
static void
handle_openflow(struct ofconn *ofconn, struct ofproto *p,
struct ofpbuf *ofp_msg)
error = handle_vendor(p, ofconn, ofp_msg->data);
break;
+ case OFPT_BARRIER_REQUEST:
+ error = handle_barrier_request(ofconn, oh);
+ break;
+
default:
if (VLOG_IS_WARN_ENABLED()) {
char *s = ofp_to_string(oh, ntohs(oh->length), 2);
}
static struct ofpbuf *
-compose_flow_exp(const struct rule *rule, long long int now, uint8_t reason)
+compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
{
- struct ofp_flow_expired *ofe;
+ struct ofp_flow_removed *ofr;
struct ofpbuf *buf;
-
- ofe = make_openflow(sizeof *ofe, OFPT_FLOW_EXPIRED, &buf);
- flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofe->match);
- ofe->priority = htons(rule->cr.priority);
- ofe->reason = reason;
- ofe->duration = htonl((now - rule->created) / 1000);
- ofe->packet_count = htonll(rule->packet_count);
- ofe->byte_count = htonll(rule->byte_count);
+ long long int tdiff = time_msec() - rule->created;
+ uint32_t sec = tdiff / 1000;
+ uint32_t msec = tdiff - (sec * 1000);
+
+ ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
+ flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
+ ofr->cookie = rule->flow_cookie;
+ ofr->priority = htons(rule->cr.priority);
+ ofr->reason = reason;
+ ofr->duration_sec = htonl(sec);
+ ofr->duration_nsec = htonl(msec * 1000000);
+ ofr->idle_timeout = htons(rule->idle_timeout);
+ ofr->packet_count = htonll(rule->packet_count);
+ ofr->byte_count = htonll(rule->byte_count);
return buf;
}
static void
-send_flow_exp(struct ofproto *p, struct rule *rule,
- long long int now, uint8_t reason)
+uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
+{
+ assert(rule->installed);
+ assert(!rule->cr.wc.wildcards);
+
+ if (rule->super) {
+ rule_remove(ofproto, rule);
+ } else {
+ rule_uninstall(ofproto, rule);
+ }
+}
+static void
+send_flow_removed(struct ofproto *p, struct rule *rule,
+ long long int now, uint8_t reason)
{
struct ofconn *ofconn;
struct ofconn *prev;
prev = NULL;
LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
- if (ofconn->send_flow_exp && rconn_is_connected(ofconn->rconn)) {
+ if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn)) {
if (prev) {
queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
} else {
- buf = compose_flow_exp(rule, now, reason);
+ buf = compose_flow_removed(rule, now, reason);
}
prev = ofconn;
}
}
}
-static void
-uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
-{
- assert(rule->installed);
- assert(!rule->cr.wc.wildcards);
-
- if (rule->super) {
- rule_remove(ofproto, rule);
- } else {
- rule_uninstall(ofproto, rule);
- }
-}
static void
expire_rule(struct cls_rule *cls_rule, void *p_)
}
if (!rule_is_hidden(rule)) {
- send_flow_exp(p, rule, now,
- (now >= hard_expire
- ? OFPER_HARD_TIMEOUT : OFPER_IDLE_TIMEOUT));
+ send_flow_removed(p, rule, now,
+ (now >= hard_expire
+ ? OFPRR_HARD_TIMEOUT : OFPRR_IDLE_TIMEOUT));
}
rule_remove(p, rule);
}
pick_fallback_dpid(void)
{
uint8_t ea[ETH_ADDR_LEN];
- eth_addr_random(ea);
- ea[0] = 0x00; /* Set Nicira OUI. */
- ea[1] = 0x23;
- ea[2] = 0x20;
+ eth_addr_nicira_random(ea);
return eth_addr_to_uint64(ea);
}
\f
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "netflow.h"
#include "tag.h"
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+
struct odp_actions;
struct ofhooks;
struct ofproto;
char *control_ip;
};
-int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
+#define DEFAULT_MFR_DESC "Nicira Networks, Inc."
+#define DEFAULT_HW_DESC "Open vSwitch"
+#define DEFAULT_SW_DESC VERSION BUILDNR
+#define DEFAULT_SERIAL_DESC "None"
+#define DEFAULT_DP_DESC "None"
+
+int ofproto_create(const char *datapath, const char *datapath_type,
+ const struct ofhooks *, void *aux,
struct ofproto **ofprotop);
void ofproto_destroy(struct ofproto *);
int ofproto_run(struct ofproto *);
/* Configuration. */
void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
-void ofproto_set_mgmt_id(struct ofproto *, uint64_t mgmt_id);
void ofproto_set_probe_interval(struct ofproto *, int probe_interval);
void ofproto_set_max_backoff(struct ofproto *, int max_backoff);
void ofproto_set_desc(struct ofproto *,
- const char *manufacturer, const char *hardware,
- const char *software, const char *serial);
+ const char *mfr_desc, const char *hw_desc,
+ const char *sw_desc, const char *serial_desc,
+ const char *dp_desc);
int ofproto_set_in_band(struct ofproto *, bool in_band);
int ofproto_set_discovery(struct ofproto *, bool discovery,
const char *accept_controller_re,
void ofproto_set_failure(struct ofproto *, bool fail_open);
void ofproto_set_rate_limit(struct ofproto *, int rate_limit, int burst_limit);
int ofproto_set_stp(struct ofproto *, bool enable_stp);
-int ofproto_set_remote_execution(struct ofproto *, const char *command_acl,
- const char *command_dir);
/* Configuration querying. */
uint64_t ofproto_get_datapath_id(const struct ofproto *);
-uint64_t ofproto_get_mgmt_id(const struct ofproto *);
int ofproto_get_probe_interval(const struct ofproto *);
int ofproto_get_max_backoff(const struct ofproto *);
bool ofproto_get_in_band(const struct ofproto *);
void ofproto_revalidate(struct ofproto *, tag_type);
struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
+ #ifdef __cplusplus
+ }
+ #endif
+
#endif /* ofproto.h */
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "pinsched.h"
+ #include <sys/types.h>
+ #include <netinet/in.h>
#include <arpa/inet.h>
+ #include <stdint.h>
#include <stdlib.h>
#include "ofpbuf.h"
#include "openflow/openflow.h"
{
struct pinsched *ps;
- ps = xcalloc(1, sizeof *ps);
+ ps = xzalloc(sizeof *ps);
port_array_init(&ps->queues);
ps->n_queued = 0;
ps->last_tx_port = PORT_ARRAY_SIZE;
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct pktbuf *
pktbuf_create(void)
{
- return xcalloc(1, sizeof *pktbuf_create());
+ return xzalloc(sizeof *pktbuf_create());
}
void
* datapath port number on which the packet was received in '*in_port'. The
* caller becomes responsible for freeing the buffer. However, if 'id'
* identifies a "null" packet buffer (created with pktbuf_get_null()), stores
- * NULL in '*bufferp' and -1 in '*in_port'.
+ * NULL in '*bufferp' and UINT16_max in '*in_port'.
*
- * On failure, stores NULL in in '*bufferp' and -1 in '*in_port'. */
+ * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
int
pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
uint16_t *in_port)
if (!pb) {
VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
"without buffers");
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
}
p = &pb->packets[id & PKTBUF_MASK];
error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY);
}
} else if (id >> PKTBUF_BITS != COOKIE_MAX) {
- COVERAGE_INC(pktbuf_bad_cookie);
+ COVERAGE_INC(pktbuf_buffer_unknown);
VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
- error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
+ error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
} else {
COVERAGE_INC(pktbuf_null_cookie);
VLOG_INFO_RL(&rl, "Received null cookie %08"PRIx32" (this is normal "
error = 0;
}
*bufferp = NULL;
- *in_port = -1;
+ *in_port = UINT16_MAX;
return error;
}