Aaron Rosen arosen@clemson.edu
Alex Yip alex@nicira.com
Alexey I. Froloff raorn@altlinux.org
+Bob Ball bob.ball@citrix.com
Brad Hall brad@nicira.com
Brandon Heller brandonh@stanford.edu
Bryan Fulton bryan@nicira.com
Gaetano Catalli gaetano.catalli@gmail.com
Ghanem Bahri bahri.ghanem@gmail.com
Giuseppe de Candia giuseppe.decandia@gmail.com
+Gregor Schaffrath grsch@net.t-labs.tu-berlin.de
Hassan Khan hassan.khan@seecs.edu.pk
Hector Oron hector.oron@gmail.com
Henrik Amren henrik@nicira.com
+post v1.1.0
+------------------------
+ - The new "-s" option for "ovs-dpctl show" prints packet and byte
+ counters for each port.
+ - Feature removals:
+ - Dropped support for "tun_id_from_cookie" OpenFlow extension.
+ (Use the extensible match extensions instead.)
+
v1.1.0 - 05 Apr 2011
------------------------
- Ability to define policies over IPv6
vSwitch doesn't process jumbograms.
+In-Band Control
+===============
+
+In-band control allows a single network to be used for OpenFlow traffic and
+other data traffic. See ovs-vswitchd.conf.db(5) for a description of
+configuring in-band control.
+
+This comment is an attempt to describe how in-band control works at a
+wire- and implementation-level. Correctly implementing in-band
+control has proven difficult due to its many subtleties, and has thus
+gone through many iterations. Please read through and understand the
+reasoning behind the chosen rules before making modifications.
+
+In Open vSwitch, in-band control is implemented as "hidden" flows (in that
+they are not visible through OpenFlow) and at a higher priority than
+wildcarded flows can be set up by through OpenFlow. This is done so that
+the OpenFlow controller cannot interfere with them and possibly break
+connectivity with its switches. It is possible to see all flows, including
+in-band ones, with the ovs-appctl "bridge/dump-flows" command.
+
+The Open vSwitch implementation of in-band control can hide traffic to
+arbitrary "remotes", where each remote is one TCP port on one IP address.
+Currently the remotes are automatically configured as the in-band OpenFlow
+controllers plus the OVSDB managers, if any. (The latter is a requirement
+because OVSDB managers are responsible for configuring OpenFlow controllers,
+so if the manager cannot be reached then OpenFlow cannot be reconfigured.)
+
+The following rules (with the OFPP_NORMAL action) are set up on any bridge
+that has any remotes:
+
+ (a) DHCP requests sent from the local port.
+ (b) ARP replies to the local port's MAC address.
+ (c) ARP requests from the local port's MAC address.
+
+In-band also sets up the following rules for each unique next-hop MAC
+address for the remotes' IPs (the "next hop" is either the remote
+itself, if it is on a local subnet, or the gateway to reach the remote):
+
+ (d) ARP replies to the next hop's MAC address.
+ (e) ARP requests from the next hop's MAC address.
+
+In-band also sets up the following rules for each unique remote IP address:
+
+ (f) ARP replies containing the remote's IP address as a target.
+ (g) ARP requests containing the remote's IP address as a source.
+
+In-band also sets up the following rules for each unique remote (IP,port)
+pair:
+
+ (h) TCP traffic to the remote's IP and port.
+ (i) TCP traffic from the remote's IP and port.
+
+The goal of these rules is to be as narrow as possible to allow a
+switch to join a network and be able to communicate with the
+remotes. As mentioned earlier, these rules have higher priority
+than the controller's rules, so if they are too broad, they may
+prevent the controller from implementing its policy. As such,
+in-band actively monitors some aspects of flow and packet processing
+so that the rules can be made more precise.
+
+In-band control monitors attempts to add flows into the datapath that
+could interfere with its duties. The datapath only allows exact
+match entries, so in-band control is able to be very precise about
+the flows it prevents. Flows that miss in the datapath are sent to
+userspace to be processed, so preventing these flows from being
+cached in the "fast path" does not affect correctness. The only type
+of flow that is currently prevented is one that would prevent DHCP
+replies from being seen by the local port. For example, a rule that
+forwarded all DHCP traffic to the controller would not be allowed,
+but one that forwarded to all ports (including the local port) would.
+
+As mentioned earlier, packets that miss in the datapath are sent to
+the userspace for processing. The userspace has its own flow table,
+the "classifier", so in-band checks whether any special processing
+is needed before the classifier is consulted. If a packet is a DHCP
+response to a request from the local port, the packet is forwarded to
+the local port, regardless of the flow table. Note that this requires
+L7 processing of DHCP replies to determine whether the 'chaddr' field
+matches the MAC address of the local port.
+
+It is interesting to note that for an L3-based in-band control
+mechanism, the majority of rules are devoted to ARP traffic. At first
+glance, some of these rules appear redundant. However, each serves an
+important role. First, in order to determine the MAC address of the
+remote side (controller or gateway) for other ARP rules, we must allow
+ARP traffic for our local port with rules (b) and (c). If we are
+between a switch and its connection to the remote, we have to
+allow the other switch's ARP traffic to through. This is done with
+rules (d) and (e), since we do not know the addresses of the other
+switches a priori, but do know the remote's or gateway's. Finally,
+if the remote is running in a local guest VM that is not reached
+through the local port, the switch that is connected to the VM must
+allow ARP traffic based on the remote's IP address, since it will
+not know the MAC address of the local port that is sending the traffic
+or the MAC address of the remote in the guest VM.
+
+With a few notable exceptions below, in-band should work in most
+network setups. The following are considered "supported' in the
+current implementation:
+
+ - Locally Connected. The switch and remote are on the same
+ subnet. This uses rules (a), (b), (c), (h), and (i).
+
+ - Reached through Gateway. The switch and remote are on
+ different subnets and must go through a gateway. This uses
+ rules (a), (b), (c), (h), and (i).
+
+ - Between Switch and Remote. This switch is between another
+ switch and the remote, and we want to allow the other
+ switch's traffic through. This uses rules (d), (e), (h), and
+ (i). It uses (b) and (c) indirectly in order to know the MAC
+ address for rules (d) and (e). Note that DHCP for the other
+ switch will not work unless an OpenFlow controller explicitly lets this
+ switch pass the traffic.
+
+ - Between Switch and Gateway. This switch is between another
+ switch and the gateway, and we want to allow the other switch's
+ traffic through. This uses the same rules and logic as the
+ "Between Switch and Remote" configuration described earlier.
+
+ - Remote on Local VM. The remote is a guest VM on the
+ system running in-band control. This uses rules (a), (b), (c),
+ (h), and (i).
+
+ - Remote on Local VM with Different Networks. The remote
+ is a guest VM on the system running in-band control, but the
+ local port is not used to connect to the remote. For
+ example, an IP address is configured on eth0 of the switch. The
+ remote's VM is connected through eth1 of the switch, but an
+ IP address has not been configured for that port on the switch.
+ As such, the switch will use eth0 to connect to the remote,
+ and eth1's rules about the local port will not work. In the
+ example, the switch attached to eth0 would use rules (a), (b),
+ (c), (h), and (i) on eth0. The switch attached to eth1 would use
+ rules (f), (g), (h), and (i).
+
+The following are explicitly *not* supported by in-band control:
+
+ - Specify Remote by Name. Currently, the remote must be
+ identified by IP address. A naive approach would be to permit
+ all DNS traffic. Unfortunately, this would prevent the
+ controller from defining any policy over DNS. Since switches
+ that are located behind us need to connect to the remote,
+ in-band cannot simply add a rule that allows DNS traffic from
+ the local port. The "correct" way to support this is to parse
+ DNS requests to allow all traffic related to a request for the
+ remote's name through. Due to the potential security
+ problems and amount of processing, we decided to hold off for
+ the time-being.
+
+ - Differing Remotes for Switches. All switches must know
+ the L3 addresses for all the remotes that other switches
+ may use, since rules need to be set up to allow traffic related
+ to those remotes through. See rules (f), (g), (h), and (i).
+
+ - Differing Routes for Switches. In order for the switch to
+ allow other switches to connect to a remote through a
+ gateway, it allows the gateway's traffic through with rules (d)
+ and (e). If the routes to the remote differ for the two
+ switches, we will not know the MAC address of the alternate
+ gateway.
+
+
Suggestions
===========
After installing or uninstalling Open vSwitch, the XenServer should be
rebooted as soon as possible.
+Open vSwitch Boot Sequence on XenServer
+---------------------------------------
+
+When Open vSwitch is installed on XenServer, its startup script
+/etc/init.d/openvswitch runs early in boot. It does roughly the
+following:
+
+ * Loads the OVS kernel module, openvswitch_mod.
+
+ * Starts ovsdb-server, the OVS configuration database.
+
+ * XenServer expects there to be no bridges configured at
+ startup, but the OVS configuration database likely still has
+ bridges configured from before reboot. To match XenServer
+ expectations, the startup script deletes all configured
+ bridges from the database.
+
+ * Starts ovs-vswitchd, the OVS switching daemon.
+
+At this point in the boot process, then, there are no Open vSwitch
+bridges, even though all of the Open vSwitch daemons are running.
+Later on in boot, /etc/init.d/management-interface (part of XenServer,
+not Open vSwitch) creates the bridge for the XAPI management interface
+by invoking /opt/xensource/libexec/interface-reconfigure. Normally
+this program consults XAPI's database to obtain information about how
+to configure the bridge, but XAPI is not running yet[*] so it instead
+consults /var/xapi/network.dbcache, which is a cached copy of the most
+recent network configuration.
+
+[*] Even if XAPI were running, if this XenServer node is a pool slave
+ then the query would have to consult the master, which requires
+ network access, which begs the question of how to configure the
+ management interface.
+
+XAPI starts later on in the boot process. XAPI can then create other
+bridges on demand using /opt/xensource/libexec/interface-reconfigure.
+Now that XAPI is running, that program consults XAPI directly instead
+of reading the cache.
+
+As part of its own startup, XAPI invokes the Open vSwitch XAPI plugin
+script /etc/xapi.d/openvswitch-cfg-update passing the "update"
+command. The plugin script does roughly the following:
+
+ * Calls /opt/xensource/libexec/interface-reconfigure with the
+ "rewrite" command, to ensure that the network cache is
+ up-to-date.
+
+ * Queries the Open vSwitch manager setting (named
+ "vswitch_controller") from the XAPI database for the
+ XenServer pool.
+
+ * If XAPI and OVS are configured for different managers, or if
+ OVS is configured for a manager but XAPI is not, runs
+ "ovs-vsctl emer-reset" to bring the Open vSwitch
+ configuration to a known state. One effect of emer-reset is
+ to deconfigure any manager from the OVS database.
+
+ * If XAPI is configured for a manger, configures the OVS
+ manager to match with "ovs-vsctl set-manager".
+
+The Open vSwitch boot sequence only configures an OVS configuration
+database manager. There is no way to directly configure an OpenFlow
+controller on XenServer and, as a consequence of the step above that
+deletes all of the bridges at boot time, controller configuration only
+persists until XenServer reboot. The configuration database manager
+can, however, configure controllers for bridges. See the BUGS section
+of ovs-controller(8) for more information on this topic.
+
Reporting Bugs
--------------
#include "actions.h"
#include "checksum.h"
#include "datapath.h"
+#include "loop_counter.h"
#include "openvswitch/datapath-protocol.h"
#include "vlan.h"
#include "vport.h"
static int do_execute_actions(struct datapath *, struct sk_buff *,
- const struct sw_flow_key *,
- const struct nlattr *actions, u32 actions_len);
+ struct sw_flow_actions *acts);
static struct sk_buff *make_writable(struct sk_buff *skb, unsigned min_headroom)
{
return skb;
}
-static bool is_ip(struct sk_buff *skb, const struct sw_flow_key *key)
+static bool is_ip(struct sk_buff *skb)
{
- return (key->dl_type == htons(ETH_P_IP) &&
+ return (OVS_CB(skb)->flow->key.dl_type == htons(ETH_P_IP) &&
skb->transport_header > skb->network_header);
}
-static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct sw_flow_key *key)
+static __sum16 *get_l4_checksum(struct sk_buff *skb)
{
+ u8 nw_proto = OVS_CB(skb)->flow->key.nw_proto;
int transport_len = skb->len - skb_transport_offset(skb);
- if (key->nw_proto == IPPROTO_TCP) {
+ if (nw_proto == IPPROTO_TCP) {
if (likely(transport_len >= sizeof(struct tcphdr)))
return &tcp_hdr(skb)->check;
- } else if (key->nw_proto == IPPROTO_UDP) {
+ } else if (nw_proto == IPPROTO_UDP) {
if (likely(transport_len >= sizeof(struct udphdr)))
return &udp_hdr(skb)->check;
}
return NULL;
}
-static struct sk_buff *set_nw_addr(struct sk_buff *skb,
- const struct sw_flow_key *key,
- const struct nlattr *a)
+static struct sk_buff *set_nw_addr(struct sk_buff *skb, const struct nlattr *a)
{
__be32 new_nwaddr = nla_get_be32(a);
struct iphdr *nh;
__sum16 *check;
__be32 *nwaddr;
- if (unlikely(!is_ip(skb, key)))
+ if (unlikely(!is_ip(skb)))
return skb;
skb = make_writable(skb, 0);
nh = ip_hdr(skb);
nwaddr = nla_type(a) == ODP_ACTION_ATTR_SET_NW_SRC ? &nh->saddr : &nh->daddr;
- check = get_l4_checksum(skb, key);
+ check = get_l4_checksum(skb);
if (likely(check))
inet_proto_csum_replace4(check, skb, *nwaddr, new_nwaddr, 1);
csum_replace4(&nh->check, *nwaddr, new_nwaddr);
return skb;
}
-static struct sk_buff *set_nw_tos(struct sk_buff *skb,
- const struct sw_flow_key *key,
- u8 nw_tos)
+static struct sk_buff *set_nw_tos(struct sk_buff *skb, u8 nw_tos)
{
- if (unlikely(!is_ip(skb, key)))
+ if (unlikely(!is_ip(skb)))
return skb;
skb = make_writable(skb, 0);
return skb;
}
-static struct sk_buff *set_tp_port(struct sk_buff *skb,
- const struct sw_flow_key *key,
- const struct nlattr *a)
+static struct sk_buff *set_tp_port(struct sk_buff *skb, const struct nlattr *a)
{
struct udphdr *th;
__sum16 *check;
__be16 *port;
- if (unlikely(!is_ip(skb, key)))
+ if (unlikely(!is_ip(skb)))
return skb;
skb = make_writable(skb, 0);
return NULL;
/* Must follow make_writable() since that can move the skb data. */
- check = get_l4_checksum(skb, key);
+ check = get_l4_checksum(skb);
if (unlikely(!check))
return skb;
*
* @skb: skbuff containing an Ethernet packet, with network header pointing
* just past the Ethernet and optional 802.1Q header.
- * @key: flow key extracted from @skb by flow_extract()
*
* Returns true if @skb is an invalid Ethernet+IPv4 ARP packet: one with screwy
* or truncated header fields or one whose inner and outer Ethernet address
* differ.
*/
-static bool is_spoofed_arp(struct sk_buff *skb, const struct sw_flow_key *key)
+static bool is_spoofed_arp(struct sk_buff *skb)
{
struct arp_eth_header *arp;
- if (key->dl_type != htons(ETH_P_ARP))
+ if (OVS_CB(skb)->flow->key.dl_type != htons(ETH_P_ARP))
return false;
if (skb_network_offset(skb) + sizeof(struct arp_eth_header) > skb->len)
kfree_skb(skb);
}
-static int output_control(struct datapath *dp, struct sk_buff *skb, u64 arg,
- const struct sw_flow_key *key)
+static int output_control(struct datapath *dp, struct sk_buff *skb, u64 arg)
{
struct dp_upcall_info upcall;
return -ENOMEM;
upcall.cmd = ODP_PACKET_CMD_ACTION;
- upcall.key = key;
+ upcall.key = &OVS_CB(skb)->flow->key;
upcall.userdata = arg;
upcall.sample_pool = 0;
upcall.actions = NULL;
/* Execute a list of actions against 'skb'. */
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
- const struct sw_flow_key *key,
- const struct nlattr *actions, u32 actions_len)
+ struct sw_flow_actions *acts)
{
/* Every output action needs a separate clone of 'skb', but the common
* case is just a single output action, so that doing a clone and
const struct nlattr *a;
int rem, err;
- for (a = actions, rem = actions_len; rem > 0; a = nla_next(a, &rem)) {
+ for (a = acts->actions, rem = acts->actions_len; rem > 0;
+ a = nla_next(a, &rem)) {
if (prev_port != -1) {
do_output(dp, skb_clone(skb, GFP_ATOMIC), prev_port);
prev_port = -1;
break;
case ODP_ACTION_ATTR_CONTROLLER:
- err = output_control(dp, skb, nla_get_u64(a), key);
+ err = output_control(dp, skb, nla_get_u64(a));
if (err) {
kfree_skb(skb);
return err;
case ODP_ACTION_ATTR_SET_NW_SRC:
case ODP_ACTION_ATTR_SET_NW_DST:
- skb = set_nw_addr(skb, key, a);
+ skb = set_nw_addr(skb, a);
break;
case ODP_ACTION_ATTR_SET_NW_TOS:
- skb = set_nw_tos(skb, key, nla_get_u8(a));
+ skb = set_nw_tos(skb, nla_get_u8(a));
break;
case ODP_ACTION_ATTR_SET_TP_SRC:
case ODP_ACTION_ATTR_SET_TP_DST:
- skb = set_tp_port(skb, key, a);
+ skb = set_tp_port(skb, a);
break;
case ODP_ACTION_ATTR_SET_PRIORITY:
break;
case ODP_ACTION_ATTR_DROP_SPOOFED_ARP:
- if (unlikely(is_spoofed_arp(skb, key)))
+ if (unlikely(is_spoofed_arp(skb)))
goto exit;
break;
}
}
static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
- const struct sw_flow_key *key,
- const struct nlattr *a, u32 actions_len)
+ struct sw_flow_actions *acts)
{
struct sk_buff *nskb;
struct vport *p = OVS_CB(skb)->vport;
return;
upcall.cmd = ODP_PACKET_CMD_SAMPLE;
- upcall.key = key;
+ upcall.key = &OVS_CB(skb)->flow->key;
upcall.userdata = 0;
upcall.sample_pool = atomic_read(&p->sflow_pool);
- upcall.actions = a;
- upcall.actions_len = actions_len;
+ upcall.actions = acts->actions;
+ upcall.actions_len = acts->actions_len;
dp_upcall(dp, nskb, &upcall);
}
/* Execute a list of actions against 'skb'. */
-int execute_actions(struct datapath *dp, struct sk_buff *skb,
- const struct sw_flow_key *key,
- const struct nlattr *actions, u32 actions_len)
+int execute_actions(struct datapath *dp, struct sk_buff *skb)
{
- if (dp->sflow_probability)
- sflow_sample(dp, skb, key, actions, actions_len);
+ struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
+ struct loop_counter *loop;
+ int error;
+
+ /* Check whether we've looped too much. */
+ loop = loop_get_counter();
+ if (unlikely(++loop->count > MAX_LOOPS))
+ loop->looping = true;
+ if (unlikely(loop->looping)) {
+ error = loop_suppress(dp, acts);
+ kfree_skb(skb);
+ goto out_loop;
+ }
+ /* Really execute actions. */
+ if (dp->sflow_probability)
+ sflow_sample(dp, skb, acts);
OVS_CB(skb)->tun_id = 0;
+ error = do_execute_actions(dp, skb, acts);
+
+ /* Check whether sub-actions looped too much. */
+ if (unlikely(loop->looping))
+ error = loop_suppress(dp, acts);
+
+out_loop:
+ /* Decrement loop counter. */
+ if (!--loop->count)
+ loop->looping = false;
+ loop_put_counter();
- return do_execute_actions(dp, skb, key, actions, actions_len);
+ return error;
}
/*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
struct sk_buff;
struct sw_flow_key;
-int execute_actions(struct datapath *dp, struct sk_buff *skb,
- const struct sw_flow_key *,
- const struct nlattr *, u32 actions_len);
+int execute_actions(struct datapath *dp, struct sk_buff *skb);
static inline void skb_clear_rxhash(struct sk_buff *skb)
{
#include "datapath.h"
#include "actions.h"
#include "flow.h"
-#include "loop_counter.h"
#include "table.h"
#include "vlan.h"
#include "vport-internal_dev.h"
struct datapath *dp = p->dp;
struct dp_stats_percpu *stats;
int stats_counter_off;
- struct sw_flow_actions *acts;
- struct loop_counter *loop;
int error;
OVS_CB(skb)->vport = p;
stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
flow_used(OVS_CB(skb)->flow, skb);
-
- acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
-
- /* Check whether we've looped too much. */
- loop = loop_get_counter();
- if (unlikely(++loop->count > MAX_LOOPS))
- loop->looping = true;
- if (unlikely(loop->looping)) {
- loop_suppress(dp, acts);
- kfree_skb(skb);
- goto out_loop;
- }
-
- /* Execute actions. */
- execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions,
- acts->actions_len);
-
- /* Check whether sub-actions looped too much. */
- if (unlikely(loop->looping))
- loop_suppress(dp, acts);
-
-out_loop:
- /* Decrement loop counter. */
- if (!--loop->count)
- loop->looping = false;
- loop_put_counter();
+ execute_actions(dp, skb);
out:
/* Update datapath statistics. */
{
u32 group = packet_mc_group(dp, upcall_info->cmd);
struct sk_buff *nskb;
- int port_no;
int err;
- if (OVS_CB(skb)->vport)
- port_no = OVS_CB(skb)->vport->port_no;
- else
- port_no = ODPP_LOCAL;
-
do {
struct odp_header *upcall;
struct sk_buff *user_skb; /* to be queued to userspace */
{
struct odp_header *odp_header = info->userhdr;
struct nlattr **a = info->attrs;
+ struct sw_flow_actions *acts;
struct sk_buff *packet;
- struct sw_flow_key key;
+ struct sw_flow *flow;
struct datapath *dp;
struct ethhdr *eth;
bool is_frag;
else
packet->protocol = htons(ETH_P_802_2);
- /* Initialize OVS_CB (it came from Netlink so might not be zeroed). */
- memset(OVS_CB(packet), 0, sizeof(struct ovs_skb_cb));
+ /* Build an sw_flow for sending this packet. */
+ flow = flow_alloc();
+ err = PTR_ERR(flow);
+ if (IS_ERR(flow))
+ goto err_kfree_skb;
- err = flow_extract(packet, -1, &key, &is_frag);
+ err = flow_extract(packet, -1, &flow->key, &is_frag);
if (err)
- goto err_kfree_skb;
+ goto err_flow_put;
+ flow->tbl_node.hash = flow_hash(&flow->key);
+
+ acts = flow_actions_alloc(a[ODP_PACKET_ATTR_ACTIONS]);
+ err = PTR_ERR(acts);
+ if (IS_ERR(acts))
+ goto err_flow_put;
+ rcu_assign_pointer(flow->sf_acts, acts);
+
+ OVS_CB(packet)->flow = flow;
rcu_read_lock();
dp = get_dp(odp_header->dp_ifindex);
err = -ENODEV;
if (!dp)
goto err_unlock;
- err = execute_actions(dp, packet, &key,
- nla_data(a[ODP_PACKET_ATTR_ACTIONS]),
- nla_len(a[ODP_PACKET_ATTR_ACTIONS]));
+ err = execute_actions(dp, packet);
rcu_read_unlock();
+
+ flow_put(flow);
return err;
err_unlock:
rcu_read_unlock();
+err_flow_put:
+ flow_put(flow);
err_kfree_skb:
kfree_skb(packet);
err:
static struct kmem_cache *flow_cache;
static unsigned int hash_seed __read_mostly;
+static int check_header(struct sk_buff *skb, int len)
+{
+ if (unlikely(skb->len < len))
+ return -EINVAL;
+ if (unlikely(!pskb_may_pull(skb, len)))
+ return -ENOMEM;
+ return 0;
+}
+
static inline bool arphdr_ok(struct sk_buff *skb)
{
- return skb->len >= skb_network_offset(skb) + sizeof(struct arp_eth_header);
+ return pskb_may_pull(skb, skb_network_offset(skb) +
+ sizeof(struct arp_eth_header));
}
static inline int check_iphdr(struct sk_buff *skb)
{
unsigned int nh_ofs = skb_network_offset(skb);
unsigned int ip_len;
+ int err;
- if (skb->len < nh_ofs + sizeof(struct iphdr))
- return -EINVAL;
+ err = check_header(skb, nh_ofs + sizeof(struct iphdr));
+ if (unlikely(err))
+ return err;
ip_len = ip_hdrlen(skb);
- if (ip_len < sizeof(struct iphdr) || skb->len < nh_ofs + ip_len)
+ if (unlikely(ip_len < sizeof(struct iphdr) ||
+ skb->len < nh_ofs + ip_len))
return -EINVAL;
- /*
- * Pull enough header bytes to account for the IP header plus the
- * longest transport header that we parse, currently 20 bytes for TCP.
- */
- if (!pskb_may_pull(skb, min(nh_ofs + ip_len + 20, skb->len)))
- return -ENOMEM;
-
skb_set_transport_header(skb, nh_ofs + ip_len);
return 0;
}
static inline bool tcphdr_ok(struct sk_buff *skb)
{
int th_ofs = skb_transport_offset(skb);
- if (skb->len >= th_ofs + sizeof(struct tcphdr)) {
- int tcp_len = tcp_hdrlen(skb);
- return (tcp_len >= sizeof(struct tcphdr)
- && skb->len >= th_ofs + tcp_len);
- }
- return false;
+ int tcp_len;
+
+ if (unlikely(!pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))))
+ return false;
+
+ tcp_len = tcp_hdrlen(skb);
+ if (unlikely(tcp_len < sizeof(struct tcphdr) ||
+ skb->len < th_ofs + tcp_len))
+ return false;
+
+ return true;
}
static inline bool udphdr_ok(struct sk_buff *skb)
{
- return skb->len >= skb_transport_offset(skb) + sizeof(struct udphdr);
+ return pskb_may_pull(skb, skb_transport_offset(skb) +
+ sizeof(struct udphdr));
}
static inline bool icmphdr_ok(struct sk_buff *skb)
{
- return skb->len >= skb_transport_offset(skb) + sizeof(struct icmphdr);
+ return pskb_may_pull(skb, skb_transport_offset(skb) +
+ sizeof(struct icmphdr));
}
u64 flow_used_time(unsigned long flow_jiffies)
int payload_ofs;
struct ipv6hdr *nh;
uint8_t nexthdr;
+ int err;
- if (unlikely(skb->len < nh_ofs + sizeof(*nh)))
- return -EINVAL;
+ err = check_header(skb, nh_ofs + sizeof(*nh));
+ if (unlikely(err))
+ return err;
nh = ipv6_hdr(skb);
nexthdr = nh->nexthdr;
return -EINVAL;
nh_len = payload_ofs - nh_ofs;
-
- /* Pull enough header bytes to account for the IP header plus the
- * longest transport header that we parse, currently 20 bytes for TCP.
- * To dig deeper than the transport header, transport parsers may need
- * to pull more header bytes.
- */
- if (unlikely(!pskb_may_pull(skb, min(nh_ofs + nh_len + 20, skb->len))))
- return -ENOMEM;
-
skb_set_transport_header(skb, nh_ofs + nh_len);
key->nw_proto = nexthdr;
return nh_len;
static bool icmp6hdr_ok(struct sk_buff *skb)
{
- return skb->len >= skb_transport_offset(skb) + sizeof(struct icmp6hdr);
+ return pskb_may_pull(skb, skb_transport_offset(skb) +
+ sizeof(struct icmp6hdr));
}
#define TCP_FLAGS_OFFSET 13
spin_lock_init(&flow->lock);
atomic_set(&flow->refcnt, 1);
+ flow->sf_acts = NULL;
flow->dead = false;
return flow;
call_rcu(&sf_acts->rcu, rcu_free_acts_callback);
}
-static void parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
+static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
{
struct qtag_prefix {
__be16 eth_type; /* ETH_P_8021Q */
};
struct qtag_prefix *qp;
- if (skb->len < sizeof(struct qtag_prefix) + sizeof(__be16))
- return;
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) +
+ sizeof(__be16))))
+ return -ENOMEM;
qp = (struct qtag_prefix *) skb->data;
key->dl_tci = qp->tci | htons(VLAN_TAG_PRESENT);
__skb_pull(skb, sizeof(struct qtag_prefix));
+
+ return 0;
}
static __be16 parse_ethertype(struct sk_buff *skb)
if (ntohs(proto) >= 1536)
return proto;
- if (unlikely(skb->len < sizeof(struct llc_snap_hdr)))
+ if (skb->len < sizeof(struct llc_snap_hdr))
return htons(ETH_P_802_2);
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct llc_snap_hdr))))
+ return htons(0);
+
llc = (struct llc_snap_hdr *) skb->data;
if (llc->dsap != LLC_SAP_SNAP ||
llc->ssap != LLC_SAP_SNAP ||
key->in_port = in_port;
*is_frag = false;
- /*
- * We would really like to pull as many bytes as we could possibly
- * want to parse into the linear data area. Currently, for IPv4,
- * that is:
- *
- * 14 Ethernet header
- * 4 VLAN header
- * 60 max IP header with options
- * 20 max TCP/UDP/ICMP header (don't care about options)
- * --
- * 98
- *
- * But Xen only allocates 64 or 72 bytes for the linear data area in
- * netback, which means that we would reallocate and copy the skb's
- * linear data on every packet if we did that. So instead just pull 64
- * bytes, which is always sufficient without IP options, and then check
- * whether we need to pull more later when we look at the IP header.
- */
- if (!pskb_may_pull(skb, min(skb->len, 64u)))
- return -ENOMEM;
-
skb_reset_mac_header(skb);
- /* Link layer. */
+ /* Link layer. We are guaranteed to have at least the 14 byte Ethernet
+ * header in the linear data area.
+ */
eth = eth_hdr(skb);
memcpy(key->dl_src, eth->h_source, ETH_ALEN);
memcpy(key->dl_dst, eth->h_dest, ETH_ALEN);
-
- /* dl_type, dl_vlan, dl_vlan_pcp. */
__skb_pull(skb, 2 * ETH_ALEN);
if (vlan_tx_tag_present(skb))
key->dl_tci = htons(vlan_get_tci(skb));
else if (eth->h_proto == htons(ETH_P_8021Q))
- parse_vlan(skb, key);
+ if (unlikely(parse_vlan(skb, key)))
+ return -ENOMEM;
key->dl_type = parse_ethertype(skb);
+ if (unlikely(key->dl_type == htons(0)))
+ return -ENOMEM;
+
skb_reset_network_header(skb);
- __skb_push(skb, skb->data - (unsigned char *)eth);
+ __skb_push(skb, skb->data - skb_mac_header(skb));
/* Network layer. */
if (key->dl_type == htons(ETH_P_IP)) {
/time.c
/tmp
/tunnel.c
+/vlan.c
/vport-capwap.c
/vport-generic.c
/vport-gre.c
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
#endif
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+
#endif /* linux/kernel.h */
/*
* Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira Networks.
*
* Significant portions of this file may be copied from parts of the Linux
* kernel, by Linus Torvalds and others.
#include "loop_counter.h"
-void loop_suppress(struct datapath *dp, struct sw_flow_actions *actions)
+int loop_suppress(struct datapath *dp, struct sw_flow_actions *actions)
{
if (net_ratelimit())
pr_warn("%s: flow looped %d times, dropping\n",
dp_name(dp), MAX_LOOPS);
actions->actions_len = 0;
+ return -ELOOP;
}
#ifndef CONFIG_PREEMPT_RT
/*
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
struct loop_counter *loop_get_counter(void);
void loop_put_counter(void);
-void loop_suppress(struct datapath *, struct sw_flow_actions *);
+int loop_suppress(struct datapath *, struct sw_flow_actions *);
#endif /* loop_counter.h */
const struct tnl_mutable_config *mutable,
const struct rtable *rt, __be16 *frag_offp)
{
+ bool df_inherit = mutable->flags & TNL_F_DF_INHERIT;
bool pmtud = mutable->flags & TNL_F_PMTUD;
- __be16 frag_off = 0;
+ __be16 frag_off = mutable->flags & TNL_F_DF_DEFAULT ? htons(IP_DF) : 0;
int mtu = 0;
unsigned int packet_length = skb->len - ETH_HLEN;
if (pmtud) {
int vlan_header = 0;
- frag_off = htons(IP_DF);
-
/* The tag needs to go in packet regardless of where it
* currently is, so subtract it from the MTU.
*/
if (skb->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
- frag_off |= iph->frag_off & htons(IP_DF);
+ if (df_inherit)
+ frag_off = iph->frag_off & htons(IP_DF);
if (pmtud && iph->frag_off & htons(IP_DF)) {
mtu = max(mtu, IP_MIN_MTU);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6)) {
- /* IPv6 requires PMTUD if the packet is above the minimum MTU. */
- if (packet_length > IPV6_MIN_MTU)
+ /* IPv6 requires end hosts to do fragmentation
+ * if the packet is above the minimum MTU.
+ */
+ if (df_inherit && packet_length > IPV6_MIN_MTU)
frag_off = htons(IP_DF);
if (pmtud) {
/* All public tunnel flags. */
#define TNL_F_PUBLIC (TNL_F_CSUM | TNL_F_TOS_INHERIT | TNL_F_TTL_INHERIT | \
- TNL_F_PMTUD | TNL_F_HDR_CACHE | TNL_F_IPSEC)
+ TNL_F_DF_INHERIT | TNL_F_DF_DEFAULT | TNL_F_PMTUD | \
+ TNL_F_HDR_CACHE | TNL_F_IPSEC)
/**
* struct tnl_mutable_config - modifiable configuration for a tunnel.
cert_entry = """remote %s {
exchange_mode main;
nat_traversal on;
+ ike_frag on;
certificate_type x509 "%s" "%s";
my_identifier asn1dn;
peers_identifier asn1dn;
NXT_FLOW_END_CONFIG__OBSOLETE,
NXT_FLOW_END__OBSOLETE,
NXT_MGMT__OBSOLETE,
-
- /* Use the high 32 bits of the cookie field as the tunnel ID in the flow
- * match. */
- NXT_TUN_ID_FROM_COOKIE,
+ NXT_TUN_ID_FROM_COOKIE__OBSOLETE,
/* Controller role support. The request body is struct nx_role_request.
* The reply echos the request. */
NXST_AGGREGATE /* Analogous to OFPST_AGGREGATE. */
};
-/* NXT_TUN_ID_FROM_COOKIE request. */
-struct nxt_tun_id_cookie {
- struct ofp_header header;
- ovs_be32 vendor; /* NX_VENDOR_ID. */
- ovs_be32 subtype; /* NXT_TUN_ID_FROM_COOKIE */
- uint8_t set; /* Nonzero to enable, zero to disable. */
- uint8_t pad[7];
-};
-OFP_ASSERT(sizeof(struct nxt_tun_id_cookie) == 24);
-
/* This command enables or disables an Open vSwitch extension that allows a
* controller to specify the OpenFlow table to which a flow should be added,
* instead of having the switch decide which table is most appropriate as
*/
NX_MP_ALG_ITER_HASH /* Iterative Hash. */
};
-
-/* Wildcard for tunnel ID. */
-#define NXFW_TUN_ID (1 << 25)
-
-#define NXFW_ALL NXFW_TUN_ID
-#define OVSFW_ALL (OFPFW_ALL | NXFW_ALL)
\f
/* Action structure for NXAST_AUTOPATH.
*
enum nx_flow_format {
NXFF_OPENFLOW10 = 0, /* Standard OpenFlow 1.0 compatible. */
- NXFF_TUN_ID_FROM_COOKIE = 1, /* OpenFlow 1.0, plus obtain tunnel ID from
- * cookie. */
NXFF_NXM = 2 /* Nicira extended match. */
};
#define TNL_F_CSUM (1 << 0) /* Checksum packets. */
#define TNL_F_TOS_INHERIT (1 << 1) /* Inherit the ToS from the inner packet. */
#define TNL_F_TTL_INHERIT (1 << 2) /* Inherit the TTL from the inner packet. */
-#define TNL_F_PMTUD (1 << 3) /* Enable path MTU discovery. */
-#define TNL_F_HDR_CACHE (1 << 4) /* Enable tunnel header caching. */
-#define TNL_F_IPSEC (1 << 5) /* Traffic is IPsec encrypted. */
+#define TNL_F_DF_INHERIT (1 << 3) /* Inherit the DF bit from the inner packet. */
+#define TNL_F_DF_DEFAULT (1 << 4) /* Set the DF bit if inherit off or not IP. */
+#define TNL_F_PMTUD (1 << 5) /* Enable path MTU discovery. */
+#define TNL_F_HDR_CACHE (1 << 6) /* Enable tunnel header caching. */
+#define TNL_F_IPSEC (1 << 7) /* Traffic is IPsec encrypted. */
#endif /* openvswitch/tunnel.h */
lib/dpif-linux.c \
lib/dpif-linux.h \
lib/netdev-linux.c \
+ lib/netdev-linux.h \
lib/netdev-vport.c \
lib/netdev-vport.h \
lib/netlink-protocol.h \
openssl dhparam -C -in $(srcdir)/lib/dh4096.pem -noout) \
| sed 's/\(get_dh[0-9]*\)()/\1(void)/' > lib/dhparams.c.tmp
mv lib/dhparams.c.tmp lib/dhparams.c
+else
+lib_libopenvswitch_a_SOURCES += lib/stream-nossl.c
endif
EXTRA_DIST += \
uint64_t tx_bytes; /* Sum across 'tx_bytes' of entries. */
/* BM_STABLE specific bonding info. */
- uint16_t stb_id; /* ID used for 'stb_slaves' ordering. */
+ uint32_t stb_id; /* ID used for 'stb_slaves' ordering. */
};
/* A bond, that is, a set of network devices grouped to improve performance or
int updelay, downdelay; /* Delay before slave goes up/down, in ms. */
bool lacp_negotiated; /* LACP negotiations were successful. */
bool bond_revalidate; /* True if flows need revalidation. */
+ uint32_t basis; /* Basis for flow hash function. */
/* SLB specific bonding info. */
struct bond_entry *hash; /* An array of (BOND_MASK + 1) elements. */
static void bond_choose_active_slave(struct bond *, struct tag_set *);
static bool bond_is_tcp_hash(const struct bond *);
static unsigned int bond_hash_src(const uint8_t mac[ETH_ADDR_LEN],
- uint16_t vlan);
-static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan);
+ uint16_t vlan, uint32_t basis);
+static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
+ uint32_t basis);
static struct bond_entry *lookup_bond_entry(const struct bond *,
const struct flow *,
uint16_t vlan);
revalidate = true;
}
+ if (bond->basis != s->basis) {
+ bond->basis = s->basis;
+ revalidate = true;
+ }
+
if (bond->detect == BLSM_CARRIER) {
struct bond_slave *slave;
* 'slave_' or destroying 'bond'.
*/
void
-bond_slave_register(struct bond *bond, void *slave_, uint16_t stb_id,
+bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
struct netdev *netdev)
{
struct bond_slave *slave = bond_slave_lookup(bond, slave_);
bond_is_tcp_hash(bond) ? "balance-tcp" : "balance-slb");
}
+ ds_put_format(&ds, "bond-hash-basis: %"PRIu32"\n", bond->basis);
+
ds_put_format(&ds, "bond-detect-mode: %s\n",
bond->monitor ? "carrier" : "miimon");
uint8_t hash;
char *hash_cstr;
unsigned int vlan;
- char *mac_s, *vlan_s;
+ uint32_t basis;
+ char *mac_s, *vlan_s, *basis_s;
char *save_ptr = NULL;
mac_s = strtok_r(args, " ", &save_ptr);
vlan_s = strtok_r(NULL, " ", &save_ptr);
+ basis_s = strtok_r(NULL, " ", &save_ptr);
if (vlan_s) {
if (sscanf(vlan_s, "%u", &vlan) != 1) {
vlan = OFP_VLAN_NONE;
}
+ if (basis_s) {
+ if (sscanf(basis_s, "%"PRIu32, &basis) != 1) {
+ unixctl_command_reply(conn, 501, "invalid basis");
+ return;
+ }
+ } else {
+ basis = 0;
+ }
+
if (sscanf(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
== ETH_ADDR_SCAN_COUNT) {
- hash = bond_hash_src(mac, vlan) & BOND_MASK;
+ hash = bond_hash_src(mac, vlan, basis) & BOND_MASK;
hash_cstr = xasprintf("%u", hash);
unixctl_command_reply(conn, 200, hash_cstr);
}
static unsigned int
-bond_hash_src(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan)
+bond_hash_src(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan, uint32_t basis)
{
- return hash_bytes(mac, ETH_ADDR_LEN, vlan);
+ return hash_3words(hash_bytes(mac, ETH_ADDR_LEN, 0), vlan, basis);
}
static unsigned int
-bond_hash_tcp(const struct flow *flow, uint16_t vlan)
+bond_hash_tcp(const struct flow *flow, uint16_t vlan, uint32_t basis)
{
struct flow hash_flow = *flow;
hash_flow.vlan_tci = vlan;
/* The symmetric quality of this hash function is not required, but
* flow_hash_symmetric_l4 already exists, and is sufficient for our
* purposes, so we use it out of convenience. */
- return flow_hash_symmetric_l4(&hash_flow, 0);
+ return flow_hash_symmetric_l4(&hash_flow, basis);
}
static unsigned int
assert(bond->balance != BM_AB);
return (bond_is_tcp_hash(bond)
- ? bond_hash_tcp(flow, vlan)
- : bond_hash_src(flow->dl_src, vlan));
+ ? bond_hash_tcp(flow, vlan, bond->basis)
+ : bond_hash_src(flow->dl_src, vlan, bond->basis));
}
static struct bond_entry *
/* Configuration for a bond as a whole. */
struct bond_settings {
char *name; /* Bond's name, for log messages. */
+ uint32_t basis; /* Flow hashing basis. */
/* Balancing configuration. */
enum bond_mode balance;
bool bond_reconfigure(struct bond *, const struct bond_settings *);
void bond_slave_register(struct bond *, void *slave_,
- uint16_t stable_id, struct netdev *);
+ uint32_t stable_id, struct netdev *);
void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
void bond_slave_unregister(struct bond *, const void *slave);
#include "bitmap.h"
#include "dpif-provider.h"
#include "netdev.h"
+#include "netdev-linux.h"
#include "netdev-vport.h"
#include "netlink-socket.h"
#include "netlink.h"
dpif_port->name = xstrdup(reply.name);
dpif_port->type = xstrdup(netdev_vport_get_netdev_type(&reply));
dpif_port->port_no = reply.port_no;
+ if (reply.stats) {
+ netdev_stats_from_rtnl_link_stats64(&dpif_port->stats,
+ reply.stats);
+ } else {
+ memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats);
+ }
ofpbuf_delete(buf);
}
return error;
struct dpif_linux_port_state {
struct nl_dump dump;
+ unsigned long *port_bitmap; /* Ports in the datapath. */
+ bool complete; /* Dump completed without error. */
};
static int
struct ofpbuf *buf;
*statep = state = xmalloc(sizeof *state);
+ state->port_bitmap = bitmap_allocate(LRU_MAX_PORTS);
+ state->complete = false;
dpif_linux_vport_init(&request);
request.cmd = ODP_DP_CMD_GET;
int error;
if (!nl_dump_next(&state->dump, &buf)) {
+ state->complete = true;
return EOF;
}
return error;
}
+ if (vport.port_no < LRU_MAX_PORTS) {
+ bitmap_set1(state->port_bitmap, vport.port_no);
+ }
+
dpif_port->name = (char *) vport.name;
dpif_port->type = (char *) netdev_vport_get_netdev_type(&vport);
dpif_port->port_no = vport.port_no;
+ if (vport.stats) {
+ netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, vport.stats);
+ } else {
+ memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats);
+ }
return 0;
}
static int
-dpif_linux_port_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_)
+dpif_linux_port_dump_done(const struct dpif *dpif_, void *state_)
{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
struct dpif_linux_port_state *state = state_;
int error = nl_dump_done(&state->dump);
+
+ if (state->complete) {
+ uint16_t i;
+
+ for (i = 0; i < LRU_MAX_PORTS; i++) {
+ if (!bitmap_is_set(state->port_bitmap, i)) {
+ dpif_linux_push_port(dpif, i);
+ }
+ }
+ }
+
+ free(state->port_bitmap);
free(state);
return error;
}
dst->name = xstrdup(src->name);
dst->type = xstrdup(src->type);
dst->port_no = src->port_no;
+ dst->stats = src->stats;
}
/* Frees memory allocated to members of 'dpif_port'.
#include <stdint.h>
#include "openflow/openflow.h"
#include "openvswitch/datapath-protocol.h"
+#include "netdev.h"
#include "util.h"
#ifdef __cplusplus
struct dpif;
struct ds;
-struct netdev;
struct nlattr;
struct ofpbuf;
struct sset;
char *name; /* Network device name, e.g. "eth0". */
char *type; /* Network device type, e.g. "system". */
uint32_t port_no; /* Port number within datapath. */
+ struct netdev_stats stats; /* Port statistics. */
};
void dpif_port_clone(struct dpif_port *, const struct dpif_port *);
void dpif_port_destroy(struct dpif_port *);
#define FWW_TP_DST ((OVS_FORCE flow_wildcards_t) (1 << 7))
/* Same meanings as corresponding OFPFW_* bits, but differ in value. */
#define FWW_NW_TOS ((OVS_FORCE flow_wildcards_t) (1 << 1))
-/* No corresponding OFPFW_* or OVSFW_* bits. */
+/* No corresponding OFPFW_* bits. */
#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 8))
/* multicast bit only */
#define FWW_ARP_SHA ((OVS_FORCE flow_wildcards_t) (1 << 9))
enum lacp_time lacp_time; /* Fast, Slow or Custom LACP time. */
long long int custom_time; /* LACP_TIME_CUSTOM transmission rate. */
- bool strict; /* True if in strict mode. */
bool negotiated; /* True if LACP negotiations were successful. */
bool update; /* True if lacp_update() needs to be called. */
+ bool heartbeat; /* LACP heartbeat mode. */
};
struct slave {
struct lacp *lacp; /* LACP object containing this slave. */
uint16_t port_id; /* Port ID. */
uint16_t port_priority; /* Port Priority. */
+ uint16_t key; /* Aggregation Key. 0 if default. */
char *name; /* Name of this slave. */
enum slave_status status; /* Slave status. */
if (!eth_addr_equals(lacp->sys_id, s->id)
|| lacp->sys_priority != s->priority
- || lacp->strict != s->strict) {
+ || lacp->heartbeat != s->heartbeat) {
memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN);
lacp->sys_priority = s->priority;
- lacp->strict = s->strict;
+ lacp->heartbeat = s->heartbeat;
lacp->update = true;
}
slave->name = xstrdup(s->name);
}
- if (slave->port_id != s->id || slave->port_priority != s->priority) {
+ if (slave->port_id != s->id
+ || slave->port_priority != s->priority
+ || slave->key != s->key) {
slave->port_id = s->id;
slave->port_priority = s->priority;
+ slave->key = s->key;
lacp->update = true;
struct lacp_info lead_pri;
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
+ if (lacp->heartbeat) {
+ HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+ slave->attached = slave->status != LACP_DEFAULTED;
+ }
+ return;
+ }
+
lacp->update = false;
lead = NULL;
slave->attached = false;
}
}
- } else if (lacp->strict) {
- HMAP_FOR_EACH (slave, node, &lacp->slaves) {
- slave->attached = false;
- }
}
}
static void
slave_get_actor(struct slave *slave, struct lacp_info *actor)
{
+ struct lacp *lacp = slave->lacp;
+ uint16_t key;
uint8_t state = 0;
- if (slave->lacp->active) {
+ if (lacp->active) {
state |= LACP_STATE_ACT;
}
- if (slave->lacp->lacp_time != LACP_TIME_SLOW) {
+ if (lacp->lacp_time != LACP_TIME_SLOW) {
state |= LACP_STATE_TIME;
}
state |= LACP_STATE_EXP;
}
- if (hmap_count(&slave->lacp->slaves) > 1) {
+ if (lacp->heartbeat || hmap_count(&lacp->slaves) > 1) {
state |= LACP_STATE_AGG;
}
- if (slave->attached || !slave->lacp->negotiated) {
+ if (slave->attached || !lacp->negotiated) {
state |= LACP_STATE_COL | LACP_STATE_DIST;
}
+ key = lacp->key_slave->key;
+ if (!key) {
+ key = lacp->key_slave->port_id;
+ }
+
actor->state = state;
- actor->key = htons(slave->lacp->key_slave->port_id);
+ actor->key = htons(key);
actor->port_priority = htons(slave->port_priority);
actor->port_id = htons(slave->port_id);
- actor->sys_priority = htons(slave->lacp->sys_priority);
- memcpy(&actor->sys_id, slave->lacp->sys_id, ETH_ADDR_LEN);
+ actor->sys_priority = htons(lacp->sys_priority);
+ memcpy(&actor->sys_id, lacp->sys_id, ETH_ADDR_LEN);
}
/* Given 'slave', populates 'priority' with data representing its LACP link
ds_put_format(&ds, "lacp: %s\n", lacp->name);
ds_put_format(&ds, "\tstatus: %s", lacp->active ? "active" : "passive");
- if (lacp->strict) {
- ds_put_cstr(&ds, " strict");
+ if (lacp->heartbeat) {
+ ds_put_cstr(&ds, " heartbeat");
}
if (lacp->negotiated) {
ds_put_cstr(&ds, " negotiated");
bool active;
enum lacp_time lacp_time;
long long int custom_time;
- bool strict;
+ bool heartbeat;
};
void lacp_init(void);
char *name;
uint16_t id;
uint16_t priority;
+ uint16_t key;
};
void lacp_slave_register(struct lacp *, void *slave_,
case OFPUTIL_OFPST_PORT_REPLY:
case OFPUTIL_OFPST_TABLE_REPLY:
case OFPUTIL_OFPST_AGGREGATE_REPLY:
- case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
case OFPUTIL_NXT_ROLE_REQUEST:
case OFPUTIL_NXT_ROLE_REPLY:
case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
*/
#include <config.h>
+
+#include "netdev-linux.h"
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
unsigned int min_burst = tc_buffer_per_jiffy(Bps) + mtu;
return tc_bytes_to_ticks(Bps, MAX(burst_bytes, min_burst));
}
-
+\f
+/* Public utility functions. */
+
+#define COPY_NETDEV_STATS \
+ dst->rx_packets = src->rx_packets; \
+ dst->tx_packets = src->tx_packets; \
+ dst->rx_bytes = src->rx_bytes; \
+ dst->tx_bytes = src->tx_bytes; \
+ dst->rx_errors = src->rx_errors; \
+ dst->tx_errors = src->tx_errors; \
+ dst->rx_dropped = src->rx_dropped; \
+ dst->tx_dropped = src->tx_dropped; \
+ dst->multicast = src->multicast; \
+ dst->collisions = src->collisions; \
+ dst->rx_length_errors = src->rx_length_errors; \
+ dst->rx_over_errors = src->rx_over_errors; \
+ dst->rx_crc_errors = src->rx_crc_errors; \
+ dst->rx_frame_errors = src->rx_frame_errors; \
+ dst->rx_fifo_errors = src->rx_fifo_errors; \
+ dst->rx_missed_errors = src->rx_missed_errors; \
+ dst->tx_aborted_errors = src->tx_aborted_errors; \
+ dst->tx_carrier_errors = src->tx_carrier_errors; \
+ dst->tx_fifo_errors = src->tx_fifo_errors; \
+ dst->tx_heartbeat_errors = src->tx_heartbeat_errors; \
+ dst->tx_window_errors = src->tx_window_errors
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst,
+ const struct rtnl_link_stats *src)
+{
+ COPY_NETDEV_STATS;
+}
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst,
+ const struct rtnl_link_stats64 *src)
+{
+ COPY_NETDEV_STATS;
+}
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst,
+ const struct netdev_stats *src)
+{
+ COPY_NETDEV_STATS;
+}
\f
/* Utility functions. */
struct ofpbuf request;
struct ofpbuf *reply;
struct ifinfomsg *ifi;
- const struct rtnl_link_stats *rtnl_stats;
struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
int error;
return EPROTO;
}
- rtnl_stats = nl_attr_get(attrs[IFLA_STATS]);
- stats->rx_packets = rtnl_stats->rx_packets;
- stats->tx_packets = rtnl_stats->tx_packets;
- stats->rx_bytes = rtnl_stats->rx_bytes;
- stats->tx_bytes = rtnl_stats->tx_bytes;
- stats->rx_errors = rtnl_stats->rx_errors;
- stats->tx_errors = rtnl_stats->tx_errors;
- stats->rx_dropped = rtnl_stats->rx_dropped;
- stats->tx_dropped = rtnl_stats->tx_dropped;
- stats->multicast = rtnl_stats->multicast;
- stats->collisions = rtnl_stats->collisions;
- stats->rx_length_errors = rtnl_stats->rx_length_errors;
- stats->rx_over_errors = rtnl_stats->rx_over_errors;
- stats->rx_crc_errors = rtnl_stats->rx_crc_errors;
- stats->rx_frame_errors = rtnl_stats->rx_frame_errors;
- stats->rx_fifo_errors = rtnl_stats->rx_fifo_errors;
- stats->rx_missed_errors = rtnl_stats->rx_missed_errors;
- stats->tx_aborted_errors = rtnl_stats->tx_aborted_errors;
- stats->tx_carrier_errors = rtnl_stats->tx_carrier_errors;
- stats->tx_fifo_errors = rtnl_stats->tx_fifo_errors;
- stats->tx_heartbeat_errors = rtnl_stats->tx_heartbeat_errors;
- stats->tx_window_errors = rtnl_stats->tx_window_errors;
+ netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(attrs[IFLA_STATS]));
ofpbuf_delete(reply);
--- /dev/null
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETDEV_LINUX_H
+#define NETDEV_LINUX_H 1
+
+/* These functions are Linux specific, so they should be used directly only by
+ * Linux-specific code. */
+
+struct netdev_stats;
+struct rtnl_link_stats;
+struct rtnl_link_stats64;
+
+void netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst,
+ const struct rtnl_link_stats *src);
+void netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst,
+ const struct rtnl_link_stats64 *src);
+void netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst,
+ const struct netdev_stats *src);
+
+#endif /* netdev-linux.h */
#include "hash.h"
#include "hmap.h"
#include "list.h"
+#include "netdev-linux.h"
#include "netdev-provider.h"
#include "netlink.h"
#include "netlink-socket.h"
return EOPNOTSUPP;
}
- stats->rx_packets = reply.stats->rx_packets;
- stats->tx_packets = reply.stats->tx_packets;
- stats->rx_bytes = reply.stats->rx_bytes;
- stats->tx_bytes = reply.stats->tx_bytes;
- stats->rx_errors = reply.stats->rx_errors;
- stats->tx_errors = reply.stats->tx_errors;
- stats->rx_dropped = reply.stats->rx_dropped;
- stats->tx_dropped = reply.stats->tx_dropped;
- stats->multicast = reply.stats->multicast;
- stats->collisions = reply.stats->collisions;
- stats->rx_length_errors = reply.stats->rx_length_errors;
- stats->rx_over_errors = reply.stats->rx_over_errors;
- stats->rx_crc_errors = reply.stats->rx_crc_errors;
- stats->rx_frame_errors = reply.stats->rx_frame_errors;
- stats->rx_fifo_errors = reply.stats->rx_fifo_errors;
- stats->rx_missed_errors = reply.stats->rx_missed_errors;
- stats->tx_aborted_errors = reply.stats->tx_aborted_errors;
- stats->tx_carrier_errors = reply.stats->tx_carrier_errors;
- stats->tx_fifo_errors = reply.stats->tx_fifo_errors;
- stats->tx_heartbeat_errors = reply.stats->tx_heartbeat_errors;
- stats->tx_window_errors = reply.stats->tx_window_errors;
+ netdev_stats_from_rtnl_link_stats64(stats, reply.stats);
ofpbuf_delete(buf);
struct dpif_linux_vport vport;
int err;
- rtnl_stats.rx_packets = stats->rx_packets;
- rtnl_stats.tx_packets = stats->tx_packets;
- rtnl_stats.rx_bytes = stats->rx_bytes;
- rtnl_stats.tx_bytes = stats->tx_bytes;
- rtnl_stats.rx_errors = stats->rx_errors;
- rtnl_stats.tx_errors = stats->tx_errors;
- rtnl_stats.rx_dropped = stats->rx_dropped;
- rtnl_stats.tx_dropped = stats->tx_dropped;
- rtnl_stats.multicast = stats->multicast;
- rtnl_stats.collisions = stats->collisions;
- rtnl_stats.rx_length_errors = stats->rx_length_errors;
- rtnl_stats.rx_over_errors = stats->rx_over_errors;
- rtnl_stats.rx_crc_errors = stats->rx_crc_errors;
- rtnl_stats.rx_frame_errors = stats->rx_frame_errors;
- rtnl_stats.rx_fifo_errors = stats->rx_fifo_errors;
- rtnl_stats.rx_missed_errors = stats->rx_missed_errors;
- rtnl_stats.tx_aborted_errors = stats->tx_aborted_errors;
- rtnl_stats.tx_carrier_errors = stats->tx_carrier_errors;
- rtnl_stats.tx_fifo_errors = stats->tx_fifo_errors;
- rtnl_stats.tx_heartbeat_errors = stats->tx_heartbeat_errors;
- rtnl_stats.tx_window_errors = stats->tx_window_errors;
+ netdev_stats_to_rtnl_link_stats64(&rtnl_stats, stats);
dpif_linux_vport_init(&vport);
vport.cmd = ODP_VPORT_CMD_SET;
ovs_be32 daddr = htonl(0);
uint32_t flags;
- flags = TNL_F_PMTUD | TNL_F_HDR_CACHE;
+ flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE;
if (!strcmp(type, "gre")) {
is_gre = true;
} else if (!strcmp(type, "ipsec_gre")) {
if (!strcmp(node->data, "true")) {
flags |= TNL_F_CSUM;
}
+ } else if (!strcmp(node->name, "df_inherit")) {
+ if (!strcmp(node->data, "true")) {
+ flags |= TNL_F_DF_INHERIT;
+ }
+ } else if (!strcmp(node->name, "df_default")) {
+ if (!strcmp(node->data, "false")) {
+ flags &= ~TNL_F_DF_DEFAULT;
+ }
} else if (!strcmp(node->name, "pmtud")) {
if (!strcmp(node->data, "false")) {
flags &= ~TNL_F_PMTUD;
if (flags & TNL_F_CSUM) {
smap_add(args, "csum", "true");
}
+ if (flags & TNL_F_DF_INHERIT) {
+ smap_add(args, "df_inherit", "true");
+ }
+ if (!(flags & TNL_F_DF_DEFAULT)) {
+ smap_add(args, "df_default", "false");
+ }
if (!(flags & TNL_F_PMTUD)) {
smap_add(args, "pmtud", "false");
}
parse_ofp_str(&fm, is_del ? NULL : &actions, string);
fm.command = command;
- min_format = ofputil_min_flow_format(&fm.cr, true, fm.cookie);
+ min_format = ofputil_min_flow_format(&fm.cr);
next_format = MAX(*cur_format, min_format);
if (next_format != *cur_format) {
struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
skip_type = false;
}
}
- if (w & NXFW_TUN_ID) {
- ds_put_cstr(&f, "tun_id_wild,");
- }
print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity,
"%d", ntohs(om->in_port));
print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
bool need_priority;
int error;
- error = ofputil_decode_flow_mod(&fm, oh, NXFF_OPENFLOW10, true);
+ error = ofputil_decode_flow_mod(&fm, oh, true);
if (error) {
ofp_print_error(s, error);
return;
struct ofputil_flow_removed fr;
int error;
- error = ofputil_decode_flow_removed(&fr, oh, NXFF_OPENFLOW10);
+ error = ofputil_decode_flow_removed(&fr, oh);
if (error) {
ofp_print_error(string, error);
return;
struct flow_stats_request fsr;
int error;
- error = ofputil_decode_flow_stats_request(&fsr, oh, NXFF_OPENFLOW10);
+ error = ofputil_decode_flow_stats_request(&fsr, oh);
if (error) {
ofp_print_error(string, error);
return;
struct ofputil_flow_stats fs;
int retval;
- retval = ofputil_decode_flow_stats_reply(&fs, &b, NXFF_OPENFLOW10);
+ retval = ofputil_decode_flow_stats_reply(&fs, &b);
if (retval) {
if (retval != EOF) {
ds_put_cstr(string, " ***parse error***");
}
}
-static void
-ofp_print_nxt_tun_id_from_cookie(struct ds *string,
- const struct nxt_tun_id_cookie *ntic)
-{
- ds_put_format(string, " set=%"PRIu8, ntic->set);
-}
-
static void
ofp_print_nxt_role_message(struct ds *string,
const struct nx_role_request *nrr)
ofp_print_ofpst_aggregate_reply(string, oh);
break;
- case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
- ofp_print_nxt_tun_id_from_cookie(string, msg);
- break;
-
case OFPUTIL_NXT_ROLE_REQUEST:
case OFPUTIL_NXT_ROLE_REPLY:
ofp_print_nxt_role_message(string, msg);
};
/* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
- * 'priority'.
- *
- * 'flow_format' must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE. In
- * the latter case only, 'flow''s tun_id field will be taken from the high bits
- * of 'cookie', if 'match''s wildcards do not indicate that tun_id is
- * wildcarded. */
+ * 'priority'. */
void
ofputil_cls_rule_from_match(const struct ofp_match *match,
- unsigned int priority,
- enum nx_flow_format flow_format,
- ovs_be64 cookie, struct cls_rule *rule)
+ unsigned int priority, struct cls_rule *rule)
{
struct flow_wildcards *wc = &rule->wc;
unsigned int ofpfw;
ovs_be16 vid, pcp;
/* Initialize rule->priority. */
- ofpfw = ntohl(match->wildcards);
- ofpfw &= flow_format == NXFF_TUN_ID_FROM_COOKIE ? OVSFW_ALL : OFPFW_ALL;
+ ofpfw = ntohl(match->wildcards) & OFPFW_ALL;
rule->priority = !ofpfw ? UINT16_MAX : priority;
/* Initialize most of rule->wc. */
wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_SRC_SHIFT);
wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT);
- if (flow_format == NXFF_TUN_ID_FROM_COOKIE && !(ofpfw & NXFW_TUN_ID)) {
- cls_rule_set_tun_id(rule, htonll(ntohll(cookie) >> 32));
- }
-
if (ofpfw & OFPFW_DL_DST) {
/* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
* Open vSwitch breaks the Ethernet destination into bits as FWW_DL_DST
cls_rule_zero_wildcarded_fields(rule);
}
-/* Convert 'rule' into the OpenFlow match structure 'match'. 'flow_format'
- * must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE.
- *
- * The NXFF_TUN_ID_FROM_COOKIE flow format requires modifying the flow cookie.
- * This function can help with that, if 'cookie_out' is nonnull. For
- * NXFF_OPENFLOW10, or if the tunnel ID is wildcarded, 'cookie_in' will be
- * copied directly to '*cookie_out'. For NXFF_TUN_ID_FROM_COOKIE when tunnel
- * ID is matched, 'cookie_in' will be modified appropriately before setting
- * '*cookie_out'.
- */
+/* Convert 'rule' into the OpenFlow match structure 'match'. */
void
-ofputil_cls_rule_to_match(const struct cls_rule *rule,
- enum nx_flow_format flow_format,
- struct ofp_match *match,
- ovs_be64 cookie_in, ovs_be64 *cookie_out)
+ofputil_cls_rule_to_match(const struct cls_rule *rule, struct ofp_match *match)
{
const struct flow_wildcards *wc = &rule->wc;
unsigned int ofpfw;
ofpfw |= OFPFW_NW_TOS;
}
- /* Tunnel ID. */
- if (flow_format == NXFF_TUN_ID_FROM_COOKIE) {
- if (wc->tun_id_mask == htonll(0)) {
- ofpfw |= NXFW_TUN_ID;
- } else {
- uint32_t cookie_lo = ntohll(cookie_in);
- uint32_t cookie_hi = ntohll(rule->flow.tun_id);
- cookie_in = htonll(cookie_lo | ((uint64_t) cookie_hi << 32));
- }
- }
- if (cookie_out) {
- *cookie_out = cookie_in;
- }
-
/* Translate VLANs. */
match->dl_vlan = htons(0);
match->dl_vlan_pcp = 0;
!= sizeof(struct nxt_flow_mod_table_id));
static const struct ofputil_msg_type nxt_messages[] = {
- { OFPUTIL_NXT_TUN_ID_FROM_COOKIE,
- NXT_TUN_ID_FROM_COOKIE, "NXT_TUN_ID_FROM_COOKIE",
- sizeof(struct nxt_tun_id_cookie), 0 },
-
{ OFPUTIL_NXT_ROLE_REQUEST,
NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
sizeof(struct nx_role_request), 0 },
{
switch (flow_format) {
case NXFF_OPENFLOW10:
- case NXFF_TUN_ID_FROM_COOKIE:
case NXFF_NXM:
return true;
}
switch (flow_format) {
case NXFF_OPENFLOW10:
return "openflow10";
- case NXFF_TUN_ID_FROM_COOKIE:
- return "tun_id_from_cookie";
case NXFF_NXM:
return "nxm";
default:
ofputil_flow_format_from_string(const char *s)
{
return (!strcmp(s, "openflow10") ? NXFF_OPENFLOW10
- : !strcmp(s, "tun_id_from_cookie") ? NXFF_TUN_ID_FROM_COOKIE
: !strcmp(s, "nxm") ? NXFF_NXM
: -1);
}
return true;
}
-static inline bool
-is_nxm_required(const struct cls_rule *rule, bool cookie_support,
- ovs_be64 cookie)
+/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
+ * (e.g. to add or remove a flow). Only NXM can handle tunnel IDs, registers,
+ * or fixing the Ethernet multicast bit. Otherwise, it's better to use
+ * NXFF_OPENFLOW10 for backward compatibility. */
+enum nx_flow_format
+ofputil_min_flow_format(const struct cls_rule *rule)
{
const struct flow_wildcards *wc = &rule->wc;
- uint32_t cookie_hi;
- uint64_t tun_id;
/* Only NXM supports separately wildcards the Ethernet multicast bit. */
if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
- return true;
+ return NXFF_NXM;
}
/* Only NXM supports matching ARP hardware addresses. */
if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
- return true;
+ return NXFF_NXM;
}
/* Only NXM supports matching IPv6 traffic. */
if (!(wc->wildcards & FWW_DL_TYPE)
&& (rule->flow.dl_type == htons(ETH_TYPE_IPV6))) {
- return true;
+ return NXFF_NXM;
}
/* Only NXM supports matching registers. */
if (!regs_fully_wildcarded(wc)) {
- return true;
+ return NXFF_NXM;
}
- switch (wc->tun_id_mask) {
- case CONSTANT_HTONLL(0):
- /* Other formats can fully wildcard tun_id. */
- break;
-
- case CONSTANT_HTONLL(UINT64_MAX):
- /* Only NXM supports tunnel ID matching without a cookie. */
- if (!cookie_support) {
- return true;
- }
-
- /* Only NXM supports 64-bit tunnel IDs. */
- tun_id = ntohll(rule->flow.tun_id);
- if (tun_id > UINT32_MAX) {
- return true;
- }
-
- /* Only NXM supports a cookie whose top 32 bits conflict with the
- * tunnel ID. */
- cookie_hi = ntohll(cookie) >> 32;
- if (cookie_hi && cookie_hi != tun_id) {
- return true;
- }
- break;
-
- default:
- /* Only NXM supports partial matches on tunnel ID. */
- return true;
+ /* Only NXM supports matching tun_id. */
+ if (wc->tun_id_mask != htonll(0)) {
+ return NXFF_NXM;
}
/* Other formats can express this rule. */
- return false;
-}
-
-/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
- * (e.g. to add or remove a flow). 'cookie_support' should be true if the
- * command to be sent includes a flow cookie (as OFPT_FLOW_MOD does, for
- * example) or false if the command does not (OFPST_FLOW and OFPST_AGGREGATE do
- * not, for example). If 'cookie_support' is true, then 'cookie' should be the
- * cookie to be sent; otherwise its value is ignored.
- *
- * The "best" flow format is chosen on this basis:
- *
- * - It must be capable of expressing the rule. NXFF_OPENFLOW10 flows can't
- * handle tunnel IDs. NXFF_TUN_ID_FROM_COOKIE flows can't handle registers
- * or fixing the Ethernet multicast bit, and can't handle tunnel IDs that
- * conflict with the high 32 bits of the cookie or commands that don't
- * support cookies.
- *
- * - Otherwise, the chosen format should be as backward compatible as
- * possible. (NXFF_OPENFLOW10 is more backward compatible than
- * NXFF_TUN_ID_FROM_COOKIE, which is more backward compatible than
- * NXFF_NXM.)
- */
-enum nx_flow_format
-ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
- ovs_be64 cookie)
-{
- if (is_nxm_required(rule, cookie_support, cookie)) {
- return NXFF_NXM;
- } else if (rule->wc.tun_id_mask != htonll(0)) {
- return NXFF_TUN_ID_FROM_COOKIE;
- } else {
- return NXFF_OPENFLOW10;
- }
+ return NXFF_OPENFLOW10;
}
/* Returns an OpenFlow message that can be used to set the flow format to
struct ofpbuf *
ofputil_make_set_flow_format(enum nx_flow_format flow_format)
{
+ struct nxt_set_flow_format *sff;
struct ofpbuf *msg;
- if (flow_format == NXFF_OPENFLOW10
- || flow_format == NXFF_TUN_ID_FROM_COOKIE) {
- struct nxt_tun_id_cookie *tic;
-
- tic = make_nxmsg(sizeof *tic, NXT_TUN_ID_FROM_COOKIE, &msg);
- tic->set = flow_format == NXFF_TUN_ID_FROM_COOKIE;
- } else {
- struct nxt_set_flow_format *sff;
-
- sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
- sff->format = htonl(flow_format);
- }
+ sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
+ sff->format = htonl(flow_format);
return msg;
}
* flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
* code.
*
- * For OFPT_FLOW_MOD messages, 'flow_format' should be the current flow format
- * at the time when the message was received. Otherwise 'flow_format' is
- * ignored.
- *
* 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
* enabled, false otherwise.
*
* Does not validate the flow_mod actions. */
int
ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh,
- enum nx_flow_format flow_format,
bool flow_mod_table_id)
{
const struct ofputil_msg_type *type;
}
/* Translate the message. */
- ofputil_cls_rule_from_match(&match, ntohs(ofm->priority), flow_format,
- ofm->cookie, &fm->cr);
+ ofputil_cls_rule_from_match(&match, ntohs(ofm->priority), &fm->cr);
fm->cookie = ofm->cookie;
command = ntohs(ofm->command);
fm->idle_timeout = ntohs(ofm->idle_timeout);
? (fm->command & 0xff) | (fm->table_id << 8)
: fm->command);
- if (flow_format == NXFF_OPENFLOW10
- || flow_format == NXFF_TUN_ID_FROM_COOKIE) {
+ if (flow_format == NXFF_OPENFLOW10) {
struct ofp_flow_mod *ofm;
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
- ofputil_cls_rule_to_match(&fm->cr, flow_format, &ofm->match,
- fm->cookie, &ofm->cookie);
- ofm->command = htons(command);
+ ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
+ ofm->command = htons(fm->command);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
ofm->priority = htons(fm->cr.priority);
static int
ofputil_decode_ofpst_flow_request(struct flow_stats_request *fsr,
const struct ofp_header *oh,
- enum nx_flow_format flow_format,
bool aggregate)
{
const struct ofp_flow_stats_request *ofsr = ofputil_stats_body(oh);
fsr->aggregate = aggregate;
- ofputil_cls_rule_from_match(&ofsr->match, 0, flow_format, 0, &fsr->match);
+ ofputil_cls_rule_from_match(&ofsr->match, 0, &fsr->match);
fsr->out_port = ntohs(ofsr->out_port);
fsr->table_id = ofsr->table_id;
}
/* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE
- * request 'oh', received when the current flow format was 'flow_format', into
- * an abstract flow_stats_request in 'fsr'. Returns 0 if successful, otherwise
- * an OpenFlow error code.
- *
- * For OFPST_FLOW and OFPST_AGGREGATE messages, 'flow_format' should be the
- * current flow format at the time when the message was received. Otherwise
- * 'flow_format' is ignored. */
+ * request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0 if
+ * successful, otherwise an OpenFlow error code. */
int
ofputil_decode_flow_stats_request(struct flow_stats_request *fsr,
- const struct ofp_header *oh,
- enum nx_flow_format flow_format)
+ const struct ofp_header *oh)
{
const struct ofputil_msg_type *type;
struct ofpbuf b;
code = ofputil_msg_type_code(type);
switch (code) {
case OFPUTIL_OFPST_FLOW_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, oh, flow_format, false);
+ return ofputil_decode_ofpst_flow_request(fsr, oh, false);
case OFPUTIL_OFPST_AGGREGATE_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, oh, flow_format, true);
+ return ofputil_decode_ofpst_flow_request(fsr, oh, true);
case OFPUTIL_NXST_FLOW_REQUEST:
return ofputil_decode_nxst_flow_request(fsr, oh, false);
{
struct ofpbuf *msg;
- if (flow_format == NXFF_OPENFLOW10
- || flow_format == NXFF_TUN_ID_FROM_COOKIE) {
+ if (flow_format == NXFF_OPENFLOW10) {
struct ofp_flow_stats_request *ofsr;
int type;
type = fsr->aggregate ? OFPST_AGGREGATE : OFPST_FLOW;
ofsr = ofputil_make_stats_request(sizeof *ofsr, type, &msg);
- ofputil_cls_rule_to_match(&fsr->match, flow_format, &ofsr->match,
- 0, NULL);
+ ofputil_cls_rule_to_match(&fsr->match, &ofsr->match);
ofsr->table_id = fsr->table_id;
ofsr->out_port = htons(fsr->out_port);
} else if (flow_format == NXFF_NXM) {
}
/* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract
- * ofputil_flow_stats in 'fs'. For OFPST_FLOW messages, 'flow_format' should
- * be the current flow format at the time when the request corresponding to the
- * reply in 'msg' was sent. Otherwise 'flow_format' is ignored.
+ * ofputil_flow_stats in 'fs'.
*
* Multiple OFPST_FLOW or NXST_FLOW replies can be packed into a single
* OpenFlow message. Calling this function multiple times for a single 'msg'
* otherwise a positive errno value. */
int
ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
- struct ofpbuf *msg,
- enum nx_flow_format flow_format)
+ struct ofpbuf *msg)
{
const struct ofputil_msg_type *type;
int code;
fs->cookie = get_32aligned_be64(&ofs->cookie);
ofputil_cls_rule_from_match(&ofs->match, ntohs(ofs->priority),
- flow_format, fs->cookie, &fs->rule);
+ &fs->rule);
fs->table_id = ofs->table_id;
fs->duration_sec = ntohl(ofs->duration_sec);
fs->duration_nsec = ntohl(ofs->duration_nsec);
return 0;
}
-/* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh', received
- * when the current flow format was 'flow_format', into an abstract
- * ofputil_flow_removed in 'fr'. Returns 0 if successful, otherwise an
- * OpenFlow error code.
- *
- * For OFPT_FLOW_REMOVED messages, 'flow_format' should be the current flow
- * format at the time when the message was received. Otherwise 'flow_format'
- * is ignored. */
+/* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh' into an
+ * abstract ofputil_flow_removed in 'fr'. Returns 0 if successful, otherwise
+ * an OpenFlow error code. */
int
ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
- const struct ofp_header *oh,
- enum nx_flow_format flow_format)
+ const struct ofp_header *oh)
{
const struct ofputil_msg_type *type;
enum ofputil_msg_code code;
ofr = (const struct ofp_flow_removed *) oh;
ofputil_cls_rule_from_match(&ofr->match, ntohs(ofr->priority),
- flow_format, ofr->cookie, &fr->rule);
+ &fr->rule);
fr->cookie = ofr->cookie;
fr->reason = ofr->reason;
fr->duration_sec = ntohl(ofr->duration_sec);
{
struct ofpbuf *msg;
- if (flow_format == NXFF_OPENFLOW10
- || flow_format == NXFF_TUN_ID_FROM_COOKIE) {
+ if (flow_format == NXFF_OPENFLOW10) {
struct ofp_flow_removed *ofr;
ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0),
&msg);
- ofputil_cls_rule_to_match(&fr->rule, flow_format, &ofr->match,
- fr->cookie, &ofr->cookie);
+ ofputil_cls_rule_to_match(&fr->rule, &ofr->match);
ofr->priority = htons(fr->rule.priority);
ofr->reason = fr->reason;
ofr->duration_sec = htonl(fr->duration_sec);
ofm->header.length = htons(size);
ofm->cookie = 0;
ofm->priority = htons(MIN(rule->priority, UINT16_MAX));
- ofputil_cls_rule_to_match(rule, NXFF_OPENFLOW10, &ofm->match, 0, NULL);
+ ofputil_cls_rule_to_match(rule, &ofm->match);
ofm->command = htons(command);
return out;
}
if (error) {
return error;
}
- if (a->vlan_vid.vlan_vid & ~7) {
+ if (a->vlan_pcp.vlan_pcp & ~7) {
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
}
return 0;
enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST };
uint32_t wc;
- wc = ntohl(m->wildcards) & OVSFW_ALL;
+ wc = ntohl(m->wildcards) & OFPFW_ALL;
if (wc & OFPFW_DL_TYPE) {
m->dl_type = 0;
OFPUTIL_OFPST_AGGREGATE_REPLY,
/* NXT_* messages. */
- OFPUTIL_NXT_TUN_ID_FROM_COOKIE,
OFPUTIL_NXT_ROLE_REQUEST,
OFPUTIL_NXT_ROLE_REPLY,
OFPUTIL_NXT_SET_FLOW_FORMAT,
/* Work with OpenFlow 1.0 ofp_match. */
void ofputil_cls_rule_from_match(const struct ofp_match *,
- unsigned int priority, enum nx_flow_format,
- ovs_be64 cookie, struct cls_rule *);
-void ofputil_cls_rule_to_match(const struct cls_rule *, enum nx_flow_format,
- struct ofp_match *,
- ovs_be64 cookie_in, ovs_be64 *cookie_out);
+ unsigned int priority, struct cls_rule *);
+void ofputil_cls_rule_to_match(const struct cls_rule *, struct ofp_match *);
void normalize_match(struct ofp_match *);
char *ofp_match_to_literal_string(const struct ofp_match *match);
bool ofputil_flow_format_is_valid(enum nx_flow_format);
const char *ofputil_flow_format_to_string(enum nx_flow_format);
int ofputil_flow_format_from_string(const char *);
-enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *,
- bool cookie_support,
- ovs_be64 cookie);
+enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *);
struct ofpbuf *ofputil_make_set_flow_format(enum nx_flow_format);
};
int ofputil_decode_flow_mod(struct flow_mod *, const struct ofp_header *,
- enum nx_flow_format, bool flow_mod_table_id);
+ bool flow_mod_table_id);
struct ofpbuf *ofputil_encode_flow_mod(const struct flow_mod *,
enum nx_flow_format,
bool flow_mod_table_id);
};
int ofputil_decode_flow_stats_request(struct flow_stats_request *,
- const struct ofp_header *,
- enum nx_flow_format);
+ const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_stats_request(
const struct flow_stats_request *, enum nx_flow_format);
};
int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *,
- struct ofpbuf *msg,
- enum nx_flow_format);
+ struct ofpbuf *msg);
/* Flow removed message, independent of flow format. */
struct ofputil_flow_removed {
};
int ofputil_decode_flow_removed(struct ofputil_flow_removed *,
- const struct ofp_header *,
- enum nx_flow_format);
+ const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
enum nx_flow_format);
--- /dev/null
+/*
+ * Copyright (c) 2011 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "stream-ssl.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(stream_nossl);
+\f
+/* Dummy function definitions, used when OVS is built without OpenSSL. */
+
+bool
+stream_ssl_is_configured(void)
+{
+ return false;
+}
+
+static void NO_RETURN
+nossl_option(const char *detail)
+{
+ VLOG_FATAL("%s specified but Open vSwitch was built without SSL support",
+ detail);
+}
+
+void
+stream_ssl_set_private_key_file(const char *file_name)
+{
+ if (file_name != NULL) {
+ nossl_option("Private key");
+ }
+}
+
+void
+stream_ssl_set_certificate_file(const char *file_name)
+{
+ if (file_name != NULL) {
+ nossl_option("Certificate");
+ }
+}
+
+void
+stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap OVS_UNUSED)
+{
+ if (file_name != NULL) {
+ nossl_option("CA certificate");
+ }
+}
+
+void
+stream_ssl_set_peer_ca_cert_file(const char *file_name)
+{
+ if (file_name != NULL) {
+ nossl_option("Peer CA certificate");
+ }
+}
+
+void
+stream_ssl_set_key_and_cert(const char *private_key_file,
+ const char *certificate_file)
+{
+ stream_ssl_set_private_key_file(private_key_file);
+ stream_ssl_set_certificate_file(certificate_file);
+}
/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 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 <stdbool.h>
-#ifdef HAVE_OPENSSL
bool stream_ssl_is_configured(void);
-
void stream_ssl_set_private_key_file(const char *file_name);
void stream_ssl_set_certificate_file(const char *file_name);
void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap);
-
+void stream_ssl_set_peer_ca_cert_file(const char *file_name);
void stream_ssl_set_key_and_cert(const char *private_key_file,
const char *certificate_file);
-
-void stream_ssl_set_peer_ca_cert_file(const char *file_name);
-
-/* Define the long options for SSL support.
- *
- * Note that the definition includes a final comma, and therefore a comma
- * must not be supplied when using the definition. This is done so that
- * compilation succeeds whether or not HAVE_OPENSSL is defined. */
-#define STREAM_SSL_LONG_OPTIONS \
+#define STREAM_SSL_LONG_OPTIONS \
{"private-key", required_argument, 0, 'p'}, \
{"certificate", required_argument, 0, 'c'}, \
- {"ca-cert", required_argument, 0, 'C'},
+ {"ca-cert", required_argument, 0, 'C'}
#define STREAM_SSL_OPTION_HANDLERS \
case 'p': \
case 'C': \
stream_ssl_set_ca_cert_file(optarg, false); \
break;
-#else /* !HAVE_OPENSSL */
-static inline bool stream_ssl_is_configured(void)
-{
- return false;
-}
-#define STREAM_SSL_LONG_OPTIONS
-#define STREAM_SSL_OPTION_HANDLERS
-#endif /* !HAVE_OPENSSL */
#endif /* stream-ssl.h */
struct shash new_controllers;
struct ofconn *ofconn, *next_ofconn;
struct ofservice *ofservice, *next_ofservice;
- bool ss_exists;
size_t i;
/* Create newly configured controllers and services.
/* Delete controllers that are no longer configured.
* Update configuration of all now-existing controllers. */
- ss_exists = false;
HMAP_FOR_EACH_SAFE (ofconn, next_ofconn, hmap_node, &mgr->controllers) {
struct ofproto_controller *c;
VLOG_DEFINE_THIS_MODULE(in_band);
-/* In-band control allows a single network to be used for OpenFlow traffic and
- * other data traffic. See ovs-vswitchd.conf.db(5) for a description of
- * configuring in-band control.
- *
- * This comment is an attempt to describe how in-band control works at a
- * wire- and implementation-level. Correctly implementing in-band
- * control has proven difficult due to its many subtleties, and has thus
- * gone through many iterations. Please read through and understand the
- * reasoning behind the chosen rules before making modifications.
- *
- * In Open vSwitch, in-band control is implemented as "hidden" flows (in that
- * they are not visible through OpenFlow) and at a higher priority than
- * wildcarded flows can be set up by through OpenFlow. This is done so that
- * the OpenFlow controller cannot interfere with them and possibly break
- * connectivity with its switches. It is possible to see all flows, including
- * in-band ones, with the ovs-appctl "bridge/dump-flows" command.
- *
- * The Open vSwitch implementation of in-band control can hide traffic to
- * arbitrary "remotes", where each remote is one TCP port on one IP address.
- * Currently the remotes are automatically configured as the in-band OpenFlow
- * controllers plus the OVSDB managers, if any. (The latter is a requirement
- * because OVSDB managers are responsible for configuring OpenFlow controllers,
- * so if the manager cannot be reached then OpenFlow cannot be reconfigured.)
- *
- * The following rules (with the OFPP_NORMAL action) are set up on any bridge
- * that has any remotes:
- *
- * (a) DHCP requests sent from the local port.
- * (b) ARP replies to the local port's MAC address.
- * (c) ARP requests from the local port's MAC address.
- *
- * In-band also sets up the following rules for each unique next-hop MAC
- * address for the remotes' IPs (the "next hop" is either the remote
- * itself, if it is on a local subnet, or the gateway to reach the remote):
- *
- * (d) ARP replies to the next hop's MAC address.
- * (e) ARP requests from the next hop's MAC address.
- *
- * In-band also sets up the following rules for each unique remote IP address:
- *
- * (f) ARP replies containing the remote's IP address as a target.
- * (g) ARP requests containing the remote's IP address as a source.
- *
- * In-band also sets up the following rules for each unique remote (IP,port)
- * pair:
- *
- * (h) TCP traffic to the remote's IP and port.
- * (i) TCP traffic from the remote's IP and port.
- *
- * The goal of these rules is to be as narrow as possible to allow a
- * switch to join a network and be able to communicate with the
- * remotes. As mentioned earlier, these rules have higher priority
- * than the controller's rules, so if they are too broad, they may
- * prevent the controller from implementing its policy. As such,
- * in-band actively monitors some aspects of flow and packet processing
- * so that the rules can be made more precise.
- *
- * In-band control monitors attempts to add flows into the datapath that
- * could interfere with its duties. The datapath only allows exact
- * match entries, so in-band control is able to be very precise about
- * the flows it prevents. Flows that miss in the datapath are sent to
- * userspace to be processed, so preventing these flows from being
- * cached in the "fast path" does not affect correctness. The only type
- * of flow that is currently prevented is one that would prevent DHCP
- * replies from being seen by the local port. For example, a rule that
- * forwarded all DHCP traffic to the controller would not be allowed,
- * but one that forwarded to all ports (including the local port) would.
- *
- * As mentioned earlier, packets that miss in the datapath are sent to
- * the userspace for processing. The userspace has its own flow table,
- * the "classifier", so in-band checks whether any special processing
- * is needed before the classifier is consulted. If a packet is a DHCP
- * response to a request from the local port, the packet is forwarded to
- * the local port, regardless of the flow table. Note that this requires
- * L7 processing of DHCP replies to determine whether the 'chaddr' field
- * matches the MAC address of the local port.
- *
- * It is interesting to note that for an L3-based in-band control
- * mechanism, the majority of rules are devoted to ARP traffic. At first
- * glance, some of these rules appear redundant. However, each serves an
- * important role. First, in order to determine the MAC address of the
- * remote side (controller or gateway) for other ARP rules, we must allow
- * ARP traffic for our local port with rules (b) and (c). If we are
- * between a switch and its connection to the remote, we have to
- * allow the other switch's ARP traffic to through. This is done with
- * rules (d) and (e), since we do not know the addresses of the other
- * switches a priori, but do know the remote's or gateway's. Finally,
- * if the remote is running in a local guest VM that is not reached
- * through the local port, the switch that is connected to the VM must
- * allow ARP traffic based on the remote's IP address, since it will
- * not know the MAC address of the local port that is sending the traffic
- * or the MAC address of the remote in the guest VM.
- *
- * With a few notable exceptions below, in-band should work in most
- * network setups. The following are considered "supported' in the
- * current implementation:
- *
- * - Locally Connected. The switch and remote are on the same
- * subnet. This uses rules (a), (b), (c), (h), and (i).
- *
- * - Reached through Gateway. The switch and remote are on
- * different subnets and must go through a gateway. This uses
- * rules (a), (b), (c), (h), and (i).
- *
- * - Between Switch and Remote. This switch is between another
- * switch and the remote, and we want to allow the other
- * switch's traffic through. This uses rules (d), (e), (h), and
- * (i). It uses (b) and (c) indirectly in order to know the MAC
- * address for rules (d) and (e). Note that DHCP for the other
- * switch will not work unless an OpenFlow controller explicitly lets this
- * switch pass the traffic.
- *
- * - Between Switch and Gateway. This switch is between another
- * switch and the gateway, and we want to allow the other switch's
- * traffic through. This uses the same rules and logic as the
- * "Between Switch and Remote" configuration described earlier.
- *
- * - Remote on Local VM. The remote is a guest VM on the
- * system running in-band control. This uses rules (a), (b), (c),
- * (h), and (i).
- *
- * - Remote on Local VM with Different Networks. The remote
- * is a guest VM on the system running in-band control, but the
- * local port is not used to connect to the remote. For
- * example, an IP address is configured on eth0 of the switch. The
- * remote's VM is connected through eth1 of the switch, but an
- * IP address has not been configured for that port on the switch.
- * As such, the switch will use eth0 to connect to the remote,
- * and eth1's rules about the local port will not work. In the
- * example, the switch attached to eth0 would use rules (a), (b),
- * (c), (h), and (i) on eth0. The switch attached to eth1 would use
- * rules (f), (g), (h), and (i).
- *
- * The following are explicitly *not* supported by in-band control:
- *
- * - Specify Remote by Name. Currently, the remote must be
- * identified by IP address. A naive approach would be to permit
- * all DNS traffic. Unfortunately, this would prevent the
- * controller from defining any policy over DNS. Since switches
- * that are located behind us need to connect to the remote,
- * in-band cannot simply add a rule that allows DNS traffic from
- * the local port. The "correct" way to support this is to parse
- * DNS requests to allow all traffic related to a request for the
- * remote's name through. Due to the potential security
- * problems and amount of processing, we decided to hold off for
- * the time-being.
- *
- * - Differing Remotes for Switches. All switches must know
- * the L3 addresses for all the remotes that other switches
- * may use, since rules need to be set up to allow traffic related
- * to those remotes through. See rules (f), (g), (h), and (i).
- *
- * - Differing Routes for Switches. In order for the switch to
- * allow other switches to connect to a remote through a
- * gateway, it allows the gateway's traffic through with rules (d)
- * and (e). If the routes to the remote differ for the two
- * switches, we will not know the MAC address of the alternate
- * gateway.
- */
-
/* Priorities used in classifier for in-band rules. These values are higher
* than any that may be set with OpenFlow, and "18" kind of looks like "IB".
* The ordering of priorities is not important because all of the rules set up
struct list bundle_node; /* In struct ofbundle's "ports" list. */
struct cfm *cfm; /* Connectivity Fault Management, if any. */
tag_type tag; /* Tag associated with this port. */
+ uint32_t bond_stable_id; /* stable_id to use as bond slave, or 0. */
};
static struct ofport_dpif *
static bool
bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
- struct lacp_slave_settings *lacp)
+ struct lacp_slave_settings *lacp,
+ uint32_t bond_stable_id)
{
struct ofport_dpif *port;
lacp_slave_register(bundle->lacp, port, lacp);
}
+ port->bond_stable_id = bond_stable_id;
+
return true;
}
ok = true;
for (i = 0; i < s->n_slaves; i++) {
if (!bundle_add_port(bundle, s->slaves[i],
- s->lacp ? &s->lacp_slaves[i] : NULL)) {
+ s->lacp ? &s->lacp_slaves[i] : NULL,
+ s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) {
ok = false;
}
}
}
LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
- uint16_t stable_id = (bundle->lacp
- ? lacp_slave_get_port_id(bundle->lacp, port)
- : port->odp_port);
- bond_slave_register(bundle->bond, port, stable_id,
+ bond_slave_register(bundle->bond, port, port->bond_stable_id,
port->up.netdev);
}
} else {
for (i = 0; i < p->n_tables; i++) {
ots[i].table_id = i;
sprintf(ots[i].name, "table%d", i);
- ots[i].wildcards = htonl(OVSFW_ALL);
+ ots[i].wildcards = htonl(OFPFW_ALL);
ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
ots[i].active_count = htonl(classifier_count(&p->tables[i]));
}
p->ofproto_class->get_tables(p, ots);
- if (ofconn_get_flow_format(ofconn) == NXFF_OPENFLOW10) {
- /* OpenFlow 1.0 only supports the OFPFW_* bits. */
- for (i = 0; i < p->n_tables; i++) {
- ots[i].wildcards &= htonl(OFPFW_ALL);
- }
- }
-
ofconn_send_reply(ofconn, msg);
return 0;
}
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofp_flow_stats *ofs;
uint64_t packet_count, byte_count;
- ovs_be64 cookie;
size_t act_len, len;
if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) {
ofs->length = htons(len);
ofs->table_id = rule->table_id;
ofs->pad = 0;
- ofputil_cls_rule_to_match(&rule->cr, ofconn_get_flow_format(ofconn),
- &ofs->match, rule->flow_cookie, &cookie);
- put_32aligned_be64(&ofs->cookie, cookie);
+ ofputil_cls_rule_to_match(&rule->cr, &ofs->match);
+ put_32aligned_be64(&ofs->cookie, rule->flow_cookie);
calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec);
ofs->priority = htons(rule->cr.priority);
ofs->idle_timeout = htons(rule->idle_timeout);
COVERAGE_INC(ofproto_flows_req);
reply = start_ofp_stats_reply(oh, 1024);
- ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target);
+ ofputil_cls_rule_from_match(&fsr->match, 0, &target);
FOR_EACH_MATCHING_TABLE (cls, fsr->table_id, ofproto) {
struct cls_cursor cursor;
struct rule *rule;
struct cls_rule target;
struct ofpbuf *msg;
- ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0,
- &target);
+ ofputil_cls_rule_from_match(&request->match, 0, &target);
msg = start_ofp_stats_reply(oh, sizeof *reply);
reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg);
return error;
}
- error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_flow_format(ofconn),
+ error = ofputil_decode_flow_mod(&fm, oh,
ofconn_get_flow_mod_table_id(ofconn));
if (error) {
return error;
}
}
-static int
-handle_tun_id_from_cookie(struct ofconn *ofconn, const struct ofp_header *oh)
-{
- const struct nxt_tun_id_cookie *msg
- = (const struct nxt_tun_id_cookie *) oh;
- enum nx_flow_format flow_format;
-
- flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10;
- ofconn_set_flow_format(ofconn, flow_format);
-
- return 0;
-}
-
static int
handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
format = ntohl(msg->format);
if (format == NXFF_OPENFLOW10
- || format == NXFF_TUN_ID_FROM_COOKIE
|| format == NXFF_NXM) {
ofconn_set_flow_format(ofconn, format);
return 0;
return 0;
/* Nicira extension requests. */
- case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
- return handle_tun_id_from_cookie(ofconn, oh);
-
case OFPUTIL_NXT_ROLE_REQUEST:
return handle_role_request(ofconn, oh);
unsigned long *trunks; /* vlan_bitmap, NULL to trunk all VLANs. */
struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */
+ uint32_t *bond_stable_ids; /* Array of n_slaves elements. */
struct lacp_settings *lacp; /* Nonnull to enable LACP. */
struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
*
* - 'name' to "table#" where # is the table ID.
*
- * - 'wildcards' to OVSFW_ALL.
+ * - 'wildcards' to OFPFW_ALL.
*
* - 'max_entries' to 1,000,000.
*
DAEMON_LONG_OPTIONS,
#ifdef HAVE_OPENSSL
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
- TABLE_LONG_OPTIONS,
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
#endif
+ TABLE_LONG_OPTIONS,
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
TABLE_OPTION_HANDLERS(&table_style)
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_BOOTSTRAP_CA_CERT:
stream_ssl_set_ca_cert_file(optarg, true);
break;
-#endif
case '?':
exit(EXIT_FAILURE);
VLOG_DEFINE_THIS_MODULE(ovsdb_server);
-#if HAVE_OPENSSL
/* SSL configuration. */
static char *private_key_file;
static char *certificate_file;
static char *ca_cert_file;
static bool bootstrap_ca_cert;
-#endif
static unixctl_cb_func ovsdb_server_exit;
static unixctl_cb_func ovsdb_server_compact;
ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
shash_destroy_free_data(&resolved_remotes);
-#if HAVE_OPENSSL
/* Configure SSL. */
stream_ssl_set_key_and_cert(query_db_string(db, private_key_file),
query_db_string(db, certificate_file));
stream_ssl_set_ca_cert_file(query_db_string(db, ca_cert_file),
bootstrap_ca_cert);
-#endif
}
static void
DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
LEAK_CHECKER_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
{"private-key", required_argument, 0, 'p'},
{"certificate", required_argument, 0, 'c'},
{"ca-cert", required_argument, 0, 'C'},
-#endif
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
DAEMON_OPTION_HANDLERS
LEAK_CHECKER_OPTION_HANDLERS
-#ifdef HAVE_OPENSSL
case 'p':
private_key_file = optarg;
break;
ca_cert_file = optarg;
bootstrap_ca_cert = true;
break;
-#endif
case '?':
exit(EXIT_FAILURE);
])
AT_CLEANUP
-AT_SETUP([NXT_TUN_ID_FROM_COOKIE])
-AT_KEYWORDS([ofp-print])
-AT_CHECK([ovs-ofctl ofp-print "\
-01 04 00 18 00 00 00 02 00 00 23 20 00 00 00 09 \
-01 00 00 00 00 00 00 00 \
-"], [0], [dnl
-NXT_TUN_ID_FROM_COOKIE (xid=0x2): set=1
-])
-AT_CLEANUP
-
AT_SETUP([NXT_ROLE_REQUEST])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
])
AT_CHECK([echo 'in_port=1,actions=0' | ovs-ofctl add-flows br0 -])
AT_CHECK([ovs-ofctl add-flow br0 in_port=0,actions=1])
-dnl Tests for a bug in which ofproto ignored tun_id in tun_id_from_cookie
-dnl flow_mod commands.
-AT_CHECK([ovs-ofctl add-flow -F tun_id_from_cookie br0 tun_id=1,actions=mod_vlan_vid:4])
AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=0 actions=output:1
cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
- cookie=0x100000000, duration=?s, table_id=0, n_packets=0, n_bytes=0, tun_id=0x1 actions=mod_vlan_vid:4
+ cookie=0x0, duration=?s, table_id=0, n_packets=0, n_bytes=0, in_port=65534 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl del-flows br0])
OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
-NXT_TUN_ID_FROM_COOKIE: set=1
-OFPT_FLOW_MOD: ADD cookie:0x123400005678 actions=FLOOD
-OFPT_FLOW_MOD: ADD actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
-OFPT_FLOW_MOD: ADD actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
-NXT_FLOW_MOD_TABLE_ID: enable
-OFPT_FLOW_MOD: ADD table_id:1 actions=drop
NXT_SET_FLOW_FORMAT: format=nxm
-NXT_FLOW_MOD: ADD table_id:255 tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
+NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD
+NXT_FLOW_MOD: ADD actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
+NXT_FLOW_MOD: ADD actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
+NXT_FLOW_MOD: ADD actions=drop
+NXT_FLOW_MOD: ADD tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
]])
AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
normalization changed ofp_match, details:
pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
normalization changed ofp_match, details:
- pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
-post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
-normalization changed ofp_match, details:
- pre: wildcards= 0x3820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
-post: wildcards= 0x3fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
-normalization changed ofp_match, details:
- pre: wildcards= 0x23820ff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
-post: wildcards= 0x23fffff in_port= 0 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
+ pre: wildcards= 0x3820ff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
+post: wildcards= 0x3fffff in_port=65534 dl_src=00:00:00:00:00:00 dl_dst=00:00:00:00:00:00 dl_vlan= 0 dl_vlan_pcp= 0 dl_type= 0 nw_tos= 0 nw_proto= 0 nw_src= 0 nw_dst= 0 tp_src= 0 tp_dst= 0
])
AT_CLEANUP
dnl OpenFlow 1.0 doesn't support tunnels.
AT_SETUP([ovs-ofctl -F option and tun_id])
AT_CHECK([ovs-ofctl -F openflow10 add-flow dummy tun_id=123,actions=drop],
- [1], [], [ovs-ofctl: flow cannot be expressed in flow format openflow10 (flow format tun_id_from_cookie or better is required)
+ [1], [], [ovs-ofctl: flow cannot be expressed in flow format openflow10 (flow format nxm or better is required)
])
AT_CLEANUP
/*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
flow_extract(packet, 0, 1, &flow);
cls_rule_init_exact(&flow, 0, &rule);
- ofputil_cls_rule_to_match(&rule, NXFF_OPENFLOW10, &extracted_match,
- 0, NULL);
+ ofputil_cls_rule_to_match(&rule, &extracted_match);
if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
char *exp_s = ofp_match_to_string(&expected_match, 2);
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
DAEMON_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
- STREAM_SSL_LONG_OPTIONS
-#endif
+ STREAM_SSL_LONG_OPTIONS,
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
DAEMON_OPTION_HANDLERS
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_BOOTSTRAP_CA_CERT:
stream_ssl_set_ca_cert_file(optarg, true);
break;
-#endif
case '?':
exit(EXIT_FAILURE);
{"version", no_argument, 0, 'V'},
DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
{"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
-#endif
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
VLOG_OPTION_HANDLERS
DAEMON_OPTION_HANDLERS
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_PEER_CA_CERT:
stream_ssl_set_peer_ca_cert_file(optarg);
break;
-#endif
case '?':
exit(EXIT_FAILURE);
Prints the name of each configured datapath on a separate line.
.
.TP
-\fBshow \fR[\fIdp\fR...]
+[\fB\-s\fR | \fB\-\-statistics\fR] \fBshow \fR[\fIdp\fR...]
Prints a summary of configured datapaths, including their datapath
numbers and a list of ports connected to each datapath. (The local
-port is identified as port 0.)
+port is identified as port 0.) If \fB\-s\fR or \fB\-\-statistics\fR
+is specified, then packet and byte counters are also printed for each
+port.
.IP
If one or more datapaths are specified, information on only those
datapaths are displayed. Otherwise, \fBovs\-dpctl\fR displays information
up may be confused about their disappearance.
.
.SH OPTIONS
+.IP "\fB\-s\fR, \fB\-\-statistics\fR"
+Causes the \fBshow\fR command to print packet and byte counters for
+each port within the datapaths that it shows.
.TP
\fB\-t\fR, \fB\-\-timeout=\fIsecs\fR
Limits \fBovs\-dpctl\fR runtime to approximately \fIsecs\fR seconds. If
VLOG_DEFINE_THIS_MODULE(dpctl);
+/* -s, --statistics: Print port statistics? */
+bool print_statistics;
+
static const struct command all_commands[];
static void usage(void) NO_RETURN;
VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
+ {"statistics", no_argument, 0, 's'},
{"timeout", required_argument, 0, 't'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
}
switch (c) {
+ case 's':
+ print_statistics = true;
+ break;
+
case 't':
timeout = strtoul(optarg, NULL, 10);
if (timeout <= 0) {
}
}
+static void
+print_stat(const char *leader, uint64_t value)
+{
+ fputs(leader, stdout);
+ if (value != UINT64_MAX) {
+ printf("%"PRIu64, value);
+ } else {
+ putchar('?');
+ }
+}
+
+static void
+print_human_size(uint64_t value)
+{
+ if (value == UINT64_MAX) {
+ /* Nothing to do. */
+ } else if (value >= 1024ULL * 1024 * 1024 * 1024) {
+ printf(" (%.1f TiB)", value / (1024.0 * 1024 * 1024 * 1024));
+ } else if (value >= 1024ULL * 1024 * 1024) {
+ printf(" (%.1f GiB)", value / (1024.0 * 1024 * 1024));
+ } else if (value >= 1024ULL * 1024) {
+ printf(" (%.1f MiB)", value / (1024.0 * 1024));
+ } else if (value >= 1024) {
+ printf(" (%.1f KiB)", value / 1024.0);
+ }
+}
+
static void
show_dpif(struct dpif *dpif)
{
putchar(')');
}
putchar('\n');
+
+ if (print_statistics) {
+ const struct netdev_stats *s = &dpif_port.stats;
+
+ print_stat("\t\tRX packets:", s->rx_packets);
+ print_stat(" errors:", s->rx_errors);
+ print_stat(" dropped:", s->rx_dropped);
+ print_stat(" overruns:", s->rx_over_errors);
+ print_stat(" frame:", s->rx_frame_errors);
+ printf("\n");
+
+ print_stat("\t\tTX packets:", s->tx_packets);
+ print_stat(" errors:", s->tx_errors);
+ print_stat(" dropped:", s->tx_dropped);
+ print_stat(" aborted:", s->tx_aborted_errors);
+ print_stat(" carrier:", s->tx_carrier_errors);
+ printf("\n");
+
+ print_stat("\t\tcollisions:", s->collisions);
+ printf("\n");
+
+ print_stat("\t\tRX bytes:", s->rx_bytes);
+ print_human_size(s->rx_bytes);
+ print_stat(" TX bytes:", s->tx_bytes);
+ print_human_size(s->tx_bytes);
+ printf("\n");
+ }
}
dpif_close(dpif);
}
This is the standard OpenFlow 1.0 flow format. It should be supported
by all OpenFlow switches.
.
-.IP "\fBtun_id_from_cookie\fR"
-This Nicira extension to OpenFlow adds minimal and limited support for
-\fBtun_id\fR, but it does not support any other Nicira flow
-extensions. (This flow format is deprecated.)
-.
.IP "\fBnxm\fR (Nicira Extended Match)"
This Nicira extension to OpenFlow is flexible and extensible. It
supports all of the Nicira flow extensions, such as \fBtun_id\fR and
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
VLOG_LONG_OPTIONS,
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
if (try_set_flow_format(vconn, NXFF_NXM)) {
flow_format = NXFF_NXM;
- } else if (try_set_flow_format(vconn, NXFF_TUN_ID_FROM_COOKIE)) {
- flow_format = NXFF_TUN_ID_FROM_COOKIE;
} else {
flow_format = NXFF_OPENFLOW10;
}
parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
open_vconn(argv[1], &vconn);
- min_flow_format = ofputil_min_flow_format(&fsr.match, false, 0);
+ min_flow_format = ofputil_min_flow_format(&fsr.match);
flow_format = negotiate_highest_flow_format(vconn, min_flow_format);
request = ofputil_encode_flow_stats_request(&fsr, flow_format);
dump_stats_transaction(argv[1], request);
version->n_actions = actions.size / sizeof *version->actions;
version->actions = ofpbuf_steal_data(&actions);
- min_ff = ofputil_min_flow_format(&fm.cr, true, fm.cookie);
+ min_ff = ofputil_min_flow_format(&fm.cr);
min_flow_format = MAX(min_flow_format, min_ff);
check_final_format_for_flow_mod(min_flow_format);
struct ofputil_flow_stats fs;
int retval;
- retval = ofputil_decode_flow_stats_reply(&fs, reply,
- flow_format);
+ retval = ofputil_decode_flow_stats_reply(&fs, reply);
if (retval) {
if (retval != EOF) {
ovs_fatal(0, "parse error in reply");
DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
LEAK_CHECKER_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
-#endif
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
LEAK_CHECKER_OPTION_HANDLERS
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_BOOTSTRAP_CA_CERT:
stream_ssl_set_ca_cert_file(optarg, true);
break;
-#endif
case '?':
exit(EXIT_FAILURE);
stdin, looking for hexadecimal packet data, and dumps each Ethernet as
a single hexadecimal string on stdout. This format is suitable for
use with the \fBofproto/trace\fR command supported by
-\fBovs\-vswitchd\fR(8) and \fBovs-openflowd\fR(8).
+\fBovs\-vswitchd\fR(8) and \fBovs-openflowd\fR(8)
+via \fBovs\-appctl\fR(8).
.PP
At least two \fB\-x\fR or \fB\-X\fR options must be given, otherwise
the output will omit the Ethernet header, which prevents the output
.
.SH "SEE ALSO"
.
+.BR ovs\-appctl (8),
.BR ovs\-vswitchd (8),
.BR ovs\-openflowd (8),
.BR ovs\-pcap (1),
If \fB@\fIname\fR is specified, then the UUID for \fIrecord\fR may be
referred to by that name later in the same \fBovs\-vsctl\fR
invocation in contexts where a UUID is expected.
+.IP
+Both \fB\-\-id\fR and the \fIcolumn\fR arguments are optional, but
+usually at least one or the other should be specified. If both are
+omitted, then \fBget\fR has no effect except to verify that
+\fIrecord\fR exists in \fItable\fR.
.
.IP "\fBset \fItable record column\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR..."
Sets the value of each specified \fIcolumn\fR in the given
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "command-line.h"
#include "compiler.h"
{"version", no_argument, 0, 'V'},
VLOG_LONG_OPTIONS,
TABLE_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
{"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
-#endif
{0, 0, 0, 0},
};
char *tmp, *short_options;
VLOG_OPTION_HANDLERS
TABLE_OPTION_HANDLERS(&table_style)
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_PEER_CA_CERT:
stream_ssl_set_peer_ca_cert_file(optarg);
break;
-#endif
case '?':
exit(EXIT_FAILURE);
static void
pre_cmd_get(struct vsctl_context *ctx)
{
+ const char *id = shash_find_data(&ctx->options, "--id");
const char *table_name = ctx->argv[1];
const struct vsctl_table_class *table;
int i;
+ /* Using "get" without --id or a column name could possibly make sense.
+ * Maybe, for example, a ovs-vsctl run wants to assert that a row exists.
+ * But it is unlikely that an interactive user would want to do that, so
+ * issue a warning if we're running on a terminal. */
+ if (!id && ctx->argc <= 3 && isatty(STDOUT_FILENO)) {
+ VLOG_WARN("\"get\" command without row arguments or \"--id\" is "
+ "possibly erroneous");
+ }
+
table = pre_get_table(ctx, table_name);
for (i = 3; i < ctx->argc; i++) {
if (!strcasecmp(ctx->argv[i], "_uuid")
/* (Re)configure if necessary. */
database_changed = ovsdb_idl_run(idl);
cfg = ovsrec_open_vswitch_first(idl);
-#ifdef HAVE_OPENSSL
+
/* Re-configure SSL. We do this on every trip through the main loop,
* instead of just when the database changes, because the contents of the
* key and certificate files can change without the database changing.
stream_ssl_set_key_and_cert(ssl->private_key, ssl->certificate);
stream_ssl_set_ca_cert_file(ssl->ca_cert, ssl->bootstrap_ca_cert);
}
-#endif
+
if (database_changed || datapath_destroyed) {
if (cfg) {
struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
sset_init(&new_ifaces);
for (i = 0; i < port->cfg->n_interfaces; i++) {
const char *name = port->cfg->interfaces[i]->name;
- sset_add(&new_ifaces, name);
+ const char *type = port->cfg->interfaces[i]->name;
+ if (strcmp(type, "null")) {
+ sset_add(&new_ifaces, name);
+ }
}
/* Get rid of deleted interfaces. */
shash_init(&new_ifaces);
for (i = 0; i < port->cfg->n_interfaces; i++) {
const struct ovsrec_interface *cfg = port->cfg->interfaces[i];
- if (!shash_add_once(&new_ifaces, cfg->name, cfg)) {
+ if (strcmp(cfg->type, "null")
+ && !shash_add_once(&new_ifaces, cfg->name, cfg)) {
VLOG_WARN("port %s: %s specified twice as port interface",
port->name, cfg->name);
iface_set_ofport(cfg, -1);
? priority
: UINT16_MAX - !list_is_short(&port->ifaces));
- s->strict = !strcmp(get_port_other_config(port->cfg, "lacp-strict",
- "false"),
- "true");
+ s->heartbeat = !strcmp(get_port_other_config(port->cfg,
+ "lacp-heartbeat",
+ "false"), "true");
+
lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow");
custom_time = atoi(lacp_time);
static void
iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
{
- int priority, portid;
+ int priority, portid, key;
portid = atoi(get_interface_other_config(iface->cfg, "lacp-port-id", "0"));
priority = atoi(get_interface_other_config(iface->cfg,
"lacp-port-priority", "0"));
+ key = atoi(get_interface_other_config(iface->cfg, "lacp-aggregation-key",
+ "0"));
if (portid <= 0 || portid > UINT16_MAX) {
portid = iface->ofp_port;
priority = UINT16_MAX;
}
+ if (key < 0 || key > UINT16_MAX) {
+ key = 0;
+ }
+
s->name = iface->name;
s->id = portid;
s->priority = priority;
+ s->key = key;
}
static void
s->up_delay = MAX(0, port->cfg->bond_updelay);
s->down_delay = MAX(0, port->cfg->bond_downdelay);
+ s->basis = atoi(get_port_other_config(port->cfg, "bond-hash-basis", "0"));
s->rebalance_interval = atoi(
get_port_other_config(port->cfg, "bond-rebalance-interval", "10000"));
if (s->rebalance_interval < 1000) {
static void
iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
{
- if (!qos || qos->type[0] == '\0') {
+ if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
netdev_set_qos(iface->netdev, NULL, NULL);
} else {
struct iface_delete_queues_cbdata cbdata;
.so lib/common.man
.so lib/leak-checker.man
.
+.SH BUGS
+.
+\fBovs\-brcompatd\fR requires the bridges that it manages to initially
+have no ports listed in their database records when it starts up.
+Otherwise, it may add duplicate ports to bridges.
+.
.SH NOTES
\fBovs\-brcompatd\fR requires the \fBbrcompat_mod.ko\fR kernel module to be
loaded.
.IP
This setting is not permanent: it persists only until the carrier
status of \fIslave\fR changes.
-.IP "\fBbond/hash\fR \fImac\fR [\fIvlan\fR]"
+.IP "\fBbond/hash\fR \fImac\fR [\fIvlan\fR] [\fIbasis\fR]"
Returns the hash value which would be used for \fImac\fR with \fIvlan\fR
-if specified.
+and \fIbasis\fR if specified.
.
.IP "\fBlacp/show\fR \fIport\fR"
Lists all of the LACP related information about the given \fIport\fR:
DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
LEAK_CHECKER_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
- STREAM_SSL_LONG_OPTIONS
+ STREAM_SSL_LONG_OPTIONS,
{"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
-#endif
{"enable-dummy", no_argument, 0, OPT_ENABLE_DUMMY},
{0, 0, 0, 0},
};
VLOG_OPTION_HANDLERS
DAEMON_OPTION_HANDLERS
LEAK_CHECKER_OPTION_HANDLERS
-
-#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
case OPT_PEER_CA_CERT:
case OPT_BOOTSTRAP_CA_CERT:
stream_ssl_set_ca_cert_file(optarg, true);
break;
-#endif
case OPT_ENABLE_DUMMY:
dummy_enable();
{"name": "Open_vSwitch",
- "version": "3.3.0",
- "cksum": "1105667635 15276",
+ "version": "3.4.2",
+ "cksum": "976911089 15276",
"tables": {
"Open_vSwitch": {
"columns": {
balancing is done. Uses a similar hashing strategy to
<code>balance-tcp</code>, falling back to <code>balance-slb</code>
style hashing when LACP negotiations are unsuccessful.</p>
- <p>Slave selection decisions are made based on LACP port ID when LACP
- negotiations are successful, falling back to openflow port number
- when unsuccessful. Thus, decisions are consistent across all
- ovs-vswitchd instances with equivalent port IDs.</p>
+ <p>Slave selection decisions are made based on
+ <code>bond-stable-id</code> if set. Otherwise, OpenFlow port
+ number is used. Decisions are consistent across all ovs-vswitchd
+ instances with equivalent <code>bond-stable-id</code>s.</p>
</dd>
</dl>
<column name="lacp">
<p>Configures LACP on this port. LACP allows directly connected
- switchs to negotiate which links may be bonded. LACP may be enabled
- on non-bonded ports for the benefit of any switchs they may be
+ switches to negotiate which links may be bonded. LACP may be enabled
+ on non-bonded ports for the benefit of any switches they may be
connected to. <code>active</code> ports are allowed to initiate LACP
negotiations. <code>passive</code> ports are allowed to participate
in LACP negotiations initiated by a remote switch, but not allowed to
<dd> The number of milliseconds between successive attempts to
poll each interface's MII. Only relevant on ports which use
<code>miimon</code> to detect failures. </dd>
+ <dt><code>bond-hash-basis</code></dt>
+ <dd> An integer hashed along with flows when choosing output slaves.
+ When changed, all flows will be assigned different hash values
+ possibly causing slave selection decisions to change.</dd>
<dt><code>lacp-system-id</code></dt>
<dd> The LACP system ID of this <ref table="Port"/>. The system ID
of a LACP bond is used to identify itself to its partners. Must
something other than <code>fast</code> or <code>slow</code> is
not supported by the LACP specification.</p>
</dd>
- <dt><code>lacp-strict</code></dt>
- <dd> When <code>true</code>, configures this <ref table="Port"/> to
- require successful LACP negotiations to enable any slaves.
- Defaults to <code>false</code> which safely allows LACP to be used
- with switchs that do not support the protocol.</dd>
+ <dt><code>lacp-heartbeat</code></dt>
+ <dd> Treats LACP like a simple heartbeat protocol for link state
+ monitoring. Most features of the LACP protocol are disabled when
+ this mode is in use.</dd>
</dl>
</column>
</group>
adds value for the GRE and encapsulated Ethernet headers.
Default is disabled, set to <code>true</code> to enable.</dd>
</dl>
+ <dl>
+ <dt><code>df_inherit</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be copied
+ from the inner IP headers (those of the encapsulated traffic)
+ to the outer (tunnel) headers. Default is disabled; set to
+ <code>true</code> to enable.</dd>
+ </dl>
+ <dl>
+ <dt><code>df_default</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be set by
+ default on tunnel headers if the <code>df_inherit</code> option
+ is not set, or if the encapsulated packet is not IP. Default
+ is enabled; set to <code>false</code> to disable.</dd>
+ </dl>
<dl>
<dt><code>pmtud</code></dt>
<dd>Optional. Enable tunnel path MTU discovery. If enabled
- ``ICMP destination unreachable - fragmentation'' needed
+ ``ICMP Destination Unreachable - Fragmentation Needed''
messages will be generated for IPv4 packets with the DF bit set
and IPv6 packets above the minimum MTU if the packet size
- exceeds the path MTU minus the size of the tunnel headers. It
- also forces the encapsulating packet DF bit to be set (it is
- always set if the inner packet implies path MTU discovery).
+ exceeds the path MTU minus the size of the tunnel headers.
Note that this option causes behavior that is typically
reserved for routers and therefore is not entirely in
compliance with the IEEE 802.1D specification for bridges.
- Default is enabled, set to <code>false</code> to disable.</dd>
+ Default is enabled; set to <code>false</code> to disable.</dd>
</dl>
<dl>
<dt><code>header_cache</code></dt>
adds value for the GRE and encapsulated Ethernet headers.
Default is disabled, set to <code>true</code> to enable.</dd>
</dl>
+ <dl>
+ <dt><code>df_inherit</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be copied
+ from the inner IP headers (those of the encapsulated traffic)
+ to the outer (tunnel) headers. Default is disabled; set to
+ <code>true</code> to enable.</dd>
+ </dl>
+ <dl>
+ <dt><code>df_default</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be set by
+ default on tunnel headers if the <code>df_inherit</code> option
+ is not set, or if the encapsulated packet is not IP. Default
+ is enabled; set to <code>false</code> to disable.</dd>
+ </dl>
<dl>
<dt><code>pmtud</code></dt>
<dd>Optional. Enable tunnel path MTU discovery. If enabled
- ``ICMP destination unreachable - fragmentation'' needed
+ ``ICMP Destination Unreachable - Fragmentation Needed''
messages will be generated for IPv4 packets with the DF bit set
and IPv6 packets above the minimum MTU if the packet size
- exceeds the path MTU minus the size of the tunnel headers. It
- also forces the encapsulating packet DF bit to be set (it is
- always set if the inner packet implies path MTU discovery).
+ exceeds the path MTU minus the size of the tunnel headers.
Note that this option causes behavior that is typically
reserved for routers and therefore is not entirely in
compliance with the IEEE 802.1D specification for bridges.
- Default is enabled, set to <code>false</code> to disable.</dd>
+ Default is enabled; set to <code>false</code> to disable.</dd>
</dl>
</dd>
<dt><code>capwap</code></dt>
(otherwise it will be the system default, typically 64).
Default is the system default TTL.</dd>
</dl>
+ <dl>
+ <dt><code>df_inherit</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be copied
+ from the inner IP headers (those of the encapsulated traffic)
+ to the outer (tunnel) headers. Default is disabled; set to
+ <code>true</code> to enable.</dd>
+ </dl>
+ <dl>
+ <dt><code>df_default</code></dt>
+ <dd>Optional. If enabled, the Don't Fragment bit will be set by
+ default on tunnel headers if the <code>df_inherit</code> option
+ is not set, or if the encapsulated packet is not IP. Default
+ is enabled; set to <code>false</code> to disable.</dd>
+ </dl>
<dl>
<dt><code>pmtud</code></dt>
<dd>Optional. Enable tunnel path MTU discovery. If enabled
- ``ICMP destination unreachable - fragmentation'' needed
+ ``ICMP Destination Unreachable - Fragmentation Needed''
messages will be generated for IPv4 packets with the DF bit set
and IPv6 packets above the minimum MTU if the packet size
- exceeds the path MTU minus the size of the tunnel headers. It
- also forces the encapsulating packet DF bit to be set (it is
- always set if the inner packet implies path MTU discovery).
+ exceeds the path MTU minus the size of the tunnel headers.
Note that this option causes behavior that is typically
reserved for routers and therefore is not entirely in
compliance with the IEEE 802.1D specification for bridges.
- Default is enabled, set to <code>false</code> to disable.</dd>
+ Default is enabled; set to <code>false</code> to disable.</dd>
</dl>
<dl>
<dt><code>header_cache</code></dt>
</dd>
</dl>
</dd>
+ <dt><code>null</code></dt>
+ <dd>An ignored interface.</dd>
</dl>
</column>
<column name="other_config">
Key-value pairs for rarely used interface features.
<dl>
+ <dt><code>bond-stable-id</code></dt>
+ <dd> A positive integer using in <code>stable</code> bond mode to
+ make slave selection decisions. Allocating
+ <code>bond-stable-id</code>s consistently across interfaces
+ participating in a bond will guarantee consistent slave selection
+ decisions across ovs-vswitchd instances when using
+ <code>stable</code> bonding mode.</dd>
<dt><code>lacp-port-id</code></dt>
<dd> The LACP port ID of this <ref table="Interface"/>. Port IDs are
used in LACP negotiations to identify individual ports
LACP negotiations <ref table="Interface"/>s with numerically lower
priorities are preferred for aggregation. Must be a number between
1 and 65535.</dd>
+ <dt><code>lacp-aggregation-key</code></dt>
+ <dd> The LACP aggregation key of this <ref table="Interface"/>.
+ <ref table="Interface"/>s with different aggregation keys may not
+ be active within a given <ref table="Port"/> at the same time. Must
+ be a number between 1 and 65535.</dd>
</dl>
</column>
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
$RPM_BUILD_ROOT/usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.py
-install -d -m 755 $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/extra/openvswitch
-find datapath/linux-2.6 -name *.ko -exec install -m 755 \{\} $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/extra/openvswitch \;
+install -d -m 755 $RPM_BUILD_ROOT/lib/modules/%{xen_version}/extra/openvswitch
+find datapath/linux-2.6 -name *.ko -exec install -m 755 \{\} $RPM_BUILD_ROOT/lib/modules/%{xen_version}/extra/openvswitch \;
install xenserver/uuid.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
# Get rid of stuff we don't want to make RPM happy.
chkconfig $s on || printf "Could not enable $s init script."
done
-if [ "$1" = "1" ]; then # $1 = 2 for upgrade
+if [ "$1" = "1" ]; then # $1 = 1 for install
# Configure system to use Open vSwitch
- echo vswitch > /etc/xensource/network.conf
-
- printf "\nYou MUST reboot the server NOW to complete the change to\n"
- printf "Open vSwitch. Attempts to modify networking on the server\n"
- printf "or any hosted VM will fail until after the reboot and could\n"
- printf "leave the server in a state requiring manual recovery.\n\n"
-else
+ /opt/xensource/bin/xe-switch-network-backend vswitch
+else # $1 = 2 for upgrade
mode=$(cat /etc/xensource/network.conf)
if [ "$mode" != "vswitch" ] && [ "$mode" != "openvswitch" ]; then
depmod %{xen_version}
%preun
-if [ "$1" = "0" ]; then # $1 = 1 for upgrade
+if [ "$1" = "0" ]; then # $1 = 0 for uninstall
+ # Configure system to use bridge
+ /opt/xensource/bin/xe-switch-network-backend bridge
+
+ # The "openvswitch" service should have been removed from
+ # "xe-switch-network-backend bridge".
for s in openvswitch openvswitch-xapi-update; do
- chkconfig --del $s || printf "Could not remove $s init script."
+ if chkconfig --list $s >/dev/null 2>&1; then
+ chkconfig --del $s || printf "Could not remove $s init script."
+ fi
done
fi
fi
done
-if [ "$1" = "0" ]; then # $1 = 1 for upgrade
+if [ "$1" = "0" ]; then # $1 = 0 for uninstall
rm -f /usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.pyc \
/usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.pyo
rm -f /etc/openvswitch/conf.db
rm -f /etc/sysconfig/openvswitch
rm -f /etc/openvswitch/vswitchd.cacert
- rm -f /var/xapi/network.dbcache
# Remove saved XenServer scripts directory, but only if it's empty
rmdir -p /usr/lib/openvswitch/xs-saved 2>/dev/null
-
- # Configure system to use bridge
- echo bridge > /etc/xensource/network.conf
-
- printf "\nYou MUST reboot the server now to complete the change to\n"
- printf "standard Xen networking. Attempts to modify networking on the\n"
- printf "server or any hosted VM will fail until after the reboot and\n"
- printf "could leave the server in a state requiring manual recovery.\n\n"
fi
+exit 0
+
%files
%defattr(-,root,root)
/etc/init.d/openvswitch
%exclude /usr/share/openvswitch/python/ovs/db/*.py[co]
%files %{module_package}
-/lib/modules/%{xen_version}/kernel/extra/openvswitch/openvswitch_mod.ko
-%exclude /lib/modules/%{xen_version}/kernel/extra/openvswitch/brcompat_mod.ko
+/lib/modules/%{xen_version}/extra/openvswitch/openvswitch_mod.ko
+%exclude /lib/modules/%{xen_version}/extra/openvswitch/brcompat_mod.ko