From: Giuseppe Lettieri Date: Tue, 10 Dec 2013 13:38:28 +0000 (+0100) Subject: Merge branch 'mainstream' X-Git-Tag: sliver-openvswitch-2.0.90-1~1 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=6b4b2f598246e87237342a9179a0d29e202ebe65;hp=f263172c99fd0a72c3f6666ffbaeaab786a3f1a8;p=sliver-openvswitch.git Merge branch 'mainstream' --- diff --git a/DESIGN b/DESIGN index d36b02507..4d654d01d 100644 --- a/DESIGN +++ b/DESIGN @@ -266,6 +266,53 @@ OpenFlow 1.3 makes these changes: 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 ============= diff --git a/NEWS b/NEWS index 38e3d9d3f..85560834e 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ Post-v2.0.0 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 diff --git a/OPENFLOW-1.1+ b/OPENFLOW-1.1+ index e194ba781..eaf2ee99e 100644 --- a/OPENFLOW-1.1+ +++ b/OPENFLOW-1.1+ @@ -54,13 +54,6 @@ OpenFlow 1.1 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. @@ -86,11 +79,6 @@ additional work specific to Openflow 1.2 are complete. (This is based 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 ------------ @@ -124,11 +112,6 @@ didn't compare the specs carefully yet.) 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 diff --git a/PORTING b/PORTING index 53c19d33d..88694a4c0 100644 --- a/PORTING +++ b/PORTING @@ -18,7 +18,7 @@ is a concordance, indexed by the area of the source tree: 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 diff --git a/acinclude.m4 b/acinclude.m4 index f987fa0bd..94f9b6186 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -240,6 +240,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ # 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], diff --git a/build-aux/cccl b/build-aux/cccl index c614ecbf5..f6972d474 100644 --- a/build-aux/cccl +++ b/build-aux/cccl @@ -90,6 +90,7 @@ EOF -g[0-9] | -g) # cl only supports one debugging level clopt="$clopt ${slash}Zi" + linkopt="$linkopt ${slash}DEBUG" ;; -L*) diff --git a/configure.ac b/configure.ac index 13d2d31b9..167cc7124 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,7 @@ OVS_CHECK_XENSERVER_VERSION 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) diff --git a/datapath/datapath.c b/datapath/datapath.c index d0a85958c..1808c3606 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -404,6 +404,13 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, 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)) { @@ -425,7 +432,8 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, 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; @@ -494,7 +502,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) 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; @@ -629,7 +637,9 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, { 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; @@ -660,25 +670,17 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, 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 @@ -695,8 +697,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, 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); @@ -720,27 +721,30 @@ error: 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; } @@ -756,6 +760,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct sw_flow_actions *acts = NULL; struct sw_flow_match match; + bool exact_5tuple; int error; /* Extract key. */ @@ -764,7 +769,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 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; @@ -803,7 +808,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 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; @@ -820,8 +825,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 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; @@ -849,8 +853,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 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]) @@ -892,7 +895,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) } 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; @@ -909,8 +912,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) 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; @@ -947,7 +949,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) } 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; @@ -957,7 +959,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) goto unlock; } - reply = ovs_flow_cmd_alloc_info(flow); + reply = ovs_flow_cmd_alloc_info(flow, info); if (!reply) { err = -ENOMEM; goto unlock; @@ -1109,17 +1111,17 @@ error: 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); @@ -1208,8 +1210,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) 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; @@ -1275,8 +1276,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) 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; @@ -1304,8 +1304,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) 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, @@ -1336,8 +1335,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info) 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; diff --git a/datapath/datapath.h b/datapath/datapath.h index 879a8309c..89ba80f9e 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -148,6 +148,8 @@ int lockdep_ovsl_is_held(void); #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) { diff --git a/datapath/flow.c b/datapath/flow.c index 57eb6b565..9b3d3a753 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -64,9 +64,14 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies) 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 && @@ -82,56 +87,79 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb) 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) diff --git a/datapath/flow.h b/datapath/flow.h index 6b68cf163..eafcfd87a 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -149,13 +149,21 @@ struct sw_flow_actions { 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; @@ -166,7 +174,7 @@ struct sw_flow { 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 { @@ -184,7 +192,8 @@ 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); diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index 75c72b361..9b26528b0 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -266,6 +266,20 @@ static bool is_all_zero(const u8 *fp, size_t size) 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) @@ -487,8 +501,9 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, 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; @@ -545,6 +560,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 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; @@ -567,6 +587,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, 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)) { @@ -598,6 +625,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, 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)) { @@ -640,6 +674,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, 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)) { @@ -671,6 +710,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, 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)) { @@ -756,6 +800,7 @@ static void sw_flow_mask_set(struct sw_flow_mask *mask, * 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) { @@ -803,10 +848,13 @@ int ovs_nla_get_match(struct sw_flow_match *match, } } - 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) @@ -844,7 +892,7 @@ int ovs_nla_get_match(struct sw_flow_match *match, } } - 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 { diff --git a/datapath/flow_netlink.h b/datapath/flow_netlink.h index 440151045..b31fbe28b 100644 --- a/datapath/flow_netlink.h +++ b/datapath/flow_netlink.h @@ -45,6 +45,7 @@ int ovs_nla_put_flow(const struct sw_flow_key *, 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 *); diff --git a/datapath/flow_table.c b/datapath/flow_table.c index 29cfcbe86..6bb68d8b2 100644 --- a/datapath/flow_table.c +++ b/datapath/flow_table.c @@ -73,7 +73,7 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, *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; @@ -85,11 +85,30 @@ struct sw_flow *ovs_flow_alloc(void) 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) @@ -123,6 +142,10 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets) 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); } @@ -438,7 +461,7 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, 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; @@ -583,15 +606,11 @@ int ovs_flow_tbl_insert(struct flow_table *table, 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; diff --git a/datapath/flow_table.h b/datapath/flow_table.h index f54aa82cf..1996e34c0 100644 --- a/datapath/flow_table.h +++ b/datapath/flow_table.h @@ -55,7 +55,7 @@ struct flow_table { 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 *); diff --git a/datapath/linux/compat/flow_dissector.c b/datapath/linux/compat/flow_dissector.c index 8592ca9fb..7a0d09b98 100644 --- a/datapath/linux/compat/flow_dissector.c +++ b/datapath/linux/compat/flow_dissector.c @@ -19,7 +19,7 @@ */ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) #include #include #include @@ -46,9 +46,25 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i 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; @@ -86,6 +102,7 @@ ipv6: 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; @@ -161,33 +178,30 @@ ipv6: } 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) @@ -206,15 +220,13 @@ 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; diff --git a/datapath/linux/compat/include/linux/net.h b/datapath/linux/compat/include/linux/net.h index 5665e2ee0..d8bf621ce 100644 --- a/datapath/linux/compat/include/linux/net.h +++ b/datapath/linux/compat/include/linux/net.h @@ -2,6 +2,7 @@ #define __LINUX_NET_WRAPPER_H 1 #include_next +#include #ifndef net_ratelimited_function #define net_ratelimited_function(function, ...) \ @@ -28,4 +29,26 @@ do { \ 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 diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 9868a9864..4f2260040 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -213,12 +213,16 @@ static inline int skb_unclone(struct sk_buff *skb, gfp_t pri) } #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); } diff --git a/datapath/linux/compat/include/net/flow_keys.h b/datapath/linux/compat/include/net/flow_keys.h index 4de17d12f..766b4b376 100644 --- a/datapath/linux/compat/include/net/flow_keys.h +++ b/datapath/linux/compat/include/net/flow_keys.h @@ -3,7 +3,7 @@ #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) #include_next #else struct flow_keys { diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h index 91be1685f..09ee23bdd 100644 --- a/datapath/linux/compat/include/net/genetlink.h +++ b/datapath/linux/compat/include/net/genetlink.h @@ -20,4 +20,13 @@ 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 */ diff --git a/datapath/linux/compat/include/net/ipv6.h b/datapath/linux/compat/include/net/ipv6.h index 71f470883..eebb1fe46 100644 --- a/datapath/linux/compat/include/net/ipv6.h +++ b/datapath/linux/compat/include/net/ipv6.h @@ -27,7 +27,7 @@ enum { 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 diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c index 844d372ab..dc4df2aaa 100644 --- a/datapath/linux/compat/utils.c +++ b/datapath/linux/compat/utils.c @@ -37,3 +37,24 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, 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; +} diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c index e4e603fbb..c2698ae9d 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -165,12 +165,17 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid) */ 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; diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h index 4ee9c5c32..92dd3c5e5 100644 --- a/include/openflow/openflow-1.1.h +++ b/include/openflow/openflow-1.1.h @@ -443,18 +443,6 @@ struct ofp11_table_mod { }; 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. */ @@ -753,12 +741,7 @@ struct ofp11_packet_in { 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); diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h index ef9409f56..bf16d59c3 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -476,11 +476,17 @@ enum ofp_table { }; 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 */ diff --git a/lib/automake.mk b/lib/automake.mk index 4d7c1c621..75608a8d8 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -17,8 +17,6 @@ lib_libopenvswitch_a_SOURCES = \ 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 \ diff --git a/lib/bfd.c b/lib/bfd.c index 25129c90d..1df5acd05 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -187,7 +187,7 @@ struct bfd { 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? */ @@ -234,7 +234,7 @@ static void bfd_put_details(struct ds *, const struct bfd *) 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); @@ -259,6 +259,20 @@ bfd_forwarding(struct bfd *bfd) OVS_EXCLUDED(mutex) 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 @@ -266,7 +280,9 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap) 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); @@ -316,7 +332,6 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg, 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); @@ -490,6 +505,7 @@ bfd_run(struct bfd *bfd) OVS_EXCLUDED(mutex) 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 @@ -499,9 +515,6 @@ bfd_run(struct bfd *bfd) OVS_EXCLUDED(mutex) 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) { @@ -638,6 +651,8 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow, /* 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; @@ -787,6 +802,7 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow, /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */ out: + bfd_forwarding__(bfd); ovs_mutex_unlock(&mutex); } @@ -812,27 +828,31 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev) /* 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. */ @@ -1033,9 +1053,6 @@ bfd_set_state(struct bfd *bfd, enum state state, enum diag diag) bfd_decay_update(bfd); } } - - /* Updates the forwarding flag. */ - bfd_forwarding__(bfd); } static uint64_t @@ -1081,32 +1098,11 @@ bfd_decay_update(struct bfd * bfd) OVS_REQUIRES(mutex) 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 @@ -1152,7 +1148,9 @@ bfd_find_by_name(const char *name) OVS_REQUIRES(mutex) 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"); diff --git a/lib/bfd.h b/lib/bfd.h index 0ad86e94e..4e7d4cb46 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -22,6 +22,7 @@ #include struct bfd; +struct dpif_flow_stats; struct flow; struct flow_wildcards; struct netdev; @@ -46,6 +47,7 @@ struct bfd *bfd_configure(struct bfd *, const char *name, 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 *); diff --git a/lib/byte-order.h b/lib/byte-order.h index f9be78be1..352f91ee6 100644 --- a/lib/byte-order.h +++ b/lib/byte-order.h @@ -1,5 +1,5 @@ /* - * 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. @@ -40,7 +40,6 @@ ovs_be64 htonll(uint64_t); uint64_t ntohll(ovs_be64); #endif -#if defined(WORDS_BIGENDIAN) static inline uint32_t uint32_byteswap(uint32_t crc) { return (((crc & 0x000000ff) << 24) | @@ -48,7 +47,6 @@ uint32_byteswap(uint32_t crc) { ((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 diff --git a/lib/flow.c b/lib/flow.c index c6683a515..0dfd01f09 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -586,6 +586,24 @@ format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), 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) { @@ -1040,6 +1058,78 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos) 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'. * @@ -1049,6 +1139,7 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos) 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; @@ -1063,7 +1154,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) 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; @@ -1077,44 +1168,32 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) 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; diff --git a/lib/flow.h b/lib/flow.h index 5e7807388..5c0007ddf 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -179,6 +179,9 @@ void flow_get_metadata(const struct flow *, struct flow_metadata *); 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 *); diff --git a/lib/match.c b/lib/match.c index 71d86beae..9e5da136e 100644 --- a/lib/match.c +++ b/lib/match.c @@ -779,7 +779,6 @@ format_ipv6_netmask(struct ds *s, const char *name, } } - static void format_be16_masked(struct ds *s, const char *name, ovs_be16 value, ovs_be16 mask) @@ -796,24 +795,39 @@ format_be16_masked(struct ds *s, const char *name, } } +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); @@ -848,17 +862,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) 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); @@ -915,32 +919,18 @@ match_format(const struct match *match, struct ds *s, unsigned int 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); @@ -1069,11 +1059,12 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) 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); } } diff --git a/lib/meta-flow.c b/lib/meta-flow.c index b37f7816e..bc972b034 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -565,7 +565,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = { 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", @@ -2215,115 +2215,6 @@ mf_get(const struct mf_field *mf, const struct match *match, 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) @@ -2595,6 +2486,81 @@ mf_from_tun_flags_string(const char *s, ovs_be16 *valuep, ovs_be16 *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 * @@ -2645,6 +2611,11 @@ mf_parse(const struct mf_field *mf, const char *s, 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(); } @@ -2731,6 +2702,13 @@ mf_format_tnl_flags_string(const ovs_be16 *valuep, struct ds *s) 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 @@ -2787,6 +2765,11 @@ mf_format(const struct mf_field *mf, 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(); } diff --git a/lib/meta-flow.h b/lib/meta-flow.h index c2b0bbc23..2c5616f0c 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -232,6 +232,7 @@ enum OVS_PACKED_ENUM mf_string { 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 { @@ -378,8 +379,6 @@ enum ofputil_protocol mf_set(const 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 *); diff --git a/lib/odp-util.c b/lib/odp-util.c index 0fd1c5159..6dbc213c2 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -2871,7 +2871,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } 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; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 92e0767d8..7fc4c7c4b 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -3196,6 +3196,23 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, 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; @@ -3260,6 +3277,120 @@ ofputil_packet_in_to_match(const struct ofputil_packet_in *pin, 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 * @@ -3269,83 +3400,30 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, { 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; } diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c index b3a87bb12..1a633cfe7 100644 --- a/lib/ovs-thread.c +++ b/lib/ovs-thread.c @@ -309,4 +309,82 @@ may_fork(void) { return !must_not_fork; } + +/* 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 diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h index 7f3195d69..c6a714269 100644 --- a/lib/ovs-thread.h +++ b/lib/ovs-thread.h @@ -496,5 +496,9 @@ pid_t xfork_at(const char *where); void forbid_forking(const char *reason); bool may_fork(void); + +/* Useful functions related to threading. */ + +unsigned int count_cpu_cores(void); #endif /* ovs-thread.h */ diff --git a/lib/packets.c b/lib/packets.c index 4bec4d19f..d87aa8eb3 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -425,7 +425,7 @@ eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], int ip_count_cidr_bits(ovs_be32 netmask) { - return 32 - ctz(ntohl(netmask)); + return 32 - ctz32(ntohl(netmask)); } void @@ -909,6 +909,39 @@ packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow) } } +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. */ diff --git a/lib/packets.h b/lib/packets.h index ef8c00ca4..d291c1445 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -643,5 +643,6 @@ void packet_set_sctp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst); 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 */ diff --git a/lib/pcap-file.c b/lib/pcap-file.c index 9091a7261..ac6871642 100644 --- a/lib/pcap-file.c +++ b/lib/pcap-file.c @@ -21,6 +21,7 @@ #include #include #include +#include "byte-order.h" #include "compiler.h" #include "ofpbuf.h" #include "vlog.h" @@ -151,10 +152,7 @@ pcap_read(FILE *file, struct ofpbuf **bufp) /* 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", diff --git a/lib/util.c b/lib/util.c index faa2cabbe..13d41a70d 100644 --- a/lib/util.c +++ b/lib/util.c @@ -346,7 +346,7 @@ ovs_strerror(int error) * 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 @@ -848,50 +848,11 @@ english_list_delimiter(size_t index, size_t total) : " 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) { @@ -914,16 +875,33 @@ 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) + \ @@ -940,22 +918,10 @@ count_1bits_32(uint32_t x) #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 diff --git a/lib/util.h b/lib/util.h index fbab74c9c..7c5eacbd8 100644 --- a/lib/util.h +++ b/lib/util.h @@ -302,10 +302,6 @@ void ignore(bool x OVS_UNUSED); /* 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 @@ -318,14 +314,21 @@ raw_ctz(uint64_t n) ? __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; } @@ -337,6 +340,80 @@ ctz64(uint64_t n) 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 @@ -361,10 +438,10 @@ zero_rightmost_1bit(uintmax_t x) 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. */ diff --git a/lib/vlog.c b/lib/vlog.c index b1ca15895..0fa1ab29c 100644 --- a/lib/vlog.c +++ b/lib/vlog.c @@ -35,6 +35,7 @@ #include "ofpbuf.h" #include "ovs-thread.h" #include "sat-math.h" +#include "socket-util.h" #include "svec.h" #include "timeval.h" #include "unixctl.h" @@ -49,18 +50,30 @@ VLOG_DEFINE_THIS_MODULE(vlog); /* 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[]; @@ -111,10 +124,13 @@ static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1; 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. */ @@ -480,6 +496,22 @@ vlog_set_verbosity(const char *arg) } } +/* 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) @@ -700,15 +732,15 @@ fetch_braces(const char *p, const char *def, char *out, size_t out_size) 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'; @@ -739,6 +771,9 @@ format_log_message(const struct vlog_module *module, enum vlog_level level, 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)); @@ -751,6 +786,11 @@ format_log_message(const struct vlog_module *module, enum vlog_level level, 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; @@ -804,6 +844,20 @@ format_log_message(const struct vlog_module *module, enum vlog_level level, } } +/* 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'. * @@ -831,7 +885,8 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level, 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); } @@ -841,15 +896,25 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level, 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); @@ -1012,10 +1077,12 @@ vlog_rate_limit(const struct vlog_module *module, enum vlog_level level, 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); } diff --git a/lib/vlog.h b/lib/vlog.h index d7d63bf11..da55405b3 100644 --- a/lib/vlog.h +++ b/lib/vlog.h @@ -44,14 +44,14 @@ extern "C" { * * 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 @@ -62,7 +62,7 @@ enum vlog_level vlog_get_level_val(const char *name); /* 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 { @@ -139,6 +139,9 @@ void vlog_set_pattern(enum vlog_facility, const char *pattern); 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); @@ -213,17 +216,26 @@ void vlog_rate_limit(const struct vlog_module *, enum vlog_level, #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. */ diff --git a/lib/vlog.man b/lib/vlog.man index 39edaeeac..f675a4b3e 100644 --- a/lib/vlog.man +++ b/lib/vlog.man @@ -60,3 +60,8 @@ Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Refer to 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. diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4 index 7c3798568..e7281add1 100644 --- a/m4/openvswitch.m4 +++ b/m4/openvswitch.m4 @@ -118,7 +118,7 @@ OpenFlow connections over SSL will not be supported. 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], @@ -432,6 +432,12 @@ static thread_local int var;], [return var;])], 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. diff --git a/ofproto/automake.mk b/ofproto/automake.mk index 432f08371..218a5b123 100644 --- a/ofproto/automake.mk +++ b/ofproto/automake.mk @@ -7,6 +7,8 @@ noinst_LIBRARIES += ofproto/libofproto.a ofproto_libofproto_a_SOURCES = \ + ofproto/bond.c \ + ofproto/bond.h \ ofproto/collectors.c \ ofproto/collectors.h \ ofproto/connmgr.c \ diff --git a/lib/bond.c b/ofproto/bond.c similarity index 100% rename from lib/bond.c rename to ofproto/bond.c diff --git a/lib/bond.h b/ofproto/bond.h similarity index 100% rename from lib/bond.h rename to ofproto/bond.h diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index a331c0b17..b0f61ca12 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1718,6 +1718,9 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, 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; @@ -1868,10 +1871,10 @@ xlate_table_action(struct xlate_ctx *ctx, /* 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, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7df04501f..5e0a7f0aa 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -213,7 +213,8 @@ struct subfacet { #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); @@ -3222,13 +3223,32 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, { 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 @@ -3240,7 +3260,13 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, 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; @@ -4247,6 +4273,9 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow, 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); @@ -4382,37 +4411,20 @@ subfacet_find(struct dpif_backer *backer, const struct nlattr *key, 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); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index c4ce8a2b9..b282abee4 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -738,7 +738,7 @@ ofproto_set_n_handler_threads(unsigned limit) 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; } } diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index 6ce08aff9..5384c32be 100644 --- a/rhel/openvswitch-fedora.spec.in +++ b/rhel/openvswitch-fedora.spec.in @@ -105,42 +105,42 @@ systemctl start openvswitch.service %{_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 diff --git a/tests/bfd.at b/tests/bfd.at index 15d2b1a33..ccb62b54e 100644 --- a/tests/bfd.at +++ b/tests/bfd.at @@ -476,8 +476,14 @@ OVS_VSWITCHD_STOP 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 -- \ @@ -503,22 +509,6 @@ do 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 @@ -528,8 +518,6 @@ 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]) @@ -541,8 +529,12 @@ BFD_CHECK_RX([p0], [500ms], [500ms], [1ms]) 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 -- \ @@ -587,22 +579,10 @@ done 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]) @@ -616,8 +596,10 @@ BFD_CHECK_RX([p0], [500ms], [500ms], [300ms]) 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 -- \ @@ -652,6 +634,7 @@ BFD_CHECK_RX([p0], [500ms], [300ms], [500ms]) # 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]) @@ -679,23 +662,16 @@ do 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]) @@ -710,6 +686,10 @@ AT_CHECK([ovs-vsctl del-br br1], [0], [ignore]) 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 -- \ @@ -736,7 +716,7 @@ BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"] # 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"]) @@ -744,7 +724,7 @@ AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwardi # 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"]) @@ -756,7 +736,7 @@ OK # 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"]) @@ -764,7 +744,7 @@ AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwardi # 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"]) @@ -775,9 +755,9 @@ OK # 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"]) @@ -824,7 +804,7 @@ BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["8"] # 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"]) diff --git a/tests/library.at b/tests/library.at index 6e28573ea..57cdd6c0d 100644 --- a/tests/library.at +++ b/tests/library.at @@ -112,6 +112,7 @@ AT_CLEANUP m4_foreach( [testname], [[ctz], + [clz], [round_up_pow2], [round_down_pow2], [count_1bits], diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 82e8c3d17..2f09c1b8b 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -469,6 +469,21 @@ tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:0 ]) 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 "\ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index b78e15653..4d8d4602d 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -252,15 +252,15 @@ table=0 in_port=1 action=dec_ttl,output:2,resubmit(1,1),output:4 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], @@ -269,11 +269,11 @@ 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 @@ -481,27 +481,27 @@ dnl Modified VLAN 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: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 @@ -521,20 +521,20 @@ 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=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. @@ -562,7 +562,7 @@ 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 @@ -582,7 +582,7 @@ 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: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 @@ -602,7 +602,7 @@ 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: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 @@ -622,7 +622,7 @@ 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: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 @@ -642,7 +642,7 @@ 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: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 @@ -689,13 +689,13 @@ 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 ]) @@ -1924,7 +1924,7 @@ HEADER 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/ /\ @@ -1961,7 +1961,7 @@ IFCOUNTERS ifspeed=100000000 direction=0 status=0 - in_octets=98 + in_octets=138 in_unicasts=3 in_multicasts=0 in_broadcasts=4294967295 @@ -2030,7 +2030,7 @@ IFCOUNTERS ifspeed=100000000 direction=0 status=0 - in_octets=98 + in_octets=138 in_unicasts=3 in_multicasts=0 in_broadcasts=4294967295 diff --git a/tests/ofproto.at b/tests/ofproto.at index 27b6b34c4..be7387d33 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -1757,6 +1757,39 @@ OFPT_BARRIER_REPLY (OF1.2): 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)]) diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 34345928a..6e6461b86 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -2470,23 +2470,27 @@ AT_SETUP([tcp flags - filtering]) 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 diff --git a/tests/test-util.c b/tests/test-util.c index 7183f46d9..9152562cb 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -61,11 +61,11 @@ test_log_2_floor(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) } 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(); } } @@ -87,13 +87,13 @@ test_ctz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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); } @@ -109,10 +109,62 @@ test_ctz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) } /* 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) @@ -964,6 +1016,7 @@ test_ovs_scan(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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}, diff --git a/utilities/ovs-appctl.8.in b/utilities/ovs-appctl.8.in index 1cf888d38..e381b2b4d 100644 --- a/utilities/ovs-appctl.8.in +++ b/utilities/ovs-appctl.8.in @@ -148,6 +148,9 @@ expanded as follows: .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. @@ -173,6 +176,9 @@ takes the same format as the \fItemplate\fR argument to \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. . diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index e5e488abd..6f2382bdb 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -728,33 +728,41 @@ above, the bitwise match forms apply only when \fBdl_type\fR and \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. diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 6ce7d2b33..c2307be1d 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -21,7 +21,6 @@ #include "async-append.h" #include "bfd.h" #include "bitmap.h" -#include "bond.h" #include "cfm.h" #include "coverage.h" #include "daemon.h" @@ -39,6 +38,7 @@ #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" @@ -3594,10 +3594,9 @@ iface_set_mac(struct iface *iface) 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); } } diff --git a/vswitchd/system-stats.c b/vswitchd/system-stats.c index 2960b87e4..1d9cb78ed 100644 --- a/vswitchd/system-stats.c +++ b/vswitchd/system-stats.c @@ -59,7 +59,7 @@ VLOG_DEFINE_THIS_MODULE(system_stats); 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); }