The table for 1.3 is the same as the one shown above for 1.2.
+OFPT_PACKET_IN
+==============
+
+The OpenFlow 1.1 specification for OFPT_PACKET_IN is confusing. The
+definition in OF1.1 openflow.h is[*]:
+
+ /* Packet received on port (datapath -> controller). */
+ struct ofp_packet_in {
+ struct ofp_header header;
+ uint32_t buffer_id; /* ID assigned by datapath. */
+ uint32_t in_port; /* Port on which frame was received. */
+ uint32_t in_phy_port; /* Physical Port on which frame was received. */
+ uint16_t total_len; /* Full length of frame. */
+ uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
+ uint8_t table_id; /* ID of the table that was looked up */
+ uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word,
+ so the IP header is 32-bit aligned. The
+ amount of data is inferred from the length
+ field in the header. Because of padding,
+ offsetof(struct ofp_packet_in, data) ==
+ sizeof(struct ofp_packet_in) - 2. */
+ };
+ OFP_ASSERT(sizeof(struct ofp_packet_in) == 24);
+
+The confusing part is the comment on the data[] member. This comment
+is a leftover from OF1.0 openflow.h, in which the comment was correct:
+sizeof(struct ofp_packet_in) is 20 in OF1.0 and offsetof(struct
+ofp_packet_in, data) is 18. When OF1.1 was written, the structure
+members were changed but the comment was carelessly not updated, and
+the comment became wrong: sizeof(struct ofp_packet_in) and
+offsetof(struct ofp_packet_in, data) are both 24 in OF1.1.
+
+That leaves the question of how to implement ofp_packet_in in OF1.1.
+The OpenFlow reference implementation for OF1.1 does not include any
+padding, that is, the first byte of the encapsulated frame immediately
+follows the 'table_id' member without a gap. Open vSwitch therefore
+implements it the same way for compatibility.
+
+For an earlier discussion, please see the thread archived at:
+https://mailman.stanford.edu/pipermail/openflow-discuss/2011-August/002604.html
+
+[*] The quoted definition is directly from OF1.1. Definitions used
+ inside OVS omit the 8-byte ofp_header members, so the sizes in
+ this discussion are 8 bytes larger than those declared in OVS
+ header files.
+
+
VLAN Matching
=============
packaged or installed by default, because too many users assumed
incorrectly that ovs-controller was a necessary or desirable part
of an Open vSwitch deployment.
+ - Added vlog option to export to a UDP syslog sink.
v2.0.0 - 15 Oct 2013
The list of remaining work items for OpenFlow 1.1 is below. It is
probably incomplete.
- * The new in_phy_port field in OFPT_PACKET_IN needs some kind of
- implementation. It has a sensible interpretation for tunnels
- but in general the physical port is not in the datapath for OVS
- so the value is not necessarily meaningful. We might have to
- just fix it as the same as in_port.
- [required for OF1.1; optional for OF1.2+]
-
* OFPT_TABLE_MOD message. This is new in OF1.1, so we need to
implement it. It should be implemented so that the default OVS
behavior does not change.
on the change log at the end of the OF1.2 spec. I didn't compare the
specs carefully yet.)
- * Action translation needs some work to transform OpenFlow 1.1
- field modification actions into OpenFlow 1.2+ "set-field"
- actions, because OpenFlow 1.2 dropped support for the OF1.1
- actions.
-
OpenFlow 1.3
------------
is missing. Support for the software switch is under review.
[optional for OF1.3+]
- * Per-connection event filtering. OF1.3 adopted Open vSwitch's
- existing design for this feature so implementation should be
- easy.
- [required for OF1.3+]
-
* Auxiliary connections. An implementation in generic code might
be a week's worth of work. The value of an implementation in
generic code is questionable, though, since much of the benefit
datapath/ vport ---
vswitchd/ iface port
ofproto/ port bundle
- lib/bond.c slave bond
+ ofproto/bond.c slave bond
lib/lacp.c slave lacp
lib/netdev.c netdev ---
database Interface Port
# quoting rules.
OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [[[^@]]proto_data_valid],
[OVS_DEFINE([HAVE_PROTO_DATA_VALID])])
+ OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [rxhash])
OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_dst(],
[OVS_DEFINE([HAVE_SKB_DST_ACCESSOR_FUNCS])])
OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h],
-g[0-9] | -g)
# cl only supports one debugging level
clopt="$clopt ${slash}Zi"
+ linkopt="$linkopt ${slash}DEBUG"
;;
-L*)
OVS_CHECK_GROFF
OVS_CHECK_GNU_MAKE
OVS_CHECK_TLS
+OVS_CHECK_ATOMIC_LIBS
OVS_CHECK_GCC4_ATOMICS
OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(1)
OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(2)
struct sk_buff *nskb = NULL;
struct sk_buff *user_skb; /* to be queued to userspace */
struct nlattr *nla;
+ struct genl_info info = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
+ .dst_sk = net->genl_sock,
+#endif
+ .snd_portid = upcall_info->portid,
+ };
+ size_t len;
int err;
if (vlan_tx_tag_present(skb)) {
goto out;
}
- user_skb = genlmsg_new(upcall_msg_size(skb, upcall_info->userdata), GFP_ATOMIC);
+ len = upcall_msg_size(skb, upcall_info->userdata);
+ user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
goto out;
packet->protocol = htons(ETH_P_802_2);
/* Build an sw_flow for sending this packet. */
- flow = ovs_flow_alloc();
+ flow = ovs_flow_alloc(false);
err = PTR_ERR(flow);
if (IS_ERR(flow))
goto err_kfree_skb;
{
const int skb_orig_len = skb->len;
struct nlattr *start;
- struct sw_flow_stats flow_stats;
+ struct ovs_flow_stats stats;
+ __be16 tcp_flags;
+ unsigned long used;
struct ovs_header *ovs_header;
struct nlattr *nla;
int err;
nla_nest_end(skb, nla);
- ovs_flow_stats_get(flow, &flow_stats);
- if (flow_stats.used &&
- nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(flow_stats.used)))
+ ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
+ if (used &&
+ nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
goto nla_put_failure;
- if (flow_stats.packet_count) {
- struct ovs_flow_stats stats = {
- .n_packets = flow_stats.packet_count,
- .n_bytes = flow_stats.byte_count,
- };
-
- if (nla_put(skb, OVS_FLOW_ATTR_STATS,
- sizeof(struct ovs_flow_stats), &stats))
- goto nla_put_failure;
- }
+ if (stats.n_packets &&
+ nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats))
+ goto nla_put_failure;
- if ((u8)ntohs(flow_stats.tcp_flags) &&
- nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS,
- (u8)ntohs(flow_stats.tcp_flags)))
+ if ((u8)ntohs(tcp_flags) &&
+ nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
goto nla_put_failure;
/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
if (start) {
const struct sw_flow_actions *sf_acts;
- sf_acts = rcu_dereference_check(flow->sf_acts,
- lockdep_ovsl_is_held());
+ sf_acts = rcu_dereference_ovsl(flow->sf_acts);
err = ovs_nla_put_actions(sf_acts->actions,
sf_acts->actions_len, skb);
return err;
}
-static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow)
+static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
+ struct genl_info *info)
{
- const struct sw_flow_actions *sf_acts;
+ size_t len;
- sf_acts = ovsl_dereference(flow->sf_acts);
+ len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
- return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
+ return genlmsg_new_unicast(len, info, GFP_KERNEL);
}
static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
struct datapath *dp,
- u32 portid, u32 seq, u8 cmd)
+ struct genl_info *info,
+ u8 cmd)
{
struct sk_buff *skb;
int retval;
- skb = ovs_flow_cmd_alloc_info(flow);
+ skb = ovs_flow_cmd_alloc_info(flow, info);
if (!skb)
return ERR_PTR(-ENOMEM);
- retval = ovs_flow_cmd_fill_info(flow, dp, skb, portid, seq, 0, cmd);
+ retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
+ info->snd_seq, 0, cmd);
BUG_ON(retval < 0);
return skb;
}
struct datapath *dp;
struct sw_flow_actions *acts = NULL;
struct sw_flow_match match;
+ bool exact_5tuple;
int error;
/* Extract key. */
goto error;
ovs_match_init(&match, &key, &mask);
- error = ovs_nla_get_match(&match,
+ error = ovs_nla_get_match(&match, &exact_5tuple,
a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
if (error)
goto error;
goto err_unlock_ovs;
/* Allocate flow. */
- flow = ovs_flow_alloc();
+ flow = ovs_flow_alloc(!exact_5tuple);
if (IS_ERR(flow)) {
error = PTR_ERR(flow);
goto err_unlock_ovs;
goto err_flow_free;
}
- reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
- info->snd_seq, OVS_FLOW_CMD_NEW);
+ reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
} else {
/* We found a matching flow. */
struct sw_flow_actions *old_acts;
rcu_assign_pointer(flow->sf_acts, acts);
ovs_nla_free_flow_actions(old_acts);
- reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
- info->snd_seq, OVS_FLOW_CMD_NEW);
+ reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
/* Clear stats. */
if (a[OVS_FLOW_ATTR_CLEAR])
}
ovs_match_init(&match, &key, NULL);
- err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+ err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL);
if (err)
return err;
goto unlock;
}
- reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
- info->snd_seq, OVS_FLOW_CMD_NEW);
+ reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
if (IS_ERR(reply)) {
err = PTR_ERR(reply);
goto unlock;
}
ovs_match_init(&match, &key, NULL);
- err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+ err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL);
if (err)
goto unlock;
goto unlock;
}
- reply = ovs_flow_cmd_alloc_info(flow);
+ reply = ovs_flow_cmd_alloc_info(flow, info);
if (!reply) {
err = -ENOMEM;
goto unlock;
return -EMSGSIZE;
}
-static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
- u32 seq, u8 cmd)
+static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp,
+ struct genl_info *info, u8 cmd)
{
struct sk_buff *skb;
int retval;
- skb = genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
+ skb = genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOMEM);
- retval = ovs_dp_cmd_fill_info(dp, skb, portid, seq, 0, cmd);
+ retval = ovs_dp_cmd_fill_info(dp, skb, info->snd_portid, info->snd_seq, 0, cmd);
if (retval < 0) {
kfree_skb(skb);
return ERR_PTR(retval);
goto err_destroy_ports_array;
}
- reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
- info->snd_seq, OVS_DP_CMD_NEW);
+ reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
err = PTR_ERR(reply);
if (IS_ERR(reply))
goto err_destroy_local_port;
if (IS_ERR(dp))
goto unlock;
- reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
- info->snd_seq, OVS_DP_CMD_DEL);
+ reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_DEL);
err = PTR_ERR(reply);
if (IS_ERR(reply))
goto unlock;
if (IS_ERR(dp))
goto unlock;
- reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
- info->snd_seq, OVS_DP_CMD_NEW);
+ reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
if (IS_ERR(reply)) {
err = PTR_ERR(reply);
netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
goto unlock;
}
- reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
- info->snd_seq, OVS_DP_CMD_NEW);
+ reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
if (IS_ERR(reply)) {
err = PTR_ERR(reply);
goto unlock;
#define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held()))
#define ovsl_dereference(p) \
rcu_dereference_protected(p, lockdep_ovsl_is_held())
+#define rcu_dereference_ovsl(p) \
+ rcu_dereference_check(p, lockdep_ovsl_is_held())
static inline struct net *ovs_dp_get_net(struct datapath *dp)
{
void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
{
- struct sw_flow_stats *stats = &flow->stats[smp_processor_id()];
+ struct flow_stats *stats;
__be16 tcp_flags = 0;
+ if (!flow->stats.is_percpu)
+ stats = flow->stats.stat;
+ else
+ stats = this_cpu_ptr(flow->stats.cpu_stats);
+
if ((flow->key.eth.type == htons(ETH_P_IP) ||
flow->key.eth.type == htons(ETH_P_IPV6)) &&
flow->key.ip.proto == IPPROTO_TCP &&
spin_unlock(&stats->lock);
}
-void ovs_flow_stats_get(struct sw_flow *flow, struct sw_flow_stats *res)
+static void stats_read(struct flow_stats *stats,
+ struct ovs_flow_stats *ovs_stats,
+ unsigned long *used, __be16 *tcp_flags)
{
- int cpu, cur_cpu;
+ spin_lock(&stats->lock);
+ if (time_after(stats->used, *used))
+ *used = stats->used;
+ *tcp_flags |= stats->tcp_flags;
+ ovs_stats->n_packets += stats->packet_count;
+ ovs_stats->n_bytes += stats->byte_count;
+ spin_unlock(&stats->lock);
+}
- memset(res, 0, sizeof(*res));
+void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
+ unsigned long *used, __be16 *tcp_flags)
+{
+ int cpu, cur_cpu;
- cur_cpu = get_cpu();
- for_each_possible_cpu(cpu) {
- struct sw_flow_stats *stats = &flow->stats[cpu];
+ *used = 0;
+ *tcp_flags = 0;
+ memset(ovs_stats, 0, sizeof(*ovs_stats));
- if (cpu == cur_cpu)
- local_bh_disable();
+ if (!flow->stats.is_percpu) {
+ stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
+ } else {
+ cur_cpu = get_cpu();
+ for_each_possible_cpu(cpu) {
+ struct flow_stats *stats;
- spin_lock(&stats->lock);
- if (time_after(stats->used, res->used))
- res->used = stats->used;
- res->packet_count += stats->packet_count;
- res->byte_count += stats->byte_count;
- res->tcp_flags |= stats->tcp_flags;
- spin_unlock(&stats->lock);
+ if (cpu == cur_cpu)
+ local_bh_disable();
- if (cpu == cur_cpu)
- local_bh_enable();
+ stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
+ stats_read(stats, ovs_stats, used, tcp_flags);
+ if (cpu == cur_cpu)
+ local_bh_enable();
+ }
+ put_cpu();
}
- put_cpu();
+}
+
+static void stats_reset(struct flow_stats *stats)
+{
+ spin_lock(&stats->lock);
+ stats->used = 0;
+ stats->packet_count = 0;
+ stats->byte_count = 0;
+ stats->tcp_flags = 0;
+ spin_unlock(&stats->lock);
}
void ovs_flow_stats_clear(struct sw_flow *flow)
{
int cpu, cur_cpu;
- cur_cpu = get_cpu();
- for_each_possible_cpu(cpu) {
- struct sw_flow_stats *stats = &flow->stats[cpu];
+ if (!flow->stats.is_percpu) {
+ stats_reset(flow->stats.stat);
+ } else {
+ cur_cpu = get_cpu();
+
+ for_each_possible_cpu(cpu) {
- if (cpu == cur_cpu)
- local_bh_disable();
+ if (cpu == cur_cpu)
+ local_bh_disable();
- spin_lock(&stats->lock);
- stats->used = 0;
- stats->packet_count = 0;
- stats->byte_count = 0;
- stats->tcp_flags = 0;
- spin_unlock(&stats->lock);
+ stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
- if (cpu == cur_cpu)
- local_bh_enable();
+ if (cpu == cur_cpu)
+ local_bh_enable();
+ }
+ put_cpu();
}
- put_cpu();
}
static int check_header(struct sk_buff *skb, int len)
struct nlattr actions[];
};
-struct sw_flow_stats {
+struct flow_stats {
u64 packet_count; /* Number of packets matched. */
u64 byte_count; /* Number of bytes matched. */
unsigned long used; /* Last used time (in jiffies). */
spinlock_t lock; /* Lock for atomic stats update. */
__be16 tcp_flags; /* Union of seen TCP flags. */
-} ____cacheline_aligned_in_smp;
+};
+
+struct sw_flow_stats {
+ bool is_percpu;
+ union {
+ struct flow_stats *stat;
+ struct flow_stats __percpu *cpu_stats;
+ };
+};
struct sw_flow {
struct rcu_head rcu;
struct sw_flow_key unmasked_key;
struct sw_flow_mask *mask;
struct sw_flow_actions __rcu *sf_acts;
- struct sw_flow_stats stats[];
+ struct sw_flow_stats stats;
};
struct arp_eth_header {
} __packed;
void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb);
-void ovs_flow_stats_get(struct sw_flow *flow, struct sw_flow_stats *res);
+void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats,
+ unsigned long *used, __be16 *tcp_flags);
void ovs_flow_stats_clear(struct sw_flow *flow);
u64 ovs_flow_used_time(unsigned long flow_jiffies);
return true;
}
+static bool is_all_set(const u8 *fp, size_t size)
+{
+ int i;
+
+ if (!fp)
+ return false;
+
+ for (i = 0; i < size; i++)
+ if (fp[i] != 0xff)
+ return false;
+
+ return true;
+}
+
static int __parse_flow_nlattrs(const struct nlattr *attr,
const struct nlattr *a[],
u64 *attrsp, bool nz)
return 0;
}
-static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
- const struct nlattr **a, bool is_mask)
+static int ovs_key_from_nlattrs(struct sw_flow_match *match, bool *exact_5tuple,
+ u64 attrs, const struct nlattr **a,
+ bool is_mask)
{
int err;
u64 orig_attrs = attrs;
SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
}
+ if (is_mask && exact_5tuple) {
+ if (match->mask->key.eth.type != htons(0xffff))
+ *exact_5tuple = false;
+ }
+
if (attrs & (1ULL << OVS_KEY_ATTR_IPV4)) {
const struct ovs_key_ipv4 *ipv4_key;
SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
ipv4_key->ipv4_dst, is_mask);
attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4);
+
+ if (is_mask && exact_5tuple && *exact_5tuple) {
+ if (ipv4_key->ipv4_proto != 0xff ||
+ ipv4_key->ipv4_src != htonl(0xffffffff) ||
+ ipv4_key->ipv4_dst != htonl(0xffffffff))
+ *exact_5tuple = false;
+ }
}
if (attrs & (1ULL << OVS_KEY_ATTR_IPV6)) {
is_mask);
attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6);
+
+ if (is_mask && exact_5tuple && *exact_5tuple) {
+ if (ipv6_key->ipv6_proto != 0xff ||
+ !is_all_set((u8 *)ipv6_key->ipv6_src, sizeof(match->key->ipv6.addr.src)) ||
+ !is_all_set((u8 *)ipv6_key->ipv6_dst, sizeof(match->key->ipv6.addr.dst)))
+ *exact_5tuple = false;
+ }
}
if (attrs & (1ULL << OVS_KEY_ATTR_ARP)) {
tcp_key->tcp_dst, is_mask);
}
attrs &= ~(1ULL << OVS_KEY_ATTR_TCP);
+
+ if (is_mask && exact_5tuple && *exact_5tuple &&
+ (tcp_key->tcp_src != htons(0xffff) ||
+ tcp_key->tcp_dst != htons(0xffff)))
+ *exact_5tuple = false;
}
if (attrs & (1ULL << OVS_KEY_ATTR_TCP_FLAGS)) {
udp_key->udp_dst, is_mask);
}
attrs &= ~(1ULL << OVS_KEY_ATTR_UDP);
+
+ if (is_mask && exact_5tuple && *exact_5tuple &&
+ (udp_key->udp_src != htons(0xffff) ||
+ udp_key->udp_dst != htons(0xffff)))
+ *exact_5tuple = false;
}
if (attrs & (1ULL << OVS_KEY_ATTR_SCTP)) {
* attribute specifies the mask field of the wildcarded flow.
*/
int ovs_nla_get_match(struct sw_flow_match *match,
+ bool *exact_5tuple,
const struct nlattr *key,
const struct nlattr *mask)
{
}
}
- err = ovs_key_from_nlattrs(match, key_attrs, a, false);
+ err = ovs_key_from_nlattrs(match, NULL, key_attrs, a, false);
if (err)
return err;
+ if (exact_5tuple)
+ *exact_5tuple = true;
+
if (mask) {
err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
if (err)
}
}
- err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
+ err = ovs_key_from_nlattrs(match, exact_5tuple, mask_attrs, a, true);
if (err)
return err;
} else {
int ovs_nla_get_flow_metadata(struct sw_flow *flow,
const struct nlattr *attr);
int ovs_nla_get_match(struct sw_flow_match *match,
+ bool *exact_5tuple,
const struct nlattr *,
const struct nlattr *);
*d++ = *s++ & *m++;
}
-struct sw_flow *ovs_flow_alloc(void)
+struct sw_flow *ovs_flow_alloc(bool percpu_stats)
{
struct sw_flow *flow;
int cpu;
flow->sf_acts = NULL;
flow->mask = NULL;
- memset(flow->stats, 0, num_possible_cpus() * sizeof(struct sw_flow_stats));
- for_each_possible_cpu(cpu)
- spin_lock_init(&flow->stats[cpu].lock);
+ flow->stats.is_percpu = percpu_stats;
+ if (!percpu_stats) {
+ flow->stats.stat = kzalloc(sizeof(*flow->stats.stat), GFP_KERNEL);
+ if (!flow->stats.stat)
+ goto err;
+
+ spin_lock_init(&flow->stats.stat->lock);
+ } else {
+ flow->stats.cpu_stats = alloc_percpu(struct flow_stats);
+ if (!flow->stats.cpu_stats)
+ goto err;
+
+ for_each_possible_cpu(cpu) {
+ struct flow_stats *cpu_stats;
+
+ cpu_stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
+ spin_lock_init(&cpu_stats->lock);
+ }
+ }
return flow;
+err:
+ kfree(flow);
+ return ERR_PTR(-ENOMEM);
}
int ovs_flow_tbl_count(struct flow_table *table)
static void flow_free(struct sw_flow *flow)
{
kfree((struct sf_flow_acts __force *)flow->sf_acts);
+ if (flow->stats.is_percpu)
+ free_percpu(flow->stats.cpu_stats);
+ else
+ kfree(flow->stats.stat);
kmem_cache_free(flow_cache, flow);
}
const struct sw_flow_key *key,
u32 *n_mask_hit)
{
- struct table_instance *ti = rcu_dereference(tbl->ti);
+ struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
struct sw_flow_mask *mask;
struct sw_flow *flow;
* Returns zero if successful or a negative error code. */
int ovs_flow_init(void)
{
- int flow_size;
-
BUILD_BUG_ON(__alignof__(struct sw_flow_key) % __alignof__(long));
BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
- flow_size = sizeof(struct sw_flow) +
- (num_possible_cpus() * sizeof(struct sw_flow_stats));
-
- flow_cache = kmem_cache_create("sw_flow", flow_size, 0, 0, NULL);
+ flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0,
+ 0, NULL);
if (flow_cache == NULL)
return -ENOMEM;
int ovs_flow_init(void);
void ovs_flow_exit(void);
-struct sw_flow *ovs_flow_alloc(void);
+struct sw_flow *ovs_flow_alloc(bool percpu_stats);
void ovs_flow_free(struct sw_flow *, bool deferred);
int ovs_flow_tbl_init(struct flow_table *);
*/
#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_vlan.h>
memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst));
}
+__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+{
+ int poff = proto_ports_offset(ip_proto);
+
+ if (poff >= 0) {
+ __be32 *ports, _ports;
+
+ ports = skb_header_pointer(skb, thoff + poff,
+ sizeof(_ports), &_ports);
+ if (ports)
+ return *ports;
+ }
+
+ return 0;
+}
+
static bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
{
- int poff, nhoff = skb_network_offset(skb);
+ int nhoff = skb_network_offset(skb);
u8 ip_proto;
__be16 proto = skb->protocol;
nhoff += sizeof(struct ipv6hdr);
break;
}
+ case __constant_htons(ETH_P_8021AD):
case __constant_htons(ETH_P_8021Q): {
const struct vlan_hdr *vlan;
struct vlan_hdr _vlan;
}
case IPPROTO_IPIP:
goto again;
+ case IPPROTO_IPV6:
+ proto = htons(ETH_P_IPV6);
+ goto ipv6;
default:
break;
}
flow->ip_proto = ip_proto;
- poff = proto_ports_offset(ip_proto);
- if (poff >= 0) {
- __be32 *ports, _ports;
-
- nhoff += poff;
- ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
- if (ports)
- flow->ports = *ports;
- }
-
+ flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto);
flow->thoff = (u16) nhoff;
return true;
}
static u32 hashrnd __read_mostly;
+static __always_inline void __flow_hash_secret_init(void)
+{
+ net_get_random_once(&hashrnd, sizeof(hashrnd));
+}
-static void init_hashrnd(void)
+static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c)
{
- if (likely(hashrnd))
- return;
- get_random_bytes(&hashrnd, sizeof(hashrnd));
+ __flow_hash_secret_init();
+ return jhash_3words(a, b, c, hashrnd);
}
u32 __skb_get_rxhash(struct sk_buff *skb)
swap(keys.port16[0], keys.port16[1]);
}
- init_hashrnd();
-
- hash = jhash_3words((__force u32)keys.dst,
- (__force u32)keys.src,
- (__force u32)keys.ports, hashrnd);
+ hash = __flow_hash_3words((__force u32)keys.dst,
+ (__force u32)keys.src,
+ (__force u32)keys.ports);
if (!hash)
hash = 1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
+#ifdef HAVE_RXHASH
skb->rxhash = hash;
#endif
return hash;
#define __LINUX_NET_WRAPPER_H 1
#include_next <linux/net.h>
+#include <linux/types.h>
#ifndef net_ratelimited_function
#define net_ratelimited_function(function, ...) \
net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
#endif
+#ifndef net_get_random_once
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+ atomic_t *done_key);
+
+#define ___NET_RANDOM_STATIC_KEY_INIT ATOMIC_INIT(0)
+
+
+#define net_get_random_once(buf, nbytes) \
+({ \
+ bool ___ret = false; \
+ static bool ___done = false; \
+ static atomic_t ___done_key = \
+ ___NET_RANDOM_STATIC_KEY_INIT; \
+ if (!atomic_read(&___done_key)) \
+ ___ret = __net_get_random_once(buf, \
+ nbytes, \
+ &___done, \
+ &___done_key); \
+ ___ret; \
+})
+#endif
+
#endif
}
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
+#define __skb_get_rxhash rpl__skb_get_rxhash
+#define skb_get_rxhash rpl_skb_get_rxhash
+
extern u32 __skb_get_rxhash(struct sk_buff *skb);
static inline __u32 skb_get_rxhash(struct sk_buff *skb)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
- if (!skb->rxhash)
+#ifdef HAVE_RXHASH
+ if (skb->rxhash)
+ return skb->rxhash;
#endif
return __skb_get_rxhash(skb);
}
#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
#include_next <net/flow_keys.h>
#else
struct flow_keys {
extern void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
u32 group, struct nlmsghdr *nlh, gfp_t flags);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+static inline struct sk_buff *genlmsg_new_unicast(size_t payload,
+ struct genl_info *info,
+ gfp_t flags)
+{
+ return genlmsg_new(payload, flags);
+}
+#endif
+
#endif /* genetlink.h */
extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff, int *fragflg);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
static inline u32 ipv6_addr_hash(const struct in6_addr *a)
{
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
csum_unfold(*sum)));
}
#endif
+
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+ atomic_t *done_key)
+{
+ static DEFINE_SPINLOCK(lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+ if (*done) {
+ spin_unlock_irqrestore(&lock, flags);
+ return false;
+ }
+
+ get_random_bytes(buf, nbytes);
+ *done = true;
+ spin_unlock_irqrestore(&lock, flags);
+
+ atomic_set(done_key, 1);
+
+ return true;
+}
*/
static u16 get_src_port(struct sk_buff *skb)
{
- int low;
- int high;
+ u32 hash = skb_get_rxhash(skb);
unsigned int range;
- struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
- u32 hash = jhash2((const u32 *)pkt_key,
- sizeof(*pkt_key) / sizeof(u32), 0);
+ int high;
+ int low;
+
+ if (!hash) {
+ struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
+
+ hash = jhash2((const u32 *)pkt_key,
+ sizeof(*pkt_key) / sizeof(u32), 0);
+ }
inet_get_local_port_range(&low, &high);
range = (high - low) + 1;
};
OFP_ASSERT(sizeof(struct ofp11_table_mod) == 8);
-/* Flags to indicate behavior of the flow table for unmatched packets.
- These flags are used in ofp_table_stats messages to describe the current
- configuration and in ofp_table_mod messages to configure table behavior. */
-enum ofp11_table_config {
- OFPTC11_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
- OFPTC11_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the
- pipeline (OpenFlow 1.0
- behavior). */
- OFPTC11_TABLE_MISS_DROP = 2 << 0, /* Drop the packet. */
-#define OFPTC11_TABLE_MISS_MASK (3 << 0)
-};
-
/* Flow setup and teardown (controller -> datapath). */
struct ofp11_flow_mod {
ovs_be64 cookie; /* Opaque controller-issued identifier. */
ovs_be16 total_len; /* Full length of frame. */
uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
uint8_t table_id; /* ID of the table that was looked up */
- /* uint8_t data[0]; Ethernet frame, halfway through 32-bit word,
- so the IP header is 32-bit aligned. The
- amount of data is inferred from the length
- field in the header. Because of padding,
- offsetof(struct ofp_packet_in, data) ==
- sizeof(struct ofp_packet_in) - 2. */
+ /* Followed by Ethernet frame. */
};
OFP_ASSERT(sizeof(struct ofp11_packet_in) == 16);
};
enum ofp_table_config {
- OFPTC_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
- OFPTC_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the
- pipeline (OpenFlow 1.0 behavior). */
- OFPTC_TABLE_MISS_DROP = 2 << 0, /* Drop the packet. */
- OFPTC_TABLE_MISS_MASK = 3 << 0
+ /* OpenFlow 1.1 and 1.2 defined this field as shown.
+ * OpenFlow 1.3 and later mark this field as deprecated, but have not
+ * reused it for any new purpose. */
+ OFPTC11_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
+ OFPTC11_TABLE_MISS_CONTINUE = 1 << 0, /* Go to next table, like OF1.0. */
+ OFPTC11_TABLE_MISS_DROP = 2 << 0, /* Drop the packet. */
+ OFPTC11_TABLE_MISS_MASK = 3 << 0,
+
+ /* OpenFlow 1.4. */
+ OFPTC14_EVICTION = 1 << 2, /* Allow table to evict flows. */
+ OFPTC14_VACANCY_EVENTS = 1 << 3, /* Enable vacancy events. */
};
#endif /* openflow/openflow-common.h */
lib/bfd.h \
lib/bitmap.c \
lib/bitmap.h \
- lib/bond.c \
- lib/bond.h \
lib/bundle.c \
lib/bundle.h \
lib/byte-order.h \
long long int next_tx; /* Next TX time. */
long long int detect_time; /* RFC 5880 6.8.4 Detection time. */
- bool forwarding; /* Interface capability of packet I/O. */
+ bool last_forwarding; /* Last calculation of forwarding flag. */
int forwarding_override; /* Manual override of 'forwarding' status. */
atomic_bool check_tnl_key; /* Verify tunnel key of inbound packets? */
static uint64_t bfd_rx_packets(const struct bfd *) OVS_REQUIRES(mutex);
static void bfd_try_decay(struct bfd *) OVS_REQUIRES(mutex);
static void bfd_decay_update(struct bfd *) OVS_REQUIRES(mutex);
-static void bfd_check_rx(struct bfd *) OVS_REQUIRES(mutex);
+
static void bfd_forwarding_if_rx_update(struct bfd *) OVS_REQUIRES(mutex);
static void bfd_unixctl_show(struct unixctl_conn *, int argc,
const char *argv[], void *aux OVS_UNUSED);
return ret;
}
+/* When forwarding_if_rx is enabled, if there are packets received,
+ * updates forwarding_if_rx_detect_time. */
+void
+bfd_account_rx(struct bfd *bfd, const struct dpif_flow_stats *stats)
+{
+ if (stats->n_packets && bfd->forwarding_if_rx) {
+ ovs_mutex_lock(&mutex);
+ bfd_forwarding__(bfd);
+ bfd_forwarding_if_rx_update(bfd);
+ bfd_forwarding__(bfd);
+ ovs_mutex_unlock(&mutex);
+ }
+}
+
/* Returns a 'smap' of key value pairs representing the status of 'bfd'
* intended for the OVS database. */
void
OVS_EXCLUDED(mutex)
{
ovs_mutex_lock(&mutex);
- smap_add(smap, "forwarding", bfd->forwarding ? "true" : "false");
+ smap_add(smap, "forwarding",
+ bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
+ ? "true" : "false");
smap_add(smap, "state", bfd_state_str(bfd->state));
smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag));
smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
if (!bfd) {
bfd = xzalloc(sizeof *bfd);
bfd->name = xstrdup(name);
- bfd->forwarding = false;
bfd->forwarding_override = -1;
bfd->disc = generate_discriminator();
hmap_insert(all_bfds, &bfd->node, bfd->disc);
if (bfd->state > STATE_DOWN && now >= bfd->detect_time) {
bfd_set_state(bfd, STATE_DOWN, DIAG_EXPIRED);
+ bfd_forwarding__(bfd);
}
/* Decay may only happen when state is STATE_UP, bfd->decay_min_rx is
bfd_try_decay(bfd);
}
- /* Always checks the reception of any packet. */
- bfd_check_rx(bfd);
-
if (bfd->min_tx != bfd->cfg_min_tx
|| (bfd->min_rx != bfd->cfg_min_rx && bfd->min_rx != bfd->decay_min_rx)
|| bfd->in_decay != old_in_decay) {
/* Increments the decay rx counter. */
bfd->decay_rx_ctl++;
+ bfd_forwarding__(bfd);
+
if (flow->nw_ttl != 255) {
/* XXX Should drop in the kernel to prevent DOS. */
goto out;
/* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
out:
+ bfd_forwarding__(bfd);
ovs_mutex_unlock(&mutex);
}
\f
/* Updates the forwarding flag. If override is not configured and
- * the forwarding flag value changes, increments the flap count. */
+ * the forwarding flag value changes, increments the flap count.
+ *
+ * Note this function may be called multiple times in a function
+ * (e.g. bfd_account_rx) before and after the bfd state or status
+ * change. This is to capture any forwarding flag flap. */
static bool
bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
{
long long int time;
- bool forwarding_old = bfd->forwarding;
+ bool last_forwarding = bfd->last_forwarding;
if (bfd->forwarding_override != -1) {
return bfd->forwarding_override == 1;
}
time = bfd->forwarding_if_rx_detect_time;
- bfd->forwarding = (bfd->state == STATE_UP
- || (bfd->forwarding_if_rx && time > time_msec()))
- && bfd->rmt_diag != DIAG_PATH_DOWN
- && bfd->rmt_diag != DIAG_CPATH_DOWN
- && bfd->rmt_diag != DIAG_RCPATH_DOWN;
- if (bfd->forwarding != forwarding_old) {
+ bfd->last_forwarding = (bfd->state == STATE_UP
+ || (bfd->forwarding_if_rx && time > time_msec()))
+ && bfd->rmt_diag != DIAG_PATH_DOWN
+ && bfd->rmt_diag != DIAG_CPATH_DOWN
+ && bfd->rmt_diag != DIAG_RCPATH_DOWN;
+ if (bfd->last_forwarding != last_forwarding) {
bfd->flap_count++;
}
- return bfd->forwarding;
+ return bfd->last_forwarding;
}
/* Helpers. */
bfd_decay_update(bfd);
}
}
-
- /* Updates the forwarding flag. */
- bfd_forwarding__(bfd);
}
static uint64_t
bfd->decay_detect_time = MAX(bfd->decay_min_rx, 2000) + time_msec();
}
-/* Checks if there are packets received during the time since last call.
- * If forwarding_if_rx is enabled and packets are received, updates the
- * forwarding_if_rx_detect_time. */
-static void
-bfd_check_rx(struct bfd *bfd) OVS_REQUIRES(mutex)
-{
- uint64_t rx_packets = bfd_rx_packets(bfd);
- int64_t diff;
-
- diff = rx_packets - bfd->rx_packets;
- bfd->rx_packets = rx_packets;
- if (diff < 0) {
- VLOG_INFO_RL(&rl, "rx_packets count is smaller than last time.");
- }
- if (bfd->forwarding_if_rx && diff > 0) {
- bfd_forwarding_if_rx_update(bfd);
- }
-}
-
-/* Updates the forwarding_if_rx_detect_time and the forwarding flag. */
static void
bfd_forwarding_if_rx_update(struct bfd *bfd) OVS_REQUIRES(mutex)
{
int64_t incr = bfd_rx_interval(bfd) * bfd->mult;
bfd->forwarding_if_rx_detect_time = MAX(incr, 2000) + time_msec();
- bfd_forwarding__(bfd);
}
static uint32_t
static void
bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex)
{
- ds_put_format(ds, "\tForwarding: %s\n", bfd->forwarding ? "true" : "false");
+ ds_put_format(ds, "\tForwarding: %s\n",
+ bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
+ ? "true" : "false");
ds_put_format(ds, "\tDetect Multiplier: %d\n", bfd->mult);
ds_put_format(ds, "\tConcatenated Path Down: %s\n",
bfd->cpath_down ? "true" : "false");
#include <inttypes.h>
struct bfd;
+struct dpif_flow_stats;
struct flow;
struct flow_wildcards;
struct netdev;
struct bfd *bfd_ref(const struct bfd *);
void bfd_unref(struct bfd *);
+void bfd_account_rx(struct bfd *, const struct dpif_flow_stats *);
bool bfd_forwarding(struct bfd *);
void bfd_get_status(const struct bfd *, struct smap *);
void bfd_set_netdev(struct bfd *, const struct netdev *);
/*
- * Copyright (c) 2008, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2010, 2011, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
uint64_t ntohll(ovs_be64);
#endif
-#if defined(WORDS_BIGENDIAN)
static inline uint32_t
uint32_byteswap(uint32_t crc) {
return (((crc & 0x000000ff) << 24) |
((crc & 0x00ff0000) >> 8) |
((crc & 0xff000000) >> 24));
}
-#endif
/* These macros may substitute for htons(), htonl(), and htonll() in contexts
* where function calls are not allowed, such as case labels. They should not
ds_chomp(ds, del);
}
+void
+format_flags_masked(struct ds *ds, const char *name,
+ const char *(*bit_to_string)(uint32_t), uint32_t flags,
+ uint32_t mask)
+{
+ if (name) {
+ ds_put_format(ds, "%s=", name);
+ }
+ while (mask) {
+ uint32_t bit = rightmost_1bit(mask);
+ const char *s = bit_to_string(bit);
+
+ ds_put_format(ds, "%s%s", (flags & bit) ? "+" : "-",
+ s ? s : "[Unknown]");
+ mask &= ~bit;
+ }
+}
+
void
flow_format(struct ds *ds, const struct flow *flow)
{
set_mpls_lse_bos(&flow->mpls_lse, bos);
}
+
+static void
+flow_compose_l4(struct ofpbuf *b, const struct flow *flow)
+{
+ if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
+ || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
+ if (flow->nw_proto == IPPROTO_TCP) {
+ struct tcp_header *tcp;
+
+ tcp = ofpbuf_put_zeros(b, sizeof *tcp);
+ tcp->tcp_src = flow->tp_src;
+ tcp->tcp_dst = flow->tp_dst;
+ tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5);
+ b->l7 = ofpbuf_tail(b);
+ } else if (flow->nw_proto == IPPROTO_UDP) {
+ struct udp_header *udp;
+
+ udp = ofpbuf_put_zeros(b, sizeof *udp);
+ udp->udp_src = flow->tp_src;
+ udp->udp_dst = flow->tp_dst;
+ b->l7 = ofpbuf_tail(b);
+ } else if (flow->nw_proto == IPPROTO_SCTP) {
+ struct sctp_header *sctp;
+
+ sctp = ofpbuf_put_zeros(b, sizeof *sctp);
+ sctp->sctp_src = flow->tp_src;
+ sctp->sctp_dst = flow->tp_dst;
+ b->l7 = ofpbuf_tail(b);
+ } else if (flow->nw_proto == IPPROTO_ICMP) {
+ struct icmp_header *icmp;
+
+ icmp = ofpbuf_put_zeros(b, sizeof *icmp);
+ icmp->icmp_type = ntohs(flow->tp_src);
+ icmp->icmp_code = ntohs(flow->tp_dst);
+ icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN);
+ b->l7 = ofpbuf_tail(b);
+ } else if (flow->nw_proto == IPPROTO_ICMPV6) {
+ struct icmp6_hdr *icmp;
+
+ icmp = ofpbuf_put_zeros(b, sizeof *icmp);
+ icmp->icmp6_type = ntohs(flow->tp_src);
+ icmp->icmp6_code = ntohs(flow->tp_dst);
+
+ if (icmp->icmp6_code == 0 &&
+ (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
+ icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
+ struct in6_addr *nd_target;
+ struct nd_opt_hdr *nd_opt;
+
+ nd_target = ofpbuf_put_zeros(b, sizeof *nd_target);
+ *nd_target = flow->nd_target;
+
+ if (!eth_addr_is_zero(flow->arp_sha)) {
+ nd_opt = ofpbuf_put_zeros(b, 8);
+ nd_opt->nd_opt_len = 1;
+ nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+ memcpy(nd_opt + 1, flow->arp_sha, ETH_ADDR_LEN);
+ }
+ if (!eth_addr_is_zero(flow->arp_tha)) {
+ nd_opt = ofpbuf_put_zeros(b, 8);
+ nd_opt->nd_opt_len = 1;
+ nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+ memcpy(nd_opt + 1, flow->arp_tha, ETH_ADDR_LEN);
+ }
+ }
+ icmp->icmp6_cksum = (OVS_FORCE uint16_t)
+ csum(icmp, (char *)ofpbuf_tail(b) - (char *)icmp);
+ b->l7 = ofpbuf_tail(b);
+ }
+ }
+}
+
/* Puts into 'b' a packet that flow_extract() would parse as having the given
* 'flow'.
*
void
flow_compose(struct ofpbuf *b, const struct flow *flow)
{
+ /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */
eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
struct eth_header *eth = b->l2;
if (flow->dl_type == htons(ETH_TYPE_IP)) {
struct ip_header *ip;
- b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
+ ip = ofpbuf_put_zeros(b, sizeof *ip);
ip->ip_ihl_ver = IP_IHL_VER(5, 4);
ip->ip_tos = flow->nw_tos;
ip->ip_ttl = flow->nw_ttl;
ip->ip_frag_off |= htons(100);
}
}
- if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
- || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
- if (flow->nw_proto == IPPROTO_TCP) {
- struct tcp_header *tcp;
-
- b->l4 = tcp = ofpbuf_put_zeros(b, sizeof *tcp);
- tcp->tcp_src = flow->tp_src;
- tcp->tcp_dst = flow->tp_dst;
- tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5);
- } else if (flow->nw_proto == IPPROTO_UDP) {
- struct udp_header *udp;
-
- b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp);
- udp->udp_src = flow->tp_src;
- udp->udp_dst = flow->tp_dst;
- } else if (flow->nw_proto == IPPROTO_SCTP) {
- struct sctp_header *sctp;
-
- b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *sctp);
- sctp->sctp_src = flow->tp_src;
- sctp->sctp_dst = flow->tp_dst;
- } else if (flow->nw_proto == IPPROTO_ICMP) {
- struct icmp_header *icmp;
-
- b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *icmp);
- icmp->icmp_type = ntohs(flow->tp_src);
- icmp->icmp_code = ntohs(flow->tp_dst);
- icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN);
- }
- b->l7 = ofpbuf_tail(b);
- }
- ip = b->l3;
+ b->l4 = ofpbuf_tail(b);
+
+ flow_compose_l4(b, flow);
+
ip->ip_tot_len = htons((uint8_t *) b->data + b->size
- (uint8_t *) b->l3);
ip->ip_csum = csum(ip, sizeof *ip);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
- /* XXX */
+ struct ovs_16aligned_ip6_hdr *nh;
+
+ nh = ofpbuf_put_zeros(b, sizeof *nh);
+ put_16aligned_be32(&nh->ip6_flow, htonl(6 << 28) |
+ htonl(flow->nw_tos << 20) | flow->ipv6_label);
+ nh->ip6_hlim = flow->nw_ttl;
+ nh->ip6_nxt = flow->nw_proto;
+
+ memcpy(&nh->ip6_src, &flow->ipv6_src, sizeof(nh->ip6_src));
+ memcpy(&nh->ip6_dst, &flow->ipv6_dst, sizeof(nh->ip6_dst));
+
+ b->l4 = ofpbuf_tail(b);
+
+ flow_compose_l4(b, flow);
+
+ nh->ip6_plen =
+ b->l7 ? htons((uint8_t *) b->l7 - (uint8_t *) b->l4) : htons(0);
} else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
flow->dl_type == htons(ETH_TYPE_RARP)) {
struct arp_eth_header *arp;
char *flow_to_string(const struct flow *);
void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
uint32_t flags, char del);
+void format_flags_masked(struct ds *ds, const char *name,
+ const char *(*bit_to_string)(uint32_t),
+ uint32_t flags, uint32_t mask);
void flow_format(struct ds *, const struct flow *);
void flow_print(FILE *, const struct flow *);
}
}
-
static void
format_be16_masked(struct ds *s, const char *name,
ovs_be16 value, ovs_be16 mask)
}
}
+static void
+format_uint32_masked(struct ds *s, const char *name,
+ uint32_t value, uint32_t mask)
+{
+ if (mask) {
+ ds_put_format(s, "%s=%#"PRIx32, name, value);
+ if (mask != UINT32_MAX) {
+ ds_put_format(s, "/%#"PRIx32, mask);
+ }
+ ds_put_char(s, ',');
+ }
+}
+
+static void
+format_be64_masked(struct ds *s, const char *name,
+ ovs_be64 value, ovs_be64 mask)
+{
+ if (mask != htonll(0)) {
+ ds_put_format(s, "%s=%#"PRIx64, name, ntohll(value));
+ if (mask != OVS_BE64_MAX) {
+ ds_put_format(s, "/%#"PRIx64, ntohll(mask));
+ }
+ ds_put_char(s, ',');
+ }
+}
+
static void
format_flow_tunnel(struct ds *s, const struct match *match)
{
const struct flow_wildcards *wc = &match->wc;
const struct flow_tnl *tnl = &match->flow.tunnel;
- switch (wc->masks.tunnel.tun_id) {
- case 0:
- break;
- case OVS_BE64_MAX:
- ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(tnl->tun_id));
- break;
- default:
- ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
- ntohll(tnl->tun_id),
- ntohll(wc->masks.tunnel.tun_id));
- break;
- }
+ format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
ds_put_format(s, "priority=%u,", priority);
}
- switch (wc->masks.pkt_mark) {
- case 0:
- break;
- case UINT32_MAX:
- ds_put_format(s, "pkt_mark=%#"PRIx32",", f->pkt_mark);
- break;
- default:
- ds_put_format(s, "pkt_mark=%#"PRIx32"/%#"PRIx32",",
- f->pkt_mark, wc->masks.pkt_mark);
- break;
- }
+ format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark);
if (wc->masks.skb_priority) {
ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority);
}
}
for (i = 0; i < FLOW_N_REGS; i++) {
- switch (wc->masks.regs[i]) {
- case 0:
- break;
- case UINT32_MAX:
- ds_put_format(s, "reg%d=0x%"PRIx32",", i, f->regs[i]);
- break;
- default:
- ds_put_format(s, "reg%d=0x%"PRIx32"/0x%"PRIx32",",
- i, f->regs[i], wc->masks.regs[i]);
- break;
+ #define REGNAME_LEN 20
+ char regname[REGNAME_LEN];
+ if (snprintf(regname, REGNAME_LEN, "reg%d", i) >= REGNAME_LEN) {
+ strcpy(regname, "reg?");
}
+ format_uint32_masked(s, regname, f->regs[i], wc->masks.regs[i]);
}
format_flow_tunnel(s, match);
- switch (wc->masks.metadata) {
- case 0:
- break;
- case OVS_BE64_MAX:
- ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
- break;
- default:
- ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
- ntohll(f->metadata), ntohll(wc->masks.metadata));
- break;
- }
+ format_be64_masked(s, "metadata", f->metadata, wc->masks.metadata);
+
if (wc->masks.in_port.ofp_port) {
ds_put_cstr(s, "in_port=");
ofputil_format_port(f->in_port.ofp_port, s);
format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
}
if (is_ip_any(f) && f->nw_proto == IPPROTO_TCP && wc->masks.tcp_flags) {
- if (wc->masks.tcp_flags == htons(UINT16_MAX)) {
+ uint16_t mask = TCP_FLAGS(wc->masks.tcp_flags);
+ if (mask == TCP_FLAGS(OVS_BE16_MAX)) {
ds_put_format(s, "tcp_flags=0x%03"PRIx16",", ntohs(f->tcp_flags));
} else {
- ds_put_format(s, "tcp_flags=0x%03"PRIx16"/0x%03"PRIx16",",
- ntohs(f->tcp_flags), ntohs(wc->masks.tcp_flags));
+ format_flags_masked(s, "tcp_flags", packet_tcp_flag_to_string,
+ ntohs(f->tcp_flags), mask);
}
}
MFF_TCP_FLAGS, "tcp_flags", NULL,
2, 12,
MFM_FULLY,
- MFS_HEXADECIMAL,
+ MFS_TCP_FLAGS,
MFP_TCP,
false,
NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
mf_get_mask(mf, &match->wc, mask);
}
-/* Assigns a random value for field 'mf' to 'value'. */
-void
-mf_random_value(const struct mf_field *mf, union mf_value *value)
-{
- random_bytes(value, mf->n_bytes);
-
- switch (mf->id) {
- case MFF_TUN_ID:
- case MFF_TUN_SRC:
- case MFF_TUN_DST:
- case MFF_TUN_TOS:
- case MFF_TUN_TTL:
- case MFF_TUN_FLAGS:
- case MFF_METADATA:
- case MFF_IN_PORT:
- case MFF_PKT_MARK:
- case MFF_SKB_PRIORITY:
- CASE_MFF_REGS:
- case MFF_ETH_SRC:
- case MFF_ETH_DST:
- case MFF_ETH_TYPE:
- case MFF_VLAN_TCI:
- case MFF_IPV4_SRC:
- case MFF_IPV4_DST:
- case MFF_IPV6_SRC:
- case MFF_IPV6_DST:
- case MFF_IP_PROTO:
- case MFF_IP_TTL:
- case MFF_ARP_SPA:
- case MFF_ARP_TPA:
- case MFF_ARP_SHA:
- case MFF_ARP_THA:
- case MFF_TCP_SRC:
- case MFF_TCP_DST:
- case MFF_UDP_SRC:
- case MFF_UDP_DST:
- case MFF_SCTP_SRC:
- case MFF_SCTP_DST:
- case MFF_ICMPV4_TYPE:
- case MFF_ICMPV4_CODE:
- case MFF_ICMPV6_TYPE:
- case MFF_ICMPV6_CODE:
- case MFF_ND_TARGET:
- case MFF_ND_SLL:
- case MFF_ND_TLL:
- break;
-
- case MFF_TCP_FLAGS:
- value->be16 &= htons(0x0fff);
- break;
-
- case MFF_IN_PORT_OXM:
- value->be32 = ofputil_port_to_ofp11(u16_to_ofp(ntohs(value->be16)));
- break;
-
- case MFF_IPV6_LABEL:
- value->be32 &= htonl(IPV6_LABEL_MASK);
- break;
-
- case MFF_IP_DSCP:
- value->u8 &= IP_DSCP_MASK;
- break;
-
- case MFF_IP_DSCP_SHIFTED:
- value->u8 &= IP_DSCP_MASK >> 2;
- break;
-
- case MFF_IP_ECN:
- value->u8 &= IP_ECN_MASK;
- break;
-
- case MFF_IP_FRAG:
- value->u8 &= FLOW_NW_FRAG_MASK;
- break;
-
- case MFF_ARP_OP:
- value->be16 &= htons(0xff);
- break;
-
- case MFF_DL_VLAN:
- value->be16 &= htons(VLAN_VID_MASK);
- break;
- case MFF_VLAN_VID:
- value->be16 &= htons(VLAN_VID_MASK | VLAN_CFI);
- break;
-
- case MFF_DL_VLAN_PCP:
- case MFF_VLAN_PCP:
- value->u8 &= 0x07;
- break;
-
- case MFF_MPLS_LABEL:
- value->be32 &= htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT);
- break;
-
- case MFF_MPLS_TC:
- value->u8 &= MPLS_TC_MASK >> MPLS_TC_SHIFT;
- break;
-
- case MFF_MPLS_BOS:
- value->u8 &= MPLS_BOS_MASK >> MPLS_BOS_SHIFT;
- break;
-
- case MFF_N_IDS:
- default:
- NOT_REACHED();
- }
-}
-
static char *
mf_from_integer_string(const struct mf_field *mf, const char *s,
uint8_t *valuep, uint8_t *maskp)
"\"csum\", \"key\")", s);
}
+static char *
+mf_from_tcp_flags_string(const char *s, ovs_be16 *flagsp, ovs_be16 *maskp)
+{
+ uint16_t flags = 0;
+ uint16_t mask = 0;
+ uint16_t bit;
+ int n;
+
+ if (ovs_scan(s, "%"SCNi16"/%"SCNi16"%n", &flags, &mask, &n) && !s[n]) {
+ *flagsp = htons(flags);
+ *maskp = htons(mask);
+ return NULL;
+ }
+ if (ovs_scan(s, "%"SCNi16"%n", &flags, &n) && !s[n]) {
+ *flagsp = htons(flags);
+ *maskp = OVS_BE16_MAX;
+ return NULL;
+ }
+
+ while (*s != '\0') {
+ bool set;
+ int name_len;
+
+ switch (*s) {
+ case '+':
+ set = true;
+ break;
+ case '-':
+ set = false;
+ break;
+ default:
+ return xasprintf("%s: TCP flag must be preceded by '+' (for SET) "
+ "or '-' (NOT SET)", s);
+ }
+ s++;
+
+ name_len = strcspn(s,"+-");
+
+ for (bit = 1; bit; bit <<= 1) {
+ const char *fname = packet_tcp_flag_to_string(bit);
+ size_t len;
+
+ if (!fname) {
+ continue;
+ }
+
+ len = strlen(fname);
+ if (len != name_len) {
+ continue;
+ }
+ if (!strncmp(s, fname, len)) {
+ if (mask & bit) {
+ return xasprintf("%s: Each TCP flag can be specified only "
+ "once", s);
+ }
+ if (set) {
+ flags |= bit;
+ }
+ mask |= bit;
+ break;
+ }
+ }
+
+ if (!bit) {
+ return xasprintf("%s: unknown TCP flag(s)", s);
+ }
+ s += name_len;
+ }
+
+ *flagsp = htons(flags);
+ *maskp = htons(mask);
+ return NULL;
+}
+
+
/* Parses 's', a string value for field 'mf', into 'value' and 'mask'. Returns
* NULL if successful, otherwise a malloc()'d string describing the error. */
char *
error = mf_from_tun_flags_string(s, &value->be16, &mask->be16);
break;
+ case MFS_TCP_FLAGS:
+ ovs_assert(mf->n_bytes == sizeof(ovs_be16));
+ error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16);
+ break;
+
default:
NOT_REACHED();
}
format_flags(s, flow_tun_flag_to_string, ntohs(*valuep), '|');
}
+static void
+mf_format_tcp_flags_string(ovs_be16 value, ovs_be16 mask, struct ds *s)
+{
+ format_flags_masked(s, NULL, packet_tcp_flag_to_string, ntohs(value),
+ TCP_FLAGS(mask));
+}
+
/* Appends to 's' a string representation of field 'mf' whose value is in
* 'value' and 'mask'. 'mask' may be NULL to indicate an exact match. */
void
mf_format_tnl_flags_string(&value->be16, s);
break;
+ case MFS_TCP_FLAGS:
+ mf_format_tcp_flags_string(value->be16,
+ mask ? mask->be16 : OVS_BE16_MAX, s);
+ break;
+
default:
NOT_REACHED();
}
MFS_OFP_PORT_OXM, /* An OpenFlow port number or name (32-bit). */
MFS_FRAG, /* no, yes, first, later, not_later */
MFS_TNL_FLAGS, /* FLOW_TNL_F_* flags */
+ MFS_TCP_FLAGS, /* TCP_* flags */
};
struct mf_field {
void mf_set_wild(const struct mf_field *, struct match *);
-void mf_random_value(const struct mf_field *, union mf_value *value);
-
/* Subfields. */
void mf_write_subfield_flow(const struct mf_subfield *,
const union mf_subvalue *, struct flow *);
} else {
goto done;
}
- if (is_mask) {
+ if (check_len > 0) { /* Happens only when 'is_mask'. */
if (!is_all_zeros(check_start, check_len) &&
flow->dl_type != htons(0xffff)) {
return ODP_FIT_ERROR;
pin->reason = opi->reason;
pin->buffer_id = ntohl(opi->buffer_id);
pin->total_len = ntohs(opi->total_len);
+ } else if (raw == OFPRAW_OFPT11_PACKET_IN) {
+ const struct ofp11_packet_in *opi;
+ enum ofperr error;
+
+ opi = ofpbuf_pull(&b, sizeof *opi);
+
+ pin->packet = b.data;
+ pin->packet_len = b.size;
+
+ pin->buffer_id = ntohl(opi->buffer_id);
+ error = ofputil_port_from_ofp11(opi->in_port, &pin->fmd.in_port);
+ if (error) {
+ return error;
+ }
+ pin->total_len = ntohs(opi->total_len);
+ pin->reason = opi->reason;
+ pin->table_id = opi->table_id;
} else if (raw == OFPRAW_NXT_PACKET_IN) {
const struct nx_packet_in *npi;
struct match match;
match_set_in_port(match, pin->fmd.in_port);
}
+static struct ofpbuf *
+ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
+{
+ struct ofp10_packet_in *opi;
+ struct ofpbuf *packet;
+
+ packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
+ htonl(0), pin->packet_len);
+ opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
+ opi->total_len = htons(pin->total_len);
+ opi->in_port = htons(ofp_to_u16(pin->fmd.in_port));
+ opi->reason = pin->reason;
+ opi->buffer_id = htonl(pin->buffer_id);
+
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+ return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin)
+{
+ struct nx_packet_in *npi;
+ struct ofpbuf *packet;
+ struct match match;
+ size_t match_len;
+
+ ofputil_packet_in_to_match(pin, &match);
+
+ /* The final argument is just an estimate of the space required. */
+ packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
+ htonl(0), (sizeof(struct flow_metadata) * 2
+ + 2 + pin->packet_len));
+ ofpbuf_put_zeros(packet, sizeof *npi);
+ match_len = nx_put_match(packet, &match, 0, 0);
+ ofpbuf_put_zeros(packet, 2);
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+ npi = packet->l3;
+ npi->buffer_id = htonl(pin->buffer_id);
+ npi->total_len = htons(pin->total_len);
+ npi->reason = pin->reason;
+ npi->table_id = pin->table_id;
+ npi->cookie = pin->cookie;
+ npi->match_len = htons(match_len);
+
+ return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
+{
+ struct ofp11_packet_in *opi;
+ struct ofpbuf *packet;
+
+ packet = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
+ htonl(0), pin->packet_len);
+ opi = ofpbuf_put_zeros(packet, sizeof *opi);
+ opi->buffer_id = htonl(pin->buffer_id);
+ opi->in_port = ofputil_port_to_ofp11(pin->fmd.in_port);
+ opi->in_phy_port = opi->in_port;
+ opi->total_len = htons(pin->total_len);
+ opi->reason = pin->reason;
+ opi->table_id = pin->table_id;
+
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+ return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
+ enum ofputil_protocol protocol)
+{
+ struct ofp13_packet_in *opi;
+ struct match match;
+ enum ofpraw packet_in_raw;
+ enum ofp_version packet_in_version;
+ size_t packet_in_size;
+ struct ofpbuf *packet;
+
+ if (protocol == OFPUTIL_P_OF12_OXM) {
+ packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
+ packet_in_version = OFP12_VERSION;
+ packet_in_size = sizeof (struct ofp12_packet_in);
+ } else {
+ packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
+ packet_in_version = OFP13_VERSION;
+ packet_in_size = sizeof (struct ofp13_packet_in);
+ }
+
+ ofputil_packet_in_to_match(pin, &match);
+
+ /* The final argument is just an estimate of the space required. */
+ packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
+ htonl(0), (sizeof(struct flow_metadata) * 2
+ + 2 + pin->packet_len));
+ ofpbuf_put_zeros(packet, packet_in_size);
+ oxm_put_match(packet, &match);
+ ofpbuf_put_zeros(packet, 2);
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+ opi = packet->l3;
+ opi->pi.buffer_id = htonl(pin->buffer_id);
+ opi->pi.total_len = htons(pin->total_len);
+ opi->pi.reason = pin->reason;
+ opi->pi.table_id = pin->table_id;
+ if (protocol == OFPUTIL_P_OF13_OXM) {
+ opi->cookie = pin->cookie;
+ }
+
+ return packet;
+}
+
/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
* in the format specified by 'packet_in_format'. */
struct ofpbuf *
{
struct ofpbuf *packet;
- /* Add OFPT_PACKET_IN. */
- if (protocol == OFPUTIL_P_OF13_OXM || protocol == OFPUTIL_P_OF12_OXM) {
- struct ofp13_packet_in *opi;
- struct match match;
- enum ofpraw packet_in_raw;
- enum ofp_version packet_in_version;
- size_t packet_in_size;
+ switch (protocol) {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
+ packet = (packet_in_format == NXPIF_NXM
+ ? ofputil_encode_nx_packet_in(pin)
+ : ofputil_encode_ofp10_packet_in(pin));
+ break;
- if (protocol == OFPUTIL_P_OF12_OXM) {
- packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
- packet_in_version = OFP12_VERSION;
- packet_in_size = sizeof (struct ofp12_packet_in);
- } else {
- packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
- packet_in_version = OFP13_VERSION;
- packet_in_size = sizeof (struct ofp13_packet_in);
- }
+ case OFPUTIL_P_OF11_STD:
+ packet = ofputil_encode_ofp11_packet_in(pin);
+ break;
- ofputil_packet_in_to_match(pin, &match);
-
- /* The final argument is just an estimate of the space required. */
- packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
- htonl(0), (sizeof(struct flow_metadata) * 2
- + 2 + pin->packet_len));
- ofpbuf_put_zeros(packet, packet_in_size);
- oxm_put_match(packet, &match);
- ofpbuf_put_zeros(packet, 2);
- ofpbuf_put(packet, pin->packet, pin->packet_len);
-
- opi = packet->l3;
- opi->pi.buffer_id = htonl(pin->buffer_id);
- opi->pi.total_len = htons(pin->total_len);
- opi->pi.reason = pin->reason;
- opi->pi.table_id = pin->table_id;
- if (protocol == OFPUTIL_P_OF13_OXM) {
- opi->cookie = pin->cookie;
- }
- } else if (packet_in_format == NXPIF_OPENFLOW10) {
- struct ofp10_packet_in *opi;
-
- packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
- htonl(0), pin->packet_len);
- opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
- opi->total_len = htons(pin->total_len);
- opi->in_port = htons(ofp_to_u16(pin->fmd.in_port));
- opi->reason = pin->reason;
- opi->buffer_id = htonl(pin->buffer_id);
-
- ofpbuf_put(packet, pin->packet, pin->packet_len);
- } else if (packet_in_format == NXPIF_NXM) {
- struct nx_packet_in *npi;
- struct match match;
- size_t match_len;
-
- ofputil_packet_in_to_match(pin, &match);
-
- /* The final argument is just an estimate of the space required. */
- packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
- htonl(0), (sizeof(struct flow_metadata) * 2
- + 2 + pin->packet_len));
- ofpbuf_put_zeros(packet, sizeof *npi);
- match_len = nx_put_match(packet, &match, 0, 0);
- ofpbuf_put_zeros(packet, 2);
- ofpbuf_put(packet, pin->packet, pin->packet_len);
-
- npi = packet->l3;
- npi->buffer_id = htonl(pin->buffer_id);
- npi->total_len = htons(pin->total_len);
- npi->reason = pin->reason;
- npi->table_id = pin->table_id;
- npi->cookie = pin->cookie;
- npi->match_len = htons(match_len);
- } else {
+ case OFPUTIL_P_OF12_OXM:
+ case OFPUTIL_P_OF13_OXM:
+ packet = ofputil_encode_ofp12_packet_in(pin, protocol);
+ break;
+
+ default:
NOT_REACHED();
}
- ofpmsg_update_length(packet);
+ ofpmsg_update_length(packet);
return packet;
}
{
return !must_not_fork;
}
+\f
+/* Parses /proc/cpuinfo for the total number of physical cores on this system
+ * across all CPU packages, not counting hyper-threads.
+ *
+ * Sets *n_cores to the total number of cores on this system, or 0 if the
+ * number cannot be determined. */
+static void
+parse_cpuinfo(long int *n_cores)
+{
+ static const char file_name[] = "/proc/cpuinfo";
+ char line[128];
+ uint64_t cpu = 0; /* Support up to 64 CPU packages on a single system. */
+ long int cores = 0;
+ FILE *stream;
+
+ stream = fopen(file_name, "r");
+ if (!stream) {
+ VLOG_WARN("%s: open failed (%s)", file_name, ovs_strerror(errno));
+ return;
+ }
+
+ while (fgets(line, sizeof line, stream)) {
+ unsigned int id;
+
+ /* Find the next CPU package. */
+ if (ovs_scan(line, "physical id%*[^:]: %u", &id)) {
+ if (id > 63) {
+ VLOG_WARN("Counted over 64 CPU packages on this system. "
+ "Parsing %s for core count may be inaccurate.",
+ file_name);
+ cores = 0;
+ break;
+ }
+
+ if (cpu & (1 << id)) {
+ /* We've already counted this package's cores. */
+ continue;
+ }
+ cpu |= 1 << id;
+
+ /* Find the number of cores for this package. */
+ while (fgets(line, sizeof line, stream)) {
+ int count;
+
+ if (ovs_scan(line, "cpu cores%*[^:]: %u", &count)) {
+ cores += count;
+ break;
+ }
+ }
+ }
+ }
+ fclose(stream);
+
+ *n_cores = cores;
+}
+
+/* Returns the total number of cores on this system, or 0 if the number cannot
+ * be determined.
+ *
+ * Tries not to count hyper-threads, but may be inaccurate - particularly on
+ * platforms that do not provide /proc/cpuinfo, but also if /proc/cpuinfo is
+ * formatted different to the layout that parse_cpuinfo() expects. */
+unsigned int
+count_cpu_cores(void)
+{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+ static long int n_cores;
+
+ if (ovsthread_once_start(&once)) {
+ parse_cpuinfo(&n_cores);
+ if (!n_cores) {
+ n_cores = sysconf(_SC_NPROCESSORS_ONLN);
+ }
+ ovsthread_once_done(&once);
+ }
+
+ return n_cores > 0 ? n_cores : 0;
+}
#endif
void forbid_forking(const char *reason);
bool may_fork(void);
+\f
+/* Useful functions related to threading. */
+
+unsigned int count_cpu_cores(void);
#endif /* ovs-thread.h */
int
ip_count_cidr_bits(ovs_be32 netmask)
{
- return 32 - ctz(ntohl(netmask));
+ return 32 - ctz32(ntohl(netmask));
}
void
}
}
+const char *
+packet_tcp_flag_to_string(uint32_t flag)
+{
+ switch (flag) {
+ case TCP_FIN:
+ return "fin";
+ case TCP_SYN:
+ return "syn";
+ case TCP_RST:
+ return "rst";
+ case TCP_PSH:
+ return "psh";
+ case TCP_ACK:
+ return "ack";
+ case TCP_URG:
+ return "urg";
+ case TCP_ECE:
+ return "ece";
+ case TCP_CWR:
+ return "cwr";
+ case TCP_NS:
+ return "ns";
+ case 0x200:
+ return "[200]";
+ case 0x400:
+ return "[400]";
+ case 0x800:
+ return "[800]";
+ default:
+ return NULL;
+ }
+}
+
/* Appends a string representation of the TCP flags value 'tcp_flags'
* (e.g. obtained via packet_get_tcp_flags() or TCP_FLAGS) to 's', in the
* format used by tcpdump. */
uint16_t packet_get_tcp_flags(const struct ofpbuf *, const struct flow *);
void packet_format_tcp_flags(struct ds *, uint16_t);
+const char *packet_tcp_flag_to_string(uint32_t flag);
#endif /* packets.h */
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include "byte-order.h"
#include "compiler.h"
#include "ofpbuf.h"
#include "vlog.h"
/* Calculate length. */
len = prh.incl_len;
if (len > 0xffff) {
- uint32_t swapped_len = (((len & 0xff000000) >> 24) |
- ((len & 0x00ff0000) >> 8) |
- ((len & 0x0000ff00) << 8) |
- ((len & 0x000000ff) << 24));
+ uint32_t swapped_len = uint32_byteswap(len);
if (swapped_len > 0xffff) {
VLOG_WARN("bad packet length %"PRIuSIZE" or %"PRIu32" "
"reading pcap file",
* is too short). We don't check the actual failure reason because
* POSIX requires strerror_r() to return the error but old glibc
* (before 2.13) returns -1 and sets errno. */
- snprintf(buffer, BUFSIZE, "Unknown error %"PRIuSIZE, error);
+ snprintf(buffer, BUFSIZE, "Unknown error %d", error);
}
#endif
: " and ");
}
-/* Given a 32 bit word 'n', calculates floor(log_2('n')). This is equivalent
- * to finding the bit position of the most significant one bit in 'n'. It is
- * an error to call this function with 'n' == 0. */
-int
-log_2_floor(uint32_t n)
-{
- ovs_assert(n);
-
-#if !defined(UINT_MAX) || !defined(UINT32_MAX)
-#error "Someone screwed up the #includes."
-#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX
- return 31 - __builtin_clz(n);
-#else
- {
- int log = 0;
-
-#define BIN_SEARCH_STEP(BITS) \
- if (n >= (1 << BITS)) { \
- log += BITS; \
- n >>= BITS; \
- }
- BIN_SEARCH_STEP(16);
- BIN_SEARCH_STEP(8);
- BIN_SEARCH_STEP(4);
- BIN_SEARCH_STEP(2);
- BIN_SEARCH_STEP(1);
-#undef BIN_SEARCH_STEP
- return log;
- }
-#endif
-}
-
-/* Given a 32 bit word 'n', calculates ceil(log_2('n')). It is an error to
- * call this function with 'n' == 0. */
-int
-log_2_ceil(uint32_t n)
-{
- return log_2_floor(n) + !is_pow2(n);
-}
-
/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
#if __GNUC__ >= 4
/* Defined inline in util.h. */
#else
+/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
int
raw_ctz(uint64_t n)
{
return count;
}
-#endif
-/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */
-static unsigned int
-count_1bits_32(uint32_t x)
+/* Returns the number of leading 0-bits in 'n'. Undefined if 'n' == 0. */
+int
+raw_clz64(uint64_t n)
{
- /* In my testing, this implementation is over twice as fast as any other
- * portable implementation that I tried, including GCC 4.4
- * __builtin_popcount(), although nonportable asm("popcnt") was over 50%
- * faster. */
+ uint64_t k;
+ int count = 63;
+
+#define CLZ_STEP(X) \
+ k = n >> (X); \
+ if (k) { \
+ count -= X; \
+ n = k; \
+ }
+ CLZ_STEP(32);
+ CLZ_STEP(16);
+ CLZ_STEP(8);
+ CLZ_STEP(4);
+ CLZ_STEP(2);
+ CLZ_STEP(1);
+#undef CLZ_STEP
+
+ return count;
+}
+#endif
+
+#if !(__GNUC__ >= 4 && defined(__corei7))
#define INIT1(X) \
((((X) & (1 << 0)) != 0) + \
(((X) & (1 << 1)) != 0) + \
#define INIT32(X) INIT16(X), INIT16((X) + 16)
#define INIT64(X) INIT32(X), INIT32((X) + 32)
- static const uint8_t count_1bits_8[256] = {
- INIT64(0), INIT64(64), INIT64(128), INIT64(192)
- };
-
- return (count_1bits_8[x & 0xff] +
- count_1bits_8[(x >> 8) & 0xff] +
- count_1bits_8[(x >> 16) & 0xff] +
- count_1bits_8[x >> 24]);
-}
-
-/* Returns the number of 1-bits in 'x', between 0 and 64 inclusive. */
-unsigned int
-count_1bits(uint64_t x)
-{
- return count_1bits_32(x) + count_1bits_32(x >> 32);
-}
+const uint8_t count_1bits_8[256] = {
+ INIT64(0), INIT64(64), INIT64(128), INIT64(192)
+};
+#endif
/* Returns true if the 'n' bytes starting at 'p' are zeros. */
bool
\f
/* Bitwise tests. */
-int log_2_floor(uint32_t);
-int log_2_ceil(uint32_t);
-unsigned int count_1bits(uint64_t);
-
/* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */
#if __GNUC__ >= 4
static inline int
? __builtin_ctz(n)
: __builtin_ctzll(n));
}
+
+static inline int
+raw_clz64(uint64_t n)
+{
+ return __builtin_clzll(n);
+}
#else
/* Defined in util.c. */
int raw_ctz(uint64_t n);
+int raw_clz64(uint64_t n);
#endif
/* Returns the number of trailing 0-bits in 'n', or 32 if 'n' is 0. */
static inline int
-ctz(uint32_t n)
+ctz32(uint32_t n)
{
return n ? raw_ctz(n) : 32;
}
return n ? raw_ctz(n) : 64;
}
+/* Returns the number of leading 0-bits in 'n', or 32 if 'n' is 0. */
+static inline int
+clz32(uint32_t n)
+{
+ return n ? raw_clz64(n) - 32 : 32;
+}
+
+/* Returns the number of leading 0-bits in 'n', or 64 if 'n' is 0. */
+static inline int
+clz64(uint64_t n)
+{
+ return n ? raw_clz64(n) : 64;
+}
+
+/* Given a word 'n', calculates floor(log_2('n')). This is equivalent
+ * to finding the bit position of the most significant one bit in 'n'. It is
+ * an error to call this function with 'n' == 0. */
+static inline int
+log_2_floor(uint64_t n)
+{
+ return 63 - raw_clz64(n);
+}
+
+/* Given a word 'n', calculates ceil(log_2('n')). It is an error to
+ * call this function with 'n' == 0. */
+static inline int
+log_2_ceil(uint64_t n)
+{
+ return log_2_floor(n) + !is_pow2(n);
+}
+
+/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */
+static inline unsigned int
+count_1bits_32(uint32_t x)
+{
+#if __GNUC__ >= 4 && defined(__corei7)
+ /* __builtin_popcount() is fast only when supported by the CPU. */
+ return __builtin_popcount(x);
+#else
+ extern const uint8_t count_1bits_8[256];
+ /* This portable implementation is the fastest one we know of for 32 bits,
+ * and faster than GCC __builtin_popcount(). */
+ return (count_1bits_8[x & 0xff] +
+ count_1bits_8[(x >> 8) & 0xff] +
+ count_1bits_8[(x >> 16) & 0xff] +
+ count_1bits_8[x >> 24]);
+#endif
+}
+
+/* Returns the number of 1-bits in 'x', between 0 and 64 inclusive. */
+static inline unsigned int
+count_1bits(uint64_t x)
+{
+ if (sizeof(void *) == 8) { /* 64-bit CPU */
+#if __GNUC__ >= 4 && defined(__corei7)
+ /* __builtin_popcountll() is fast only when supported by the CPU. */
+ return __builtin_popcountll(x);
+#else
+ /* This portable implementation is the fastest one we know of for 64
+ * bits, and about 3x faster than GCC 4.7 __builtin_popcountll(). */
+ const uint64_t h55 = UINT64_C(0x5555555555555555);
+ const uint64_t h33 = UINT64_C(0x3333333333333333);
+ const uint64_t h0F = UINT64_C(0x0F0F0F0F0F0F0F0F);
+ const uint64_t h01 = UINT64_C(0x0101010101010101);
+ x -= (x >> 1) & h55; /* Count of each 2 bits in-place. */
+ x = (x & h33) + ((x >> 2) & h33); /* Count of each 4 bits in-place. */
+ x = (x + (x >> 4)) & h0F; /* Count of each 8 bits in-place. */
+ return (x * h01) >> 56; /* Sum of all bytes. */
+#endif
+ } else { /* 32-bit CPU */
+ return count_1bits_32(x) + count_1bits_32(x >> 32);
+ }
+}
+
/* Returns the rightmost 1-bit in 'x' (e.g. 01011000 => 00001000), or 0 if 'x'
* is 0. */
static inline uintmax_t
static inline uint32_t
rightmost_1bit_idx(uint32_t x)
{
- return x ? ctz(x) : 32;
+ return ctz32(x);
}
-/* Returns the index of the rightmost 1-bit in 'x' (e.g. 01011000 => 6), or 32
+/* Returns the index of the leftmost 1-bit in 'x' (e.g. 01011000 => 6), or 32
* if 'x' is 0.
*
* This function only works with 32-bit integers. */
#include "ofpbuf.h"
#include "ovs-thread.h"
#include "sat-math.h"
+#include "socket-util.h"
#include "svec.h"
#include "timeval.h"
#include "unixctl.h"
/* Name for each logging level. */
static const char *const level_names[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) #NAME,
VLOG_LEVELS
#undef VLOG_LEVEL
};
/* Syslog value for each logging level. */
static const int syslog_levels[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) SYSLOG_LEVEL,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) SYSLOG_LEVEL,
VLOG_LEVELS
#undef VLOG_LEVEL
};
+/* RFC 5424 defines specific values for each syslog level. Normally LOG_* use
+ * the same values. Verify that in fact they're the same. If we get assertion
+ * failures here then we need to define a separate rfc5424_levels[] array. */
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) \
+ BUILD_ASSERT_DECL(SYSLOG_LEVEL == RFC5424);
+VLOG_LEVELS
+#undef VLOG_LEVELS
+
+/* Similarly, RFC 5424 defines the local0 facility with the value ordinarily
+ * used for LOG_LOCAL0. */
+BUILD_ASSERT_DECL(LOG_LOCAL0 == (16 << 3));
+
/* The log modules. */
#if USE_LINKER_SECTIONS
extern struct vlog_module *__start_vlog_modules[];
static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
static bool log_async OVS_GUARDED_BY(log_file_mutex);
+/* Syslog export configuration. */
+static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
+
static void format_log_message(const struct vlog_module *, enum vlog_level,
- enum vlog_facility,
+ const char *pattern,
const char *message, va_list, struct ds *)
- PRINTF_FORMAT(4, 0) OVS_REQ_RDLOCK(&pattern_rwlock);
+ PRINTF_FORMAT(4, 0);
/* Searches the 'n_names' in 'names'. Returns the index of a match for
* 'target', or 'n_names' if no name matches. */
}
}
+/* Set the vlog udp syslog target. */
+void
+vlog_set_syslog_target(const char *target)
+{
+ int new_fd;
+
+ inet_open_active(SOCK_DGRAM, target, 0, NULL, &new_fd, 0);
+
+ ovs_rwlock_wrlock(&pattern_rwlock);
+ if (syslog_fd >= 0) {
+ close(syslog_fd);
+ }
+ syslog_fd = new_fd;
+ ovs_rwlock_unlock(&pattern_rwlock);
+}
+
static void
vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
void *aux OVS_UNUSED)
static void
format_log_message(const struct vlog_module *module, enum vlog_level level,
- enum vlog_facility facility,
- const char *message, va_list args_, struct ds *s)
+ const char *pattern, const char *message,
+ va_list args_, struct ds *s)
{
char tmp[128];
va_list args;
const char *p;
ds_clear(s);
- for (p = facilities[facility].pattern; *p != '\0'; ) {
+ for (p = pattern; *p != '\0'; ) {
const char *subprogram_name;
enum { LEFT, RIGHT } justify = RIGHT;
int pad = '0';
case 'A':
ds_put_cstr(s, program_name);
break;
+ case 'B':
+ ds_put_format(s, "%d", LOG_LOCAL0 + syslog_levels[level]);
+ break;
case 'c':
p = fetch_braces(p, "", tmp, sizeof tmp);
ds_put_cstr(s, vlog_get_module_name(module));
p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
ds_put_strftime_msec(s, tmp, time_wall_msec(), true);
break;
+ case 'E':
+ gethostname(tmp, sizeof tmp);
+ tmp[sizeof tmp - 1] = '\0';
+ ds_put_cstr(s, tmp);
+ break;
case 'm':
/* Format user-supplied log message and trim trailing new-lines. */
length = s->length;
}
}
+/* Exports the given 'syslog_message' to the configured udp syslog sink. */
+static void
+send_to_syslog_fd(const char *s, size_t length)
+ OVS_REQ_RDLOCK(pattern_rwlock)
+{
+ static size_t max_length = SIZE_MAX;
+ size_t send_len = MIN(length, max_length);
+
+ while (write(syslog_fd, s, send_len) < 0 && errno == EMSGSIZE) {
+ send_len -= send_len / 20;
+ max_length = send_len;
+ }
+}
+
/* Writes 'message' to the log at the given 'level' and as coming from the
* given 'module'.
*
ovs_rwlock_rdlock(&pattern_rwlock);
if (log_to_console) {
- format_log_message(module, level, VLF_CONSOLE, message, args, &s);
+ format_log_message(module, level, facilities[VLF_CONSOLE].pattern,
+ message, args, &s);
ds_put_char(&s, '\n');
fputs(ds_cstr(&s), stderr);
}
char *save_ptr = NULL;
char *line;
- format_log_message(module, level, VLF_SYSLOG, message, args, &s);
+ format_log_message(module, level, facilities[VLF_SYSLOG].pattern,
+ message, args, &s);
for (line = strtok_r(s.string, "\n", &save_ptr); line;
line = strtok_r(NULL, "\n", &save_ptr)) {
syslog(syslog_level, "%s", line);
}
+
+ if (syslog_fd >= 0) {
+ format_log_message(module, level,
+ "<%B>1 %D{%Y-%m-%dT%H:%M:%S.###Z} "
+ "%E %A %P %c - \xef\xbb\xbf%m",
+ message, args, &s);
+ send_to_syslog_fd(ds_cstr(&s), s.length);
+ }
}
if (log_to_file) {
- format_log_message(module, level, VLF_FILE, message, args, &s);
+ format_log_message(module, level, facilities[VLF_FILE].pattern,
+ message, args, &s);
ds_put_char(&s, '\n');
ovs_mutex_lock(&log_file_mutex);
void
vlog_usage(void)
{
- printf("\nLogging options:\n"
- " -v, --verbose=[SPEC] set logging levels\n"
- " -v, --verbose set maximum verbosity level\n"
- " --log-file[=FILE] enable logging to specified FILE\n"
- " (default: %s/%s.log)\n",
+ printf("\n\
+Logging options:\n\
+ -vSPEC, --verbose=SPEC set logging levels\n\
+ -v, --verbose set maximum verbosity level\n\
+ --log-file[=FILE] enable logging to specified FILE\n\
+ (default: %s/%s.log)\n\
+ --syslog-target=HOST:PORT also send syslog msgs to HOST:PORT via UDP\n",
ovs_logdir(), program_name);
}
*
* ovs-appctl(8) defines each of the log levels. */
#define VLOG_LEVELS \
- VLOG_LEVEL(OFF, LOG_ALERT) \
- VLOG_LEVEL(EMER, LOG_ALERT) \
- VLOG_LEVEL(ERR, LOG_ERR) \
- VLOG_LEVEL(WARN, LOG_WARNING) \
- VLOG_LEVEL(INFO, LOG_NOTICE) \
- VLOG_LEVEL(DBG, LOG_DEBUG)
+ VLOG_LEVEL(OFF, LOG_ALERT, 1) \
+ VLOG_LEVEL(EMER, LOG_ALERT, 1) \
+ VLOG_LEVEL(ERR, LOG_ERR, 3) \
+ VLOG_LEVEL(WARN, LOG_WARNING, 4) \
+ VLOG_LEVEL(INFO, LOG_NOTICE, 5) \
+ VLOG_LEVEL(DBG, LOG_DEBUG, 7)
enum vlog_level {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) VLL_##NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424_LEVEL) VLL_##NAME,
VLOG_LEVELS
#undef VLOG_LEVEL
VLL_N_LEVELS
/* Facilities that we can log to. */
#define VLOG_FACILITIES \
- VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m") \
+ VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m") \
VLOG_FACILITY(CONSOLE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m") \
VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m")
enum vlog_facility {
int vlog_set_log_file(const char *file_name);
int vlog_reopen_log_file(void);
+/* Configure syslog target. */
+void vlog_set_syslog_target(const char *target);
+
/* Initialization. */
void vlog_init(void);
void vlog_enable_async(void);
#define VLOG_DBG_ONCE(...) VLOG_ONCE(VLL_DBG, __VA_ARGS__)
/* Command line processing. */
-#define VLOG_OPTION_ENUMS OPT_LOG_FILE
-#define VLOG_LONG_OPTIONS \
- {"verbose", optional_argument, NULL, 'v'}, \
- {"log-file", optional_argument, NULL, OPT_LOG_FILE}
+#define VLOG_OPTION_ENUMS \
+ OPT_LOG_FILE, \
+ OPT_SYSLOG_TARGET
+
+#define VLOG_LONG_OPTIONS \
+ {"verbose", optional_argument, NULL, 'v'}, \
+ {"log-file", optional_argument, NULL, OPT_LOG_FILE}, \
+ {"syslog-target", optional_argument, NULL, OPT_SYSLOG_TARGET}
+
#define VLOG_OPTION_HANDLERS \
case 'v': \
vlog_set_verbosity(optarg); \
break; \
case OPT_LOG_FILE: \
vlog_set_log_file(optarg); \
+ break; \
+ case OPT_SYSLOG_TARGET: \
+ vlog_set_syslog_target(optarg); \
break;
+
void vlog_usage(void);
/* Implementation details. */
Enables logging to a file. If \fIfile\fR is specified, then it is
used as the exact name for the log file. The default log file name
used if \fIfile\fR is omitted is \fB@LOGDIR@/\*(PN.log\fR.
+.
+.IP "\fB\-\-syslog\-target=\fIhost\fB:\fIport\fR"
+Send syslog messages to UDP \fIport\fR on \fIhost\fR, in addition to
+the system syslog. The \fIhost\fR must be a numerical IP address, not
+a hostname.
dnl Checks for libraries needed by lib/socket-util.c.
AC_DEFUN([OVS_CHECK_SOCKET_LIBS],
[AC_CHECK_LIB([socket], [connect])
- AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])])
+ AC_SEARCH_LIBS([gethostbyname], [resolv])])
dnl Checks for the directory in which to store the PKI.
AC_DEFUN([OVS_CHECK_PKIDIR],
fi
fi])
+dnl OVS_CHECK_ATOMIC_LIBS
+dnl
+dnl Check to see if -latomic is need for GCC atomic built-ins.
+AC_DEFUN([OVS_CHECK_ATOMIC_LIBS],
+ [AC_SEARCH_LIBS([__atomic_load_8], [atomic])])
+
dnl OVS_CHECK_GCC4_ATOMICS
dnl
dnl Checks whether the compiler and linker support GCC 4.0+ atomic built-ins.
noinst_LIBRARIES += ofproto/libofproto.a
ofproto_libofproto_a_SOURCES = \
+ ofproto/bond.c \
+ ofproto/bond.h \
ofproto/collectors.c \
ofproto/collectors.h \
ofproto/connmgr.c \
if (ctx->xin->resubmit_stats) {
netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats);
netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats);
+ if (peer->bfd) {
+ bfd_account_rx(peer->bfd, ctx->xin->resubmit_stats);
+ }
}
return;
/* XXX
* check if table configuration flags
- * OFPTC_TABLE_MISS_CONTROLLER, default.
- * OFPTC_TABLE_MISS_CONTINUE,
- * OFPTC_TABLE_MISS_DROP
- * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
+ * OFPTC11_TABLE_MISS_CONTROLLER, default.
+ * OFPTC11_TABLE_MISS_CONTINUE,
+ * OFPTC11_TABLE_MISS_DROP
+ * When OF1.0, OFPTC11_TABLE_MISS_CONTINUE is used. What to do? */
xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
choose_miss_rule(xport ? xport->config : 0,
ctx->xbridge->miss_rule,
#define SUBFACET_DESTROY_MAX_BATCH 50
-static struct subfacet *subfacet_create(struct facet *, struct flow_miss *);
+static struct subfacet *subfacet_create(struct facet *, struct flow_miss *,
+ uint32_t key_hash);
static struct subfacet *subfacet_find(struct dpif_backer *,
const struct nlattr *key, size_t key_len,
uint32_t key_hash);
{
enum subfacet_path want_path;
struct subfacet *subfacet;
+ uint32_t key_hash;
+ /* Update facet stats. */
facet->packet_count += miss->stats.n_packets;
facet->prev_packet_count += miss->stats.n_packets;
facet->byte_count += miss->stats.n_bytes;
facet->prev_byte_count += miss->stats.n_bytes;
- want_path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
+ /* Look for an existing subfacet. If we find one, update its used time. */
+ key_hash = odp_flow_key_hash(miss->key, miss->key_len);
+ if (!list_is_empty(&facet->subfacets)) {
+ subfacet = subfacet_find(miss->ofproto->backer,
+ miss->key, miss->key_len, key_hash);
+ if (subfacet) {
+ if (subfacet->facet == facet) {
+ subfacet->used = MAX(subfacet->used, miss->stats.used);
+ } else {
+ /* This shouldn't happen. */
+ VLOG_ERR_RL(&rl, "subfacet with wrong facet");
+ subfacet_destroy(subfacet);
+ subfacet = NULL;
+ }
+ }
+ } else {
+ subfacet = NULL;
+ }
/* Don't install the flow if it's the result of the "userspace"
* action for an already installed facet. This can occur when a
return;
}
- subfacet = subfacet_create(facet, miss);
+ /* Create a subfacet, if we don't already have one. */
+ if (!subfacet) {
+ subfacet = subfacet_create(facet, miss, key_hash);
+ }
+
+ /* Install the subfacet, if it's not already installed. */
+ want_path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
if (subfacet->path != want_path) {
struct flow_miss_op *op = &ops[(*n_ops)++];
struct dpif_flow_put *put = &op->dpif_op.u.flow_put;
in_port = get_ofp_port(ofproto, flow->in_port.ofp_port);
if (in_port && in_port->is_tunnel) {
netdev_vport_inc_rx(in_port->up.netdev, stats);
+ if (in_port->bfd) {
+ bfd_account_rx(in_port->bfd, stats);
+ }
}
xlate_in_init(&xin, ofproto, flow, NULL, stats->tcp_flags, NULL);
return NULL;
}
-/* Searches 'facet' (within 'ofproto') for a subfacet with the specified
- * 'key_fitness', 'key', and 'key_len' members in 'miss'. Returns the
- * existing subfacet if there is one, otherwise creates and returns a
- * new subfacet. */
+/* Creates and returns a new subfacet within 'facet' for the flow in 'miss'.
+ * 'key_hash' must be a hash over miss->key. The caller must have already
+ * ensured that no subfacet subfacet already exists. */
static struct subfacet *
-subfacet_create(struct facet *facet, struct flow_miss *miss)
+subfacet_create(struct facet *facet, struct flow_miss *miss, uint32_t key_hash)
{
struct dpif_backer *backer = miss->ofproto->backer;
const struct nlattr *key = miss->key;
size_t key_len = miss->key_len;
- uint32_t key_hash;
struct subfacet *subfacet;
- key_hash = odp_flow_key_hash(key, key_len);
-
- if (list_is_empty(&facet->subfacets)) {
- subfacet = &facet->one_subfacet;
- } else {
- subfacet = subfacet_find(backer, key, key_len, key_hash);
- if (subfacet) {
- if (subfacet->facet == facet) {
- return subfacet;
- }
-
- /* This shouldn't happen. */
- VLOG_ERR_RL(&rl, "subfacet with wrong facet");
- subfacet_destroy(subfacet);
- }
-
- subfacet = xmalloc(sizeof *subfacet);
- }
+ subfacet = (list_is_empty(&facet->subfacets)
+ ? &facet->one_subfacet
+ : xmalloc(sizeof *subfacet));
COVERAGE_INC(subfacet_create);
hmap_insert(&backer->subfacets, &subfacet->hmap_node, key_hash);
if (limit) {
n_handler_threads = limit;
} else {
- int n_proc = sysconf(_SC_NPROCESSORS_ONLN);
+ int n_proc = count_cpu_cores();
n_handler_threads = n_proc > 2 ? n_proc - 2 : 1;
}
}
%{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
%{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
/usr/share/openvswitch/bugtool-plugins/
-/usr/share/openvswitch/python/ovs/__init__.py
-/usr/share/openvswitch/python/ovs/daemon.py
-/usr/share/openvswitch/python/ovs/db/__init__.py
-/usr/share/openvswitch/python/ovs/db/data.py
-/usr/share/openvswitch/python/ovs/db/error.py
-/usr/share/openvswitch/python/ovs/db/idl.py
-/usr/share/openvswitch/python/ovs/db/parser.py
-/usr/share/openvswitch/python/ovs/db/schema.py
-/usr/share/openvswitch/python/ovs/db/types.py
-/usr/share/openvswitch/python/ovs/dirs.py
-/usr/share/openvswitch/python/ovs/fatal_signal.py
-/usr/share/openvswitch/python/ovs/json.py
-/usr/share/openvswitch/python/ovs/jsonrpc.py
-/usr/share/openvswitch/python/ovs/ovsuuid.py
-/usr/share/openvswitch/python/ovs/poller.py
-/usr/share/openvswitch/python/ovs/process.py
-/usr/share/openvswitch/python/ovs/reconnect.py
-/usr/share/openvswitch/python/ovs/socket_util.py
-/usr/share/openvswitch/python/ovs/stream.py
-/usr/share/openvswitch/python/ovs/timeval.py
-/usr/share/openvswitch/python/ovs/util.py
-/usr/share/openvswitch/python/ovs/version.py
-/usr/share/openvswitch/python/ovs/unixctl/__init__.py
-/usr/share/openvswitch/python/ovs/unixctl/client.py
-/usr/share/openvswitch/python/ovs/unixctl/server.py
-/usr/share/openvswitch/python/uuid.py
-/usr/share/openvswitch/python/argparse.py
-/usr/share/openvswitch/python/ovs/vlog.py
-/usr/share/openvswitch/python/ovstest/__init__.py
-/usr/share/openvswitch/python/ovstest/args.py
-/usr/share/openvswitch/python/ovstest/rpcserver.py
-/usr/share/openvswitch/python/ovstest/tcp.py
-/usr/share/openvswitch/python/ovstest/udp.py
-/usr/share/openvswitch/python/ovstest/util.py
-/usr/share/openvswitch/python/ovstest/vswitch.py
-/usr/share/openvswitch/python/ovstest/tests.py
+/usr/share/openvswitch/python/ovs/__init__.py*
+/usr/share/openvswitch/python/ovs/daemon.py*
+/usr/share/openvswitch/python/ovs/db/__init__.py*
+/usr/share/openvswitch/python/ovs/db/data.py*
+/usr/share/openvswitch/python/ovs/db/error.py*
+/usr/share/openvswitch/python/ovs/db/idl.py*
+/usr/share/openvswitch/python/ovs/db/parser.py*
+/usr/share/openvswitch/python/ovs/db/schema.py*
+/usr/share/openvswitch/python/ovs/db/types.py*
+/usr/share/openvswitch/python/ovs/dirs.py*
+/usr/share/openvswitch/python/ovs/fatal_signal.py*
+/usr/share/openvswitch/python/ovs/json.py*
+/usr/share/openvswitch/python/ovs/jsonrpc.py*
+/usr/share/openvswitch/python/ovs/ovsuuid.py*
+/usr/share/openvswitch/python/ovs/poller.py*
+/usr/share/openvswitch/python/ovs/process.py*
+/usr/share/openvswitch/python/ovs/reconnect.py*
+/usr/share/openvswitch/python/ovs/socket_util.py*
+/usr/share/openvswitch/python/ovs/stream.py*
+/usr/share/openvswitch/python/ovs/timeval.py*
+/usr/share/openvswitch/python/ovs/util.py*
+/usr/share/openvswitch/python/ovs/version.py*
+/usr/share/openvswitch/python/ovs/unixctl/__init__.py*
+/usr/share/openvswitch/python/ovs/unixctl/client.py*
+/usr/share/openvswitch/python/ovs/unixctl/server.py*
+/usr/share/openvswitch/python/uuid.py*
+/usr/share/openvswitch/python/argparse.py*
+/usr/share/openvswitch/python/ovs/vlog.py*
+/usr/share/openvswitch/python/ovstest/__init__.py*
+/usr/share/openvswitch/python/ovstest/args.py*
+/usr/share/openvswitch/python/ovstest/rpcserver.py*
+/usr/share/openvswitch/python/ovstest/tcp.py*
+/usr/share/openvswitch/python/ovstest/udp.py*
+/usr/share/openvswitch/python/ovstest/util.py*
+/usr/share/openvswitch/python/ovstest/vswitch.py*
+/usr/share/openvswitch/python/ovstest/tests.py*
/usr/share/openvswitch/scripts/ovs-bugtool-*
/usr/share/openvswitch/scripts/ovs-check-dead-ifs
/usr/share/openvswitch/scripts/ovs-lib
AT_CLEANUP
# Tests below are for bfd forwarding_if_rx feature.
-# forwarding_if_rx Test1: bfd is enabled on one end of link.
-AT_SETUP([bfd - bfd forwarding_if_rx 1])
+
+# forwarding_if_rx Test1
+# Test1 tests the case when bfd is only enabled on one end of the link.
+# Under this situation, the bfd state should be DOWN and the forwarding
+# flag should be FALSE by default. However, if forwarding_if_rx is
+# enabled, as long as there is packet received, the bfd forwarding flag
+# should be TRUE.
+AT_SETUP([bfd - bfd forwarding_if_rx - bfd on one side])
OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
add-port br1 p1 -- set Interface p1 type=patch \
options:peer=p0 ofport_request=2 -- \
BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
done
-# receive one packet.
-AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
- [0], [stdout], [])
-# wait for 1000ms
-for i in `seq 0 14`; do ovs-appctl time/warp 100; done
-# the forwarding flag should turn to true sometime in this 1000ms, since there is data received.
-BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
-
-# Stop sending packets for 2000ms.
-for i in `seq 0 19`; do ovs-appctl time/warp 100; done
-BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
-
# receive packet at 1/100ms rate for 2000ms.
for i in `seq 0 19`
do
done
# the forwarding flag should be true, since there is data received.
BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
# reset bfd forwarding_if_rx.
AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
AT_CLEANUP
-# forwarding_if_rx Test2: bfd is enabled on both ends of link.
-AT_SETUP([bfd - bfd forwarding_if_rx 2])
+
+# forwarding_if_rx Test2
+# Test2 is for testing that the enable of forwarding_if_rx will not
+# affect the normal bfd communication. bfd is enabled on both ends of
+# the link.
+AT_SETUP([bfd - bfd forwarding_if_rx - bfd on both sides])
OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
add-port br1 p1 -- set Interface p1 type=patch \
options:peer=p0 ofport_request=2 -- \
ovs-appctl time/warp 500
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-# receive packet at 1/100ms rate for 1000ms.
-for i in `seq 0 9`
-do
- AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
- [0], [stdout], [])
- ovs-appctl time/warp 100
- # the forwarding flag should always be true during this time.
- BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-done
-
# reset bfd forwarding_if_rx.
AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
# forwarding flag should turn to false since the STATE is DOWN.
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
# re-enable bfd on the other end. the states should be up.
AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true bfd:min_tx=300 bfd:min_rx=300])
AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
AT_CLEANUP
-# forwarding_if_rx Test3: bfd is enabled on both ends of link and decay is enabled.
-AT_SETUP([bfd - bfd forwarding_if_rx 3])
+# forwarding_if_rx Test3
+# Test3 is for testing that the enable of forwarding_if_rx will not
+# affect the bfd decay feature. bfd is enabled on both ends of the link.
+AT_SETUP([bfd - bfd forwarding_if_rx - with bfd decay])
OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
add-port br1 p1 -- set Interface p1 type=patch \
options:peer=p0 ofport_request=2 -- \
# wait for 5000ms to decay.
for i in `seq 0 9`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
BFD_CHECK_RX([p0], [1000ms], [1000ms], [500ms])
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
done
-# stop receiving for 3000ms.
-for i in `seq 0 29`; do ovs-appctl time/warp 100; done
+# stop receiving for 5000ms.
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
# reset bfd forwarding_if_rx.
AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false])
-# forwarding flag should turn to false since the STATE is DOWN.
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [300ms], [300ms], [1ms])
-
# re-enable bfd forwarding_if_rx.
AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=true])
-# there should be no change.
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [300ms], [300ms], [1ms])
# re-enable bfd on the other end. the states should be up.
AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true bfd:min_tx=300 bfd:min_rx=300])
AT_CLEANUP
# test bfd:flap_count.
+# This test contains three part:
+# part 1. tests the flap_count on normal bfd monitored link.
+# part 2. tests the flap_count when forwarding override is used.
+# part 3. tests the flap_count when forwarding_if_rx is enabled.
AT_SETUP([bfd - flap_count])
#Create 2 bridges connected by patch ports and enable bfd
OVS_VSWITCHD_START([add-br br1 -- \
# turn bfd on p1 off, should increment the bfd:flap_count on p0.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["2"])
AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
# turn bfd on p1 on again, should increment the bfd:flap_count on p0.
# p1 should still have flap_count = "1", since it is reset.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
# turn bfd on p1 off, should not increment the bfd:flap_count on p0, since forwarding_override is on.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
# turn bfd on p1 on again, should not increment the bfd:flap_count on p0, since forwarding override is on.
# p1 should still have flap_count = "1", since it is reset.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
# turn bfd on p1 off and on, should increment the bfd:flap_count on p0.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["5"])
BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
# turn on the bfd on p1.
AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
# even though there is no data traffic, since p1 bfd is on again, should increment the flap_count.
BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["9"])
BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
m4_foreach(
[testname],
[[ctz],
+ [clz],
[round_up_pow2],
[round_down_pow2],
[count_1bits],
])
AT_CLEANUP
+AT_SETUP([OFPT_PACKET_IN - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 0a 00 54 00 00 00 00 00 00 01 11 00 00 00 03 \
+00 00 00 03 00 3c 00 00 \
+50 54 00 00 00 06 50 54 00 00 00 05 08 00 \
+45 00 00 28 bd 12 00 00 40 06 3c 6a c0 a8 00 01 \
+c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
+50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_IN (OF1.1) (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=0x002 tcp_csum:26e8
+])
+AT_CLEANUP
+
AT_SETUP([OFPT_PACKET_IN - OF1.2])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
table=1 in_port=1 action=dec_ttl,output:3
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
AT_CHECK([tail -3 stdout], [0],
- [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),2,4
+ [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),2,4
This flow is handled by the userspace slow path because it:
- Sends "packet-in" messages to the OpenFlow controller.
])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=3,frag=no)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=3,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),3,4
+ [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),3,4
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
AT_CAPTURE_FILE([ofctl_monitor.log])
AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=42 in_port=1 (via invalid_ttl) data_len=42 (unbuffered)
-icmp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=1,icmp_type=0,icmp_code=0
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=34 in_port=1 (via invalid_ttl) data_len=34 (unbuffered)
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1
])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:41,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:41,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
])
dnl Modified MPLS controller action.
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=41:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=41:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
])
dnl Modified MPLS controller action.
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:44,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:44,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no))'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:45,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:45,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:46,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:46,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:47,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:47,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
for i in 1 2 3; do
- ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:48,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:48,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
done
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
])
pkt_len=64
stripped=4
hdr_len=60
- hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+ hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
])
AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
ifspeed=100000000
direction=0
status=0
- in_octets=98
+ in_octets=138
in_unicasts=3
in_multicasts=0
in_broadcasts=4294967295
ifspeed=100000000
direction=0
status=0
- in_octets=98
+ in_octets=138
in_unicasts=3
in_multicasts=0
in_broadcasts=4294967295
OVS_VSWITCHD_STOP
AT_CLEANUP
+dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
+dnl specified by OpenFlow 1.1) and OFPP_CONTROLLER (used by some
+dnl controllers despite the spec) as meaning a packet that was generated
+dnl by the controller.
+AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.1)])
+OVS_VSWITCHD_START
+
+# Start a monitor listening for packet-ins.
+AT_CHECK([ovs-ofctl -O OpenFlow11 monitor br0 --detach --no-chdir --pidfile])
+ovs-appctl -t ovs-ofctl ofctl/send 0209000c0123456700000080
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+AT_CAPTURE_FILE([monitor.log])
+
+# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
+AT_CHECK([ovs-ofctl -O OpenFlow11 packet-out br0 none controller '0001020304050010203040501234'])
+AT_CHECK([ovs-ofctl -O OpenFlow11 packet-out br0 4294967293 controller '0001020304050010203040505678'])
+
+# Stop the monitor and check its output.
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
+OFPT_PACKET_IN (OF1.1): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
+metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+OFPT_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
+metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
+OFPT_BARRIER_REPLY (OF1.1):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
dnl This test checks that metadata is encoded in packet_in structures,
dnl supported by NXAST.
AT_SETUP([ofproto - packet-out with metadata (NXM)])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
-- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
AT_DATA([flows.txt], [dnl
- in_port=1,tcp,tp_dst=80,tcp_flags=0x02/0x17,action=2 # Allow outbound web traffic bare-SYN
- in_port=1,tcp,tp_dst=80,tcp_flags=0x10/0x10,action=2 # Allow outbound web traffic with ACK bit
- in_port=1,tcp,tp_dst=80,tcp_flags=0x04/0x04,action=2 # Allow outbound web traffic with RST bit
- in_port=2,tcp,tp_src=80,tcp_flags=0x10/0x10,action=1 # Allow inbound web traffic with ACK bit
- in_port=2,tcp,tp_src=80,tcp_flags=0x04/0x04,action=1 # Allow inbound web traffic with RST bit
+ in_port=1,tcp,tp_dst=80,tcp_flags=+syn-rst-ack-fin,action=2 # Allow outbound web traffic bare-SYN
+ in_port=1,tcp,tp_dst=80,tcp_flags=+ack,action=2 # Allow outbound web traffic with ACK bit
+ in_port=1,tcp,tp_dst=80,tcp_flags=+rst,action=2 # Allow outbound web traffic with RST bit
+ in_port=2,tcp,tp_src=80,tcp_flags=+ack,action=1 # Allow inbound web traffic with ACK bit
+ in_port=2,tcp,tp_src=80,tcp_flags=+rst,action=1 # Allow inbound web traffic with RST bit
priority=0,in_port=1,action=drop # Default drop outbound
priority=0,in_port=2,action=drop # Default drop inbound
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-ofctl add-flow br0 "tcp,tcp_flags=+ack-ack,action="], [1], [],
+ [ovs-ofctl: ack: Each TCP flag can be specified only once
+])
+
AT_CHECK([ovs-appctl dpif/show | tail -n +5], [0], [dnl
p1 1/1: (dummy)
p2 2/2: (dummy)
])
-dnl Outbound web traffic with base-SYN
+dnl Outbound web traffic with bare-SYN
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=80),tcp_flags(0x002)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: 2
}
static void
-check_ctz(uint32_t x, int n)
+check_ctz32(uint32_t x, int n)
{
- if (ctz(x) != n) {
- fprintf(stderr, "ctz(%"PRIu32") is %d but should be %d\n",
- x, ctz(x), n);
+ if (ctz32(x) != n) {
+ fprintf(stderr, "ctz32(%"PRIu32") is %d but should be %d\n",
+ x, ctz32(x), n);
abort();
}
}
for (n = 0; n < 32; n++) {
/* Check minimum x such that f(x) == n. */
- check_ctz(1 << n, n);
+ check_ctz32(1 << n, n);
/* Check maximum x such that f(x) == n. */
- check_ctz(UINT32_MAX << n, n);
+ check_ctz32(UINT32_MAX << n, n);
/* Check a random value in the middle. */
- check_ctz((random_uint32() | 1) << n, n);
+ check_ctz32((random_uint32() | 1) << n, n);
}
}
/* Check ctz(0). */
- check_ctz(0, 32);
+ check_ctz32(0, 32);
check_ctz64(0, 64);
}
+static void
+check_clz32(uint32_t x, int n)
+{
+ if (clz32(x) != n) {
+ fprintf(stderr, "clz32(%"PRIu32") is %d but should be %d\n",
+ x, clz32(x), n);
+ abort();
+ }
+}
+
+static void
+check_clz64(uint64_t x, int n)
+{
+ if (clz64(x) != n) {
+ fprintf(stderr, "clz64(%"PRIu64") is %d but should be %d\n",
+ x, clz64(x), n);
+ abort();
+ }
+}
+
+static void
+test_clz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ int n;
+
+ for (n = 0; n < 32; n++) {
+ /* Check minimum x such that f(x) == n. */
+ check_clz32((1u << 31) >> n, n);
+
+ /* Check maximum x such that f(x) == n. */
+ check_clz32(UINT32_MAX >> n, n);
+
+ /* Check a random value in the middle. */
+ check_clz32((random_uint32() | 1u << 31) >> n, n);
+ }
+
+ for (n = 0; n < 64; n++) {
+ /* Check minimum x such that f(x) == n. */
+ check_clz64((UINT64_C(1) << 63) >> n, n);
+
+ /* Check maximum x such that f(x) == n. */
+ check_clz64(UINT64_MAX >> n, n);
+
+ /* Check a random value in the middle. */
+ check_clz64((random_uint64() | UINT64_C(1) << 63) >> n, n);
+ }
+
+ /* Check clz(0). */
+ check_clz32(0, 32);
+ check_clz64(0, 64);
+}
+
/* Returns a random number in the range 'min'...'max' inclusive. */
static uint32_t
random_in_range(uint32_t min, uint32_t max)
\f
static const struct command commands[] = {
{"ctz", 0, 0, test_ctz},
+ {"clz", 0, 0, test_clz},
{"round_up_pow2", 0, 0, test_round_up_pow2},
{"round_down_pow2", 0, 0, test_round_down_pow2},
{"count_1bits", 0, 0, test_count_1bits},
.IP \fB%A\fR
The name of the application logging the message, e.g. \fBovs\-vswitchd\fR.
.
+.IP \fB%B\fR
+The RFC5424 syslog PRI of the message.
+.
.IP \fB%c\fR
The name of the module (as shown by \fBovs\-appctl \-\-list\fR) logging
the message.
\fBstrftime\fR(3). Supports the same extension for sub-second
resolution as \fB%d{\fR...\fB}\fR.
.
+.IP \fB%E\fR
+The hostname of the node running the application.
+.
.IP \fB%m\fR
The message being logged.
.
\fBnw_proto\fR specify TCP or UDP or SCTP.
.
.IP \fBtcp_flags=\fIflags\fB/\fImask\fR
+.IQ \fBtcp_flags=\fR[\fB+\fIflag\fR...][\fB-\fIflag\fR...]
Bitwise match on TCP flags. The \fIflags\fR and \fImask\fR are 16-bit
numbers written in decimal or in hexadecimal prefixed by \fB0x\fR.
Each 1-bit in \fImask\fR requires that the corresponding bit in
\fIflags\fR must match. Each 0-bit in \fImask\fR causes the corresponding
bit to be ignored.
.IP
+Alternatively, the flags can be specified by their symbolic names
+(listed below), each preceded by either \fB+\fR for a flag that must
+be set, or \fB\-\fR for a flag that must be unset, without any other
+delimiters between the flags. Flags not mentioned are wildcarded.
+For example, \fBtcp,tcp_flags=+syn\-ack\fR matches TCP SYNs that are
+not ACKs.
+.IP
TCP protocol currently defines 9 flag bits, and additional 3 bits are
reserved (must be transmitted as zero), see RFCs 793, 3168, and 3540.
The flag bits are, numbering from the least significant bit:
.RS
-.IP "\fB0: FIN\fR"
+.IP "\fB0: fin\fR"
No more data from sender.
-.IP "\fB1: SYN\fR"
+.IP "\fB1: syn\fR"
Synchronize sequence numbers.
-.IP "\fB2: RST\fR"
+.IP "\fB2: rst\fR"
Reset the connection.
-.IP "\fB3: PSH\fR"
+.IP "\fB3: psh\fR"
Push function.
-.IP "\fB4: ACK\fR"
+.IP "\fB4: ack\fR"
Acknowledgement field significant.
-.IP "\fB5: URG\fR"
+.IP "\fB5: urg\fR"
Urgent pointer field significant.
-.IP "\fB6: ECE\fR"
+.IP "\fB6: ece\fR"
ECN Echo.
-.IP "\fB7: CWR\fR"
+.IP "\fB7: cwr\fR"
Congestion Windows Reduced.
-.IP "\fB8: NS\fR"
+.IP "\fB8: ns\fR"
Nonce Sum.
.IP "\fB9-11:\fR"
Reserved.
#include "async-append.h"
#include "bfd.h"
#include "bitmap.h"
-#include "bond.h"
#include "cfm.h"
#include "coverage.h"
#include "daemon.h"
#include "ofp-print.h"
#include "ofp-util.h"
#include "ofpbuf.h"
+#include "ofproto/bond.h"
#include "ofproto/ofproto.h"
#include "poll-loop.h"
#include "sha1.h"
static void
iface_set_ofport(const struct ovsrec_interface *if_cfg, ofp_port_t ofport)
{
- int64_t port_;
- port_ = (ofport == OFPP_NONE) ? -1 : ofp_to_u16(ofport);
if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
- ovsrec_interface_set_ofport(if_cfg, &port_, 1);
+ int64_t port = ofport == OFPP_NONE ? -1 : ofp_to_u16(ofport);
+ ovsrec_interface_set_ofport(if_cfg, &port, 1);
}
}
static void
get_cpu_cores(struct smap *stats)
{
- long int n_cores = sysconf(_SC_NPROCESSORS_ONLN);
+ long int n_cores = count_cpu_cores();
if (n_cores > 0) {
smap_add_format(stats, "cpu", "%ld", n_cores);
}