Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sat, 6 Jul 2013 17:00:44 +0000 (19:00 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sat, 6 Jul 2013 17:00:44 +0000 (19:00 +0200)
21 files changed:
Makefile.am
OPENFLOW-1.1+
build-aux/thread-safety-blacklist [new file with mode: 0644]
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/linux/compat/include/linux/kernel.h
datapath/linux/compat/include/net/gre.h
datapath/tunnel.c
lib/flow.c
lib/netdev-bsd.c
lib/odp-util.c
lib/random.c
lib/vconn.c
ofproto/ofproto-dpif.c
tests/ofproto.at
tests/test-atomic.c
tests/test-classifier.c
tests/test-hindex.c
tests/test-hmap.c
tests/test-util.c

index eed5a74..4c58b93 100644 (file)
@@ -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)
index fb39873..d08a46e 100644 (file)
@@ -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 (file)
index 0000000..42560df
--- /dev/null
@@ -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(
index 3680391..2f02f71 100644 (file)
@@ -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;
 }
 
index 559df69..d14a162 100644 (file)
@@ -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 */
index 2ac36b6..c76c18d 100644 (file)
@@ -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;
index 2fa5cc8..fdd2005 100644 (file)
 #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
index 139e4ab..bd0c3d4 100644 (file)
@@ -4,10 +4,10 @@
 #include <linux/skbuff.h>
 #include <net/ip_tunnels.h>
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
 #include_next <net/gre.h>
 
-#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
index 9102786..ef46a69 100644 (file)
@@ -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;
index 1a5084b..d899d26 100644 (file)
@@ -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);
         }
index f2cf852..401d03a 100644 (file)
@@ -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;
     }
index 14994a9..b233cbe 100644 (file)
@@ -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;
     }
index 45d428c..da29fd0 100644 (file)
@@ -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 <sys/time.h>
 
 #include "entropy.h"
+#include "hash.h"
+#include "ovs-thread.h"
 #include "timeval.h"
 #include "util.h"
 
  * 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;
 }
index 449a36e..15ac119 100644 (file)
@@ -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);
index 5ca16b7..2d42c83 100644 (file)
@@ -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);
 }
 \f
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
index b3823a3..53d5cad 100644 (file)
@@ -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
index 27bf552..21d8c9e 100644 (file)
@@ -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);                         \
         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
index 601aaf8..7fb1447 100644 (file)
@@ -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
index b5fe9f0..7a3ef72 100644 (file)
@@ -21,6 +21,7 @@
 #include "hindex.h"
 #include <string.h>
 #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;
index c202eae..6102be3 100644 (file)
@@ -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 <string.h>
 #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;
index 3422af3..5afe2f7 100644 (file)
@@ -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;