From: Giuseppe Lettieri Date: Sat, 6 Jul 2013 17:00:44 +0000 (+0200) Subject: Merge branch 'mainstream' X-Git-Tag: sliver-openvswitch-1.10.90-3~4 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=a12945b3b8cd4d483e5e8f2a1adb6576badf1d4d;hp=f567ab92db2443285842cc3c8d91fdd37c986637;p=sliver-openvswitch.git Merge branch 'mainstream' --- diff --git a/Makefile.am b/Makefile.am index eed5a74d8..4c58b93c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -211,6 +211,20 @@ check-assert-h-usage: fi .PHONY: check-assert-h-usage +ALL_LOCAL += thread-safety-check +thread-safety-check: + @if test -e '$(srcdir)'/.git && (git --version) >/dev/null 2>&1 && \ + grep -n -f '$(srcdir)'/build-aux/thread-safety-blacklist \ + `git ls-files '$(srcdir)' | grep '\.[ch]$$' \ + | $(EGREP) -v '^datapath|^lib/sflow|^third-party'` \ + | $(EGREP) -v ':[ ]*/?\*'; \ + then \ + echo "See above for list of calls to functions that are"; \ + echo "blacklisted due to thread safety issues"; \ + exit 1; \ + fi +EXTRA_DIST += build-aux/thread-safety-blacklist + if HAVE_GROFF ALL_LOCAL += manpage-check manpage-check: $(man_MANS) $(dist_man_MANS) $(noinst_man_MANS) diff --git a/OPENFLOW-1.1+ b/OPENFLOW-1.1+ index fb398730f..d08a46ee4 100644 --- a/OPENFLOW-1.1+ +++ b/OPENFLOW-1.1+ @@ -62,10 +62,6 @@ probably incomplete. so the value is not necessarily meaningful. We might have to just fix it as the same as in_port. - * On OF1.1+ flow_mods, updates by MODIFY are now much better - specified. Check that OVS implements the new behavior, fix it - if not. - * OFPT_TABLE_MOD stats. 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. @@ -94,16 +90,8 @@ end of the OF1.2 spec. I didn't compare the specs carefully yet.) * OFPT_FLOW_MOD: - * MODIFY and MODIFY_STRICT commands now never insert new flows - in the table. We will still need variations that do, - though, both to support older OpenFlow protocols and to get - sensible behavior for the internal implementation of the - NXAST_LEARN action. - * New flag OFPFF_RESET_COUNTS. - * New cookie field behavior. - * Add ability to delete flow in all tables. * Update DESIGN to describe OF1.2 behavior also. diff --git a/build-aux/thread-safety-blacklist b/build-aux/thread-safety-blacklist new file mode 100644 index 000000000..42560df9c --- /dev/null +++ b/build-aux/thread-safety-blacklist @@ -0,0 +1,90 @@ +\basctime( +\bbasename( +\bcatgets( +\bcrypt( +\bctermid( +\bctime( +\bdbm_clearerr( +\bdbm_close( +\bdbm_delete( +\bdbm_error( +\bdbm_fetch( +\bdbm_firstkey( +\bdbm_nextkey( +\bdbm_open( +\bdbm_store( +\bdirname( +\bdlerror( +\bdrand48( +\becvt( +\bencrypt( +\bendgrent( +\bendpwent( +\bendutxent( +\bfcvt( +\bftw( +\bgcvt( +\bgetc_unlocked( +\bgetchar_unlocked( +\bgetdate( +\bgetgrent( +\bgetgrgid( +\bgetgrnam( +\bgethostbyaddr( +\bgethostbyname( +\bgethostent( +\bgetlogin( +\bgetmntent( +\bgetnetbyaddr( +\bgetnetbyname( +\bgetnetent( +\bgetprotobyname( +\bgetprotobynumber( +\bgetprotoent( +\bgetpwent( +\bgetpwnam( +\bgetpwuid( +\bgetservbyname( +\bgetservbyport( +\bgetservent( +\bgetutxent( +\bgetutxid( +\bgetutxline( +\bgmtime( +\bhcreate( +\bhdestroy( +\bhsearch( +\binet_ntoa( +\bl64a( +\blgamma( +\blgammaf( +\blgammal( +\blocaleconv( +\blocaltime( +\blrand48( +\bmrand48( +\bnftw( +\bnl_langinfo( +\bptsname( +\bputc_unlocked( +\bputchar_unlocked( +\bputenv( +\bpututxline( +\brand( +\bsetenv( +\bsetgrent( +\bsetkey( +\bsetpwent( +\bsetutxent( +\bsigprocmask( +\bstrerror( +\bstrsignal( +\bstrtok( +\bsystem( +\btmpnam( +\bttyname( +\bunsetenv( +\bwcrtomb( +\bwcsrtombs( +\bwcstombs( +\bwctomb( diff --git a/datapath/datapath.c b/datapath/datapath.c index 3680391ce..2f02f71b6 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -1126,7 +1126,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, u32 seq, u32 flags, u8 cmd) { const int skb_orig_len = skb->len; - const struct sw_flow_actions *sf_acts; + struct sw_flow_mask *mask; struct nlattr *start; struct ovs_flow_stats stats; struct ovs_header *ovs_header; @@ -1135,8 +1135,6 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, u8 tcp_flags; int err; - sf_acts = ovsl_dereference(flow->sf_acts); - ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd); if (!ovs_header) return -EMSGSIZE; @@ -1158,8 +1156,8 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, if (!nla) goto nla_put_failure; - err = ovs_flow_to_nlattrs(&flow->key, - &ovsl_dereference(flow->mask)->key, skb); + mask = rcu_dereference_check(flow->mask, lockdep_ovsl_is_held()); + err = ovs_flow_to_nlattrs(&flow->key, &mask->key, skb); if (err) goto error; @@ -1197,6 +1195,11 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, */ start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS); if (start) { + const struct sw_flow_actions *sf_acts; + + sf_acts = rcu_dereference_check(flow->sf_acts, + lockdep_ovsl_is_held()); + err = actions_to_attr(sf_acts->actions, sf_acts->actions_len, skb); if (!err) nla_nest_end(skb, start); @@ -1358,8 +1361,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) /* The unmasked key has to be the same for flow updates. */ error = -EINVAL; - if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) + if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) { + OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n"); goto err_unlock_ovs; + } /* Update actions. */ old_acts = ovsl_dereference(flow->sf_acts); @@ -1407,8 +1412,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct sw_flow_match match; int err; - if (!a[OVS_FLOW_ATTR_KEY]) + if (!a[OVS_FLOW_ATTR_KEY]) { + OVS_NLERR("Flow get message rejected, Key attribute missing.\n"); return -EINVAL; + } ovs_match_init(&match, &key, NULL); err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL); @@ -1507,15 +1514,14 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) struct datapath *dp; struct flow_table *table; - ovs_lock(); + rcu_read_lock(); dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); if (!dp) { - ovs_unlock(); + rcu_read_unlock(); return -ENODEV; } - table = ovsl_dereference(dp->table); - + table = rcu_dereference(dp->table); for (;;) { struct sw_flow *flow; u32 bucket, obj; @@ -1535,7 +1541,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) cb->args[0] = bucket; cb->args[1] = obj; } - ovs_unlock(); + rcu_read_unlock(); return skb->len; } diff --git a/datapath/datapath.h b/datapath/datapath.h index 559df6954..d14a16214 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -204,4 +204,8 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 portid, u32 seq, int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb); void ovs_dp_notify_wq(struct work_struct *work); + +#define OVS_NLERR(fmt, ...) \ + pr_info_once(fmt "netlink: ", ##__VA_ARGS__) + #endif /* datapath.h */ diff --git a/datapath/flow.c b/datapath/flow.c index 2ac36b6fb..c76c18da3 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -205,13 +205,19 @@ static bool ovs_match_validate(const struct sw_flow_match *match, } } - if ((key_attrs & key_expected) != key_expected) + if ((key_attrs & key_expected) != key_expected) { /* Key attributes check failed. */ + OVS_NLERR("Missing expected key attributes (key_attrs=%llx, expected=%llx).\n", + key_attrs, key_expected); return false; + } - if ((mask_attrs & mask_allowed) != mask_attrs) + if ((mask_attrs & mask_allowed) != mask_attrs) { /* Mask attributes check failed. */ + OVS_NLERR("Contain more than allowed mask fields (mask_attrs=%llx, mask_allowed=%llx).\n", + mask_attrs, mask_allowed); return false; + } return true; } @@ -1126,24 +1132,33 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, u16 type = nla_type(nla); int expected_len; - if (type > OVS_KEY_ATTR_MAX || attrs & (1ULL << type)) - return -EINVAL; + if (type > OVS_KEY_ATTR_MAX) { + OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n", + type, OVS_KEY_ATTR_MAX); + } - expected_len = ovs_key_lens[type]; - if (nla_len(nla) != expected_len && expected_len != -1) + if (attrs & (1ULL << type)) { + OVS_NLERR("Duplicate key attribute (type %d).\n", type); return -EINVAL; + } - if (attrs & (1ULL << type)) - /* Duplicated field. */ + expected_len = ovs_key_lens[type]; + if (nla_len(nla) != expected_len && expected_len != -1) { + OVS_NLERR("Key attribute has unexpected length (type=%d" + ", length=%d, expected=%d).\n", type, + nla_len(nla), expected_len); return -EINVAL; + } if (!nz || !is_all_zero(nla_data(nla), expected_len)) { attrs |= 1ULL << type; a[type] = nla; } } - if (rem) + if (rem) { + OVS_NLERR("Message has %d unknown bytes.\n", rem); return -EINVAL; + } *attrsp = attrs; return 0; @@ -1181,9 +1196,18 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, }; - if (type > OVS_TUNNEL_KEY_ATTR_MAX || - ovs_tunnel_key_lens[type] != nla_len(a)) + if (type > OVS_TUNNEL_KEY_ATTR_MAX) { + OVS_NLERR("Unknown IPv4 tunnel attribute (type=%d, max=%d)\n", + type, OVS_TUNNEL_KEY_ATTR_MAX); + return -EINVAL; + } + + if (ovs_tunnel_key_lens[type] != nla_len(a)) { + OVS_NLERR("IPv4 tunnel attribute type has unexpected " + " legnth (type=%d, length=%d, expected=%d.)\n", + type, nla_len(a), ovs_tunnel_key_lens[type]); return -EINVAL; + } switch (type) { case OVS_TUNNEL_KEY_ATTR_ID: @@ -1221,14 +1245,20 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask); - if (rem > 0) + if (rem > 0) { + OVS_NLERR("IPv4 tunnel attribute has %d unknown bytes.\n", rem); return -EINVAL; + } - if (!match->key->tun_key.ipv4_dst) + if (!match->key->tun_key.ipv4_dst) { + OVS_NLERR("IPv4 tunnel destination address is zero.\n"); return -EINVAL; + } - if (!ttl) + if (!ttl) { + OVS_NLERR("IPv4 tunnel TTL is zero.\n"); return -EINVAL; + } return 0; } @@ -1289,8 +1319,10 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, if (*attrs & (1ULL << OVS_KEY_ATTR_SKB_MARK)) { uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER) - if (!is_mask && mark != 0) + if (!is_mask && mark != 0) { + OVS_NLERR("skb->mark must be zero on this kernel (mark=%d).\n", mark); return -EINVAL; + } #endif SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK); @@ -1330,8 +1362,10 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); if (!is_mask) - if (!(tci & htons(VLAN_TAG_PRESENT))) + if (!(tci & htons(VLAN_TAG_PRESENT))) { + OVS_NLERR("VLAN TCI does not have VLAN_TAG_PRESENT bit set.\n"); return -EINVAL; + } SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask); attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN); @@ -1341,8 +1375,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, __be16 eth_type; eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); - if (!is_mask && ntohs(eth_type) < ETH_P_802_3_MIN) + if (!is_mask && ntohs(eth_type) < ETH_P_802_3_MIN) { + OVS_NLERR("EtherType is less than mimimum (type=%x, min=%x).\n", + ntohs(eth_type), ETH_P_802_3_MIN); return -EINVAL; + } SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask); attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); @@ -1354,8 +1391,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_ipv4 *ipv4_key; ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); - if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) + if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) { + OVS_NLERR("Unknown IPv4 fragment type (value=%d, max=%d).\n", + ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ip.proto, ipv4_key->ipv4_proto, is_mask); SW_FLOW_KEY_PUT(match, ip.tos, @@ -1375,8 +1415,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_ipv6 *ipv6_key; ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); - if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) + if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) { + OVS_NLERR("Unknown IPv6 fragment type (value=%d, max=%d).\n", + ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ipv6.label, ipv6_key->ipv6_label, is_mask); SW_FLOW_KEY_PUT(match, ip.proto, @@ -1403,8 +1446,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_arp *arp_key; arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); - if (!is_mask && (arp_key->arp_op & htons(0xff00))) + if (!is_mask && (arp_key->arp_op & htons(0xff00))) { + OVS_NLERR("Unknown ARP opcode (opcode=%d).\n", + arp_key->arp_op); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ipv4.addr.src, arp_key->arp_sip, is_mask); @@ -1539,8 +1585,10 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match, encap_valid = true; key_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); err = parse_flow_nlattrs(encap, a, &key_attrs); - } else + } else { + OVS_NLERR("Encap attribute is set for a non-VLAN frame.\n"); err = -EINVAL; + } if (err) return err; @@ -1566,8 +1614,12 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match, mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); encap = a[OVS_KEY_ATTR_ENCAP]; err = parse_flow_mask_nlattrs(encap, a, &mask_attrs); - } else + } else { + OVS_NLERR("VLAN frames must have an exact match" + " on the TPID (mask=%x).\n", + ntohs(eth_type)); err = -EINVAL; + } if (err) return err; diff --git a/datapath/linux/compat/include/linux/kernel.h b/datapath/linux/compat/include/linux/kernel.h index 2fa5cc811..fdd20058c 100644 --- a/datapath/linux/compat/include/linux/kernel.h +++ b/datapath/linux/compat/include/linux/kernel.h @@ -39,6 +39,40 @@ #define pr_warn pr_warning #endif +/* + * Print a one-time message (analogous to WARN_ONCE() et al): + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) +#undef printk_once +#define printk_once(fmt, ...) \ +({ \ + static bool __print_once; \ + \ + if (!__print_once) { \ + __print_once = true; \ + printk(fmt, ##__VA_ARGS__); \ + } \ +}) + +#define pr_emerg_once(fmt, ...) \ + printk_once(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) +#define pr_alert_once(fmt, ...) \ + printk_once(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) +#define pr_crit_once(fmt, ...) \ + printk_once(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) +#define pr_err_once(fmt, ...) \ + printk_once(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) +#define pr_warn_once(fmt, ...) \ + printk_once(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) +#define pr_notice_once(fmt, ...) \ + printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) +#define pr_info_once(fmt, ...) \ + printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) +#define pr_cont_once(fmt, ...) \ + printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__) + +#endif + #if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) #error "CONFIG_PREEMPT is broken before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\"" #endif diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index 139e4ab0d..bd0c3d42c 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -4,10 +4,10 @@ #include #include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) #include_next -#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) */ +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) */ #define GREPROTO_CISCO 0 #define GREPROTO_MAX 2 diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 910278686..ef46a69de 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -186,7 +186,9 @@ u16 ovs_tnl_get_src_port(struct sk_buff *skb) int low; int high; unsigned int range; - u32 hash = OVS_CB(skb)->flow->hash; + struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key; + u32 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/lib/flow.c b/lib/flow.c index 1a5084b60..d899d260d 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -795,7 +795,7 @@ flow_mask_hash_fields(const struct flow *flow, struct flow_wildcards *wc, if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); - } else { + } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src); memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst); } diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index f2cf852d8..401d03a5d 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -197,7 +197,7 @@ netdev_bsd_init(void) af_link_sock = socket(AF_LINK, SOCK_DGRAM, 0); status = af_link_sock >= 0 ? 0 : errno; if (status) { - VLOG_ERR("failed to create link socket: %s", Ovs_strerror(status)); + VLOG_ERR("failed to create link socket: %s", ovs_strerror(status)); close(af_inet_sock); af_inet_sock = -1; } diff --git a/lib/odp-util.c b/lib/odp-util.c index 14994a911..b233cbe18 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1058,7 +1058,7 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, ovs_be16 vlan_tci = nl_attr_get_be16(a); if (!is_exact) { ovs_be16 mask = nl_attr_get_be16(ma); - ds_put_format(ds, "vid=%"PRIu16"/%"PRIx16",pcp=%d/0x%x,cfi=%d/%d", + ds_put_format(ds, "vid=%"PRIu16"/0x%"PRIx16",pcp=%d/0x%x,cfi=%d/%d", vlan_tci_to_vid(vlan_tci), vlan_tci_to_vid(mask), vlan_tci_to_pcp(vlan_tci), @@ -2373,7 +2373,7 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data, * 802.3 SNAP packet with valid eth_type). */ if (is_mask) { - nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, data->dl_type); + nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(UINT16_MAX)); } goto unencap; } diff --git a/lib/random.c b/lib/random.c index 45d428c6b..da29fd0cf 100644 --- a/lib/random.c +++ b/lib/random.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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. @@ -22,6 +22,8 @@ #include #include "entropy.h" +#include "hash.h" +#include "ovs-thread.h" #include "timeval.h" #include "util.h" @@ -37,21 +39,25 @@ * cryptographic-quality randomness. */ /* Current random state. */ -static uint32_t seed; +DEFINE_PER_THREAD_DATA(uint32_t, seed, 0); static uint32_t random_next(void); void random_init(void) { - while (!seed) { + uint32_t *seedp = seed_get(); + while (!*seedp) { struct timeval tv; uint32_t entropy; + pthread_t self; xgettimeofday(&tv); get_entropy_or_die(&entropy, 4); + self = pthread_self(); - seed = tv.tv_sec ^ tv.tv_usec ^ entropy; + *seedp = (tv.tv_sec ^ tv.tv_usec ^ entropy + ^ hash_bytes(&self, sizeof self, 0)); } } @@ -59,7 +65,7 @@ void random_set_seed(uint32_t seed_) { ovs_assert(seed_); - seed = seed_; + *seed_get() = seed_; } void @@ -120,9 +126,11 @@ random_range(int max) static uint32_t random_next(void) { - seed ^= seed << 13; - seed ^= seed >> 17; - seed ^= seed << 5; + uint32_t *seedp = seed_get_unsafe(); - return seed; + *seedp ^= *seedp << 13; + *seedp ^= *seedp >> 17; + *seedp ^= *seedp << 5; + + return *seedp; } diff --git a/lib/vconn.c b/lib/vconn.c index 449a36e90..15ac11909 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -461,7 +461,7 @@ version_bitmap_to_string(uint32_t bitmap) } else if (is_pow2((bitmap >> 1) + 1)) { ds_put_cstr(&s, "version "); ofputil_format_version(&s, leftmost_1bit_idx(bitmap)); - ds_put_cstr(&s, "and earlier"); + ds_put_cstr(&s, " and earlier"); } else { ds_put_cstr(&s, "versions "); ofputil_format_version_bitmap(&s, bitmap); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 5ca16b7f0..2d42c83b2 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -404,6 +404,10 @@ static void update_moving_averages(struct dpif_backer *backer); * for debugging the asynchronous flow_mod implementation.) */ static bool clogged; +/* By default, flows in the datapath are wildcarded (megaflows). They + * may be disabled with the "ovs-appctl dpif/disable-megaflows" command. */ +static bool enable_megaflows = true; + /* All existing ofproto_dpif instances, indexed by ->up.name. */ static struct hmap all_ofproto_dpifs = HMAP_INITIALIZER(&all_ofproto_dpifs); @@ -3476,8 +3480,10 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, subfacet->path = want_path; ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf); - odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks, - &miss->flow, UINT32_MAX); + if (enable_megaflows) { + odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks, + &miss->flow, UINT32_MAX); + } op->xout_garbage = false; op->dpif_op.type = DPIF_OP_FLOW_PUT; @@ -5064,8 +5070,10 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions, } ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf); - odp_flow_key_from_mask(&mask, &facet->xout.wc.masks, - &facet->flow, UINT32_MAX); + if (enable_megaflows) { + odp_flow_key_from_mask(&mask, &facet->xout.wc.masks, + &facet->flow, UINT32_MAX); + } ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key, subfacet->key_len, mask.data, mask.size, @@ -6388,6 +6396,48 @@ ofproto_unixctl_dpif_dump_megaflows(struct unixctl_conn *conn, ds_destroy(&ds); } +/* Disable using the megaflows. + * + * This command is only needed for advanced debugging, so it's not + * documented in the man page. */ +static void +ofproto_unixctl_dpif_disable_megaflows(struct unixctl_conn *conn, + int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, + void *aux OVS_UNUSED) +{ + struct ofproto_dpif *ofproto; + + enable_megaflows = false; + + HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) { + flush(&ofproto->up); + } + + unixctl_command_reply(conn, "megaflows disabled"); +} + +/* Re-enable using megaflows. + * + * This command is only needed for advanced debugging, so it's not + * documented in the man page. */ +static void +ofproto_unixctl_dpif_enable_megaflows(struct unixctl_conn *conn, + int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, + void *aux OVS_UNUSED) +{ + struct ofproto_dpif *ofproto; + + enable_megaflows = true; + + HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) { + flush(&ofproto->up); + } + + unixctl_command_reply(conn, "megaflows enabled"); +} + static void ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], @@ -6501,6 +6551,10 @@ ofproto_dpif_unixctl_init(void) ofproto_unixctl_dpif_del_flows, NULL); unixctl_command_register("dpif/dump-megaflows", "bridge", 1, 1, ofproto_unixctl_dpif_dump_megaflows, NULL); + unixctl_command_register("dpif/disable-megaflows", "", 0, 0, + ofproto_unixctl_dpif_disable_megaflows, NULL); + unixctl_command_register("dpif/enable-megaflows", "", 0, 0, + ofproto_unixctl_dpif_enable_megaflows, NULL); } /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) diff --git a/tests/ofproto.at b/tests/ofproto.at index b3823a37c..53d5cad4c 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -340,7 +340,7 @@ OVS_VSWITCHD_STOP AT_CLEANUP dnl The OpenFlow 1.2 spec states that the cookie may not be modified -AT_SETUP([ofproto - no mod flow with cookie change (OpenFlow1.2)]) +AT_SETUP([ofproto - no mod flow with cookie change (OpenFlow 1.2)]) OVS_VSWITCHD_START AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=1,actions=1]) AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl diff --git a/tests/test-atomic.c b/tests/test-atomic.c index 27bf5520e..21d8c9e11 100644 --- a/tests/test-atomic.c +++ b/tests/test-atomic.c @@ -22,7 +22,7 @@ #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE) \ { \ ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \ - BASE_TYPE value, orig; \ + BASE_TYPE value; \ \ atomic_read(&x, &value); \ ovs_assert(value == 1); \ @@ -34,31 +34,6 @@ atomic_init(&x, 3); \ atomic_read(&x, &value); \ ovs_assert(value == 3); \ - \ - atomic_add(&x, 1, &orig); \ - ovs_assert(orig == 3); \ - atomic_read(&x, &value); \ - ovs_assert(value == 4); \ - \ - atomic_sub(&x, 2, &orig); \ - ovs_assert(orig == 4); \ - atomic_read(&x, &value); \ - ovs_assert(value == 2); \ - \ - atomic_or(&x, 6, &orig); \ - ovs_assert(orig == 2); \ - atomic_read(&x, &value); \ - ovs_assert(value == 6); \ - \ - atomic_and(&x, 10, &orig); \ - ovs_assert(orig == 6); \ - atomic_read(&x, &value); \ - ovs_assert(value == 2); \ - \ - atomic_xor(&x, 10, &orig); \ - ovs_assert(orig == 2); \ - atomic_read(&x, &value); \ - ovs_assert(value == 8); \ } int diff --git a/tests/test-classifier.c b/tests/test-classifier.c index 601aaf87e..7fb1447c8 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 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. @@ -34,6 +34,7 @@ #include "flow.h" #include "ofp-util.h" #include "packets.h" +#include "random.h" #include "unaligned.h" #undef NDEBUG @@ -405,7 +406,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls) struct flow flow; unsigned int x; - x = rand () % N_FLOW_VALUES; + x = random_range(N_FLOW_VALUES); memset(&flow, 0, sizeof flow); flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)]; flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)]; @@ -581,7 +582,7 @@ static void shuffle(unsigned int *p, size_t n) { for (; n > 1; n--, p++) { - unsigned int *q = &p[rand() % n]; + unsigned int *q = &p[random_range(n)]; unsigned int tmp = *p; *p = *q; *q = tmp; @@ -592,7 +593,7 @@ static void shuffle_u32s(uint32_t *p, size_t n) { for (; n > 1; n--, p++) { - uint32_t *q = &p[rand() % n]; + uint32_t *q = &p[random_range(n)]; uint32_t tmp = *p; *p = *q; *q = tmp; @@ -881,7 +882,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) int i; do { - wcf = rand() & ((1u << CLS_N_FIELDS) - 1); + wcf = random_uint32() & ((1u << CLS_N_FIELDS) - 1); value_mask = ~wcf & ((1u << CLS_N_FIELDS) - 1); } while ((1 << count_ones(value_mask)) < N_RULES); @@ -889,10 +890,10 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) tcls_init(&tcls); for (i = 0; i < N_RULES; i++) { - unsigned int priority = rand(); + unsigned int priority = random_uint32(); do { - value_pats[i] = rand() & value_mask; + value_pats[i] = random_uint32() & value_mask; } while (array_contains(value_pats, i, value_pats[i])); rules[i] = make_rule(wcf, priority, value_pats[i]); @@ -930,7 +931,7 @@ test_many_rules_in_n_tables(int n_tables) assert(n_tables < 10); for (i = 0; i < n_tables; i++) { do { - wcfs[i] = rand() & ((1u << CLS_N_FIELDS) - 1); + wcfs[i] = random_uint32() & ((1u << CLS_N_FIELDS) - 1); } while (array_contains(wcfs, i, wcfs[i])); } @@ -939,7 +940,7 @@ test_many_rules_in_n_tables(int n_tables) struct classifier cls; struct tcls tcls; - srand(iteration); + random_set_seed(iteration + 1); for (i = 0; i < MAX_RULES; i++) { priorities[i] = i * 129; } @@ -951,8 +952,8 @@ test_many_rules_in_n_tables(int n_tables) for (i = 0; i < MAX_RULES; i++) { struct test_rule *rule; unsigned int priority = priorities[i]; - int wcf = wcfs[rand() % n_tables]; - int value_pat = rand() & ((1u << CLS_N_FIELDS) - 1); + int wcf = wcfs[random_range(n_tables)]; + int value_pat = random_uint32() & ((1u << CLS_N_FIELDS) - 1); rule = make_rule(wcf, priority, value_pat); tcls_insert(&tcls, rule); classifier_insert(&cls, &rule->cls_rule); @@ -965,7 +966,7 @@ test_many_rules_in_n_tables(int n_tables) struct test_rule *target; struct cls_cursor cursor; - target = clone_rule(tcls.rules[rand() % tcls.n_rules]); + target = clone_rule(tcls.rules[random_range(tcls.n_rules)]); cls_cursor_init(&cursor, &cls, &target->cls_rule); CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cls_rule, &cursor) { @@ -1004,7 +1005,7 @@ random_value(void) { 0xffffffff, 0xaaaaaaaa, 0x55555555, 0x80000000, 0x00000001, 0xface0000, 0x00d00d1e, 0xdeadbeef }; - return values[random_uint32() % ARRAY_SIZE(values)]; + return values[random_range(ARRAY_SIZE(values))]; } static bool diff --git a/tests/test-hindex.c b/tests/test-hindex.c index b5fe9f014..7a3ef7212 100644 --- a/tests/test-hindex.c +++ b/tests/test-hindex.c @@ -21,6 +21,7 @@ #include "hindex.h" #include #include "hash.h" +#include "random.h" #include "util.h" #undef NDEBUG @@ -108,7 +109,7 @@ static void shuffle(int *p, size_t n) { for (; n > 1; n--, p++) { - int *q = &p[rand() % n]; + int *q = &p[random_range(n)]; int tmp = *p; *p = *q; *q = tmp; diff --git a/tests/test-hmap.c b/tests/test-hmap.c index c202eae14..6102be332 100644 --- a/tests/test-hmap.c +++ b/tests/test-hmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 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. @@ -21,6 +21,7 @@ #include "hmap.h" #include #include "hash.h" +#include "random.h" #include "util.h" #undef NDEBUG @@ -108,7 +109,7 @@ static void shuffle(int *p, size_t n) { for (; n > 1; n--, p++) { - int *q = &p[rand() % n]; + int *q = &p[random_range(n)]; int tmp = *p; *p = *q; *q = tmp; diff --git a/tests/test-util.c b/tests/test-util.c index 3422af3a2..5afe2f7c5 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012 Nicira, Inc. + * Copyright (c) 2011, 2012, 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. @@ -94,7 +94,7 @@ static void shuffle(unsigned int *p, size_t n) { for (; n > 1; n--, p++) { - unsigned int *q = &p[rand() % n]; + unsigned int *q = &p[random_range(n)]; unsigned int tmp = *p; *p = *q; *q = tmp; @@ -297,7 +297,7 @@ test_bitwise_is_all_zeros(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Change a random 0-bit into a 1-bit. */ do { - bit = htonll(UINT64_C(1) << (random_uint32() % 64)); + bit = htonll(UINT64_C(1) << (random_range(64))); } while (x & bit); x |= bit;