diff --git a/0001-openvswitch-merge-compiler.h-files-into-one-file.patch b/0001-openvswitch-merge-compiler.h-files-into-one-file.patch index 7343ee9..a172538 100644 --- a/0001-openvswitch-merge-compiler.h-files-into-one-file.patch +++ b/0001-openvswitch-merge-compiler.h-files-into-one-file.patch @@ -82,10 +82,10 @@ Signed-off-by: Ferdinand Thiessen 74 files changed, 108 insertions(+), 141 deletions(-) delete mode 100644 lib/compiler.h -diff --git a/include/openvswitch/compiler.h b/include/openvswitch/compiler.h -index cf009f826..ed155c766 100644 ---- a/include/openvswitch/compiler.h -+++ b/include/openvswitch/compiler.h +Index: openvswitch-2.17.2/include/openvswitch/compiler.h +=================================================================== +--- openvswitch-2.17.2.orig/include/openvswitch/compiler.h ++++ openvswitch-2.17.2/include/openvswitch/compiler.h @@ -27,6 +27,16 @@ #define __has_extension(x) 0 #endif @@ -121,10 +121,10 @@ index cf009f826..ed155c766 100644 #endif #if __has_feature(c_thread_safety_attributes) -diff --git a/lib/bundle.h b/lib/bundle.h -index b3b9cdcee..73e9f86bd 100644 ---- a/lib/bundle.h -+++ b/lib/bundle.h +Index: openvswitch-2.17.2/lib/bundle.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/bundle.h ++++ openvswitch-2.17.2/lib/bundle.h @@ -23,7 +23,7 @@ #include #include @@ -134,10 +134,10 @@ index b3b9cdcee..73e9f86bd 100644 #include "openflow/nicira-ext.h" #include "openvswitch/ofp-errors.h" #include "openvswitch/types.h" -diff --git a/lib/command-line.h b/lib/command-line.h -index fc2a2690f..957a53fc8 100644 ---- a/lib/command-line.h -+++ b/lib/command-line.h +Index: openvswitch-2.17.2/lib/command-line.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/command-line.h ++++ openvswitch-2.17.2/lib/command-line.h @@ -19,7 +19,7 @@ /* Utilities for command-line parsing. */ @@ -147,10 +147,9 @@ index fc2a2690f..957a53fc8 100644 struct option; -diff --git a/lib/compiler.h b/lib/compiler.h -deleted file mode 100644 -index 03af47a03..000000000 ---- a/lib/compiler.h +Index: openvswitch-2.17.2/lib/compiler.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/compiler.h +++ /dev/null @@ -1,44 +0,0 @@ -/* @@ -197,10 +196,10 @@ index 03af47a03..000000000 -#endif - -#endif /* compiler.h */ -diff --git a/lib/coverage.h b/lib/coverage.h -index dea990e6f..8eb5a1e12 100644 ---- a/lib/coverage.h -+++ b/lib/coverage.h +Index: openvswitch-2.17.2/lib/coverage.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/coverage.h ++++ openvswitch-2.17.2/lib/coverage.h @@ -28,7 +28,7 @@ * a useful debugging tool. */ @@ -210,10 +209,10 @@ index dea990e6f..8eb5a1e12 100644 /* Makes coverage_run run every 5000 ms (5 seconds). * If this value is redefined, the new value must -diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c -index 707456158..0c459156f 100644 ---- a/lib/db-ctl-base.c -+++ b/lib/db-ctl-base.c +Index: openvswitch-2.17.2/lib/db-ctl-base.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/db-ctl-base.c ++++ openvswitch-2.17.2/lib/db-ctl-base.c @@ -22,8 +22,7 @@ #include "db-ctl-base.h" @@ -224,10 +223,10 @@ index 707456158..0c459156f 100644 #include "dirs.h" #include "openvswitch/dynamic-string.h" #include "fatal-signal.h" -diff --git a/lib/db-ctl-base.h b/lib/db-ctl-base.h -index 284b573d0..1cea6559b 100644 ---- a/lib/db-ctl-base.h -+++ b/lib/db-ctl-base.h +Index: openvswitch-2.17.2/lib/db-ctl-base.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/db-ctl-base.h ++++ openvswitch-2.17.2/lib/db-ctl-base.h @@ -17,7 +17,7 @@ #ifndef DB_CTL_BASE_H #define DB_CTL_BASE_H 1 @@ -237,10 +236,10 @@ index 284b573d0..1cea6559b 100644 #include "openvswitch/dynamic-string.h" #include "openvswitch/shash.h" -diff --git a/lib/dns-resolve-stub.c b/lib/dns-resolve-stub.c -index 859c76f6b..b54581d8b 100644 ---- a/lib/dns-resolve-stub.c -+++ b/lib/dns-resolve-stub.c +Index: openvswitch-2.17.2/lib/dns-resolve-stub.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dns-resolve-stub.c ++++ openvswitch-2.17.2/lib/dns-resolve-stub.c @@ -16,7 +16,7 @@ #include @@ -250,10 +249,10 @@ index 859c76f6b..b54581d8b 100644 void dns_resolve_init(bool is_daemon OVS_UNUSED) -diff --git a/lib/dpctl.c b/lib/dpctl.c -index 29041fa3e..81cbe3730 100644 ---- a/lib/dpctl.c -+++ b/lib/dpctl.c +Index: openvswitch-2.17.2/lib/dpctl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpctl.c ++++ openvswitch-2.17.2/lib/dpctl.c @@ -27,8 +27,7 @@ #include #include @@ -264,10 +263,10 @@ index 29041fa3e..81cbe3730 100644 #include "ct-dpif.h" #include "dirs.h" #include "dpctl.h" -diff --git a/lib/dpctl.h b/lib/dpctl.h -index 9d0052152..557f32936 100644 ---- a/lib/dpctl.h -+++ b/lib/dpctl.h +Index: openvswitch-2.17.2/lib/dpctl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpctl.h ++++ openvswitch-2.17.2/lib/dpctl.h @@ -18,7 +18,7 @@ #include @@ -277,11 +276,11 @@ index 9d0052152..557f32936 100644 struct dpctl_params { /* True if it is called by ovs-appctl command. */ -diff --git a/lib/dpif-netdev-extract-avx512.c b/lib/dpif-netdev-extract-avx512.c -index c1c1fefb6..b8bb4f38d 100644 ---- a/lib/dpif-netdev-extract-avx512.c -+++ b/lib/dpif-netdev-extract-avx512.c -@@ -468,12 +468,12 @@ mfex_handle_tcp_flags(const struct tcp_header *tcp, uint64_t *block) +Index: openvswitch-2.17.2/lib/dpif-netdev-extract-avx512.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-extract-avx512.c ++++ openvswitch-2.17.2/lib/dpif-netdev-extract-avx512.c +@@ -468,12 +468,12 @@ mfex_handle_tcp_flags(const struct tcp_h } /* Generic loop to process any mfex profile. This code is specialized into @@ -296,11 +295,11 @@ index c1c1fefb6..b8bb4f38d 100644 __attribute__ ((hot)) mfex_avx512_process(struct dp_packet_batch *packets, struct netdev_flow_key *keys, -diff --git a/lib/dpif-netdev-lookup-avx512-gather.c b/lib/dpif-netdev-lookup-avx512-gather.c -index 7bc1e9e9a..6e50f6ecd 100644 ---- a/lib/dpif-netdev-lookup-avx512-gather.c -+++ b/lib/dpif-netdev-lookup-avx512-gather.c -@@ -152,7 +152,7 @@ netdev_rule_matches_key(const struct dpcls_rule *rule, +Index: openvswitch-2.17.2/lib/dpif-netdev-lookup-avx512-gather.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-lookup-avx512-gather.c ++++ openvswitch-2.17.2/lib/dpif-netdev-lookup-avx512-gather.c +@@ -152,7 +152,7 @@ netdev_rule_matches_key(const struct dpc * u64_lanes_mask: bitmask of lanes to process. * use_vpop: compile-time constant indicating if VPOPCNT instruction allowed. */ @@ -318,11 +317,11 @@ index 7bc1e9e9a..6e50f6ecd 100644 avx512_lookup_impl(struct dpcls_subtable *subtable, uint32_t keys_map, const struct netdev_flow_key *keys[], -diff --git a/lib/dpif-netdev-lookup-generic.c b/lib/dpif-netdev-lookup-generic.c -index 6c74ac3a1..37a069401 100644 ---- a/lib/dpif-netdev-lookup-generic.c -+++ b/lib/dpif-netdev-lookup-generic.c -@@ -170,12 +170,12 @@ netdev_rule_matches_key(const struct dpcls_rule *rule, +Index: openvswitch-2.17.2/lib/dpif-netdev-lookup-generic.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-lookup-generic.c ++++ openvswitch-2.17.2/lib/dpif-netdev-lookup-generic.c +@@ -170,12 +170,12 @@ netdev_rule_matches_key(const struct dpc * unroll loops and flatten out code-sequences based on the knowledge of the * mf_bits_* compile time values. This results in improved performance. * @@ -338,10 +337,10 @@ index 6c74ac3a1..37a069401 100644 lookup_generic_impl(struct dpcls_subtable *subtable, uint32_t keys_map, const struct netdev_flow_key *keys[], -diff --git a/lib/fat-rwlock.h b/lib/fat-rwlock.h -index 181fa9238..49480819b 100644 ---- a/lib/fat-rwlock.h -+++ b/lib/fat-rwlock.h +Index: openvswitch-2.17.2/lib/fat-rwlock.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/fat-rwlock.h ++++ openvswitch-2.17.2/lib/fat-rwlock.h @@ -17,7 +17,7 @@ #ifndef FAT_RWLOCK_H #define FAT_RWLOCK_H 1 @@ -351,10 +350,10 @@ index 181fa9238..49480819b 100644 #include "openvswitch/list.h" #include "ovs-thread.h" -diff --git a/lib/guarded-list.h b/lib/guarded-list.h -index 80ce22c12..7f1d257e1 100644 ---- a/lib/guarded-list.h -+++ b/lib/guarded-list.h +Index: openvswitch-2.17.2/lib/guarded-list.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/guarded-list.h ++++ openvswitch-2.17.2/lib/guarded-list.h @@ -18,7 +18,7 @@ #define GUARDED_LIST_H 1 @@ -364,10 +363,10 @@ index 80ce22c12..7f1d257e1 100644 #include "openvswitch/list.h" #include "ovs-thread.h" -diff --git a/lib/if-notifier-stub.c b/lib/if-notifier-stub.c -index a5b529a4a..32c0e7a9e 100644 ---- a/lib/if-notifier-stub.c -+++ b/lib/if-notifier-stub.c +Index: openvswitch-2.17.2/lib/if-notifier-stub.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/if-notifier-stub.c ++++ openvswitch-2.17.2/lib/if-notifier-stub.c @@ -17,7 +17,7 @@ #include #include "if-notifier.h" @@ -377,10 +376,10 @@ index a5b529a4a..32c0e7a9e 100644 struct if_notifier * if_notifier_create(if_notify_func *cb OVS_UNUSED, void *aux OVS_UNUSED) -diff --git a/lib/learn.h b/lib/learn.h -index 2bdfee702..d962d48c8 100644 ---- a/lib/learn.h -+++ b/lib/learn.h +Index: openvswitch-2.17.2/lib/learn.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/learn.h ++++ openvswitch-2.17.2/lib/learn.h @@ -17,7 +17,7 @@ #ifndef LEARN_H #define LEARN_H 1 @@ -390,10 +389,10 @@ index 2bdfee702..d962d48c8 100644 #include "openvswitch/ofp-errors.h" struct ds; -diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c -index dfeb2a800..1b5b4db57 100644 ---- a/lib/lldp/lldp.c -+++ b/lib/lldp/lldp.c +Index: openvswitch-2.17.2/lib/lldp/lldp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldp.c ++++ openvswitch-2.17.2/lib/lldp/lldp.c @@ -25,7 +25,7 @@ #include #include @@ -403,10 +402,10 @@ index dfeb2a800..1b5b4db57 100644 #include "dp-packet.h" #include "packets.h" -diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c -index a024dc5e5..a600da550 100644 ---- a/lib/lldp/lldpd.c -+++ b/lib/lldp/lldpd.c +Index: openvswitch-2.17.2/lib/lldp/lldpd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldpd.c ++++ openvswitch-2.17.2/lib/lldp/lldpd.c @@ -39,7 +39,7 @@ #include #include @@ -416,10 +415,10 @@ index a024dc5e5..a600da550 100644 #include "openvswitch/dynamic-string.h" #include "openvswitch/list.h" #include "packets.h" -diff --git a/lib/multipath.h b/lib/multipath.h -index 4158302a7..5c09f731d 100644 ---- a/lib/multipath.h -+++ b/lib/multipath.h +Index: openvswitch-2.17.2/lib/multipath.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/multipath.h ++++ openvswitch-2.17.2/lib/multipath.h @@ -18,7 +18,7 @@ #define MULTIPATH_H 1 @@ -429,10 +428,10 @@ index 4158302a7..5c09f731d 100644 #include "openvswitch/ofp-errors.h" struct ds; -diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h -index 22ae2ce53..ba05b8b4c 100644 ---- a/lib/netdev-native-tnl.h -+++ b/lib/netdev-native-tnl.h +Index: openvswitch-2.17.2/lib/netdev-native-tnl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-native-tnl.h ++++ openvswitch-2.17.2/lib/netdev-native-tnl.h @@ -19,7 +19,7 @@ #include @@ -442,10 +441,10 @@ index 22ae2ce53..ba05b8b4c 100644 #include "dp-packet.h" #include "packets.h" #include "unixctl.h" -diff --git a/lib/netdev-vport-private.h b/lib/netdev-vport-private.h -index d89a28c66..490894f1a 100644 ---- a/lib/netdev-vport-private.h -+++ b/lib/netdev-vport-private.h +Index: openvswitch-2.17.2/lib/netdev-vport-private.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-vport-private.h ++++ openvswitch-2.17.2/lib/netdev-vport-private.h @@ -19,7 +19,7 @@ #include @@ -455,10 +454,10 @@ index d89a28c66..490894f1a 100644 #include "netdev.h" #include "netdev-provider.h" #include "ovs-thread.h" -diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h -index 9d756a265..3f47f2fca 100644 ---- a/lib/netdev-vport.h -+++ b/lib/netdev-vport.h +Index: openvswitch-2.17.2/lib/netdev-vport.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-vport.h ++++ openvswitch-2.17.2/lib/netdev-vport.h @@ -19,7 +19,7 @@ #include @@ -468,10 +467,10 @@ index 9d756a265..3f47f2fca 100644 struct dpif_netlink_vport; struct dpif_flow_stats; -diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c -index 78f1bf60b..8dca46e55 100644 ---- a/lib/netlink-conntrack.c -+++ b/lib/netlink-conntrack.c +Index: openvswitch-2.17.2/lib/netlink-conntrack.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-conntrack.c ++++ openvswitch-2.17.2/lib/netlink-conntrack.c @@ -27,7 +27,7 @@ #include @@ -481,10 +480,10 @@ index 78f1bf60b..8dca46e55 100644 #include "openvswitch/dynamic-string.h" #include "netlink.h" #include "netlink-socket.h" -diff --git a/lib/netlink-conntrack.h b/lib/netlink-conntrack.h -index 81c74549b..4972dc6ca 100644 ---- a/lib/netlink-conntrack.h -+++ b/lib/netlink-conntrack.h +Index: openvswitch-2.17.2/lib/netlink-conntrack.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-conntrack.h ++++ openvswitch-2.17.2/lib/netlink-conntrack.h @@ -20,7 +20,7 @@ #include @@ -494,10 +493,10 @@ index 81c74549b..4972dc6ca 100644 #include "ct-dpif.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/hmap.h" -diff --git a/lib/nx-match.h b/lib/nx-match.h -index 3120ac0a0..967c8d93f 100644 ---- a/lib/nx-match.h -+++ b/lib/nx-match.h +Index: openvswitch-2.17.2/lib/nx-match.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/nx-match.h ++++ openvswitch-2.17.2/lib/nx-match.h @@ -20,7 +20,7 @@ #include #include @@ -507,10 +506,10 @@ index 3120ac0a0..967c8d93f 100644 #include "flow.h" #include "openvswitch/meta-flow.h" #include "openvswitch/ofp-errors.h" -diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c -index 006837c2e..f7fb96c5c 100644 ---- a/lib/ofp-actions.c -+++ b/lib/ofp-actions.c +Index: openvswitch-2.17.2/lib/ofp-actions.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-actions.c ++++ openvswitch-2.17.2/lib/ofp-actions.c @@ -22,7 +22,7 @@ #include "bundle.h" #include "byte-order.h" @@ -520,10 +519,10 @@ index 006837c2e..f7fb96c5c 100644 #include "dummy.h" #include "openvswitch/hmap.h" #include "learn.h" -diff --git a/lib/ofp-print.c b/lib/ofp-print.c -index b0facbf9f..db7318205 100644 ---- a/lib/ofp-print.c -+++ b/lib/ofp-print.c +Index: openvswitch-2.17.2/lib/ofp-print.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-print.c ++++ openvswitch-2.17.2/lib/ofp-print.c @@ -30,7 +30,7 @@ #include "bundle.h" #include "byte-order.h" @@ -533,10 +532,10 @@ index b0facbf9f..db7318205 100644 #include "dp-packet.h" #include "flow.h" #include "learn.h" -diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h -index 8fdce0cf8..341e0d0cc 100644 ---- a/lib/ovs-atomic.h -+++ b/lib/ovs-atomic.h +Index: openvswitch-2.17.2/lib/ovs-atomic.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic.h ++++ openvswitch-2.17.2/lib/ovs-atomic.h @@ -322,7 +322,7 @@ #include #include @@ -546,10 +545,10 @@ index 8fdce0cf8..341e0d0cc 100644 #include "util.h" #define IN_OVS_ATOMIC_H -diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h -index ecc251a7f..2030bdb64 100644 ---- a/lib/ovs-numa.h -+++ b/lib/ovs-numa.h +Index: openvswitch-2.17.2/lib/ovs-numa.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-numa.h ++++ openvswitch-2.17.2/lib/ovs-numa.h @@ -20,7 +20,7 @@ #include #include @@ -559,12 +558,12 @@ index ecc251a7f..2030bdb64 100644 #include "openvswitch/hmap.h" #define OVS_CORE_UNSPEC INT_MAX -diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h -index ecc4c9201..5e31181d8 100644 ---- a/lib/ovs-rcu.h -+++ b/lib/ovs-rcu.h -@@ -157,7 +157,7 @@ - * +Index: openvswitch-2.17.2/lib/ovs-rcu.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-rcu.h ++++ openvswitch-2.17.2/lib/ovs-rcu.h +@@ -170,7 +170,7 @@ + * } */ -#include "compiler.h" @@ -572,10 +571,10 @@ index ecc4c9201..5e31181d8 100644 #include "ovs-atomic.h" #if __GNUC__ -diff --git a/lib/ovs-router.c b/lib/ovs-router.c -index 09b81c6e5..e52cbb0bf 100644 ---- a/lib/ovs-router.c -+++ b/lib/ovs-router.c +Index: openvswitch-2.17.2/lib/ovs-router.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-router.c ++++ openvswitch-2.17.2/lib/ovs-router.c @@ -31,8 +31,8 @@ #include @@ -587,10 +586,10 @@ index 09b81c6e5..e52cbb0bf 100644 #include "dpif.h" #include "fatal-signal.h" #include "openvswitch/dynamic-string.h" -diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c -index 805cba622..542dbbc7d 100644 ---- a/lib/ovs-thread.c -+++ b/lib/ovs-thread.c +Index: openvswitch-2.17.2/lib/ovs-thread.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-thread.c ++++ openvswitch-2.17.2/lib/ovs-thread.c @@ -23,7 +23,7 @@ #endif #include @@ -600,10 +599,10 @@ index 805cba622..542dbbc7d 100644 #include "fatal-signal.h" #include "hash.h" #include "openvswitch/list.h" -diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h -index 47115a7b8..a27ce91ed 100644 ---- a/lib/ovsdb-data.h -+++ b/lib/ovsdb-data.h +Index: openvswitch-2.17.2/lib/ovsdb-data.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-data.h ++++ openvswitch-2.17.2/lib/ovsdb-data.h @@ -17,7 +17,7 @@ #define OVSDB_DATA_H 1 @@ -613,10 +612,10 @@ index 47115a7b8..a27ce91ed 100644 #include "ovsdb-types.h" #include "openvswitch/json.h" #include "openvswitch/shash.h" -diff --git a/lib/ovsdb-error.h b/lib/ovsdb-error.h -index 77a60e074..1621f0eac 100644 ---- a/lib/ovsdb-error.h -+++ b/lib/ovsdb-error.h +Index: openvswitch-2.17.2/lib/ovsdb-error.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-error.h ++++ openvswitch-2.17.2/lib/ovsdb-error.h @@ -16,7 +16,7 @@ #ifndef OVSDB_ERROR_H #define OVSDB_ERROR_H 1 @@ -626,10 +625,10 @@ index 77a60e074..1621f0eac 100644 struct json; -diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h -index d00599616..48cff8a83 100644 ---- a/lib/ovsdb-idl.h -+++ b/lib/ovsdb-idl.h +Index: openvswitch-2.17.2/lib/ovsdb-idl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-idl.h ++++ openvswitch-2.17.2/lib/ovsdb-idl.h @@ -37,7 +37,7 @@ #include @@ -639,10 +638,10 @@ index d00599616..48cff8a83 100644 #include "ovsdb-types.h" #include "ovsdb-data.h" #include "openvswitch/list.h" -diff --git a/lib/ovsdb-parser.h b/lib/ovsdb-parser.h -index 62e4c004f..8af64de36 100644 ---- a/lib/ovsdb-parser.h -+++ b/lib/ovsdb-parser.h +Index: openvswitch-2.17.2/lib/ovsdb-parser.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-parser.h ++++ openvswitch-2.17.2/lib/ovsdb-parser.h @@ -17,7 +17,7 @@ #define OVSDB_PARSER_H 1 @@ -652,10 +651,10 @@ index 62e4c004f..8af64de36 100644 #include "openvswitch/json.h" #include "sset.h" #include "util.h" -diff --git a/lib/ovsdb-types.h b/lib/ovsdb-types.h -index b9eb0928d..1776fdbec 100644 ---- a/lib/ovsdb-types.h -+++ b/lib/ovsdb-types.h +Index: openvswitch-2.17.2/lib/ovsdb-types.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-types.h ++++ openvswitch-2.17.2/lib/ovsdb-types.h @@ -19,7 +19,7 @@ #include #include @@ -665,10 +664,10 @@ index b9eb0928d..1776fdbec 100644 #include "uuid.h" #ifdef __cplusplus -diff --git a/lib/packets.h b/lib/packets.h -index 5bdf6e4bb..ee4d96542 100644 ---- a/lib/packets.h -+++ b/lib/packets.h +Index: openvswitch-2.17.2/lib/packets.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/packets.h ++++ openvswitch-2.17.2/lib/packets.h @@ -21,7 +21,7 @@ #include #include @@ -678,10 +677,10 @@ index 5bdf6e4bb..ee4d96542 100644 #include "openvswitch/geneve.h" #include "openvswitch/packets.h" #include "openvswitch/types.h" -diff --git a/lib/pcap-file.c b/lib/pcap-file.c -index 41835f6f4..67c9b9bea 100644 ---- a/lib/pcap-file.c -+++ b/lib/pcap-file.c +Index: openvswitch-2.17.2/lib/pcap-file.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/pcap-file.c ++++ openvswitch-2.17.2/lib/pcap-file.c @@ -22,7 +22,7 @@ #include #include @@ -691,10 +690,10 @@ index 41835f6f4..67c9b9bea 100644 #include "dp-packet.h" #include "flow.h" #include "openvswitch/hmap.h" -diff --git a/lib/route-table-stub.c b/lib/route-table-stub.c -index dd0b096d4..be3254855 100644 ---- a/lib/route-table-stub.c -+++ b/lib/route-table-stub.c +Index: openvswitch-2.17.2/lib/route-table-stub.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/route-table-stub.c ++++ openvswitch-2.17.2/lib/route-table-stub.c @@ -14,7 +14,7 @@ #include @@ -704,10 +703,10 @@ index dd0b096d4..be3254855 100644 #include "ovs-router.h" #include "route-table.h" -diff --git a/lib/rstp.h b/lib/rstp.h -index 39a13b58c..90ea67d58 100644 ---- a/lib/rstp.h -+++ b/lib/rstp.h +Index: openvswitch-2.17.2/lib/rstp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/rstp.h ++++ openvswitch-2.17.2/lib/rstp.h @@ -33,7 +33,7 @@ #include @@ -717,10 +716,10 @@ index 39a13b58c..90ea67d58 100644 #include "util.h" /* Thread Safety: Callers passing in RSTP and RSTP port object -diff --git a/lib/sha1.c b/lib/sha1.c -index 87360d9cd..18f245c8b 100644 ---- a/lib/sha1.c -+++ b/lib/sha1.c +Index: openvswitch-2.17.2/lib/sha1.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/sha1.c ++++ openvswitch-2.17.2/lib/sha1.c @@ -33,7 +33,7 @@ #include "sha1.h" #include @@ -730,10 +729,10 @@ index 87360d9cd..18f245c8b 100644 #include "util.h" /* a bit faster & bigger, if defined */ -diff --git a/lib/stp.h b/lib/stp.h -index c64089af4..a0a127978 100644 ---- a/lib/stp.h -+++ b/lib/stp.h +Index: openvswitch-2.17.2/lib/stp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stp.h ++++ openvswitch-2.17.2/lib/stp.h @@ -22,7 +22,7 @@ #include @@ -743,10 +742,10 @@ index c64089af4..a0a127978 100644 #include "util.h" struct dp_packet; -diff --git a/lib/syslog-direct.c b/lib/syslog-direct.c -index 85ca9e292..fd23a050e 100644 ---- a/lib/syslog-direct.c -+++ b/lib/syslog-direct.c +Index: openvswitch-2.17.2/lib/syslog-direct.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-direct.c ++++ openvswitch-2.17.2/lib/syslog-direct.c @@ -20,7 +20,7 @@ #include #include @@ -756,10 +755,10 @@ index 85ca9e292..fd23a050e 100644 #include "openvswitch/dynamic-string.h" #include "socket-util.h" #include "syslog-provider.h" -diff --git a/lib/syslog-libc.c b/lib/syslog-libc.c -index b702d4121..f3f3e24c0 100644 ---- a/lib/syslog-libc.c -+++ b/lib/syslog-libc.c +Index: openvswitch-2.17.2/lib/syslog-libc.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-libc.c ++++ openvswitch-2.17.2/lib/syslog-libc.c @@ -21,7 +21,7 @@ #include #include @@ -769,10 +768,10 @@ index b702d4121..f3f3e24c0 100644 #include "openvswitch/dynamic-string.h" #include "socket-util.h" #include "syslog-provider.h" -diff --git a/lib/syslog-null.c b/lib/syslog-null.c -index 9dbd13911..294795f71 100644 ---- a/lib/syslog-null.c -+++ b/lib/syslog-null.c +Index: openvswitch-2.17.2/lib/syslog-null.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-null.c ++++ openvswitch-2.17.2/lib/syslog-null.c @@ -17,7 +17,7 @@ #include @@ -782,10 +781,10 @@ index 9dbd13911..294795f71 100644 #include "syslog-provider.h" #include "util.h" -diff --git a/lib/table.h b/lib/table.h -index 33263e2a2..c68b8944b 100644 ---- a/lib/table.h -+++ b/lib/table.h +Index: openvswitch-2.17.2/lib/table.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/table.h ++++ openvswitch-2.17.2/lib/table.h @@ -19,7 +19,7 @@ #include @@ -795,10 +794,10 @@ index 33263e2a2..c68b8944b 100644 #include "openvswitch/json.h" struct ds; -diff --git a/lib/tun-metadata.c b/lib/tun-metadata.c -index af0bcbde8..168634a74 100644 ---- a/lib/tun-metadata.c -+++ b/lib/tun-metadata.c +Index: openvswitch-2.17.2/lib/tun-metadata.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/tun-metadata.c ++++ openvswitch-2.17.2/lib/tun-metadata.c @@ -19,7 +19,7 @@ #include @@ -808,10 +807,10 @@ index af0bcbde8..168634a74 100644 #include "openvswitch/hmap.h" #include "openvswitch/match.h" #include "nx-match.h" -diff --git a/lib/unicode.h b/lib/unicode.h -index 4a8baca68..5f86beab8 100644 ---- a/lib/unicode.h -+++ b/lib/unicode.h +Index: openvswitch-2.17.2/lib/unicode.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/unicode.h ++++ openvswitch-2.17.2/lib/unicode.h @@ -19,7 +19,7 @@ #include @@ -821,10 +820,10 @@ index 4a8baca68..5f86beab8 100644 /* Returns true if 'c' is a Unicode code point, otherwise false. */ static inline bool -diff --git a/lib/util.c b/lib/util.c -index 1195c7982..eb2341422 100644 ---- a/lib/util.c -+++ b/lib/util.c +Index: openvswitch-2.17.2/lib/util.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/util.c ++++ openvswitch-2.17.2/lib/util.c @@ -202,7 +202,7 @@ xstrdup(const char *s) return xmemdup0(s, strlen(s)); } @@ -834,10 +833,10 @@ index 1195c7982..eb2341422 100644 nullable_xstrdup(const char *s) { return s ? xstrdup(s) : NULL; -diff --git a/lib/util.h b/lib/util.h -index aea19d45f..964fb4f20 100644 ---- a/lib/util.h -+++ b/lib/util.h +Index: openvswitch-2.17.2/lib/util.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/util.h ++++ openvswitch-2.17.2/lib/util.h @@ -26,7 +26,7 @@ #include #include @@ -890,7 +889,7 @@ index aea19d45f..964fb4f20 100644 void free_cacheline(void *); void ovs_strlcpy(char *dst, const char *src, size_t size); -@@ -185,9 +185,9 @@ void ovs_strzcpy(char *dst, const char *src, size_t size); +@@ -185,9 +185,9 @@ void ovs_strzcpy(char *dst, const char * int string_ends_with(const char *str, const char *suffix); @@ -902,10 +901,10 @@ index aea19d45f..964fb4f20 100644 void free_size_align(void *); /* The C standards say that neither the 'dst' nor 'src' argument to -diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c -index 30e7caf54..772881b0d 100644 ---- a/ofproto/ofproto-dpif-sflow.c -+++ b/ofproto/ofproto-dpif-sflow.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-sflow.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.c @@ -23,7 +23,7 @@ #include #include @@ -915,10 +914,10 @@ index 30e7caf54..772881b0d 100644 #include "dpif.h" #include "hash.h" #include "openvswitch/hmap.h" -diff --git a/ovsdb/column.h b/ovsdb/column.h -index f75a1076d..890295629 100644 ---- a/ovsdb/column.h -+++ b/ovsdb/column.h +Index: openvswitch-2.17.2/ovsdb/column.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/column.h ++++ openvswitch-2.17.2/ovsdb/column.h @@ -17,7 +17,7 @@ #define OVSDB_COLUMN_H 1 @@ -928,10 +927,10 @@ index f75a1076d..890295629 100644 #include "ovsdb-types.h" struct ovsdb_table; -diff --git a/ovsdb/condition.h b/ovsdb/condition.h -index c794966ce..65728fb32 100644 ---- a/ovsdb/condition.h -+++ b/ovsdb/condition.h +Index: openvswitch-2.17.2/ovsdb/condition.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/condition.h ++++ openvswitch-2.17.2/ovsdb/condition.h @@ -17,7 +17,7 @@ #define OVSDB_CONDITION_H 1 @@ -941,10 +940,10 @@ index c794966ce..65728fb32 100644 #include "ovsdb-data.h" #include "bitmap.h" #include "ovsdb-condition.h" -diff --git a/ovsdb/file.h b/ovsdb/file.h -index be4f6ad27..0ee758958 100644 ---- a/ovsdb/file.h -+++ b/ovsdb/file.h +Index: openvswitch-2.17.2/ovsdb/file.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/file.h ++++ openvswitch-2.17.2/ovsdb/file.h @@ -17,7 +17,7 @@ #define OVSDB_FILE_H 1 @@ -954,10 +953,10 @@ index be4f6ad27..0ee758958 100644 struct ovsdb; struct ovsdb_schema; -diff --git a/ovsdb/log.h b/ovsdb/log.h -index 90714ea13..d823058f5 100644 ---- a/ovsdb/log.h -+++ b/ovsdb/log.h +Index: openvswitch-2.17.2/ovsdb/log.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/log.h ++++ openvswitch-2.17.2/ovsdb/log.h @@ -37,7 +37,7 @@ #include @@ -967,10 +966,10 @@ index 90714ea13..d823058f5 100644 struct ds; struct json; -diff --git a/ovsdb/mutation.h b/ovsdb/mutation.h -index 7566ef199..dfb2d6940 100644 ---- a/ovsdb/mutation.h -+++ b/ovsdb/mutation.h +Index: openvswitch-2.17.2/ovsdb/mutation.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/mutation.h ++++ openvswitch-2.17.2/ovsdb/mutation.h @@ -17,7 +17,7 @@ #define OVSDB_MUTATION_H 1 @@ -980,10 +979,10 @@ index 7566ef199..dfb2d6940 100644 #include "ovsdb-data.h" struct json; -diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c -index f1b8d6491..db5eebc17 100644 ---- a/ovsdb/ovsdb-client.c -+++ b/ovsdb/ovsdb-client.c +Index: openvswitch-2.17.2/ovsdb/ovsdb-client.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-client.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-client.c @@ -28,7 +28,7 @@ #include "command-line.h" @@ -993,10 +992,10 @@ index f1b8d6491..db5eebc17 100644 #include "daemon.h" #include "dirs.h" #include "openvswitch/dynamic-string.h" -diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c -index d4a9e34cc..8465666e5 100644 ---- a/ovsdb/ovsdb-tool.c -+++ b/ovsdb/ovsdb-tool.c +Index: openvswitch-2.17.2/ovsdb/ovsdb-tool.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-tool.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-tool.c @@ -23,8 +23,7 @@ #include @@ -1007,10 +1006,10 @@ index d4a9e34cc..8465666e5 100644 #include "dirs.h" #include "openvswitch/dynamic-string.h" #include "fatal-signal.h" -diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h -index ec2d235ec..b9e09b897 100644 ---- a/ovsdb/ovsdb.h -+++ b/ovsdb/ovsdb.h +Index: openvswitch-2.17.2/ovsdb/ovsdb.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb.h ++++ openvswitch-2.17.2/ovsdb/ovsdb.h @@ -16,7 +16,7 @@ #ifndef OVSDB_OVSDB_H #define OVSDB_OVSDB_H 1 @@ -1020,10 +1019,10 @@ index ec2d235ec..b9e09b897 100644 #include "openvswitch/hmap.h" #include "openvswitch/list.h" #include "openvswitch/shash.h" -diff --git a/ovsdb/raft-rpc.c b/ovsdb/raft-rpc.c -index dd14d8109..051291b0f 100644 ---- a/ovsdb/raft-rpc.c -+++ b/ovsdb/raft-rpc.c +Index: openvswitch-2.17.2/ovsdb/raft-rpc.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft-rpc.c ++++ openvswitch-2.17.2/ovsdb/raft-rpc.c @@ -19,7 +19,7 @@ #include "raft-rpc.h" #include @@ -1033,10 +1032,10 @@ index dd14d8109..051291b0f 100644 #include "jsonrpc.h" #include "ovsdb-error.h" #include "ovsdb-parser.h" -diff --git a/ovsdb/raft.h b/ovsdb/raft.h -index 599bc0ae8..5f2c0c773 100644 ---- a/ovsdb/raft.h -+++ b/ovsdb/raft.h +Index: openvswitch-2.17.2/ovsdb/raft.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft.h ++++ openvswitch-2.17.2/ovsdb/raft.h @@ -61,7 +61,7 @@ #include @@ -1046,10 +1045,10 @@ index 599bc0ae8..5f2c0c773 100644 #include "uuid.h" struct json; -diff --git a/ovsdb/storage.h b/ovsdb/storage.h -index ff026b77f..7d03d4015 100644 ---- a/ovsdb/storage.h -+++ b/ovsdb/storage.h +Index: openvswitch-2.17.2/ovsdb/storage.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/storage.h ++++ openvswitch-2.17.2/ovsdb/storage.h @@ -18,7 +18,7 @@ #include @@ -1059,10 +1058,10 @@ index ff026b77f..7d03d4015 100644 struct json; struct ovsdb_schema; -diff --git a/ovsdb/table.h b/ovsdb/table.h -index ce69a5d13..de2619514 100644 ---- a/ovsdb/table.h -+++ b/ovsdb/table.h +Index: openvswitch-2.17.2/ovsdb/table.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/table.h ++++ openvswitch-2.17.2/ovsdb/table.h @@ -17,7 +17,7 @@ #define OVSDB_TABLE_H 1 @@ -1072,10 +1071,10 @@ index ce69a5d13..de2619514 100644 #include "openvswitch/hmap.h" #include "openvswitch/shash.h" -diff --git a/ovsdb/transaction.h b/ovsdb/transaction.h -index 6b5bb7f24..5c0bb3834 100644 ---- a/ovsdb/transaction.h -+++ b/ovsdb/transaction.h +Index: openvswitch-2.17.2/ovsdb/transaction.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/transaction.h ++++ openvswitch-2.17.2/ovsdb/transaction.h @@ -17,7 +17,7 @@ #define OVSDB_TRANSACTION_H 1 @@ -1085,10 +1084,10 @@ index 6b5bb7f24..5c0bb3834 100644 struct json; struct ovsdb; -diff --git a/tests/ovstest.h b/tests/ovstest.h -index ddd7f3eb9..72fe6d152 100644 ---- a/tests/ovstest.h -+++ b/tests/ovstest.h +Index: openvswitch-2.17.2/tests/ovstest.h +=================================================================== +--- openvswitch-2.17.2.orig/tests/ovstest.h ++++ openvswitch-2.17.2/tests/ovstest.h @@ -17,7 +17,7 @@ #ifndef OVSTEST_H #define OVSTEST_H @@ -1098,10 +1097,10 @@ index ddd7f3eb9..72fe6d152 100644 #include "command-line.h" -diff --git a/tests/test-reconnect.c b/tests/test-reconnect.c -index c84bb1cdb..7262ea774 100644 ---- a/tests/test-reconnect.c -+++ b/tests/test-reconnect.c +Index: openvswitch-2.17.2/tests/test-reconnect.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-reconnect.c ++++ openvswitch-2.17.2/tests/test-reconnect.c @@ -21,8 +21,8 @@ #include #include @@ -1112,10 +1111,10 @@ index c84bb1cdb..7262ea774 100644 #include "ovstest.h" #include "svec.h" #include "util.h" -diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c -index 56d7a942b..46d248694 100644 ---- a/utilities/ovs-dpctl.c -+++ b/utilities/ovs-dpctl.c +Index: openvswitch-2.17.2/utilities/ovs-dpctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-dpctl.c ++++ openvswitch-2.17.2/utilities/ovs-dpctl.c @@ -31,8 +31,8 @@ #include #include @@ -1126,10 +1125,10 @@ index 56d7a942b..46d248694 100644 #include "dirs.h" #include "dpctl.h" #include "fatal-signal.h" -diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c -index ede7f1e61..85df32d7e 100644 ---- a/utilities/ovs-ofctl.c -+++ b/utilities/ovs-ofctl.c +Index: openvswitch-2.17.2/utilities/ovs-ofctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-ofctl.c ++++ openvswitch-2.17.2/utilities/ovs-ofctl.c @@ -34,7 +34,7 @@ #include "command-line.h" #include "daemon.h" @@ -1139,10 +1138,10 @@ index ede7f1e61..85df32d7e 100644 #include "dirs.h" #include "dp-packet.h" #include "fatal-signal.h" -diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c -index b489ff5fc..c3d4bc7ff 100644 ---- a/utilities/ovs-testcontroller.c -+++ b/utilities/ovs-testcontroller.c +Index: openvswitch-2.17.2/utilities/ovs-testcontroller.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-testcontroller.c ++++ openvswitch-2.17.2/utilities/ovs-testcontroller.c @@ -24,8 +24,8 @@ #include #include @@ -1153,10 +1152,10 @@ index b489ff5fc..c3d4bc7ff 100644 #include "daemon.h" #include "fatal-signal.h" #include "learning-switch.h" -diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c -index 37cc72d40..6013e9f57 100644 ---- a/utilities/ovs-vsctl.c -+++ b/utilities/ovs-vsctl.c +Index: openvswitch-2.17.2/utilities/ovs-vsctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-vsctl.c ++++ openvswitch-2.17.2/utilities/ovs-vsctl.c @@ -29,8 +29,8 @@ #include "db-ctl-base.h" @@ -1167,10 +1166,10 @@ index 37cc72d40..6013e9f57 100644 #include "dirs.h" #include "fatal-signal.h" #include "hash.h" -diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c -index 407bfc60e..09004e79b 100644 ---- a/vswitchd/ovs-vswitchd.c -+++ b/vswitchd/ovs-vswitchd.c +Index: openvswitch-2.17.2/vswitchd/ovs-vswitchd.c +=================================================================== +--- openvswitch-2.17.2.orig/vswitchd/ovs-vswitchd.c ++++ openvswitch-2.17.2/vswitchd/ovs-vswitchd.c @@ -26,8 +26,8 @@ #endif @@ -1181,10 +1180,10 @@ index 407bfc60e..09004e79b 100644 #include "daemon.h" #include "dirs.h" #include "dpif.h" -diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c -index ab552457d..6c9259fba 100644 ---- a/vtep/vtep-ctl.c -+++ b/vtep/vtep-ctl.c +Index: openvswitch-2.17.2/vtep/vtep-ctl.c +=================================================================== +--- openvswitch-2.17.2.orig/vtep/vtep-ctl.c ++++ openvswitch-2.17.2/vtep/vtep-ctl.c @@ -29,9 +29,9 @@ #include "db-ctl-base.h" @@ -1197,6 +1196,3 @@ index ab552457d..6c9259fba 100644 #include "fatal-signal.h" #include "hash.h" #include "openvswitch/json.h" --- -2.35.1 - diff --git a/0002-build-Seperated-common-used-headers.patch b/0002-build-Seperated-common-used-headers.patch index 0e73113..5824657 100644 --- a/0002-build-Seperated-common-used-headers.patch +++ b/0002-build-Seperated-common-used-headers.patch @@ -579,10 +579,10 @@ Subject: [PATCH 2/2] build: Seperated common used headers rename {lib => include/openvswitch}/ovsdb-set-op.h (97%) rename {lib => include/openvswitch}/ovsdb-types.h (99%) -diff --git a/Makefile.am b/Makefile.am -index cb8076433..cfed54cc5 100644 ---- a/Makefile.am -+++ b/Makefile.am +Index: openvswitch-2.17.2/Makefile.am +=================================================================== +--- openvswitch-2.17.2.orig/Makefile.am ++++ openvswitch-2.17.2/Makefile.am @@ -242,7 +242,7 @@ config-h-check: exit 1; \ fi; \ @@ -592,10 +592,10 @@ index cb8076433..cfed54cc5 100644 then \ echo "See above for list of violations of the rule that"; \ echo "public openvswitch header file should not include internal library."; \ -diff --git a/build-aux/extract-odp-netlink-h b/build-aux/extract-odp-netlink-h -index bc1cc35a7..190aa0a7e 100755 ---- a/build-aux/extract-odp-netlink-h -+++ b/build-aux/extract-odp-netlink-h +Index: openvswitch-2.17.2/build-aux/extract-odp-netlink-h +=================================================================== +--- openvswitch-2.17.2.orig/build-aux/extract-odp-netlink-h ++++ openvswitch-2.17.2/build-aux/extract-odp-netlink-h @@ -8,6 +8,9 @@ /* -*- mode: c; buffer-read-only: t -*- */\ /* Generated automatically from -- do not modify! */\ @@ -616,11 +616,11 @@ index bc1cc35a7..190aa0a7e 100755 +} // extern "C"\ +#endif\ +\ -diff --git a/build-aux/extract-odp-netlink-macros-h b/build-aux/extract-odp-netlink-macros-h -index 7152f298c..050069a2b 100755 ---- a/build-aux/extract-odp-netlink-macros-h -+++ b/build-aux/extract-odp-netlink-macros-h -@@ -42,6 +42,9 @@ echo "/* Generated automatically from -- do not modify! +Index: openvswitch-2.17.2/build-aux/extract-odp-netlink-macros-h +=================================================================== +--- openvswitch-2.17.2.orig/build-aux/extract-odp-netlink-macros-h ++++ openvswitch-2.17.2/build-aux/extract-odp-netlink-macros-h +@@ -42,6 +42,9 @@ echo "/* Generated automatically from @@ -690,10 +690,10 @@ index c377e9b24..2dd9ea83a 100644 #include "flow_table.h" #include "meter.h" #include "vport-internal_dev.h" -diff --git a/datapath/flow.c b/datapath/flow.c -index 5a00c238c..17aa5770e 100644 ---- a/datapath/flow.c -+++ b/datapath/flow.c +Index: openvswitch-2.17.2/datapath/flow.c +=================================================================== +--- openvswitch-2.17.2.orig/datapath/flow.c ++++ openvswitch-2.17.2/datapath/flow.c @@ -50,7 +50,7 @@ #include "datapath.h" @@ -703,10 +703,10 @@ index 5a00c238c..17aa5770e 100644 #include "flow_netlink.h" #include "vport.h" -diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c -index 996041602..f4af09c1d 100644 ---- a/datapath/flow_netlink.c -+++ b/datapath/flow_netlink.c +Index: openvswitch-2.17.2/datapath/flow_netlink.c +=================================================================== +--- openvswitch-2.17.2.orig/datapath/flow_netlink.c ++++ openvswitch-2.17.2/datapath/flow_netlink.c @@ -51,7 +51,7 @@ #include "datapath.h" @@ -716,10 +716,10 @@ index 996041602..f4af09c1d 100644 #include "flow_netlink.h" #include "gso.h" -diff --git a/datapath/flow_netlink.h b/datapath/flow_netlink.h -index e10df2b5c..939a6cde3 100644 ---- a/datapath/flow_netlink.h -+++ b/datapath/flow_netlink.h +Index: openvswitch-2.17.2/datapath/flow_netlink.h +=================================================================== +--- openvswitch-2.17.2.orig/datapath/flow_netlink.h ++++ openvswitch-2.17.2/datapath/flow_netlink.h @@ -34,7 +34,7 @@ #include #include @@ -729,10 +729,10 @@ index e10df2b5c..939a6cde3 100644 size_t ovs_tun_key_attr_size(void); size_t ovs_key_attr_size(void); -diff --git a/datapath/flow_table.c b/datapath/flow_table.c -index 650338fb0..c5706e625 100644 ---- a/datapath/flow_table.c -+++ b/datapath/flow_table.c +Index: openvswitch-2.17.2/datapath/flow_table.c +=================================================================== +--- openvswitch-2.17.2.orig/datapath/flow_table.c ++++ openvswitch-2.17.2/datapath/flow_table.c @@ -16,7 +16,7 @@ * 02110-1301, USA */ @@ -742,10 +742,10 @@ index 650338fb0..c5706e625 100644 #include "datapath.h" #include #include -diff --git a/datapath/flow_table.h b/datapath/flow_table.h -index 1a76886b5..596a5a66d 100644 ---- a/datapath/flow_table.h -+++ b/datapath/flow_table.h +Index: openvswitch-2.17.2/datapath/flow_table.h +=================================================================== +--- openvswitch-2.17.2.orig/datapath/flow_table.h ++++ openvswitch-2.17.2/datapath/flow_table.h @@ -33,7 +33,7 @@ #include #include @@ -755,10 +755,10 @@ index 1a76886b5..596a5a66d 100644 struct mask_cache_entry { u32 skb_hash; -diff --git a/datapath/meter.h b/datapath/meter.h -index 964ace265..494aaf622 100644 ---- a/datapath/meter.h -+++ b/datapath/meter.h +Index: openvswitch-2.17.2/datapath/meter.h +=================================================================== +--- openvswitch-2.17.2.orig/datapath/meter.h ++++ openvswitch-2.17.2/datapath/meter.h @@ -17,7 +17,7 @@ #include #include @@ -768,20 +768,19 @@ index 964ace265..494aaf622 100644 struct datapath; #define DP_MAX_BANDS 1 -diff --git a/include/automake.mk b/include/automake.mk -index e982da87d..701a01dbf 100644 ---- a/include/automake.mk -+++ b/include/automake.mk +Index: openvswitch-2.17.2/include/automake.mk +=================================================================== +--- openvswitch-2.17.2.orig/include/automake.mk ++++ openvswitch-2.17.2/include/automake.mk @@ -16,3 +16,4 @@ include include/openvswitch/automake.mk include include/sparse/automake.mk include include/windows/automake.mk include include/linux/automake.mk +include include/internal/automake.mk -diff --git a/include/internal/automake.mk b/include/internal/automake.mk -new file mode 100644 -index 000000000..c39a2feb6 +Index: openvswitch-2.17.2/include/internal/automake.mk +=================================================================== --- /dev/null -+++ b/include/internal/automake.mk ++++ openvswitch-2.17.2/include/internal/automake.mk @@ -0,0 +1,77 @@ +# Common headers needed by openvswitch and some depending projects like OVN + @@ -860,726 +859,19230 @@ index 000000000..c39a2feb6 + lib/vswitch-idl.h \ + vtep/vtep-idl.h + -diff --git a/lib/bitmap.h b/include/internal/bitmap.h -similarity index 99% -rename from lib/bitmap.h -rename to include/internal/bitmap.h -index 0b62066c6..c73b9d1ee 100644 ---- a/lib/bitmap.h -+++ b/include/internal/bitmap.h -@@ -19,7 +19,7 @@ - - #include - #include +Index: openvswitch-2.17.2/lib/bitmap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/bitmap.h ++++ /dev/null +@@ -1,295 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef BITMAP_H +-#define BITMAP_H 1 +- +-#include +-#include -#include "util.h" +- +-static inline unsigned long * +-bitmap_unit__(const unsigned long *bitmap, size_t offset) +-{ +- return CONST_CAST(unsigned long *, &bitmap[offset / BITMAP_ULONG_BITS]); +-} +- +-static inline unsigned long +-bitmap_bit__(size_t offset) +-{ +- return 1UL << (offset % BITMAP_ULONG_BITS); +-} +- +-static inline size_t +-bitmap_n_longs(size_t n_bits) +-{ +- return BITMAP_N_LONGS(n_bits); +-} +- +-static inline size_t +-bitmap_n_bytes(size_t n_bits) +-{ +- return bitmap_n_longs(n_bits) * sizeof(unsigned long int); +-} +- +-static inline unsigned long * +-bitmap_allocate(size_t n_bits) +-{ +- return xzalloc(bitmap_n_bytes(n_bits)); +-} +- +-/* Initializes bitmap to all-1-bits and returns the bitmap pointer. */ +-static inline unsigned long * +-bitmap_init1(unsigned long *bitmap, size_t n_bits) +-{ +- size_t n_longs = bitmap_n_longs(n_bits); +- size_t n_bytes = bitmap_n_bytes(n_bits); +- size_t r_bits = n_bits % BITMAP_ULONG_BITS; +- +- memset(bitmap, 0xff, n_bytes); +- if (r_bits) { +- bitmap[n_longs - 1] = (1UL << r_bits) - 1; +- } +- return bitmap; +-} +- +-/* Allocates and returns a bitmap initialized to all-1-bits. */ +-static inline unsigned long * +-bitmap_allocate1(size_t n_bits) +-{ +- return bitmap_init1(xmalloc(bitmap_n_bytes(n_bits)), n_bits); +-} +- +-static inline unsigned long * +-bitmap_clone(const unsigned long *bitmap, size_t n_bits) +-{ +- return xmemdup(bitmap, bitmap_n_bytes(n_bits)); +-} +- +-static inline void +-bitmap_free(unsigned long *bitmap) +-{ +- free(bitmap); +-} +- +-static inline bool +-bitmap_is_set(const unsigned long *bitmap, size_t offset) +-{ +- return (*bitmap_unit__(bitmap, offset) & bitmap_bit__(offset)) != 0; +-} +- +-static inline unsigned long * +-bitmap_set1(unsigned long *bitmap, size_t offset) +-{ +- *bitmap_unit__(bitmap, offset) |= bitmap_bit__(offset); +- return bitmap; +-} +- +-static inline unsigned long * +-bitmap_set0(unsigned long *bitmap, size_t offset) +-{ +- *bitmap_unit__(bitmap, offset) &= ~bitmap_bit__(offset); +- return bitmap; +-} +- +-static inline unsigned long * +-bitmap_set(unsigned long *bitmap, size_t offset, bool value) +-{ +- return (value) ? bitmap_set1(bitmap, offset) : bitmap_set0(bitmap, offset); +-} +- +-/* Sets 'n' bits of a single unit. */ +-static inline void +-bitmap_set_n__(unsigned long *bitmap, size_t start, size_t n, bool value) +-{ +- unsigned long mask = ((1UL << n) - 1) << start % BITMAP_ULONG_BITS; +- +- if (value) { +- *bitmap_unit__(bitmap, start) |= mask; +- } else { +- *bitmap_unit__(bitmap, start) &= ~mask; +- } +-} +- +-/* Sets 'count' consecutive bits in 'bitmap', starting at bit offset 'start', +- * to 'value'. */ +-static inline unsigned long * +-bitmap_set_multiple(unsigned long *bitmap, size_t start, size_t count, +- bool value) +-{ +- if (count && start % BITMAP_ULONG_BITS) { +- size_t n = MIN(count, BITMAP_ULONG_BITS - start % BITMAP_ULONG_BITS); +- +- bitmap_set_n__(bitmap, start, n, value); +- count -= n; +- start += n; +- } +- for (; count >= BITMAP_ULONG_BITS; count -= BITMAP_ULONG_BITS) { +- *bitmap_unit__(bitmap, start) = (unsigned long)!value - 1; +- start += BITMAP_ULONG_BITS; +- } +- if (count) { +- bitmap_set_n__(bitmap, start, count, value); +- } +- return bitmap; +-} +- +-/* Returns the number of 1-bits in the 'n'-bit bitmap at 'bitmap'. */ +-static inline size_t +-bitmap_count1(const unsigned long int *bitmap, size_t n) +-{ +- size_t i; +- size_t count = 0; +- +- BUILD_ASSERT(ULONG_MAX <= UINT64_MAX); +- for (i = 0; i < BITMAP_N_LONGS(n); i++) { +- count += count_1bits(bitmap[i]); +- } +- return count; +-} +- +-/* "dst &= arg;" for n-bit dst and arg. */ +-static inline unsigned long * +-bitmap_and(unsigned long *dst, const unsigned long *arg, size_t n) +-{ +- size_t i; +- +- for (i = 0; i < BITMAP_N_LONGS(n); i++) { +- dst[i] &= arg[i]; +- } +- return dst; +-} +- +-/* "dst |= arg;" for n-bit dst and arg. */ +-static inline unsigned long * +-bitmap_or(unsigned long *dst, const unsigned long *arg, size_t n) +-{ +- size_t i; +- +- for (i = 0; i < BITMAP_N_LONGS(n); i++) { +- dst[i] |= arg[i]; +- } +- return dst; +-} +- +-/* "dst = ~dst;" for n-bit dst. */ +-static inline unsigned long * +-bitmap_not(unsigned long *dst, size_t n) +-{ +- size_t i; +- +- for (i = 0; i < n / BITMAP_ULONG_BITS; i++) { +- dst[i] = ~dst[i]; +- } +- if (n % BITMAP_ULONG_BITS) { +- dst[i] ^= (1UL << (n % BITMAP_ULONG_BITS)) - 1; +- } +- return dst; +-} +- +-/* Compares the 'n' bits in bitmaps 'a' and 'b'. Returns true if all bits are +- * equal, false otherwise. */ +-static inline bool +-bitmap_equal(const unsigned long *a, const unsigned long *b, size_t n) +-{ +- if (memcmp(a, b, n / BITMAP_ULONG_BITS * sizeof(unsigned long))) { +- return false; +- } +- if (n % BITMAP_ULONG_BITS) { +- unsigned long mask = (1UL << n % BITMAP_ULONG_BITS) - 1; +- unsigned long diff = *bitmap_unit__(a, n) ^ *bitmap_unit__(b, n); +- +- return !(diff & mask); +- } +- return true; +-} +- +-/* Scans 'bitmap' from bit offset 'start' to 'end', excluding 'end' itself. +- * Returns the bit offset of the lowest-numbered bit set to 'target', or 'end' +- * if all of the bits are set to '!target'. 'target' is typically a +- * compile-time constant, so it makes sense to inline this. Compiler may also +- * optimize parts away depending on the 'start' and 'end' values passed in. */ +-static inline size_t +-bitmap_scan(const unsigned long *bitmap, bool target, size_t start, size_t end) +-{ +- if (OVS_LIKELY(start < end)) { +- unsigned long *p, unit; +- +- p = bitmap_unit__(bitmap, start); +- unit = (target ? *p : ~*p) >> (start % BITMAP_ULONG_BITS); +- if (!unit) { +- start -= start % BITMAP_ULONG_BITS; /* Round down. */ +- start += BITMAP_ULONG_BITS; /* Start of the next unit. */ +- +- for (; start < end; start += BITMAP_ULONG_BITS) { +- unit = target ? *++p : ~*++p; +- if (unit) { +- goto found; +- } +- } +- return end; +- } +-found: +- start += raw_ctz(unit); /* unit != 0 */ +- if (OVS_LIKELY(start < end)) { +- return start; +- } +- } +- return end; +-} +- +-/* Returns true if the 1-bits in 'super' are a superset of the 1-bits in 'sub', +- * false otherwise. 'super' and 'sub' both have 'n_bits' bits. */ +-static inline bool +-bitmap_is_superset(const unsigned long int *super, +- const unsigned long int *sub, size_t n_bits) +-{ +- size_t n_longs = bitmap_n_longs(n_bits); +- for (size_t i = 0; i < n_longs; i++) { +- if (!uint_is_superset(super[i], sub[i])) { +- return false; +- } +- } +- return true; +-} +- +-/* Returns true if all of the 'n' bits in 'bitmap' are 0, +- * false if at least one bit is a 1.*/ +-static inline bool +-bitmap_is_all_zeros(const unsigned long *bitmap, size_t n) +-{ +- return bitmap_scan(bitmap, true, 0, n) == n; +-} +- +-#define BITMAP_FOR_EACH_1_RANGE(IDX, BEGIN, END, BITMAP) \ +- for ((IDX) = bitmap_scan(BITMAP, true, BEGIN, END); (IDX) < (END); \ +- (IDX) = bitmap_scan(BITMAP, true, (IDX) + 1, END)) +-#define BITMAP_FOR_EACH_1(IDX, SIZE, BITMAP) \ +- BITMAP_FOR_EACH_1_RANGE(IDX, 0, SIZE, BITMAP) +- +-/* More efficient access to a map of single ullong. */ +-#define ULLONG_FOR_EACH_1(IDX, MAP) \ +- for (uint64_t map__ = (MAP); \ +- map__ && (((IDX) = raw_ctz(map__)), true); \ +- map__ = zero_rightmost_1bit(map__)) +- +-#define ULLONG_SET0(MAP, OFFSET) ((MAP) &= ~(1ULL << (OFFSET))) +-#define ULLONG_SET1(MAP, OFFSET) ((MAP) |= 1ULL << (OFFSET)) +- +-/* Returns the value of a bit in a map as a bool. */ +-#define ULLONG_GET(MAP, OFFSET) !!((MAP) & (1ULL << (OFFSET))) +- +-#endif /* bitmap.h */ +Index: openvswitch-2.17.2/include/internal/bitmap.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/bitmap.h +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef BITMAP_H ++#define BITMAP_H 1 ++ ++#include ++#include +#include "internal/util.h" - - static inline unsigned long * - bitmap_unit__(const unsigned long *bitmap, size_t offset) -diff --git a/lib/bundle.h b/include/internal/bundle.h -similarity index 100% -rename from lib/bundle.h -rename to include/internal/bundle.h -diff --git a/lib/byte-order.h b/include/internal/byte-order.h -similarity index 100% -rename from lib/byte-order.h -rename to include/internal/byte-order.h -diff --git a/lib/classifier.h b/include/internal/classifier.h -similarity index 99% -rename from lib/classifier.h -rename to include/internal/classifier.h -index f646a8f74..79a2124b8 100644 ---- a/lib/classifier.h -+++ b/include/internal/classifier.h -@@ -298,13 +298,13 @@ - * still be RCU postponed, as the rule's visibility attribute may be examined - * parallel to the rule's removal. */ - ++ ++static inline unsigned long * ++bitmap_unit__(const unsigned long *bitmap, size_t offset) ++{ ++ return CONST_CAST(unsigned long *, &bitmap[offset / BITMAP_ULONG_BITS]); ++} ++ ++static inline unsigned long ++bitmap_bit__(size_t offset) ++{ ++ return 1UL << (offset % BITMAP_ULONG_BITS); ++} ++ ++static inline size_t ++bitmap_n_longs(size_t n_bits) ++{ ++ return BITMAP_N_LONGS(n_bits); ++} ++ ++static inline size_t ++bitmap_n_bytes(size_t n_bits) ++{ ++ return bitmap_n_longs(n_bits) * sizeof(unsigned long int); ++} ++ ++static inline unsigned long * ++bitmap_allocate(size_t n_bits) ++{ ++ return xzalloc(bitmap_n_bytes(n_bits)); ++} ++ ++/* Initializes bitmap to all-1-bits and returns the bitmap pointer. */ ++static inline unsigned long * ++bitmap_init1(unsigned long *bitmap, size_t n_bits) ++{ ++ size_t n_longs = bitmap_n_longs(n_bits); ++ size_t n_bytes = bitmap_n_bytes(n_bits); ++ size_t r_bits = n_bits % BITMAP_ULONG_BITS; ++ ++ memset(bitmap, 0xff, n_bytes); ++ if (r_bits) { ++ bitmap[n_longs - 1] = (1UL << r_bits) - 1; ++ } ++ return bitmap; ++} ++ ++/* Allocates and returns a bitmap initialized to all-1-bits. */ ++static inline unsigned long * ++bitmap_allocate1(size_t n_bits) ++{ ++ return bitmap_init1(xmalloc(bitmap_n_bytes(n_bits)), n_bits); ++} ++ ++static inline unsigned long * ++bitmap_clone(const unsigned long *bitmap, size_t n_bits) ++{ ++ return xmemdup(bitmap, bitmap_n_bytes(n_bits)); ++} ++ ++static inline void ++bitmap_free(unsigned long *bitmap) ++{ ++ free(bitmap); ++} ++ ++static inline bool ++bitmap_is_set(const unsigned long *bitmap, size_t offset) ++{ ++ return (*bitmap_unit__(bitmap, offset) & bitmap_bit__(offset)) != 0; ++} ++ ++static inline unsigned long * ++bitmap_set1(unsigned long *bitmap, size_t offset) ++{ ++ *bitmap_unit__(bitmap, offset) |= bitmap_bit__(offset); ++ return bitmap; ++} ++ ++static inline unsigned long * ++bitmap_set0(unsigned long *bitmap, size_t offset) ++{ ++ *bitmap_unit__(bitmap, offset) &= ~bitmap_bit__(offset); ++ return bitmap; ++} ++ ++static inline unsigned long * ++bitmap_set(unsigned long *bitmap, size_t offset, bool value) ++{ ++ return (value) ? bitmap_set1(bitmap, offset) : bitmap_set0(bitmap, offset); ++} ++ ++/* Sets 'n' bits of a single unit. */ ++static inline void ++bitmap_set_n__(unsigned long *bitmap, size_t start, size_t n, bool value) ++{ ++ unsigned long mask = ((1UL << n) - 1) << start % BITMAP_ULONG_BITS; ++ ++ if (value) { ++ *bitmap_unit__(bitmap, start) |= mask; ++ } else { ++ *bitmap_unit__(bitmap, start) &= ~mask; ++ } ++} ++ ++/* Sets 'count' consecutive bits in 'bitmap', starting at bit offset 'start', ++ * to 'value'. */ ++static inline unsigned long * ++bitmap_set_multiple(unsigned long *bitmap, size_t start, size_t count, ++ bool value) ++{ ++ if (count && start % BITMAP_ULONG_BITS) { ++ size_t n = MIN(count, BITMAP_ULONG_BITS - start % BITMAP_ULONG_BITS); ++ ++ bitmap_set_n__(bitmap, start, n, value); ++ count -= n; ++ start += n; ++ } ++ for (; count >= BITMAP_ULONG_BITS; count -= BITMAP_ULONG_BITS) { ++ *bitmap_unit__(bitmap, start) = (unsigned long)!value - 1; ++ start += BITMAP_ULONG_BITS; ++ } ++ if (count) { ++ bitmap_set_n__(bitmap, start, count, value); ++ } ++ return bitmap; ++} ++ ++/* Returns the number of 1-bits in the 'n'-bit bitmap at 'bitmap'. */ ++static inline size_t ++bitmap_count1(const unsigned long int *bitmap, size_t n) ++{ ++ size_t i; ++ size_t count = 0; ++ ++ BUILD_ASSERT(ULONG_MAX <= UINT64_MAX); ++ for (i = 0; i < BITMAP_N_LONGS(n); i++) { ++ count += count_1bits(bitmap[i]); ++ } ++ return count; ++} ++ ++/* "dst &= arg;" for n-bit dst and arg. */ ++static inline unsigned long * ++bitmap_and(unsigned long *dst, const unsigned long *arg, size_t n) ++{ ++ size_t i; ++ ++ for (i = 0; i < BITMAP_N_LONGS(n); i++) { ++ dst[i] &= arg[i]; ++ } ++ return dst; ++} ++ ++/* "dst |= arg;" for n-bit dst and arg. */ ++static inline unsigned long * ++bitmap_or(unsigned long *dst, const unsigned long *arg, size_t n) ++{ ++ size_t i; ++ ++ for (i = 0; i < BITMAP_N_LONGS(n); i++) { ++ dst[i] |= arg[i]; ++ } ++ return dst; ++} ++ ++/* "dst = ~dst;" for n-bit dst. */ ++static inline unsigned long * ++bitmap_not(unsigned long *dst, size_t n) ++{ ++ size_t i; ++ ++ for (i = 0; i < n / BITMAP_ULONG_BITS; i++) { ++ dst[i] = ~dst[i]; ++ } ++ if (n % BITMAP_ULONG_BITS) { ++ dst[i] ^= (1UL << (n % BITMAP_ULONG_BITS)) - 1; ++ } ++ return dst; ++} ++ ++/* Compares the 'n' bits in bitmaps 'a' and 'b'. Returns true if all bits are ++ * equal, false otherwise. */ ++static inline bool ++bitmap_equal(const unsigned long *a, const unsigned long *b, size_t n) ++{ ++ if (memcmp(a, b, n / BITMAP_ULONG_BITS * sizeof(unsigned long))) { ++ return false; ++ } ++ if (n % BITMAP_ULONG_BITS) { ++ unsigned long mask = (1UL << n % BITMAP_ULONG_BITS) - 1; ++ unsigned long diff = *bitmap_unit__(a, n) ^ *bitmap_unit__(b, n); ++ ++ return !(diff & mask); ++ } ++ return true; ++} ++ ++/* Scans 'bitmap' from bit offset 'start' to 'end', excluding 'end' itself. ++ * Returns the bit offset of the lowest-numbered bit set to 'target', or 'end' ++ * if all of the bits are set to '!target'. 'target' is typically a ++ * compile-time constant, so it makes sense to inline this. Compiler may also ++ * optimize parts away depending on the 'start' and 'end' values passed in. */ ++static inline size_t ++bitmap_scan(const unsigned long *bitmap, bool target, size_t start, size_t end) ++{ ++ if (OVS_LIKELY(start < end)) { ++ unsigned long *p, unit; ++ ++ p = bitmap_unit__(bitmap, start); ++ unit = (target ? *p : ~*p) >> (start % BITMAP_ULONG_BITS); ++ if (!unit) { ++ start -= start % BITMAP_ULONG_BITS; /* Round down. */ ++ start += BITMAP_ULONG_BITS; /* Start of the next unit. */ ++ ++ for (; start < end; start += BITMAP_ULONG_BITS) { ++ unit = target ? *++p : ~*++p; ++ if (unit) { ++ goto found; ++ } ++ } ++ return end; ++ } ++found: ++ start += raw_ctz(unit); /* unit != 0 */ ++ if (OVS_LIKELY(start < end)) { ++ return start; ++ } ++ } ++ return end; ++} ++ ++/* Returns true if the 1-bits in 'super' are a superset of the 1-bits in 'sub', ++ * false otherwise. 'super' and 'sub' both have 'n_bits' bits. */ ++static inline bool ++bitmap_is_superset(const unsigned long int *super, ++ const unsigned long int *sub, size_t n_bits) ++{ ++ size_t n_longs = bitmap_n_longs(n_bits); ++ for (size_t i = 0; i < n_longs; i++) { ++ if (!uint_is_superset(super[i], sub[i])) { ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* Returns true if all of the 'n' bits in 'bitmap' are 0, ++ * false if at least one bit is a 1.*/ ++static inline bool ++bitmap_is_all_zeros(const unsigned long *bitmap, size_t n) ++{ ++ return bitmap_scan(bitmap, true, 0, n) == n; ++} ++ ++#define BITMAP_FOR_EACH_1_RANGE(IDX, BEGIN, END, BITMAP) \ ++ for ((IDX) = bitmap_scan(BITMAP, true, BEGIN, END); (IDX) < (END); \ ++ (IDX) = bitmap_scan(BITMAP, true, (IDX) + 1, END)) ++#define BITMAP_FOR_EACH_1(IDX, SIZE, BITMAP) \ ++ BITMAP_FOR_EACH_1_RANGE(IDX, 0, SIZE, BITMAP) ++ ++/* More efficient access to a map of single ullong. */ ++#define ULLONG_FOR_EACH_1(IDX, MAP) \ ++ for (uint64_t map__ = (MAP); \ ++ map__ && (((IDX) = raw_ctz(map__)), true); \ ++ map__ = zero_rightmost_1bit(map__)) ++ ++#define ULLONG_SET0(MAP, OFFSET) ((MAP) &= ~(1ULL << (OFFSET))) ++#define ULLONG_SET1(MAP, OFFSET) ((MAP) |= 1ULL << (OFFSET)) ++ ++/* Returns the value of a bit in a map as a bool. */ ++#define ULLONG_GET(MAP, OFFSET) !!((MAP) & (1ULL << (OFFSET))) ++ ++#endif /* bitmap.h */ +Index: openvswitch-2.17.2/lib/classifier.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/classifier.h ++++ /dev/null +@@ -1,482 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef CLASSIFIER_H +-#define CLASSIFIER_H 1 +- +-/* Flow classifier. +- * +- * +- * What? +- * ===== +- * +- * A flow classifier holds any number of "rules", each of which specifies +- * values to match for some fields or subfields and a priority. Each OpenFlow +- * table is implemented as a flow classifier. +- * +- * The classifier has two primary design goals. The first is obvious: given a +- * set of packet headers, as quickly as possible find the highest-priority rule +- * that matches those headers. The following section describes the second +- * goal. +- * +- * +- * "Un-wildcarding" +- * ================ +- * +- * A primary goal of the flow classifier is to produce, as a side effect of a +- * packet lookup, a wildcard mask that indicates which bits of the packet +- * headers were essential to the classification result. Ideally, a 1-bit in +- * any position of this mask means that, if the corresponding bit in the packet +- * header were flipped, then the classification result might change. A 0-bit +- * means that changing the packet header bit would have no effect. Thus, the +- * wildcarded bits are the ones that played no role in the classification +- * decision. +- * +- * Such a wildcard mask is useful with datapaths that support installing flows +- * that wildcard fields or subfields. If an OpenFlow lookup for a TCP flow +- * does not actually look at the TCP source or destination ports, for example, +- * then the switch may install into the datapath a flow that wildcards the port +- * numbers, which in turn allows the datapath to handle packets that arrive for +- * other TCP source or destination ports without additional help from +- * ovs-vswitchd. This is useful for the Open vSwitch software and, +- * potentially, for ASIC-based switches as well. +- * +- * Some properties of the wildcard mask: +- * +- * - "False 1-bits" are acceptable, that is, setting a bit in the wildcard +- * mask to 1 will never cause a packet to be forwarded the wrong way. +- * As a corollary, a wildcard mask composed of all 1-bits will always +- * yield correct (but often needlessly inefficient) behavior. +- * +- * - "False 0-bits" can cause problems, so they must be avoided. In the +- * extreme case, a mask of all 0-bits is only correct if the classifier +- * contains only a single flow that matches all packets. +- * +- * - 0-bits are desirable because they allow the datapath to act more +- * autonomously, relying less on ovs-vswitchd to process flow setups, +- * thereby improving performance. +- * +- * - We don't know a good way to generate wildcard masks with the maximum +- * (correct) number of 0-bits. We use various approximations, described +- * in later sections. +- * +- * - Wildcard masks for lookups in a given classifier yield a +- * non-overlapping set of rules. More specifically: +- * +- * Consider an classifier C1 filled with an arbitrary collection of rules +- * and an empty classifier C2. Now take a set of packet headers H and +- * look it up in C1, yielding a highest-priority matching rule R1 and +- * wildcard mask M. Form a new classifier rule R2 out of packet headers +- * H and mask M, and add R2 to C2 with a fixed priority. If one were to +- * do this for every possible set of packet headers H, then this +- * process would not attempt to add any overlapping rules to C2, that is, +- * any packet lookup using the rules generated by this process matches at +- * most one rule in C2. +- * +- * During the lookup process, the classifier starts out with a wildcard mask +- * that is all 0-bits, that is, fully wildcarded. As lookup proceeds, each +- * step tends to add constraints to the wildcard mask, that is, change +- * wildcarded 0-bits into exact-match 1-bits. We call this "un-wildcarding". +- * A lookup step that examines a particular field must un-wildcard that field. +- * In general, un-wildcarding is necessary for correctness but undesirable for +- * performance. +- * +- * +- * Basic Classifier Design +- * ======================= +- * +- * Suppose that all the rules in a classifier had the same form. For example, +- * suppose that they all matched on the source and destination Ethernet address +- * and wildcarded all the other fields. Then the obvious way to implement a +- * classifier would be a hash table on the source and destination Ethernet +- * addresses. If new classification rules came along with a different form, +- * you could add a second hash table that hashed on the fields matched in those +- * rules. With two hash tables, you look up a given flow in each hash table. +- * If there are no matches, the classifier didn't contain a match; if you find +- * a match in one of them, that's the result; if you find a match in both of +- * them, then the result is the rule with the higher priority. +- * +- * This is how the classifier works. In a "struct classifier", each form of +- * "struct cls_rule" present (based on its ->match.mask) goes into a separate +- * "struct cls_subtable". A lookup does a hash lookup in every "struct +- * cls_subtable" in the classifier and tracks the highest-priority match that +- * it finds. The subtables are kept in a descending priority order according +- * to the highest priority rule in each subtable, which allows lookup to skip +- * over subtables that can't possibly have a higher-priority match than already +- * found. Eliminating lookups through priority ordering aids both classifier +- * primary design goals: skipping lookups saves time and avoids un-wildcarding +- * fields that those lookups would have examined. +- * +- * One detail: a classifier can contain multiple rules that are identical other +- * than their priority. When this happens, only the highest priority rule out +- * of a group of otherwise identical rules is stored directly in the "struct +- * cls_subtable", with the other almost-identical rules chained off a linked +- * list inside that highest-priority rule. +- * +- * The following sub-sections describe various optimizations over this simple +- * approach. +- * +- * +- * Staged Lookup (Wildcard Optimization) +- * ------------------------------------- +- * +- * Subtable lookup is performed in ranges defined for struct flow, starting +- * from metadata (registers, in_port, etc.), then L2 header, L3, and finally +- * L4 ports. Whenever it is found that there are no matches in the current +- * subtable, the rest of the subtable can be skipped. +- * +- * Staged lookup does not reduce lookup time, and it may increase it, because +- * it changes a single hash table lookup into multiple hash table lookups. +- * It reduces un-wildcarding significantly in important use cases. +- * +- * +- * Prefix Tracking (Wildcard Optimization) +- * --------------------------------------- +- * +- * Classifier uses prefix trees ("tries") for tracking the used +- * address space, enabling skipping classifier tables containing +- * longer masks than necessary for the given address. This reduces +- * un-wildcarding for datapath flows in parts of the address space +- * without host routes, but consulting extra data structures (the +- * tries) may slightly increase lookup time. +- * +- * Trie lookup is interwoven with staged lookup, so that a trie is +- * searched only when the configured trie field becomes relevant for +- * the lookup. The trie lookup results are retained so that each trie +- * is checked at most once for each classifier lookup. +- * +- * This implementation tracks the number of rules at each address +- * prefix for the whole classifier. More aggressive table skipping +- * would be possible by maintaining lists of tables that have prefixes +- * at the lengths encountered on tree traversal, or by maintaining +- * separate tries for subsets of rules separated by metadata fields. +- * +- * Prefix tracking is configured via OVSDB "Flow_Table" table, +- * "fieldspec" column. "fieldspec" is a string map where a "prefix" +- * key tells which fields should be used for prefix tracking. The +- * value of the "prefix" key is a comma separated list of field names. +- * +- * There is a maximum number of fields that can be enabled for any one +- * flow table. Currently this limit is 3. +- * +- * +- * Partitioning (Lookup Time and Wildcard Optimization) +- * ---------------------------------------------------- +- * +- * Suppose that a given classifier is being used to handle multiple stages in a +- * pipeline using "resubmit", with metadata (that is, the OpenFlow 1.1+ field +- * named "metadata") distinguishing between the different stages. For example, +- * metadata value 1 might identify ingress rules, metadata value 2 might +- * identify ACLs, and metadata value 3 might identify egress rules. Such a +- * classifier is essentially partitioned into multiple sub-classifiers on the +- * basis of the metadata value. +- * +- * The classifier has a special optimization to speed up matching in this +- * scenario: +- * +- * - Each cls_subtable that matches on metadata gets a tag derived from the +- * subtable's mask, so that it is likely that each subtable has a unique +- * tag. (Duplicate tags have a performance cost but do not affect +- * correctness.) +- * +- * - For each metadata value matched by any cls_rule, the classifier +- * constructs a "struct cls_partition" indexed by the metadata value. +- * The cls_partition has a 'tags' member whose value is the bitwise-OR of +- * the tags of each cls_subtable that contains any rule that matches on +- * the cls_partition's metadata value. In other words, struct +- * cls_partition associates metadata values with subtables that need to +- * be checked with flows with that specific metadata value. +- * +- * Thus, a flow lookup can start by looking up the partition associated with +- * the flow's metadata, and then skip over any cls_subtable whose 'tag' does +- * not intersect the partition's 'tags'. (The flow must also be looked up in +- * any cls_subtable that doesn't match on metadata. We handle that by giving +- * any such cls_subtable TAG_ALL as its 'tags' so that it matches any tag.) +- * +- * Partitioning saves lookup time by reducing the number of subtable lookups. +- * Each eliminated subtable lookup also reduces the amount of un-wildcarding. +- * +- * +- * Classifier Versioning +- * ===================== +- * +- * Classifier lookups are always done in a specific classifier version, where +- * a version is defined to be a natural number. +- * +- * When a new rule is added to a classifier, it is set to become visible in a +- * specific version. If the version number used at insert time is larger than +- * any version number currently used in lookups, the new rule is said to be +- * invisible to lookups. This means that lookups won't find the rule, but the +- * rule is immediately available to classifier iterations. +- * +- * Similarly, a rule can be marked as to be deleted in a future version. To +- * delete a rule in a way to not remove the rule before all ongoing lookups are +- * finished, the rule should be made invisible in a specific version number. +- * Then, when all the lookups use a later version number, the rule can be +- * actually removed from the classifier. +- * +- * Classifiers can hold duplicate rules (rules with the same match criteria and +- * priority) when at most one of these duplicates is visible in any given +- * lookup version. The caller responsible for classifier modifications must +- * maintain this invariant. +- * +- * The classifier supports versioning for two reasons: +- * +- * 1. Support for versioned modifications makes it possible to perform an +- * arbitrary series of classifier changes as one atomic transaction, +- * where intermediate versions of the classifier are not visible to any +- * lookups. Also, when a rule is added for a future version, or marked +- * for removal after the current version, such modifications can be +- * reverted without any visible effects to any of the current lookups. +- * +- * 2. Performance: Adding (or deleting) a large set of rules can, in +- * pathological cases, have a cost proportional to the number of rules +- * already in the classifier. When multiple rules are being added (or +- * deleted) in one go, though, this pathological case cost can be +- * typically avoided, as long as it is OK for any new rules to be +- * invisible until the batch change is complete. +- * +- * Note that the classifier_replace() function replaces a rule immediately, and +- * is therefore not safe to use with versioning. It is still available for the +- * users that do not use versioning. +- * +- * +- * Deferred Publication +- * ==================== +- * +- * Removing large number of rules from classifier can be costly, as the +- * supporting data structures are teared down, in many cases just to be +- * re-instantiated right after. In the worst case, as when each rule has a +- * different match pattern (mask), the maintenance of the match patterns can +- * have cost O(N^2), where N is the number of different match patterns. To +- * alleviate this, the classifier supports a "deferred mode", in which changes +- * in internal data structures needed for future version lookups may not be +- * fully computed yet. The computation is finalized when the deferred mode is +- * turned off. +- * +- * This feature can be used with versioning such that all changes to future +- * versions are made in the deferred mode. Then, right before making the new +- * version visible to lookups, the deferred mode is turned off so that all the +- * data structures are ready for lookups with the new version number. +- * +- * To use deferred publication, first call classifier_defer(). Then, modify +- * the classifier via additions (classifier_insert() with a specific, future +- * version number) and deletions (use cls_rule_make_removable_after_version()). +- * Then call classifier_publish(), and after that, announce the new version +- * number to be used in lookups. +- * +- * +- * Thread-safety +- * ============= +- * +- * The classifier may safely be accessed by many reader threads concurrently +- * and by a single writer, or by multiple writers when they guarantee mutually +- * exclusive access to classifier modifications. +- * +- * Since the classifier rules are RCU protected, the rule destruction after +- * removal from the classifier must be RCU postponed. Also, when versioning is +- * used, the rule removal itself needs to be typically RCU postponed. In this +- * case the rule destruction is doubly RCU postponed, i.e., the second +- * ovsrcu_postpone() call to destruct the rule is called from the first RCU +- * callback that removes the rule. +- * +- * Rules that have never been visible to lookups are an exception to the above +- * rule. Such rules can be removed immediately, but their destruction must +- * still be RCU postponed, as the rule's visibility attribute may be examined +- * parallel to the rule's removal. */ +- -#include "cmap.h" -+#include "internal/cmap.h" - #include "openvswitch/match.h" - #include "openvswitch/meta-flow.h" +-#include "openvswitch/match.h" +-#include "openvswitch/meta-flow.h" -#include "pvector.h" -#include "rculist.h" +-#include "openvswitch/type-props.h" +-#include "versions.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* Classifier internal data structures. */ +-struct cls_subtable; +-struct cls_match; +- +-struct mf_field; +-typedef OVSRCU_TYPE(struct mf_field *) rcu_field_ptr; +-struct trie_node; +-typedef OVSRCU_TYPE(struct trie_node *) rcu_trie_ptr; +- +-/* Prefix trie for a 'field' */ +-struct cls_trie { +- rcu_field_ptr field; /* Trie field, or NULL. */ +- rcu_trie_ptr root; /* NULL if none. */ +-}; +- +-enum { +- CLS_MAX_INDICES = 3, /* Maximum number of lookup indices per subtable. */ +- CLS_MAX_TRIES = 3 /* Maximum number of prefix trees per classifier. */ +-}; +- +-/* A flow classifier. */ +-struct classifier { +- int n_rules; /* Total number of rules. */ +- uint8_t n_flow_segments; +- uint8_t flow_segments[CLS_MAX_INDICES]; /* Flow segment boundaries to use +- * for staged lookup. */ +- struct cmap subtables_map; /* Contains "struct cls_subtable"s. */ +- struct pvector subtables; +- struct cmap partitions; /* Contains "struct cls_partition"s. */ +- struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */ +- unsigned int n_tries; +- bool publish; /* Make changes visible to lookups? */ +-}; +- +-struct cls_conjunction { +- uint32_t id; +- uint8_t clause; +- uint8_t n_clauses; +-}; +- +-/* A rule to be inserted to the classifier. */ +-struct cls_rule { +- struct rculist node; /* In struct cls_subtable 'rules_list'. */ +- const int priority; /* Larger numbers are higher priorities. */ +- OVSRCU_TYPE(struct cls_match *) cls_match; /* NULL if not in a +- * classifier. */ +- const struct minimatch match; /* Matching rule. */ +-}; +- +-/* Constructor/destructor. Must run single-threaded. */ +-void classifier_init(struct classifier *, const uint8_t *flow_segments); +-void classifier_destroy(struct classifier *); +- +-/* Modifiers. Caller MUST exclude concurrent calls from other threads. */ +-bool classifier_set_prefix_fields(struct classifier *, +- const enum mf_field_id *trie_fields, +- unsigned int n_trie_fields); +- +-void cls_rule_init(struct cls_rule *, const struct match *, int priority); +-void cls_rule_init_from_minimatch(struct cls_rule *, const struct minimatch *, +- int priority); +-void cls_rule_clone(struct cls_rule *, const struct cls_rule *); +-void cls_rule_move(struct cls_rule *dst, struct cls_rule *src); +-void cls_rule_destroy(struct cls_rule *); +- +-void cls_rule_set_conjunctions(struct cls_rule *, +- const struct cls_conjunction *, size_t n); +-void cls_rule_make_invisible_in_version(const struct cls_rule *, +- ovs_version_t); +-void cls_rule_restore_visibility(const struct cls_rule *); +- +-void classifier_insert(struct classifier *, const struct cls_rule *, +- ovs_version_t, const struct cls_conjunction *, +- size_t n_conjunctions); +-const struct cls_rule *classifier_replace(struct classifier *, +- const struct cls_rule *, +- ovs_version_t, +- const struct cls_conjunction *, +- size_t n_conjunctions); +-bool classifier_remove(struct classifier *, const struct cls_rule *); +-void classifier_remove_assert(struct classifier *, const struct cls_rule *); +-static inline void classifier_defer(struct classifier *); +-static inline void classifier_publish(struct classifier *); +- +-/* Lookups. These are RCU protected and may run concurrently with modifiers +- * and each other. */ +-const struct cls_rule *classifier_lookup(const struct classifier *, +- ovs_version_t, struct flow *, +- struct flow_wildcards *); +-bool classifier_rule_overlaps(const struct classifier *, +- const struct cls_rule *, ovs_version_t); +-const struct cls_rule *classifier_find_rule_exactly(const struct classifier *, +- const struct cls_rule *, +- ovs_version_t); +-const struct cls_rule *classifier_find_match_exactly(const struct classifier *, +- const struct match *, +- int priority, +- ovs_version_t); +-const struct cls_rule *classifier_find_minimatch_exactly( +- const struct classifier *, const struct minimatch *, +- int priority, ovs_version_t); +- +-bool classifier_is_empty(const struct classifier *); +-int classifier_count(const struct classifier *); +- +-/* Classifier rule properties. These are RCU protected and may run +- * concurrently with modifiers and each other. */ +-bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *); +-void cls_rule_format(const struct cls_rule *, const struct tun_table *, +- const struct ofputil_port_map *, struct ds *); +-bool cls_rule_is_catchall(const struct cls_rule *); +-bool cls_rule_is_loose_match(const struct cls_rule *rule, +- const struct minimatch *criteria); +-bool cls_rule_visible_in_version(const struct cls_rule *, ovs_version_t); +- +-/* Iteration. +- * +- * Iteration is lockless and RCU-protected. Concurrent threads may perform all +- * kinds of concurrent modifications without ruining the iteration. Obviously, +- * any modifications may or may not be visible to the concurrent iterator, but +- * all the rules not deleted are visited by the iteration. The iterating +- * thread may also modify the classifier rules itself. +- * +- * 'TARGET' iteration only iterates rules matching the 'TARGET' criteria. +- * Rather than looping through all the rules and skipping ones that can't +- * match, 'TARGET' iteration skips whole subtables, if the 'TARGET' happens to +- * be more specific than the subtable. */ +-struct cls_cursor { +- const struct classifier *cls; +- const struct cls_subtable *subtable; +- const struct cls_rule *target; +- ovs_version_t version; /* Version to iterate. */ +- struct pvector_cursor subtables; +- const struct cls_rule *rule; +-}; +- +-struct cls_cursor cls_cursor_start(const struct classifier *, +- const struct cls_rule *target, +- ovs_version_t); +-void cls_cursor_advance(struct cls_cursor *); +- +-#define CLS_FOR_EACH(RULE, MEMBER, CLS) \ +- CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, NULL, OVS_VERSION_MAX) +-#define CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, TARGET, VERSION) \ +- for (struct cls_cursor cursor__ = cls_cursor_start(CLS, TARGET, VERSION); \ +- (cursor__.rule \ +- ? (INIT_CONTAINER(RULE, cursor__.rule, MEMBER), \ +- cls_cursor_advance(&cursor__), \ +- true) \ +- : false); \ +- ) +- +- +-static inline void +-classifier_defer(struct classifier *cls) +-{ +- cls->publish = false; +-} +- +-static inline void +-classifier_publish(struct classifier *cls) +-{ +- cls->publish = true; +- pvector_publish(&cls->subtables); +-} +- +-#ifdef __cplusplus +-} +-#endif +-#endif /* classifier.h */ +Index: openvswitch-2.17.2/include/internal/classifier.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/classifier.h +@@ -0,0 +1,482 @@ ++/* ++ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef CLASSIFIER_H ++#define CLASSIFIER_H 1 ++ ++/* Flow classifier. ++ * ++ * ++ * What? ++ * ===== ++ * ++ * A flow classifier holds any number of "rules", each of which specifies ++ * values to match for some fields or subfields and a priority. Each OpenFlow ++ * table is implemented as a flow classifier. ++ * ++ * The classifier has two primary design goals. The first is obvious: given a ++ * set of packet headers, as quickly as possible find the highest-priority rule ++ * that matches those headers. The following section describes the second ++ * goal. ++ * ++ * ++ * "Un-wildcarding" ++ * ================ ++ * ++ * A primary goal of the flow classifier is to produce, as a side effect of a ++ * packet lookup, a wildcard mask that indicates which bits of the packet ++ * headers were essential to the classification result. Ideally, a 1-bit in ++ * any position of this mask means that, if the corresponding bit in the packet ++ * header were flipped, then the classification result might change. A 0-bit ++ * means that changing the packet header bit would have no effect. Thus, the ++ * wildcarded bits are the ones that played no role in the classification ++ * decision. ++ * ++ * Such a wildcard mask is useful with datapaths that support installing flows ++ * that wildcard fields or subfields. If an OpenFlow lookup for a TCP flow ++ * does not actually look at the TCP source or destination ports, for example, ++ * then the switch may install into the datapath a flow that wildcards the port ++ * numbers, which in turn allows the datapath to handle packets that arrive for ++ * other TCP source or destination ports without additional help from ++ * ovs-vswitchd. This is useful for the Open vSwitch software and, ++ * potentially, for ASIC-based switches as well. ++ * ++ * Some properties of the wildcard mask: ++ * ++ * - "False 1-bits" are acceptable, that is, setting a bit in the wildcard ++ * mask to 1 will never cause a packet to be forwarded the wrong way. ++ * As a corollary, a wildcard mask composed of all 1-bits will always ++ * yield correct (but often needlessly inefficient) behavior. ++ * ++ * - "False 0-bits" can cause problems, so they must be avoided. In the ++ * extreme case, a mask of all 0-bits is only correct if the classifier ++ * contains only a single flow that matches all packets. ++ * ++ * - 0-bits are desirable because they allow the datapath to act more ++ * autonomously, relying less on ovs-vswitchd to process flow setups, ++ * thereby improving performance. ++ * ++ * - We don't know a good way to generate wildcard masks with the maximum ++ * (correct) number of 0-bits. We use various approximations, described ++ * in later sections. ++ * ++ * - Wildcard masks for lookups in a given classifier yield a ++ * non-overlapping set of rules. More specifically: ++ * ++ * Consider an classifier C1 filled with an arbitrary collection of rules ++ * and an empty classifier C2. Now take a set of packet headers H and ++ * look it up in C1, yielding a highest-priority matching rule R1 and ++ * wildcard mask M. Form a new classifier rule R2 out of packet headers ++ * H and mask M, and add R2 to C2 with a fixed priority. If one were to ++ * do this for every possible set of packet headers H, then this ++ * process would not attempt to add any overlapping rules to C2, that is, ++ * any packet lookup using the rules generated by this process matches at ++ * most one rule in C2. ++ * ++ * During the lookup process, the classifier starts out with a wildcard mask ++ * that is all 0-bits, that is, fully wildcarded. As lookup proceeds, each ++ * step tends to add constraints to the wildcard mask, that is, change ++ * wildcarded 0-bits into exact-match 1-bits. We call this "un-wildcarding". ++ * A lookup step that examines a particular field must un-wildcard that field. ++ * In general, un-wildcarding is necessary for correctness but undesirable for ++ * performance. ++ * ++ * ++ * Basic Classifier Design ++ * ======================= ++ * ++ * Suppose that all the rules in a classifier had the same form. For example, ++ * suppose that they all matched on the source and destination Ethernet address ++ * and wildcarded all the other fields. Then the obvious way to implement a ++ * classifier would be a hash table on the source and destination Ethernet ++ * addresses. If new classification rules came along with a different form, ++ * you could add a second hash table that hashed on the fields matched in those ++ * rules. With two hash tables, you look up a given flow in each hash table. ++ * If there are no matches, the classifier didn't contain a match; if you find ++ * a match in one of them, that's the result; if you find a match in both of ++ * them, then the result is the rule with the higher priority. ++ * ++ * This is how the classifier works. In a "struct classifier", each form of ++ * "struct cls_rule" present (based on its ->match.mask) goes into a separate ++ * "struct cls_subtable". A lookup does a hash lookup in every "struct ++ * cls_subtable" in the classifier and tracks the highest-priority match that ++ * it finds. The subtables are kept in a descending priority order according ++ * to the highest priority rule in each subtable, which allows lookup to skip ++ * over subtables that can't possibly have a higher-priority match than already ++ * found. Eliminating lookups through priority ordering aids both classifier ++ * primary design goals: skipping lookups saves time and avoids un-wildcarding ++ * fields that those lookups would have examined. ++ * ++ * One detail: a classifier can contain multiple rules that are identical other ++ * than their priority. When this happens, only the highest priority rule out ++ * of a group of otherwise identical rules is stored directly in the "struct ++ * cls_subtable", with the other almost-identical rules chained off a linked ++ * list inside that highest-priority rule. ++ * ++ * The following sub-sections describe various optimizations over this simple ++ * approach. ++ * ++ * ++ * Staged Lookup (Wildcard Optimization) ++ * ------------------------------------- ++ * ++ * Subtable lookup is performed in ranges defined for struct flow, starting ++ * from metadata (registers, in_port, etc.), then L2 header, L3, and finally ++ * L4 ports. Whenever it is found that there are no matches in the current ++ * subtable, the rest of the subtable can be skipped. ++ * ++ * Staged lookup does not reduce lookup time, and it may increase it, because ++ * it changes a single hash table lookup into multiple hash table lookups. ++ * It reduces un-wildcarding significantly in important use cases. ++ * ++ * ++ * Prefix Tracking (Wildcard Optimization) ++ * --------------------------------------- ++ * ++ * Classifier uses prefix trees ("tries") for tracking the used ++ * address space, enabling skipping classifier tables containing ++ * longer masks than necessary for the given address. This reduces ++ * un-wildcarding for datapath flows in parts of the address space ++ * without host routes, but consulting extra data structures (the ++ * tries) may slightly increase lookup time. ++ * ++ * Trie lookup is interwoven with staged lookup, so that a trie is ++ * searched only when the configured trie field becomes relevant for ++ * the lookup. The trie lookup results are retained so that each trie ++ * is checked at most once for each classifier lookup. ++ * ++ * This implementation tracks the number of rules at each address ++ * prefix for the whole classifier. More aggressive table skipping ++ * would be possible by maintaining lists of tables that have prefixes ++ * at the lengths encountered on tree traversal, or by maintaining ++ * separate tries for subsets of rules separated by metadata fields. ++ * ++ * Prefix tracking is configured via OVSDB "Flow_Table" table, ++ * "fieldspec" column. "fieldspec" is a string map where a "prefix" ++ * key tells which fields should be used for prefix tracking. The ++ * value of the "prefix" key is a comma separated list of field names. ++ * ++ * There is a maximum number of fields that can be enabled for any one ++ * flow table. Currently this limit is 3. ++ * ++ * ++ * Partitioning (Lookup Time and Wildcard Optimization) ++ * ---------------------------------------------------- ++ * ++ * Suppose that a given classifier is being used to handle multiple stages in a ++ * pipeline using "resubmit", with metadata (that is, the OpenFlow 1.1+ field ++ * named "metadata") distinguishing between the different stages. For example, ++ * metadata value 1 might identify ingress rules, metadata value 2 might ++ * identify ACLs, and metadata value 3 might identify egress rules. Such a ++ * classifier is essentially partitioned into multiple sub-classifiers on the ++ * basis of the metadata value. ++ * ++ * The classifier has a special optimization to speed up matching in this ++ * scenario: ++ * ++ * - Each cls_subtable that matches on metadata gets a tag derived from the ++ * subtable's mask, so that it is likely that each subtable has a unique ++ * tag. (Duplicate tags have a performance cost but do not affect ++ * correctness.) ++ * ++ * - For each metadata value matched by any cls_rule, the classifier ++ * constructs a "struct cls_partition" indexed by the metadata value. ++ * The cls_partition has a 'tags' member whose value is the bitwise-OR of ++ * the tags of each cls_subtable that contains any rule that matches on ++ * the cls_partition's metadata value. In other words, struct ++ * cls_partition associates metadata values with subtables that need to ++ * be checked with flows with that specific metadata value. ++ * ++ * Thus, a flow lookup can start by looking up the partition associated with ++ * the flow's metadata, and then skip over any cls_subtable whose 'tag' does ++ * not intersect the partition's 'tags'. (The flow must also be looked up in ++ * any cls_subtable that doesn't match on metadata. We handle that by giving ++ * any such cls_subtable TAG_ALL as its 'tags' so that it matches any tag.) ++ * ++ * Partitioning saves lookup time by reducing the number of subtable lookups. ++ * Each eliminated subtable lookup also reduces the amount of un-wildcarding. ++ * ++ * ++ * Classifier Versioning ++ * ===================== ++ * ++ * Classifier lookups are always done in a specific classifier version, where ++ * a version is defined to be a natural number. ++ * ++ * When a new rule is added to a classifier, it is set to become visible in a ++ * specific version. If the version number used at insert time is larger than ++ * any version number currently used in lookups, the new rule is said to be ++ * invisible to lookups. This means that lookups won't find the rule, but the ++ * rule is immediately available to classifier iterations. ++ * ++ * Similarly, a rule can be marked as to be deleted in a future version. To ++ * delete a rule in a way to not remove the rule before all ongoing lookups are ++ * finished, the rule should be made invisible in a specific version number. ++ * Then, when all the lookups use a later version number, the rule can be ++ * actually removed from the classifier. ++ * ++ * Classifiers can hold duplicate rules (rules with the same match criteria and ++ * priority) when at most one of these duplicates is visible in any given ++ * lookup version. The caller responsible for classifier modifications must ++ * maintain this invariant. ++ * ++ * The classifier supports versioning for two reasons: ++ * ++ * 1. Support for versioned modifications makes it possible to perform an ++ * arbitrary series of classifier changes as one atomic transaction, ++ * where intermediate versions of the classifier are not visible to any ++ * lookups. Also, when a rule is added for a future version, or marked ++ * for removal after the current version, such modifications can be ++ * reverted without any visible effects to any of the current lookups. ++ * ++ * 2. Performance: Adding (or deleting) a large set of rules can, in ++ * pathological cases, have a cost proportional to the number of rules ++ * already in the classifier. When multiple rules are being added (or ++ * deleted) in one go, though, this pathological case cost can be ++ * typically avoided, as long as it is OK for any new rules to be ++ * invisible until the batch change is complete. ++ * ++ * Note that the classifier_replace() function replaces a rule immediately, and ++ * is therefore not safe to use with versioning. It is still available for the ++ * users that do not use versioning. ++ * ++ * ++ * Deferred Publication ++ * ==================== ++ * ++ * Removing large number of rules from classifier can be costly, as the ++ * supporting data structures are teared down, in many cases just to be ++ * re-instantiated right after. In the worst case, as when each rule has a ++ * different match pattern (mask), the maintenance of the match patterns can ++ * have cost O(N^2), where N is the number of different match patterns. To ++ * alleviate this, the classifier supports a "deferred mode", in which changes ++ * in internal data structures needed for future version lookups may not be ++ * fully computed yet. The computation is finalized when the deferred mode is ++ * turned off. ++ * ++ * This feature can be used with versioning such that all changes to future ++ * versions are made in the deferred mode. Then, right before making the new ++ * version visible to lookups, the deferred mode is turned off so that all the ++ * data structures are ready for lookups with the new version number. ++ * ++ * To use deferred publication, first call classifier_defer(). Then, modify ++ * the classifier via additions (classifier_insert() with a specific, future ++ * version number) and deletions (use cls_rule_make_removable_after_version()). ++ * Then call classifier_publish(), and after that, announce the new version ++ * number to be used in lookups. ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * The classifier may safely be accessed by many reader threads concurrently ++ * and by a single writer, or by multiple writers when they guarantee mutually ++ * exclusive access to classifier modifications. ++ * ++ * Since the classifier rules are RCU protected, the rule destruction after ++ * removal from the classifier must be RCU postponed. Also, when versioning is ++ * used, the rule removal itself needs to be typically RCU postponed. In this ++ * case the rule destruction is doubly RCU postponed, i.e., the second ++ * ovsrcu_postpone() call to destruct the rule is called from the first RCU ++ * callback that removes the rule. ++ * ++ * Rules that have never been visible to lookups are an exception to the above ++ * rule. Such rules can be removed immediately, but their destruction must ++ * still be RCU postponed, as the rule's visibility attribute may be examined ++ * parallel to the rule's removal. */ ++ ++#include "internal/cmap.h" ++#include "openvswitch/match.h" ++#include "openvswitch/meta-flow.h" +#include "internal/pvector.h" +#include "internal/rculist.h" - #include "openvswitch/type-props.h" --#include "versions.h" ++#include "openvswitch/type-props.h" +#include "internal/versions.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/cmap.h b/include/internal/cmap.h -similarity index 99% -rename from lib/cmap.h -rename to include/internal/cmap.h -index c502d2311..f7b09c2fe 100644 ---- a/lib/cmap.h -+++ b/include/internal/cmap.h -@@ -19,8 +19,8 @@ - - #include - #include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Classifier internal data structures. */ ++struct cls_subtable; ++struct cls_match; ++ ++struct mf_field; ++typedef OVSRCU_TYPE(struct mf_field *) rcu_field_ptr; ++struct trie_node; ++typedef OVSRCU_TYPE(struct trie_node *) rcu_trie_ptr; ++ ++/* Prefix trie for a 'field' */ ++struct cls_trie { ++ rcu_field_ptr field; /* Trie field, or NULL. */ ++ rcu_trie_ptr root; /* NULL if none. */ ++}; ++ ++enum { ++ CLS_MAX_INDICES = 3, /* Maximum number of lookup indices per subtable. */ ++ CLS_MAX_TRIES = 3 /* Maximum number of prefix trees per classifier. */ ++}; ++ ++/* A flow classifier. */ ++struct classifier { ++ int n_rules; /* Total number of rules. */ ++ uint8_t n_flow_segments; ++ uint8_t flow_segments[CLS_MAX_INDICES]; /* Flow segment boundaries to use ++ * for staged lookup. */ ++ struct cmap subtables_map; /* Contains "struct cls_subtable"s. */ ++ struct pvector subtables; ++ struct cmap partitions; /* Contains "struct cls_partition"s. */ ++ struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */ ++ unsigned int n_tries; ++ bool publish; /* Make changes visible to lookups? */ ++}; ++ ++struct cls_conjunction { ++ uint32_t id; ++ uint8_t clause; ++ uint8_t n_clauses; ++}; ++ ++/* A rule to be inserted to the classifier. */ ++struct cls_rule { ++ struct rculist node; /* In struct cls_subtable 'rules_list'. */ ++ const int priority; /* Larger numbers are higher priorities. */ ++ OVSRCU_TYPE(struct cls_match *) cls_match; /* NULL if not in a ++ * classifier. */ ++ const struct minimatch match; /* Matching rule. */ ++}; ++ ++/* Constructor/destructor. Must run single-threaded. */ ++void classifier_init(struct classifier *, const uint8_t *flow_segments); ++void classifier_destroy(struct classifier *); ++ ++/* Modifiers. Caller MUST exclude concurrent calls from other threads. */ ++bool classifier_set_prefix_fields(struct classifier *, ++ const enum mf_field_id *trie_fields, ++ unsigned int n_trie_fields); ++ ++void cls_rule_init(struct cls_rule *, const struct match *, int priority); ++void cls_rule_init_from_minimatch(struct cls_rule *, const struct minimatch *, ++ int priority); ++void cls_rule_clone(struct cls_rule *, const struct cls_rule *); ++void cls_rule_move(struct cls_rule *dst, struct cls_rule *src); ++void cls_rule_destroy(struct cls_rule *); ++ ++void cls_rule_set_conjunctions(struct cls_rule *, ++ const struct cls_conjunction *, size_t n); ++void cls_rule_make_invisible_in_version(const struct cls_rule *, ++ ovs_version_t); ++void cls_rule_restore_visibility(const struct cls_rule *); ++ ++void classifier_insert(struct classifier *, const struct cls_rule *, ++ ovs_version_t, const struct cls_conjunction *, ++ size_t n_conjunctions); ++const struct cls_rule *classifier_replace(struct classifier *, ++ const struct cls_rule *, ++ ovs_version_t, ++ const struct cls_conjunction *, ++ size_t n_conjunctions); ++bool classifier_remove(struct classifier *, const struct cls_rule *); ++void classifier_remove_assert(struct classifier *, const struct cls_rule *); ++static inline void classifier_defer(struct classifier *); ++static inline void classifier_publish(struct classifier *); ++ ++/* Lookups. These are RCU protected and may run concurrently with modifiers ++ * and each other. */ ++const struct cls_rule *classifier_lookup(const struct classifier *, ++ ovs_version_t, struct flow *, ++ struct flow_wildcards *); ++bool classifier_rule_overlaps(const struct classifier *, ++ const struct cls_rule *, ovs_version_t); ++const struct cls_rule *classifier_find_rule_exactly(const struct classifier *, ++ const struct cls_rule *, ++ ovs_version_t); ++const struct cls_rule *classifier_find_match_exactly(const struct classifier *, ++ const struct match *, ++ int priority, ++ ovs_version_t); ++const struct cls_rule *classifier_find_minimatch_exactly( ++ const struct classifier *, const struct minimatch *, ++ int priority, ovs_version_t); ++ ++bool classifier_is_empty(const struct classifier *); ++int classifier_count(const struct classifier *); ++ ++/* Classifier rule properties. These are RCU protected and may run ++ * concurrently with modifiers and each other. */ ++bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *); ++void cls_rule_format(const struct cls_rule *, const struct tun_table *, ++ const struct ofputil_port_map *, struct ds *); ++bool cls_rule_is_catchall(const struct cls_rule *); ++bool cls_rule_is_loose_match(const struct cls_rule *rule, ++ const struct minimatch *criteria); ++bool cls_rule_visible_in_version(const struct cls_rule *, ovs_version_t); ++ ++/* Iteration. ++ * ++ * Iteration is lockless and RCU-protected. Concurrent threads may perform all ++ * kinds of concurrent modifications without ruining the iteration. Obviously, ++ * any modifications may or may not be visible to the concurrent iterator, but ++ * all the rules not deleted are visited by the iteration. The iterating ++ * thread may also modify the classifier rules itself. ++ * ++ * 'TARGET' iteration only iterates rules matching the 'TARGET' criteria. ++ * Rather than looping through all the rules and skipping ones that can't ++ * match, 'TARGET' iteration skips whole subtables, if the 'TARGET' happens to ++ * be more specific than the subtable. */ ++struct cls_cursor { ++ const struct classifier *cls; ++ const struct cls_subtable *subtable; ++ const struct cls_rule *target; ++ ovs_version_t version; /* Version to iterate. */ ++ struct pvector_cursor subtables; ++ const struct cls_rule *rule; ++}; ++ ++struct cls_cursor cls_cursor_start(const struct classifier *, ++ const struct cls_rule *target, ++ ovs_version_t); ++void cls_cursor_advance(struct cls_cursor *); ++ ++#define CLS_FOR_EACH(RULE, MEMBER, CLS) \ ++ CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, NULL, OVS_VERSION_MAX) ++#define CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, TARGET, VERSION) \ ++ for (struct cls_cursor cursor__ = cls_cursor_start(CLS, TARGET, VERSION); \ ++ (cursor__.rule \ ++ ? (INIT_CONTAINER(RULE, cursor__.rule, MEMBER), \ ++ cls_cursor_advance(&cursor__), \ ++ true) \ ++ : false); \ ++ ) ++ ++ ++static inline void ++classifier_defer(struct classifier *cls) ++{ ++ cls->publish = false; ++} ++ ++static inline void ++classifier_publish(struct classifier *cls) ++{ ++ cls->publish = true; ++ pvector_publish(&cls->subtables); ++} ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* classifier.h */ +Index: openvswitch-2.17.2/lib/cmap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/cmap.h ++++ /dev/null +@@ -1,297 +0,0 @@ +-/* +- * Copyright (c) 2014, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef CMAP_H +-#define CMAP_H 1 +- +-#include +-#include -#include "ovs-rcu.h" -#include "util.h" +- +-/* Concurrent hash map +- * =================== +- * +- * A single-writer, multiple-reader hash table that efficiently supports +- * duplicates. +- * +- * +- * Thread-safety +- * ============= +- * +- * The general rules are: +- * +- * - Only a single thread may safely call into cmap_insert(), +- * cmap_remove(), or cmap_replace() at any given time. +- * +- * - Any number of threads may use functions and macros that search or +- * iterate through a given cmap, even in parallel with other threads +- * calling cmap_insert(), cmap_remove(), or cmap_replace(). +- * +- * There is one exception: cmap_find_protected() is only safe if no thread +- * is currently calling cmap_insert(), cmap_remove(), or cmap_replace(). +- * (Use ordinary cmap_find() if that is not guaranteed.) +- * +- * - See "Iteration" below for additional thread safety rules. +- * +- * Writers must use special care to ensure that any elements that they remove +- * do not get freed or reused until readers have finished with them. This +- * includes inserting the element back into its original cmap or a different +- * one. One correct way to do this is to free them from an RCU callback with +- * ovsrcu_postpone(). +- */ +- +-/* A concurrent hash map node, to be embedded inside the data structure being +- * mapped. +- * +- * All nodes linked together on a chain have exactly the same hash value. */ +-struct cmap_node { +- OVSRCU_TYPE(struct cmap_node *) next; /* Next node with same hash. */ +-}; +- +-static inline struct cmap_node * +-cmap_node_next(const struct cmap_node *node) +-{ +- return ovsrcu_get(struct cmap_node *, &node->next); +-} +- +-static inline struct cmap_node * +-cmap_node_next_protected(const struct cmap_node *node) +-{ +- return ovsrcu_get_protected(struct cmap_node *, &node->next); +-} +- +-/* Concurrent hash map. */ +-struct cmap { +- OVSRCU_TYPE(struct cmap_impl *) impl; +-}; +- +-/* Initializer for an empty cmap. */ +-#define CMAP_INITIALIZER { \ +- .impl = OVSRCU_INITIALIZER((struct cmap_impl *) &empty_cmap) \ +- } +-extern OVS_ALIGNED_VAR(CACHE_LINE_SIZE) const struct cmap_impl empty_cmap; +- +-/* Initialization. */ +-void cmap_init(struct cmap *); +-void cmap_destroy(struct cmap *); +- +-/* Count. */ +-size_t cmap_count(const struct cmap *); +-bool cmap_is_empty(const struct cmap *); +- +-/* Insertion and deletion. Return the current count after the operation. */ +-size_t cmap_insert(struct cmap *, struct cmap_node *, uint32_t hash); +-static inline size_t cmap_remove(struct cmap *, struct cmap_node *, +- uint32_t hash); +-size_t cmap_replace(struct cmap *, struct cmap_node *old_node, +- struct cmap_node *new_node, uint32_t hash); +- +-/* Search. +- * +- * These macros iterate NODE over all of the nodes in CMAP that have hash value +- * equal to HASH. MEMBER must be the name of the 'struct cmap_node' member +- * within NODE. +- * +- * CMAP and HASH are evaluated only once. NODE is evaluated many times. +- * +- * After a normal exit of the loop (not through a "break;" statement) NODE is +- * NULL. +- * +- * Thread-safety +- * ============= +- * +- * CMAP_NODE_FOR_EACH will reliably visit each of the nodes starting with +- * CMAP_NODE, even with concurrent insertions and deletions. (Of +- * course, if nodes are being inserted or deleted, it might or might not visit +- * the nodes actually being inserted or deleted.) +- * +- * CMAP_NODE_FOR_EACH_PROTECTED may only be used if the containing CMAP is +- * guaranteed not to change during iteration. It may be only slightly faster. +- * +- * CMAP_FOR_EACH_WITH_HASH will reliably visit each of the nodes with the +- * specified hash in CMAP, even with concurrent insertions and deletions. (Of +- * course, if nodes with the given HASH are being inserted or deleted, it might +- * or might not visit the nodes actually being inserted or deleted.) +- * +- * CMAP_FOR_EACH_WITH_HASH_PROTECTED may only be used if CMAP is guaranteed not +- * to change during iteration. It may be very slightly faster. +- */ +-#define CMAP_NODE_FOR_EACH(NODE, MEMBER, CMAP_NODE) \ +- for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node); \ +- CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ +- UPDATE_MULTIVAR(NODE, cmap_node_next(ITER_VAR(NODE)))) +-#define CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, CMAP_NODE) \ +- for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node); \ +- CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ +- UPDATE_MULTIVAR(NODE, cmap_node_next_protected(ITER_VAR(NODE)))) +- +-#define CMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, CMAP) \ +- CMAP_NODE_FOR_EACH(NODE, MEMBER, cmap_find(CMAP, HASH)) +-#define CMAP_FOR_EACH_WITH_HASH_PROTECTED(NODE, MEMBER, HASH, CMAP) \ +- CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, cmap_find_protected(CMAP, HASH)) +- +-const struct cmap_node *cmap_find(const struct cmap *, uint32_t hash); +-struct cmap_node *cmap_find_protected(const struct cmap *, uint32_t hash); +- +-/* Find node by index or find index by hash. The 'index' of a cmap entry is a +- * way to combine the specific bucket and the entry of the bucket into a +- * convenient single integer value. In other words, it is the index of the +- * entry and each entry has an unique index. It is not used internally by +- * cmap. +- * Currently the functions assume index will not be larger than uint32_t. In +- * OvS table size is usually much smaller than this size.*/ +-const struct cmap_node * cmap_find_by_index(const struct cmap *, +- uint32_t index); +-uint32_t cmap_find_index(const struct cmap *, uint32_t hash); +- +-/* Looks up multiple 'hashes', when the corresponding bit in 'map' is 1, +- * and sets the corresponding pointer in 'nodes', if the hash value was +- * found from the 'cmap'. In other cases the 'nodes' values are not changed, +- * i.e., no NULL pointers are stored there. +- * Returns a map where a bit is set to 1 if the corresponding 'nodes' pointer +- * was stored, 0 otherwise. +- * Generally, the caller wants to use CMAP_NODE_FOR_EACH to verify for +- * hash collisions. */ +-unsigned long cmap_find_batch(const struct cmap *cmap, unsigned long map, +- uint32_t hashes[], +- const struct cmap_node *nodes[]); +- +-/* Iteration. +- * +- * +- * Thread-safety +- * ============= +- * +- * Iteration is safe even in a cmap that is changing concurrently. However: +- * +- * - In the presence of concurrent calls to cmap_insert(), any given +- * iteration might skip some nodes and might visit some nodes more than +- * once. If this is a problem, then the iterating code should lock the +- * data structure (a rwlock can be used to allow multiple threads to +- * iterate in parallel). +- * +- * - Concurrent calls to cmap_remove() don't have the same problem. (A +- * node being deleted may be visited once or not at all. Other nodes +- * will be visited once.) +- * +- * - If the cmap is changing, it is not safe to quiesce while iterating. +- * Even if the changes are done by the same thread that's performing the +- * iteration (Corollary: it is not safe to call cmap_remove() and quiesce +- * in the loop body). +- * +- * +- * Example +- * ======= +- * +- * struct my_node { +- * struct cmap_node cmap_node; +- * int extra_data; +- * }; +- * +- * struct cmap my_map; +- * struct my_node *my_node; +- * +- * cmap_init(&my_map); +- * ...add data... +- * CMAP_FOR_EACH (my_node, cmap_node, &my_map) { +- * ...operate on my_node... +- * } +- * +- * CMAP_FOR_EACH is "safe" in the sense of HMAP_FOR_EACH_SAFE. That is, it is +- * safe to free the current node before going on to the next iteration. Most +- * of the time, though, this doesn't matter for a cmap because node +- * deallocation has to be postponed until the next grace period. This means +- * that this guarantee is useful only in deallocation code already executing at +- * postponed time, when it is known that the RCU grace period has already +- * expired. +- */ +- +-#define CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER) \ +- ((CURSOR)->node \ +- ? (INIT_CONTAINER(NODE, (CURSOR)->node, MEMBER), \ +- cmap_cursor_advance(CURSOR), \ +- true) \ +- : (NODE = NULL, false)) +- +-#define CMAP_CURSOR_FOR_EACH(NODE, MEMBER, CURSOR, CMAP) \ +- for (*(CURSOR) = cmap_cursor_start(CMAP); \ +- CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER); \ +- ) +- +-#define CMAP_CURSOR_FOR_EACH_CONTINUE(NODE, MEMBER, CURSOR) \ +- while (CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER)) +- +-struct cmap_cursor { +- const struct cmap_impl *impl; +- uint32_t bucket_idx; +- int entry_idx; +- struct cmap_node *node; +-}; +- +-struct cmap_cursor cmap_cursor_start(const struct cmap *); +-void cmap_cursor_advance(struct cmap_cursor *); +- +-/* Generate a unique name for the cursor with the __COUNTER__ macro to +- * allow nesting of CMAP_FOR_EACH loops. */ +-#define CMAP_FOR_EACH__(NODE, MEMBER, CMAP, CURSOR_NAME) \ +- for (struct cmap_cursor CURSOR_NAME = cmap_cursor_start(CMAP); \ +- CMAP_CURSOR_FOR_EACH__(NODE, &CURSOR_NAME, MEMBER); \ +- ) +- +-#define CMAP_FOR_EACH(NODE, MEMBER, CMAP) \ +- CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ +- OVS_JOIN(cursor_, __COUNTER__)) +- +-static inline struct cmap_node *cmap_first(const struct cmap *); +- +-/* Another, less preferred, form of iteration, for use in situations where it +- * is difficult to maintain a pointer to a cmap_node. */ +-struct cmap_position { +- unsigned int bucket; +- unsigned int entry; +- unsigned int offset; +-}; +- +-struct cmap_node *cmap_next_position(const struct cmap *, +- struct cmap_position *); +- +-/* Returns the first node in 'cmap', in arbitrary order, or a null pointer if +- * 'cmap' is empty. */ +-static inline struct cmap_node * +-cmap_first(const struct cmap *cmap) +-{ +- struct cmap_position pos = { 0, 0, 0 }; +- +- return cmap_next_position(cmap, &pos); +-} +- +-/* Removes 'node' from 'cmap'. The caller must ensure that 'cmap' cannot +- * change concurrently (from another thread). +- * +- * 'node' must not be destroyed or modified or inserted back into 'cmap' or +- * into any other concurrent hash map while any other thread might be accessing +- * it. One correct way to do this is to free it from an RCU callback with +- * ovsrcu_postpone(). +- * +- * Returns the current number of nodes in the cmap after the removal. */ +-static inline size_t +-cmap_remove(struct cmap *cmap, struct cmap_node *node, uint32_t hash) +-{ +- return cmap_replace(cmap, node, NULL, hash); +-} +- +-#endif /* cmap.h */ +Index: openvswitch-2.17.2/include/internal/cmap.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/cmap.h +@@ -0,0 +1,297 @@ ++/* ++ * Copyright (c) 2014, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef CMAP_H ++#define CMAP_H 1 ++ ++#include ++#include +#include "openvswitch/ovs-rcu.h" +#include "internal/util.h" - - /* Concurrent hash map - * =================== -diff --git a/lib/colors.h b/include/internal/colors.h -similarity index 100% -rename from lib/colors.h -rename to include/internal/colors.h -diff --git a/lib/command-line.h b/include/internal/command-line.h -similarity index 100% -rename from lib/command-line.h -rename to include/internal/command-line.h -diff --git a/lib/coverage.h b/include/internal/coverage.h -similarity index 99% -rename from lib/coverage.h -rename to include/internal/coverage.h -index 8eb5a1e12..cf0ff7f8b 100644 ---- a/lib/coverage.h -+++ b/include/internal/coverage.h -@@ -27,7 +27,7 @@ - * for traditional coverage instrumentation with e.g. "gcov", but it is still - * a useful debugging tool. */ - ++ ++/* Concurrent hash map ++ * =================== ++ * ++ * A single-writer, multiple-reader hash table that efficiently supports ++ * duplicates. ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * The general rules are: ++ * ++ * - Only a single thread may safely call into cmap_insert(), ++ * cmap_remove(), or cmap_replace() at any given time. ++ * ++ * - Any number of threads may use functions and macros that search or ++ * iterate through a given cmap, even in parallel with other threads ++ * calling cmap_insert(), cmap_remove(), or cmap_replace(). ++ * ++ * There is one exception: cmap_find_protected() is only safe if no thread ++ * is currently calling cmap_insert(), cmap_remove(), or cmap_replace(). ++ * (Use ordinary cmap_find() if that is not guaranteed.) ++ * ++ * - See "Iteration" below for additional thread safety rules. ++ * ++ * Writers must use special care to ensure that any elements that they remove ++ * do not get freed or reused until readers have finished with them. This ++ * includes inserting the element back into its original cmap or a different ++ * one. One correct way to do this is to free them from an RCU callback with ++ * ovsrcu_postpone(). ++ */ ++ ++/* A concurrent hash map node, to be embedded inside the data structure being ++ * mapped. ++ * ++ * All nodes linked together on a chain have exactly the same hash value. */ ++struct cmap_node { ++ OVSRCU_TYPE(struct cmap_node *) next; /* Next node with same hash. */ ++}; ++ ++static inline struct cmap_node * ++cmap_node_next(const struct cmap_node *node) ++{ ++ return ovsrcu_get(struct cmap_node *, &node->next); ++} ++ ++static inline struct cmap_node * ++cmap_node_next_protected(const struct cmap_node *node) ++{ ++ return ovsrcu_get_protected(struct cmap_node *, &node->next); ++} ++ ++/* Concurrent hash map. */ ++struct cmap { ++ OVSRCU_TYPE(struct cmap_impl *) impl; ++}; ++ ++/* Initializer for an empty cmap. */ ++#define CMAP_INITIALIZER { \ ++ .impl = OVSRCU_INITIALIZER((struct cmap_impl *) &empty_cmap) \ ++ } ++extern OVS_ALIGNED_VAR(CACHE_LINE_SIZE) const struct cmap_impl empty_cmap; ++ ++/* Initialization. */ ++void cmap_init(struct cmap *); ++void cmap_destroy(struct cmap *); ++ ++/* Count. */ ++size_t cmap_count(const struct cmap *); ++bool cmap_is_empty(const struct cmap *); ++ ++/* Insertion and deletion. Return the current count after the operation. */ ++size_t cmap_insert(struct cmap *, struct cmap_node *, uint32_t hash); ++static inline size_t cmap_remove(struct cmap *, struct cmap_node *, ++ uint32_t hash); ++size_t cmap_replace(struct cmap *, struct cmap_node *old_node, ++ struct cmap_node *new_node, uint32_t hash); ++ ++/* Search. ++ * ++ * These macros iterate NODE over all of the nodes in CMAP that have hash value ++ * equal to HASH. MEMBER must be the name of the 'struct cmap_node' member ++ * within NODE. ++ * ++ * CMAP and HASH are evaluated only once. NODE is evaluated many times. ++ * ++ * After a normal exit of the loop (not through a "break;" statement) NODE is ++ * NULL. ++ * ++ * Thread-safety ++ * ============= ++ * ++ * CMAP_NODE_FOR_EACH will reliably visit each of the nodes starting with ++ * CMAP_NODE, even with concurrent insertions and deletions. (Of ++ * course, if nodes are being inserted or deleted, it might or might not visit ++ * the nodes actually being inserted or deleted.) ++ * ++ * CMAP_NODE_FOR_EACH_PROTECTED may only be used if the containing CMAP is ++ * guaranteed not to change during iteration. It may be only slightly faster. ++ * ++ * CMAP_FOR_EACH_WITH_HASH will reliably visit each of the nodes with the ++ * specified hash in CMAP, even with concurrent insertions and deletions. (Of ++ * course, if nodes with the given HASH are being inserted or deleted, it might ++ * or might not visit the nodes actually being inserted or deleted.) ++ * ++ * CMAP_FOR_EACH_WITH_HASH_PROTECTED may only be used if CMAP is guaranteed not ++ * to change during iteration. It may be very slightly faster. ++ */ ++#define CMAP_NODE_FOR_EACH(NODE, MEMBER, CMAP_NODE) \ ++ for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node); \ ++ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ ++ UPDATE_MULTIVAR(NODE, cmap_node_next(ITER_VAR(NODE)))) ++#define CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, CMAP_NODE) \ ++ for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node); \ ++ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ ++ UPDATE_MULTIVAR(NODE, cmap_node_next_protected(ITER_VAR(NODE)))) ++ ++#define CMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, CMAP) \ ++ CMAP_NODE_FOR_EACH(NODE, MEMBER, cmap_find(CMAP, HASH)) ++#define CMAP_FOR_EACH_WITH_HASH_PROTECTED(NODE, MEMBER, HASH, CMAP) \ ++ CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, cmap_find_protected(CMAP, HASH)) ++ ++const struct cmap_node *cmap_find(const struct cmap *, uint32_t hash); ++struct cmap_node *cmap_find_protected(const struct cmap *, uint32_t hash); ++ ++/* Find node by index or find index by hash. The 'index' of a cmap entry is a ++ * way to combine the specific bucket and the entry of the bucket into a ++ * convenient single integer value. In other words, it is the index of the ++ * entry and each entry has an unique index. It is not used internally by ++ * cmap. ++ * Currently the functions assume index will not be larger than uint32_t. In ++ * OvS table size is usually much smaller than this size.*/ ++const struct cmap_node * cmap_find_by_index(const struct cmap *, ++ uint32_t index); ++uint32_t cmap_find_index(const struct cmap *, uint32_t hash); ++ ++/* Looks up multiple 'hashes', when the corresponding bit in 'map' is 1, ++ * and sets the corresponding pointer in 'nodes', if the hash value was ++ * found from the 'cmap'. In other cases the 'nodes' values are not changed, ++ * i.e., no NULL pointers are stored there. ++ * Returns a map where a bit is set to 1 if the corresponding 'nodes' pointer ++ * was stored, 0 otherwise. ++ * Generally, the caller wants to use CMAP_NODE_FOR_EACH to verify for ++ * hash collisions. */ ++unsigned long cmap_find_batch(const struct cmap *cmap, unsigned long map, ++ uint32_t hashes[], ++ const struct cmap_node *nodes[]); ++ ++/* Iteration. ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * Iteration is safe even in a cmap that is changing concurrently. However: ++ * ++ * - In the presence of concurrent calls to cmap_insert(), any given ++ * iteration might skip some nodes and might visit some nodes more than ++ * once. If this is a problem, then the iterating code should lock the ++ * data structure (a rwlock can be used to allow multiple threads to ++ * iterate in parallel). ++ * ++ * - Concurrent calls to cmap_remove() don't have the same problem. (A ++ * node being deleted may be visited once or not at all. Other nodes ++ * will be visited once.) ++ * ++ * - If the cmap is changing, it is not safe to quiesce while iterating. ++ * Even if the changes are done by the same thread that's performing the ++ * iteration (Corollary: it is not safe to call cmap_remove() and quiesce ++ * in the loop body). ++ * ++ * ++ * Example ++ * ======= ++ * ++ * struct my_node { ++ * struct cmap_node cmap_node; ++ * int extra_data; ++ * }; ++ * ++ * struct cmap my_map; ++ * struct my_node *my_node; ++ * ++ * cmap_init(&my_map); ++ * ...add data... ++ * CMAP_FOR_EACH (my_node, cmap_node, &my_map) { ++ * ...operate on my_node... ++ * } ++ * ++ * CMAP_FOR_EACH is "safe" in the sense of HMAP_FOR_EACH_SAFE. That is, it is ++ * safe to free the current node before going on to the next iteration. Most ++ * of the time, though, this doesn't matter for a cmap because node ++ * deallocation has to be postponed until the next grace period. This means ++ * that this guarantee is useful only in deallocation code already executing at ++ * postponed time, when it is known that the RCU grace period has already ++ * expired. ++ */ ++ ++#define CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER) \ ++ ((CURSOR)->node \ ++ ? (INIT_CONTAINER(NODE, (CURSOR)->node, MEMBER), \ ++ cmap_cursor_advance(CURSOR), \ ++ true) \ ++ : (NODE = NULL, false)) ++ ++#define CMAP_CURSOR_FOR_EACH(NODE, MEMBER, CURSOR, CMAP) \ ++ for (*(CURSOR) = cmap_cursor_start(CMAP); \ ++ CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER); \ ++ ) ++ ++#define CMAP_CURSOR_FOR_EACH_CONTINUE(NODE, MEMBER, CURSOR) \ ++ while (CMAP_CURSOR_FOR_EACH__(NODE, CURSOR, MEMBER)) ++ ++struct cmap_cursor { ++ const struct cmap_impl *impl; ++ uint32_t bucket_idx; ++ int entry_idx; ++ struct cmap_node *node; ++}; ++ ++struct cmap_cursor cmap_cursor_start(const struct cmap *); ++void cmap_cursor_advance(struct cmap_cursor *); ++ ++/* Generate a unique name for the cursor with the __COUNTER__ macro to ++ * allow nesting of CMAP_FOR_EACH loops. */ ++#define CMAP_FOR_EACH__(NODE, MEMBER, CMAP, CURSOR_NAME) \ ++ for (struct cmap_cursor CURSOR_NAME = cmap_cursor_start(CMAP); \ ++ CMAP_CURSOR_FOR_EACH__(NODE, &CURSOR_NAME, MEMBER); \ ++ ) ++ ++#define CMAP_FOR_EACH(NODE, MEMBER, CMAP) \ ++ CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ ++ OVS_JOIN(cursor_, __COUNTER__)) ++ ++static inline struct cmap_node *cmap_first(const struct cmap *); ++ ++/* Another, less preferred, form of iteration, for use in situations where it ++ * is difficult to maintain a pointer to a cmap_node. */ ++struct cmap_position { ++ unsigned int bucket; ++ unsigned int entry; ++ unsigned int offset; ++}; ++ ++struct cmap_node *cmap_next_position(const struct cmap *, ++ struct cmap_position *); ++ ++/* Returns the first node in 'cmap', in arbitrary order, or a null pointer if ++ * 'cmap' is empty. */ ++static inline struct cmap_node * ++cmap_first(const struct cmap *cmap) ++{ ++ struct cmap_position pos = { 0, 0, 0 }; ++ ++ return cmap_next_position(cmap, &pos); ++} ++ ++/* Removes 'node' from 'cmap'. The caller must ensure that 'cmap' cannot ++ * change concurrently (from another thread). ++ * ++ * 'node' must not be destroyed or modified or inserted back into 'cmap' or ++ * into any other concurrent hash map while any other thread might be accessing ++ * it. One correct way to do this is to free it from an RCU callback with ++ * ovsrcu_postpone(). ++ * ++ * Returns the current number of nodes in the cmap after the removal. */ ++static inline size_t ++cmap_remove(struct cmap *cmap, struct cmap_node *node, uint32_t hash) ++{ ++ return cmap_replace(cmap, node, NULL, hash); ++} ++ ++#endif /* cmap.h */ +Index: openvswitch-2.17.2/lib/coverage.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/coverage.h ++++ /dev/null +@@ -1,94 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef COVERAGE_H +-#define COVERAGE_H 1 +- +-/* This file implements a simple form of coverage instrumentation. Points in +- * source code that are of interest must be explicitly annotated with +- * COVERAGE_INC. The coverage counters may be logged at any time with +- * coverage_log(). +- * +- * This form of coverage instrumentation is intended to be so lightweight that +- * it can be enabled in production builds. It is obviously not a substitute +- * for traditional coverage instrumentation with e.g. "gcov", but it is still +- * a useful debugging tool. */ +- -#include "ovs-thread.h" +-#include "openvswitch/compiler.h" +- +-/* Makes coverage_run run every 5000 ms (5 seconds). +- * If this value is redefined, the new value must +- * divide 60000 (1 minute). */ +-#define COVERAGE_RUN_INTERVAL 5000 +-BUILD_ASSERT_DECL(60000 % COVERAGE_RUN_INTERVAL == 0); +- +-#define COVERAGE_CLEAR_INTERVAL 1000 +-BUILD_ASSERT_DECL(COVERAGE_RUN_INTERVAL % COVERAGE_CLEAR_INTERVAL == 0); +- +-/* Defines the moving average array length. */ +-#define MIN_AVG_LEN (60000/COVERAGE_RUN_INTERVAL) +-#define HR_AVG_LEN 60 +- +-/* A coverage counter. */ +-struct coverage_counter { +- const char *const name; /* Textual name. */ +- unsigned int (*const count)(void); /* Gets, zeros this thread's count. */ +- unsigned long long int total; /* Total count. */ +- unsigned long long int last_total; +- /* The moving average arrays. */ +- unsigned int min[MIN_AVG_LEN]; +- unsigned int hr[HR_AVG_LEN]; +-}; +- +-void coverage_counter_register(struct coverage_counter*); +- +-/* Defines COUNTER. There must be exactly one such definition at file scope +- * within a program. */ +-#define COVERAGE_DEFINE(COUNTER) \ +- DEFINE_STATIC_PER_THREAD_DATA(unsigned int, \ +- counter_##COUNTER, 0); \ +- static unsigned int COUNTER##_count(void) \ +- { \ +- unsigned int *countp = counter_##COUNTER##_get(); \ +- unsigned int count = *countp; \ +- *countp = 0; \ +- return count; \ +- } \ +- static inline void COUNTER##_add(unsigned int n) \ +- { \ +- *counter_##COUNTER##_get() += n; \ +- } \ +- extern struct coverage_counter counter_##COUNTER; \ +- struct coverage_counter counter_##COUNTER \ +- = { #COUNTER, COUNTER##_count, 0, 0, {0}, {0} }; \ +- OVS_CONSTRUCTOR(COUNTER##_init_coverage) { \ +- coverage_counter_register(&counter_##COUNTER); \ +- } +- +-/* Adds 1 to COUNTER. */ +-#define COVERAGE_INC(COUNTER) COVERAGE_ADD(COUNTER, 1) +- +-/* Adds AMOUNT to COUNTER. */ +-#define COVERAGE_ADD(COUNTER, AMOUNT) COUNTER##_add(AMOUNT) +- +-void coverage_init(void); +-void coverage_log(void); +-void coverage_clear(void); +-void coverage_try_clear(void); +-void coverage_run(void); +- +-#endif /* coverage.h */ +Index: openvswitch-2.17.2/include/internal/coverage.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/coverage.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef COVERAGE_H ++#define COVERAGE_H 1 ++ ++/* This file implements a simple form of coverage instrumentation. Points in ++ * source code that are of interest must be explicitly annotated with ++ * COVERAGE_INC. The coverage counters may be logged at any time with ++ * coverage_log(). ++ * ++ * This form of coverage instrumentation is intended to be so lightweight that ++ * it can be enabled in production builds. It is obviously not a substitute ++ * for traditional coverage instrumentation with e.g. "gcov", but it is still ++ * a useful debugging tool. */ ++ +#include "openvswitch/ovs-thread.h" - #include "openvswitch/compiler.h" - - /* Makes coverage_run run every 5000 ms (5 seconds). -diff --git a/lib/crc32c.h b/include/internal/crc32c.h -similarity index 100% -rename from lib/crc32c.h -rename to include/internal/crc32c.h -diff --git a/lib/csum.h b/include/internal/csum.h -similarity index 100% -rename from lib/csum.h -rename to include/internal/csum.h -diff --git a/lib/daemon.h b/include/internal/daemon.h -similarity index 100% -rename from lib/daemon.h -rename to include/internal/daemon.h -diff --git a/lib/db-ctl-base.h b/include/internal/db-ctl-base.h -similarity index 100% -rename from lib/db-ctl-base.h -rename to include/internal/db-ctl-base.h -diff --git a/lib/dhcp.h b/include/internal/dhcp.h -similarity index 97% -rename from lib/dhcp.h -rename to include/internal/dhcp.h -index c904af6c4..1d1380408 100644 ---- a/lib/dhcp.h -+++ b/include/internal/dhcp.h -@@ -18,8 +18,8 @@ - #define DHCP_H 1 - - #include ++#include "openvswitch/compiler.h" ++ ++/* Makes coverage_run run every 5000 ms (5 seconds). ++ * If this value is redefined, the new value must ++ * divide 60000 (1 minute). */ ++#define COVERAGE_RUN_INTERVAL 5000 ++BUILD_ASSERT_DECL(60000 % COVERAGE_RUN_INTERVAL == 0); ++ ++#define COVERAGE_CLEAR_INTERVAL 1000 ++BUILD_ASSERT_DECL(COVERAGE_RUN_INTERVAL % COVERAGE_CLEAR_INTERVAL == 0); ++ ++/* Defines the moving average array length. */ ++#define MIN_AVG_LEN (60000/COVERAGE_RUN_INTERVAL) ++#define HR_AVG_LEN 60 ++ ++/* A coverage counter. */ ++struct coverage_counter { ++ const char *const name; /* Textual name. */ ++ unsigned int (*const count)(void); /* Gets, zeros this thread's count. */ ++ unsigned long long int total; /* Total count. */ ++ unsigned long long int last_total; ++ /* The moving average arrays. */ ++ unsigned int min[MIN_AVG_LEN]; ++ unsigned int hr[HR_AVG_LEN]; ++}; ++ ++void coverage_counter_register(struct coverage_counter*); ++ ++/* Defines COUNTER. There must be exactly one such definition at file scope ++ * within a program. */ ++#define COVERAGE_DEFINE(COUNTER) \ ++ DEFINE_STATIC_PER_THREAD_DATA(unsigned int, \ ++ counter_##COUNTER, 0); \ ++ static unsigned int COUNTER##_count(void) \ ++ { \ ++ unsigned int *countp = counter_##COUNTER##_get(); \ ++ unsigned int count = *countp; \ ++ *countp = 0; \ ++ return count; \ ++ } \ ++ static inline void COUNTER##_add(unsigned int n) \ ++ { \ ++ *counter_##COUNTER##_get() += n; \ ++ } \ ++ extern struct coverage_counter counter_##COUNTER; \ ++ struct coverage_counter counter_##COUNTER \ ++ = { #COUNTER, COUNTER##_count, 0, 0, {0}, {0} }; \ ++ OVS_CONSTRUCTOR(COUNTER##_init_coverage) { \ ++ coverage_counter_register(&counter_##COUNTER); \ ++ } ++ ++/* Adds 1 to COUNTER. */ ++#define COVERAGE_INC(COUNTER) COVERAGE_ADD(COUNTER, 1) ++ ++/* Adds AMOUNT to COUNTER. */ ++#define COVERAGE_ADD(COUNTER, AMOUNT) COUNTER##_add(AMOUNT) ++ ++void coverage_init(void); ++void coverage_log(void); ++void coverage_clear(void); ++void coverage_try_clear(void); ++void coverage_run(void); ++ ++#endif /* coverage.h */ +Index: openvswitch-2.17.2/lib/dhcp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dhcp.h ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* +- * Copyright (c) 2008, 2011 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DHCP_H +-#define DHCP_H 1 +- +-#include -#include "packets.h" -#include "util.h" +- +-/* Ports used by DHCP. */ +-#define DHCP_SERVER_PORT 67 /* Port used by DHCP server. */ +-#define DHCP_CLIENT_PORT 68 /* Port used by DHCP client. */ +- +-#define DHCP_MAGIC_COOKIE 0x63825363 +- +-#define DHCP_HEADER_LEN 236 +-OVS_PACKED( +-struct dhcp_header { +- uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */ +- uint8_t htype; /* ARP_HRD_ETHERNET (typically). */ +- uint8_t hlen; /* ETH_ADDR_LEN (typically). */ +- uint8_t hops; /* Hop count; set to 0 by client. */ +- ovs_be32 xid; /* Transaction ID. */ +- ovs_be16 secs; /* Since client started address acquisition. */ +- ovs_be16 flags; /* DHCP_FLAGS_*. */ +- ovs_be32 ciaddr; /* Client IP, if it has a lease for one. */ +- ovs_be32 yiaddr; /* Client ("your") IP address. */ +- ovs_be32 siaddr; /* Next server IP address. */ +- ovs_be32 giaddr; /* Relay agent IP address. */ +- uint8_t chaddr[16]; /* Client hardware address. */ +- char sname[64]; /* Optional server host name. */ +- char file[128]; /* Boot file name. */ +- /* Followed by variable-length options field. */ +-}); +-BUILD_ASSERT_DECL(DHCP_HEADER_LEN == sizeof(struct dhcp_header)); +- +-#define DHCP_OP_REQUEST 1 +-#define DHCP_OP_REPLY 2 +- +-#define DHCP_MSG_DISCOVER 1 +-#define DHCP_MSG_OFFER 2 +-#define DHCP_MSG_REQUEST 3 +-#define DHCP_MSG_ACK 5 +-#define DHCP_MSG_NAK 6 +- +-#define DHCP_OPT_PAD 0 +-#define DHCP_OPT_REQ_IP 50 +-#define DHCP_OPT_MSG_TYPE 53 +-#define DHCP_OPT_END 255 +- +-#endif /* dhcp.h */ +Index: openvswitch-2.17.2/include/internal/dhcp.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/dhcp.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (c) 2008, 2011 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DHCP_H ++#define DHCP_H 1 ++ ++#include +#include "internal/packets.h" +#include "internal/util.h" - - /* Ports used by DHCP. */ - #define DHCP_SERVER_PORT 67 /* Port used by DHCP server. */ -diff --git a/lib/dhparams.h b/include/internal/dhparams.h -similarity index 100% -rename from lib/dhparams.h -rename to include/internal/dhparams.h -diff --git a/lib/dirs.h b/include/internal/dirs.h -similarity index 100% -rename from lib/dirs.h -rename to include/internal/dirs.h -diff --git a/lib/dp-packet.h b/include/internal/dp-packet.h -similarity index 99% -rename from lib/dp-packet.h -rename to include/internal/dp-packet.h -index ee0805ae6..f7072b201 100644 ---- a/lib/dp-packet.h -+++ b/include/internal/dp-packet.h -@@ -25,12 +25,12 @@ - #include - #endif - ++ ++/* Ports used by DHCP. */ ++#define DHCP_SERVER_PORT 67 /* Port used by DHCP server. */ ++#define DHCP_CLIENT_PORT 68 /* Port used by DHCP client. */ ++ ++#define DHCP_MAGIC_COOKIE 0x63825363 ++ ++#define DHCP_HEADER_LEN 236 ++OVS_PACKED( ++struct dhcp_header { ++ uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */ ++ uint8_t htype; /* ARP_HRD_ETHERNET (typically). */ ++ uint8_t hlen; /* ETH_ADDR_LEN (typically). */ ++ uint8_t hops; /* Hop count; set to 0 by client. */ ++ ovs_be32 xid; /* Transaction ID. */ ++ ovs_be16 secs; /* Since client started address acquisition. */ ++ ovs_be16 flags; /* DHCP_FLAGS_*. */ ++ ovs_be32 ciaddr; /* Client IP, if it has a lease for one. */ ++ ovs_be32 yiaddr; /* Client ("your") IP address. */ ++ ovs_be32 siaddr; /* Next server IP address. */ ++ ovs_be32 giaddr; /* Relay agent IP address. */ ++ uint8_t chaddr[16]; /* Client hardware address. */ ++ char sname[64]; /* Optional server host name. */ ++ char file[128]; /* Boot file name. */ ++ /* Followed by variable-length options field. */ ++}); ++BUILD_ASSERT_DECL(DHCP_HEADER_LEN == sizeof(struct dhcp_header)); ++ ++#define DHCP_OP_REQUEST 1 ++#define DHCP_OP_REPLY 2 ++ ++#define DHCP_MSG_DISCOVER 1 ++#define DHCP_MSG_OFFER 2 ++#define DHCP_MSG_REQUEST 3 ++#define DHCP_MSG_ACK 5 ++#define DHCP_MSG_NAK 6 ++ ++#define DHCP_OPT_PAD 0 ++#define DHCP_OPT_REQ_IP 50 ++#define DHCP_OPT_MSG_TYPE 53 ++#define DHCP_OPT_END 255 ++ ++#endif /* dhcp.h */ +Index: openvswitch-2.17.2/lib/dp-packet.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dp-packet.h ++++ /dev/null +@@ -1,1092 +0,0 @@ +-/* +- * 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DPBUF_H +-#define DPBUF_H 1 +- +-#include +-#include +- +-#ifdef DPDK_NETDEV +-#include +-#include +-#endif +- -#include "netdev-afxdp.h" -#include "netdev-dpdk.h" -+#include "internal/netdev-afxdp.h" -+#include "internal/netdev-dpdk.h" - #include "openvswitch/list.h" +-#include "openvswitch/list.h" -#include "packets.h" -#include "util.h" -#include "flow.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-enum OVS_PACKED_ENUM dp_packet_source { +- DPBUF_MALLOC, /* Obtained via malloc(). */ +- DPBUF_STACK, /* Un-movable stack space or static buffer. */ +- DPBUF_STUB, /* Starts on stack, may expand into heap. */ +- DPBUF_DPDK, /* buffer data is from DPDK allocated memory. +- * ref to dp_packet_init_dpdk() in dp-packet.c. +- */ +- DPBUF_AFXDP, /* Buffer data from XDP frame. */ +-}; +- +-#define DP_PACKET_CONTEXT_SIZE 64 +- +-#ifdef DPDK_NETDEV +-#define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = DPDK_DEF +-#else +-#define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = GENERIC_DEF +-#endif +- +-/* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ +-enum dp_packet_offload_mask { +- /* Value 0 is not used. */ +- /* Is the 'rss_hash' valid? */ +- DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, RTE_MBUF_F_RX_RSS_HASH, 0x1), +- /* Is the 'flow_mark' valid? */ +- DEF_OL_FLAG(DP_PACKET_OL_FLOW_MARK, RTE_MBUF_F_RX_FDIR_ID, 0x2), +- /* Bad L4 checksum in the packet. */ +- DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_BAD, RTE_MBUF_F_RX_L4_CKSUM_BAD, 0x4), +- /* Bad IP checksum in the packet. */ +- DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_BAD, RTE_MBUF_F_RX_IP_CKSUM_BAD, 0x8), +- /* Valid L4 checksum in the packet. */ +- DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_GOOD, RTE_MBUF_F_RX_L4_CKSUM_GOOD, +- 0x10), +- /* Valid IP checksum in the packet. */ +- DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_GOOD, RTE_MBUF_F_RX_IP_CKSUM_GOOD, +- 0x20), +- /* TCP Segmentation Offload. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_SEG, RTE_MBUF_F_TX_TCP_SEG, 0x40), +- /* Offloaded packet is IPv4. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_IPV4, RTE_MBUF_F_TX_IPV4, 0x80), +- /* Offloaded packet is IPv6. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_IPV6, RTE_MBUF_F_TX_IPV6, 0x100), +- /* Offload TCP checksum. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_CKSUM, RTE_MBUF_F_TX_TCP_CKSUM, 0x200), +- /* Offload UDP checksum. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, RTE_MBUF_F_TX_UDP_CKSUM, 0x400), +- /* Offload SCTP checksum. */ +- DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM, 0x800), +- /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ +-}; +- +-#define DP_PACKET_OL_SUPPORTED_MASK (DP_PACKET_OL_RSS_HASH | \ +- DP_PACKET_OL_FLOW_MARK | \ +- DP_PACKET_OL_RX_L4_CKSUM_BAD | \ +- DP_PACKET_OL_RX_IP_CKSUM_BAD | \ +- DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ +- DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ +- DP_PACKET_OL_TX_TCP_SEG | \ +- DP_PACKET_OL_TX_IPV4 | \ +- DP_PACKET_OL_TX_IPV6 | \ +- DP_PACKET_OL_TX_TCP_CKSUM | \ +- DP_PACKET_OL_TX_UDP_CKSUM | \ +- DP_PACKET_OL_TX_SCTP_CKSUM) +- +-#define DP_PACKET_OL_TX_L4_MASK (DP_PACKET_OL_TX_TCP_CKSUM | \ +- DP_PACKET_OL_TX_UDP_CKSUM | \ +- DP_PACKET_OL_TX_SCTP_CKSUM) +-#define DP_PACKET_OL_RX_IP_CKSUM_MASK (DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ +- DP_PACKET_OL_RX_IP_CKSUM_BAD) +-#define DP_PACKET_OL_RX_L4_CKSUM_MASK (DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ +- DP_PACKET_OL_RX_L4_CKSUM_BAD) +- +-/* Buffer for holding packet data. A dp_packet is automatically reallocated +- * as necessary if it grows too large for the available memory. +- * By default the packet type is set to Ethernet (PT_ETH). +- */ +-struct dp_packet { +-#ifdef DPDK_NETDEV +- struct rte_mbuf mbuf; /* DPDK mbuf */ +-#else +- void *base_; /* First byte of allocated space. */ +- uint16_t allocated_; /* Number of bytes allocated. */ +- uint16_t data_ofs; /* First byte actually in use. */ +- uint32_t size_; /* Number of bytes in use. */ +- uint32_t ol_flags; /* Offloading flags. */ +- uint32_t rss_hash; /* Packet hash. */ +- uint32_t flow_mark; /* Packet flow mark. */ +-#endif +- enum dp_packet_source source; /* Source of memory allocated as 'base'. */ +- +- /* All the following elements of this struct are copied in a single call +- * of memcpy in dp_packet_clone_with_headroom. */ +- uint16_t l2_pad_size; /* Detected l2 padding size. +- * Padding is non-pullable. */ +- uint16_t l2_5_ofs; /* MPLS label stack offset, or UINT16_MAX */ +- uint16_t l3_ofs; /* Network-level header offset, +- * or UINT16_MAX. */ +- uint16_t l4_ofs; /* Transport-level header offset, +- or UINT16_MAX. */ +- uint32_t cutlen; /* length in bytes to cut from the end. */ +- ovs_be32 packet_type; /* Packet type as defined in OpenFlow */ +- union { +- struct pkt_metadata md; +- uint64_t data[DP_PACKET_CONTEXT_SIZE / 8]; +- }; +-}; +- +-#if HAVE_AF_XDP +-struct dp_packet_afxdp { +- struct umem_pool *mpool; +- struct dp_packet packet; +-}; +-#endif +- +-static inline void *dp_packet_data(const struct dp_packet *); +-static inline void dp_packet_set_data(struct dp_packet *, void *); +-static inline void *dp_packet_base(const struct dp_packet *); +-static inline void dp_packet_set_base(struct dp_packet *, void *); +- +-static inline uint32_t dp_packet_size(const struct dp_packet *); +-static inline void dp_packet_set_size(struct dp_packet *, uint32_t); +- +-static inline uint16_t dp_packet_get_allocated(const struct dp_packet *); +-static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t); +- +-void *dp_packet_resize_l2(struct dp_packet *, int increment); +-void *dp_packet_resize_l2_5(struct dp_packet *, int increment); +-static inline void *dp_packet_eth(const struct dp_packet *); +-static inline void dp_packet_reset_offsets(struct dp_packet *); +-static inline uint16_t dp_packet_l2_pad_size(const struct dp_packet *); +-static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint16_t); +-static inline void *dp_packet_l2_5(const struct dp_packet *); +-static inline void dp_packet_set_l2_5(struct dp_packet *, void *); +-static inline void *dp_packet_l3(const struct dp_packet *); +-static inline void dp_packet_set_l3(struct dp_packet *, void *); +-static inline void *dp_packet_l4(const struct dp_packet *); +-static inline void dp_packet_set_l4(struct dp_packet *, void *); +-static inline size_t dp_packet_l4_size(const struct dp_packet *); +-static inline const void *dp_packet_get_tcp_payload(const struct dp_packet *); +-static inline const void *dp_packet_get_udp_payload(const struct dp_packet *); +-static inline const void *dp_packet_get_sctp_payload(const struct dp_packet *); +-static inline const void *dp_packet_get_icmp_payload(const struct dp_packet *); +-static inline const void *dp_packet_get_nd_payload(const struct dp_packet *); +- +-void dp_packet_use(struct dp_packet *, void *, size_t); +-void dp_packet_use_stub(struct dp_packet *, void *, size_t); +-void dp_packet_use_const(struct dp_packet *, const void *, size_t); +-#if HAVE_AF_XDP +-void dp_packet_use_afxdp(struct dp_packet *, void *, size_t, size_t); +-#endif +-void dp_packet_init_dpdk(struct dp_packet *); +- +-void dp_packet_init(struct dp_packet *, size_t); +-void dp_packet_uninit(struct dp_packet *); +- +-struct dp_packet *dp_packet_new(size_t); +-struct dp_packet *dp_packet_new_with_headroom(size_t, size_t headroom); +-struct dp_packet *dp_packet_clone(const struct dp_packet *); +-struct dp_packet *dp_packet_clone_with_headroom(const struct dp_packet *, +- size_t headroom); +-struct dp_packet *dp_packet_clone_data(const void *, size_t); +-struct dp_packet *dp_packet_clone_data_with_headroom(const void *, size_t, +- size_t headroom); +-void dp_packet_resize(struct dp_packet *b, size_t new_headroom, +- size_t new_tailroom); +-static inline void dp_packet_delete(struct dp_packet *); +-static inline void dp_packet_swap(struct dp_packet *, struct dp_packet *); +- +-static inline void *dp_packet_at(const struct dp_packet *, size_t offset, +- size_t size); +-static inline void *dp_packet_at_assert(const struct dp_packet *, +- size_t offset, size_t size); +-static inline void *dp_packet_tail(const struct dp_packet *); +-static inline void *dp_packet_end(const struct dp_packet *); +- +-void *dp_packet_put_uninit(struct dp_packet *, size_t); +-void *dp_packet_put_zeros(struct dp_packet *, size_t); +-void *dp_packet_put(struct dp_packet *, const void *, size_t); +-char *dp_packet_put_hex(struct dp_packet *, const char *s, size_t *n); +-void dp_packet_reserve(struct dp_packet *, size_t); +-void dp_packet_reserve_with_tailroom(struct dp_packet *, size_t headroom, +- size_t tailroom); +-void *dp_packet_push_uninit(struct dp_packet *, size_t); +-void *dp_packet_push_zeros(struct dp_packet *, size_t); +-void *dp_packet_push(struct dp_packet *, const void *, size_t); +- +-static inline size_t dp_packet_headroom(const struct dp_packet *); +-static inline size_t dp_packet_tailroom(const struct dp_packet *); +-void dp_packet_prealloc_headroom(struct dp_packet *, size_t); +-void dp_packet_prealloc_tailroom(struct dp_packet *, size_t); +-void dp_packet_shift(struct dp_packet *, int); +- +-static inline void dp_packet_clear(struct dp_packet *); +-static inline void *dp_packet_pull(struct dp_packet *, size_t); +-static inline void *dp_packet_try_pull(struct dp_packet *, size_t); +- +-void *dp_packet_steal_data(struct dp_packet *); +- +-static inline bool dp_packet_equal(const struct dp_packet *, +- const struct dp_packet *); +- +- +-/* Frees memory that 'b' points to, as well as 'b' itself. */ +-static inline void +-dp_packet_delete(struct dp_packet *b) +-{ +- if (b) { +- if (b->source == DPBUF_DPDK) { +- /* If this dp_packet was allocated by DPDK it must have been +- * created as a dp_packet */ +- free_dpdk_buf((struct dp_packet*) b); +- return; +- } +- +- if (b->source == DPBUF_AFXDP) { +- free_afxdp_buf(b); +- return; +- } +- +- dp_packet_uninit(b); +- free(b); +- } +-} +- +-/* Swaps content of two packets. */ +-static inline void +-dp_packet_swap(struct dp_packet *a, struct dp_packet *b) +-{ +- ovs_assert(a->source == DPBUF_MALLOC || a->source == DPBUF_STUB); +- ovs_assert(b->source == DPBUF_MALLOC || b->source == DPBUF_STUB); +- struct dp_packet c = *a; +- +- *a = *b; +- *b = c; +-} +- +-/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to +- * byte 'offset'. Otherwise, returns a null pointer. */ +-static inline void * +-dp_packet_at(const struct dp_packet *b, size_t offset, size_t size) +-{ +- return offset + size <= dp_packet_size(b) +- ? (char *) dp_packet_data(b) + offset +- : NULL; +-} +- +-/* Returns a pointer to byte 'offset' in 'b', which must contain at least +- * 'offset + size' bytes of data. */ +-static inline void * +-dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size) +-{ +- ovs_assert(offset + size <= dp_packet_size(b)); +- return ((char *) dp_packet_data(b)) + offset; +-} +- +-/* Returns a pointer to byte following the last byte of data in use in 'b'. */ +-static inline void * +-dp_packet_tail(const struct dp_packet *b) +-{ +- return (char *) dp_packet_data(b) + dp_packet_size(b); +-} +- +-/* Returns a pointer to byte following the last byte allocated for use (but +- * not necessarily in use) in 'b'. */ +-static inline void * +-dp_packet_end(const struct dp_packet *b) +-{ +- return (char *) dp_packet_base(b) + dp_packet_get_allocated(b); +-} +- +-/* Returns the number of bytes of headroom in 'b', that is, the number of bytes +- * of unused space in dp_packet 'b' before the data that is in use. (Most +- * commonly, the data in a dp_packet is at its beginning, and thus the +- * dp_packet's headroom is 0.) */ +-static inline size_t +-dp_packet_headroom(const struct dp_packet *b) +-{ +- return (char *) dp_packet_data(b) - (char *) dp_packet_base(b); +-} +- +-/* Returns the number of bytes that may be appended to the tail end of +- * dp_packet 'b' before the dp_packet must be reallocated. */ +-static inline size_t +-dp_packet_tailroom(const struct dp_packet *b) +-{ +- return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); +-} +- +-/* Clears any data from 'b'. */ +-static inline void +-dp_packet_clear(struct dp_packet *b) +-{ +- dp_packet_set_data(b, dp_packet_base(b)); +- dp_packet_set_size(b, 0); +-} +- +-/* Removes 'size' bytes from the head end of 'b', which must contain at least +- * 'size' bytes of data. Returns the first byte of data removed. */ +-static inline void * +-dp_packet_pull(struct dp_packet *b, size_t size) +-{ +- void *data = dp_packet_data(b); +- ovs_assert(dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size); +- dp_packet_set_data(b, (char *) dp_packet_data(b) + size); +- dp_packet_set_size(b, dp_packet_size(b) - size); +- return data; +-} +- +-/* If 'b' has at least 'size' bytes of data, removes that many bytes from the +- * head end of 'b' and returns the first byte removed. Otherwise, returns a +- * null pointer without modifying 'b'. */ +-static inline void * +-dp_packet_try_pull(struct dp_packet *b, size_t size) +-{ +- return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size +- ? dp_packet_pull(b, size) : NULL; +-} +- +-static inline bool +-dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b) +-{ +- return dp_packet_size(a) == dp_packet_size(b) && +- !memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a)); +-} +- +-static inline bool +-dp_packet_is_eth(const struct dp_packet *b) +-{ +- return b->packet_type == htonl(PT_ETH); +-} +- +-/* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2 +- * headers, so return NULL if it is not set. */ +-static inline void * +-dp_packet_eth(const struct dp_packet *b) +-{ +- return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX) +- ? dp_packet_data(b) : NULL; +-} +- +-/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be +- * retrieved. */ +-static inline void +-dp_packet_reset_offsets(struct dp_packet *b) +-{ +- b->l2_pad_size = 0; +- b->l2_5_ofs = UINT16_MAX; +- b->l3_ofs = UINT16_MAX; +- b->l4_ofs = UINT16_MAX; +-} +- +-static inline uint16_t +-dp_packet_l2_pad_size(const struct dp_packet *b) +-{ +- return b->l2_pad_size; +-} +- +-static inline void +-dp_packet_set_l2_pad_size(struct dp_packet *b, uint16_t pad_size) +-{ +- ovs_assert(pad_size <= dp_packet_size(b)); +- b->l2_pad_size = pad_size; +-} +- +-static inline void * +-dp_packet_l2_5(const struct dp_packet *b) +-{ +- return b->l2_5_ofs != UINT16_MAX +- ? (char *) dp_packet_data(b) + b->l2_5_ofs +- : NULL; +-} +- +-static inline void +-dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) +-{ +- b->l2_5_ofs = l2_5 +- ? (char *) l2_5 - (char *) dp_packet_data(b) +- : UINT16_MAX; +-} +- +-static inline void * +-dp_packet_l3(const struct dp_packet *b) +-{ +- return b->l3_ofs != UINT16_MAX +- ? (char *) dp_packet_data(b) + b->l3_ofs +- : NULL; +-} +- +-static inline void +-dp_packet_set_l3(struct dp_packet *b, void *l3) +-{ +- b->l3_ofs = l3 ? (char *) l3 - (char *) dp_packet_data(b) : UINT16_MAX; +-} +- +-static inline void * +-dp_packet_l4(const struct dp_packet *b) +-{ +- return b->l4_ofs != UINT16_MAX +- ? (char *) dp_packet_data(b) + b->l4_ofs +- : NULL; +-} +- +-static inline void +-dp_packet_set_l4(struct dp_packet *b, void *l4) +-{ +- b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; +-} +- +-/* Returns the size of the packet from the beginning of the L3 header to the +- * end of the L3 payload. Hence L2 padding is not included. */ +-static inline size_t +-dp_packet_l3_size(const struct dp_packet *b) +-{ +- return OVS_LIKELY(b->l3_ofs != UINT16_MAX) +- ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l3(b) +- - dp_packet_l2_pad_size(b) +- : 0; +-} +- +-/* Returns the size of the packet from the beginning of the L4 header to the +- * end of the L4 payload. Hence L2 padding is not included. */ +-static inline size_t +-dp_packet_l4_size(const struct dp_packet *b) +-{ +- return OVS_LIKELY(b->l4_ofs != UINT16_MAX) +- ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) +- - dp_packet_l2_pad_size(b) +- : 0; +-} +- +-static inline const void * +-dp_packet_get_tcp_payload(const struct dp_packet *b) +-{ +- size_t l4_size = dp_packet_l4_size(b); +- +- if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { +- struct tcp_header *tcp = dp_packet_l4(b); +- int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; +- +- if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { +- return (const char *)tcp + tcp_len; +- } +- } +- return NULL; +-} +- +-static inline uint32_t +-dp_packet_get_tcp_payload_length(const struct dp_packet *pkt) +-{ +- const char *tcp_payload = dp_packet_get_tcp_payload(pkt); +- if (tcp_payload) { +- return ((char *) dp_packet_tail(pkt) - dp_packet_l2_pad_size(pkt) +- - tcp_payload); +- } else { +- return 0; +- } +-} +- +-static inline const void * +-dp_packet_get_udp_payload(const struct dp_packet *b) +-{ +- return OVS_LIKELY(dp_packet_l4_size(b) >= UDP_HEADER_LEN) +- ? (const char *)dp_packet_l4(b) + UDP_HEADER_LEN : NULL; +-} +- +-static inline const void * +-dp_packet_get_sctp_payload(const struct dp_packet *b) +-{ +- return OVS_LIKELY(dp_packet_l4_size(b) >= SCTP_HEADER_LEN) +- ? (const char *)dp_packet_l4(b) + SCTP_HEADER_LEN : NULL; +-} +- +-static inline const void * +-dp_packet_get_icmp_payload(const struct dp_packet *b) +-{ +- return OVS_LIKELY(dp_packet_l4_size(b) >= ICMP_HEADER_LEN) +- ? (const char *)dp_packet_l4(b) + ICMP_HEADER_LEN : NULL; +-} +- +-static inline const void * +-dp_packet_get_nd_payload(const struct dp_packet *b) +-{ +- return OVS_LIKELY(dp_packet_l4_size(b) >= ND_MSG_LEN) +- ? (const char *)dp_packet_l4(b) + ND_MSG_LEN : NULL; +-} +- +-#ifdef DPDK_NETDEV +-static inline uint64_t * +-dp_packet_ol_flags_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint64_t *, &b->mbuf.ol_flags); +-} +- +-static inline uint32_t * +-dp_packet_rss_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint32_t *, &b->mbuf.hash.rss); +-} +- +-static inline uint32_t * +-dp_packet_flow_mark_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint32_t *, &b->mbuf.hash.fdir.hi); +-} +- +-#else +-static inline uint32_t * +-dp_packet_ol_flags_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint32_t *, &b->ol_flags); +-} +- +-static inline uint32_t * +-dp_packet_rss_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint32_t *, &b->rss_hash); +-} +- +-static inline uint32_t * +-dp_packet_flow_mark_ptr(const struct dp_packet *b) +-{ +- return CONST_CAST(uint32_t *, &b->flow_mark); +-} +-#endif +- +-#ifdef DPDK_NETDEV +-BUILD_ASSERT_DECL(offsetof(struct dp_packet, mbuf) == 0); +- +-static inline void +-dp_packet_init_specific(struct dp_packet *p) +-{ +- /* This initialization is needed for packets that do not come from DPDK +- * interfaces, when vswitchd is built with --with-dpdk. */ +- p->mbuf.ol_flags = p->mbuf.tx_offload = p->mbuf.packet_type = 0; +- p->mbuf.nb_segs = 1; +- p->mbuf.next = NULL; +-} +- +-static inline void * +-dp_packet_base(const struct dp_packet *b) +-{ +- return b->mbuf.buf_addr; +-} +- +-static inline void +-dp_packet_set_base(struct dp_packet *b, void *d) +-{ +- b->mbuf.buf_addr = d; +-} +- +-static inline uint32_t +-dp_packet_size(const struct dp_packet *b) +-{ +- return b->mbuf.pkt_len; +-} +- +-static inline void +-dp_packet_set_size(struct dp_packet *b, uint32_t v) +-{ +- /* netdev-dpdk does not currently support segmentation; consequently, for +- * all intents and purposes, 'data_len' (16 bit) and 'pkt_len' (32 bit) may +- * be used interchangably. +- * +- * On the datapath, it is expected that the size of packets +- * (and thus 'v') will always be <= UINT16_MAX; this means that there is no +- * loss of accuracy in assigning 'v' to 'data_len'. +- */ +- b->mbuf.data_len = (uint16_t)v; /* Current seg length. */ +- b->mbuf.pkt_len = v; /* Total length of all segments linked to +- * this segment. */ +-} +- +-static inline uint16_t +-__packet_data(const struct dp_packet *b) +-{ +- return b->mbuf.data_off; +-} +- +-static inline void +-__packet_set_data(struct dp_packet *b, uint16_t v) +-{ +- b->mbuf.data_off = v; +-} +- +-static inline uint16_t +-dp_packet_get_allocated(const struct dp_packet *b) +-{ +- return b->mbuf.buf_len; +-} +- +-static inline void +-dp_packet_set_allocated(struct dp_packet *b, uint16_t s) +-{ +- b->mbuf.buf_len = s; +-} +- +-#else /* DPDK_NETDEV */ +- +-static inline void +-dp_packet_init_specific(struct dp_packet *p OVS_UNUSED) +-{ +- /* There are no implementation-specific fields for initialization. */ +-} +- +-static inline void * +-dp_packet_base(const struct dp_packet *b) +-{ +- return b->base_; +-} +- +-static inline void +-dp_packet_set_base(struct dp_packet *b, void *d) +-{ +- b->base_ = d; +-} +- +-static inline uint32_t +-dp_packet_size(const struct dp_packet *b) +-{ +- return b->size_; +-} +- +-static inline void +-dp_packet_set_size(struct dp_packet *b, uint32_t v) +-{ +- b->size_ = v; +-} +- +-static inline uint16_t +-__packet_data(const struct dp_packet *b) +-{ +- return b->data_ofs; +-} +- +-static inline void +-__packet_set_data(struct dp_packet *b, uint16_t v) +-{ +- b->data_ofs = v; +-} +- +-static inline uint16_t +-dp_packet_get_allocated(const struct dp_packet *b) +-{ +- return b->allocated_; +-} +- +-static inline void +-dp_packet_set_allocated(struct dp_packet *b, uint16_t s) +-{ +- b->allocated_ = s; +-} +- +-#endif /* DPDK_NETDEV */ +- +-static inline void +-dp_packet_reset_cutlen(struct dp_packet *b) +-{ +- b->cutlen = 0; +-} +- +-static inline uint32_t +-dp_packet_set_cutlen(struct dp_packet *b, uint32_t max_len) +-{ +- if (max_len < ETH_HEADER_LEN) { +- max_len = ETH_HEADER_LEN; +- } +- +- if (max_len >= dp_packet_size(b)) { +- b->cutlen = 0; +- } else { +- b->cutlen = dp_packet_size(b) - max_len; +- } +- return b->cutlen; +-} +- +-static inline uint32_t +-dp_packet_get_cutlen(const struct dp_packet *b) +-{ +- /* Always in valid range if user uses dp_packet_set_cutlen. */ +- return b->cutlen; +-} +- +-static inline uint32_t +-dp_packet_get_send_len(const struct dp_packet *b) +-{ +- return dp_packet_size(b) - dp_packet_get_cutlen(b); +-} +- +-static inline void * +-dp_packet_data(const struct dp_packet *b) +-{ +- return __packet_data(b) != UINT16_MAX +- ? (char *) dp_packet_base(b) + __packet_data(b) : NULL; +-} +- +-static inline void +-dp_packet_set_data(struct dp_packet *b, void *data) +-{ +- if (data) { +- __packet_set_data(b, (char *) data - (char *) dp_packet_base(b)); +- } else { +- __packet_set_data(b, UINT16_MAX); +- } +-} +- +-static inline void +-dp_packet_reset_packet(struct dp_packet *b, int off) +-{ +- dp_packet_set_size(b, dp_packet_size(b) - off); +- dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off)); +- dp_packet_reset_offsets(b); +-} +- +-enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ +- +-struct dp_packet_batch { +- size_t count; +- bool trunc; /* true if the batch needs truncate. */ +- struct dp_packet *packets[NETDEV_MAX_BURST]; +-}; +- +-static inline void +-dp_packet_batch_init(struct dp_packet_batch *batch) +-{ +- batch->count = 0; +- batch->trunc = false; +-} +- +-static inline void +-dp_packet_batch_add__(struct dp_packet_batch *batch, +- struct dp_packet *packet, size_t limit) +-{ +- if (batch->count < limit) { +- batch->packets[batch->count++] = packet; +- } else { +- dp_packet_delete(packet); +- } +-} +- +-/* When the batch is full, 'packet' will be dropped and freed. */ +-static inline void +-dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet) +-{ +- dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); +-} +- +-static inline size_t +-dp_packet_batch_size(const struct dp_packet_batch *batch) +-{ +- return batch->count; +-} +- +-/* Clear 'batch' for refill. Use dp_packet_batch_refill() to add +- * packets back into the 'batch'. */ +-static inline void +-dp_packet_batch_refill_init(struct dp_packet_batch *batch) +-{ +- batch->count = 0; +-}; +- +-static inline void +-dp_packet_batch_refill(struct dp_packet_batch *batch, +- struct dp_packet *packet, size_t idx) +-{ +- dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1)); +-} +- +-static inline void +-dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct dp_packet *p) +-{ +- dp_packet_batch_init(batch); +- batch->count = 1; +- batch->packets[0] = p; +-} +- +-static inline bool +-dp_packet_batch_is_empty(const struct dp_packet_batch *batch) +-{ +- return !dp_packet_batch_size(batch); +-} +- +-static inline bool +-dp_packet_batch_is_full(const struct dp_packet_batch *batch) +-{ +- return dp_packet_batch_size(batch) == NETDEV_MAX_BURST; +-} +- +-#define DP_PACKET_BATCH_FOR_EACH(IDX, PACKET, BATCH) \ +- for (size_t IDX = 0; IDX < dp_packet_batch_size(BATCH); IDX++) \ +- if (PACKET = BATCH->packets[IDX], true) +- +-/* Use this macro for cases where some packets in the 'BATCH' may be +- * dropped after going through each packet in the 'BATCH'. +- * +- * For packets to stay in the 'BATCH', they need to be refilled back +- * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns +- * the packets that are not refilled. +- * +- * Caller needs to supply 'SIZE', that stores the current number of +- * packets in 'BATCH'. It is best to declare this variable with +- * the 'const' modifier since it should not be modified by +- * the iterator. */ +-#define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) \ +- for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; IDX++) \ +- if (PACKET = BATCH->packets[IDX], true) +- +-static inline void +-dp_packet_batch_clone(struct dp_packet_batch *dst, +- struct dp_packet_batch *src) +-{ +- struct dp_packet *packet; +- +- dp_packet_batch_init(dst); +- DP_PACKET_BATCH_FOR_EACH (i, packet, src) { +- if (i + 1 < dp_packet_batch_size(src)) { +- OVS_PREFETCH(src->packets[i + 1]); +- } +- +- uint32_t headroom = dp_packet_headroom(packet); +- struct dp_packet *pkt_clone; +- +- pkt_clone = dp_packet_clone_with_headroom(packet, headroom); +- dp_packet_batch_add(dst, pkt_clone); +- } +- dst->trunc = src->trunc; +-} +- +-static inline void +-dp_packet_delete_batch(struct dp_packet_batch *batch, bool should_steal) +-{ +- if (should_steal) { +- struct dp_packet *packet; +- +- DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { +- dp_packet_delete(packet); +- } +- dp_packet_batch_init(batch); +- } +-} +- +-static inline void +-dp_packet_batch_init_packet_fields(struct dp_packet_batch *batch) +-{ +- struct dp_packet *packet; +- +- DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { +- dp_packet_reset_cutlen(packet); +- packet->packet_type = htonl(PT_ETH); +- } +-} +- +-static inline void +-dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) +-{ +- if (batch->trunc) { +- struct dp_packet *packet; +- +- DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { +- dp_packet_set_size(packet, dp_packet_get_send_len(packet)); +- dp_packet_reset_cutlen(packet); +- } +- batch->trunc = false; +- } +-} +- +-static inline void +-dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) +-{ +- if (batch->trunc) { +- struct dp_packet *packet; +- +- DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { +- dp_packet_reset_cutlen(packet); +- } +- batch->trunc = false; +- } +-} +- +-/* Returns the RSS hash of the packet 'p'. Note that the returned value is +- * correct only if 'dp_packet_rss_valid(p)' returns 'true'. */ +-static inline uint32_t +-dp_packet_get_rss_hash(const struct dp_packet *p) +-{ +- return *dp_packet_rss_ptr(p); +-} +- +-static inline void +-dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) +-{ +- *dp_packet_rss_ptr(p) = hash; +- *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_RSS_HASH; +-} +- +-static inline bool +-dp_packet_rss_valid(const struct dp_packet *p) +-{ +- return *dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RSS_HASH; +-} +- +-static inline void +-dp_packet_reset_offload(struct dp_packet *p) +-{ +- *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_SUPPORTED_MASK; +-} +- +-static inline bool +-dp_packet_has_flow_mark(const struct dp_packet *p, uint32_t *mark) +-{ +- if (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_FLOW_MARK) { +- *mark = *dp_packet_flow_mark_ptr(p); +- return true; +- } +- +- return false; +-} +- +-static inline void +-dp_packet_set_flow_mark(struct dp_packet *p, uint32_t mark) +-{ +- *dp_packet_flow_mark_ptr(p) = mark; +- *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_FLOW_MARK; +-} +- +-/* Returns the L4 cksum offload bitmask. */ +-static inline uint64_t +-dp_packet_hwol_l4_mask(const struct dp_packet *b) +-{ +- return *dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK; +-} +- +-/* Return true if the packet 'b' requested L4 checksum offload. */ +-static inline bool +-dp_packet_hwol_tx_l4_checksum(const struct dp_packet *b) +-{ +- return !!dp_packet_hwol_l4_mask(b); +-} +- +-/* Returns 'true' if packet 'b' is marked for TCP segmentation offloading. */ +-static inline bool +-dp_packet_hwol_is_tso(const struct dp_packet *b) +-{ +- return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_TCP_SEG); +-} +- +-/* Returns 'true' if packet 'b' is marked for IPv4 checksum offloading. */ +-static inline bool +-dp_packet_hwol_is_ipv4(const struct dp_packet *b) +-{ +- return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_IPV4); +-} +- +-/* Returns 'true' if packet 'b' is marked for TCP checksum offloading. */ +-static inline bool +-dp_packet_hwol_l4_is_tcp(const struct dp_packet *b) +-{ +- return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == +- DP_PACKET_OL_TX_TCP_CKSUM; +-} +- +-/* Returns 'true' if packet 'b' is marked for UDP checksum offloading. */ +-static inline bool +-dp_packet_hwol_l4_is_udp(struct dp_packet *b) +-{ +- return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == +- DP_PACKET_OL_TX_UDP_CKSUM; +-} +- +-/* Returns 'true' if packet 'b' is marked for SCTP checksum offloading. */ +-static inline bool +-dp_packet_hwol_l4_is_sctp(struct dp_packet *b) +-{ +- return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == +- DP_PACKET_OL_TX_SCTP_CKSUM; +-} +- +-/* Mark packet 'b' for IPv4 checksum offloading. */ +-static inline void +-dp_packet_hwol_set_tx_ipv4(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV4; +-} +- +-/* Mark packet 'b' for IPv6 checksum offloading. */ +-static inline void +-dp_packet_hwol_set_tx_ipv6(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV6; +-} +- +-/* Mark packet 'b' for TCP checksum offloading. It implies that either +- * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ +-static inline void +-dp_packet_hwol_set_csum_tcp(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_CKSUM; +-} +- +-/* Mark packet 'b' for UDP checksum offloading. It implies that either +- * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ +-static inline void +-dp_packet_hwol_set_csum_udp(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_UDP_CKSUM; +-} +- +-/* Mark packet 'b' for SCTP checksum offloading. It implies that either +- * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ +-static inline void +-dp_packet_hwol_set_csum_sctp(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_SCTP_CKSUM; +-} +- +-/* Mark packet 'b' for TCP segmentation offloading. It implies that +- * either the packet 'b' is marked for IPv4 or IPv6 checksum offloading +- * and also for TCP checksum offloading. */ +-static inline void +-dp_packet_hwol_set_tcp_seg(struct dp_packet *b) +-{ +- *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_SEG; +-} +- +-static inline bool +-dp_packet_ip_checksum_valid(const struct dp_packet *p) +-{ +- return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == +- DP_PACKET_OL_RX_IP_CKSUM_GOOD; +-} +- +-static inline bool +-dp_packet_ip_checksum_bad(const struct dp_packet *p) +-{ +- return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == +- DP_PACKET_OL_RX_IP_CKSUM_BAD; +-} +- +-static inline bool +-dp_packet_l4_checksum_valid(const struct dp_packet *p) +-{ +- return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == +- DP_PACKET_OL_RX_L4_CKSUM_GOOD; +-} +- +-static inline bool +-dp_packet_l4_checksum_bad(const struct dp_packet *p) +-{ +- return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == +- DP_PACKET_OL_RX_L4_CKSUM_BAD; +-} +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* dp-packet.h */ +Index: openvswitch-2.17.2/include/internal/dp-packet.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/dp-packet.h +@@ -0,0 +1,1092 @@ ++/* ++ * 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DPBUF_H ++#define DPBUF_H 1 ++ ++#include ++#include ++ ++#ifdef DPDK_NETDEV ++#include ++#include ++#endif ++ ++#include "internal/netdev-afxdp.h" ++#include "internal/netdev-dpdk.h" ++#include "openvswitch/list.h" +#include "internal/packets.h" +#include "internal/util.h" +#include "internal/flow.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/fatal-signal.h b/include/internal/fatal-signal.h -similarity index 100% -rename from lib/fatal-signal.h -rename to include/internal/fatal-signal.h -diff --git a/lib/flow.h b/include/internal/flow.h -similarity index 99% -rename from lib/flow.h -rename to include/internal/flow.h -index c647ad83c..c8be4d59c 100644 ---- a/lib/flow.h -+++ b/include/internal/flow.h -@@ -22,15 +22,15 @@ - #include - #include - #include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++enum OVS_PACKED_ENUM dp_packet_source { ++ DPBUF_MALLOC, /* Obtained via malloc(). */ ++ DPBUF_STACK, /* Un-movable stack space or static buffer. */ ++ DPBUF_STUB, /* Starts on stack, may expand into heap. */ ++ DPBUF_DPDK, /* buffer data is from DPDK allocated memory. ++ * ref to dp_packet_init_dpdk() in dp-packet.c. ++ */ ++ DPBUF_AFXDP, /* Buffer data from XDP frame. */ ++}; ++ ++#define DP_PACKET_CONTEXT_SIZE 64 ++ ++#ifdef DPDK_NETDEV ++#define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = DPDK_DEF ++#else ++#define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = GENERIC_DEF ++#endif ++ ++/* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ ++enum dp_packet_offload_mask { ++ /* Value 0 is not used. */ ++ /* Is the 'rss_hash' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, RTE_MBUF_F_RX_RSS_HASH, 0x1), ++ /* Is the 'flow_mark' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_FLOW_MARK, RTE_MBUF_F_RX_FDIR_ID, 0x2), ++ /* Bad L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_BAD, RTE_MBUF_F_RX_L4_CKSUM_BAD, 0x4), ++ /* Bad IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_BAD, RTE_MBUF_F_RX_IP_CKSUM_BAD, 0x8), ++ /* Valid L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_GOOD, RTE_MBUF_F_RX_L4_CKSUM_GOOD, ++ 0x10), ++ /* Valid IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_GOOD, RTE_MBUF_F_RX_IP_CKSUM_GOOD, ++ 0x20), ++ /* TCP Segmentation Offload. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_SEG, RTE_MBUF_F_TX_TCP_SEG, 0x40), ++ /* Offloaded packet is IPv4. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV4, RTE_MBUF_F_TX_IPV4, 0x80), ++ /* Offloaded packet is IPv6. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV6, RTE_MBUF_F_TX_IPV6, 0x100), ++ /* Offload TCP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_CKSUM, RTE_MBUF_F_TX_TCP_CKSUM, 0x200), ++ /* Offload UDP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, RTE_MBUF_F_TX_UDP_CKSUM, 0x400), ++ /* Offload SCTP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM, 0x800), ++ /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ ++}; ++ ++#define DP_PACKET_OL_SUPPORTED_MASK (DP_PACKET_OL_RSS_HASH | \ ++ DP_PACKET_OL_FLOW_MARK | \ ++ DP_PACKET_OL_RX_L4_CKSUM_BAD | \ ++ DP_PACKET_OL_RX_IP_CKSUM_BAD | \ ++ DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ ++ DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ ++ DP_PACKET_OL_TX_TCP_SEG | \ ++ DP_PACKET_OL_TX_IPV4 | \ ++ DP_PACKET_OL_TX_IPV6 | \ ++ DP_PACKET_OL_TX_TCP_CKSUM | \ ++ DP_PACKET_OL_TX_UDP_CKSUM | \ ++ DP_PACKET_OL_TX_SCTP_CKSUM) ++ ++#define DP_PACKET_OL_TX_L4_MASK (DP_PACKET_OL_TX_TCP_CKSUM | \ ++ DP_PACKET_OL_TX_UDP_CKSUM | \ ++ DP_PACKET_OL_TX_SCTP_CKSUM) ++#define DP_PACKET_OL_RX_IP_CKSUM_MASK (DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ ++ DP_PACKET_OL_RX_IP_CKSUM_BAD) ++#define DP_PACKET_OL_RX_L4_CKSUM_MASK (DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ ++ DP_PACKET_OL_RX_L4_CKSUM_BAD) ++ ++/* Buffer for holding packet data. A dp_packet is automatically reallocated ++ * as necessary if it grows too large for the available memory. ++ * By default the packet type is set to Ethernet (PT_ETH). ++ */ ++struct dp_packet { ++#ifdef DPDK_NETDEV ++ struct rte_mbuf mbuf; /* DPDK mbuf */ ++#else ++ void *base_; /* First byte of allocated space. */ ++ uint16_t allocated_; /* Number of bytes allocated. */ ++ uint16_t data_ofs; /* First byte actually in use. */ ++ uint32_t size_; /* Number of bytes in use. */ ++ uint32_t ol_flags; /* Offloading flags. */ ++ uint32_t rss_hash; /* Packet hash. */ ++ uint32_t flow_mark; /* Packet flow mark. */ ++#endif ++ enum dp_packet_source source; /* Source of memory allocated as 'base'. */ ++ ++ /* All the following elements of this struct are copied in a single call ++ * of memcpy in dp_packet_clone_with_headroom. */ ++ uint16_t l2_pad_size; /* Detected l2 padding size. ++ * Padding is non-pullable. */ ++ uint16_t l2_5_ofs; /* MPLS label stack offset, or UINT16_MAX */ ++ uint16_t l3_ofs; /* Network-level header offset, ++ * or UINT16_MAX. */ ++ uint16_t l4_ofs; /* Transport-level header offset, ++ or UINT16_MAX. */ ++ uint32_t cutlen; /* length in bytes to cut from the end. */ ++ ovs_be32 packet_type; /* Packet type as defined in OpenFlow */ ++ union { ++ struct pkt_metadata md; ++ uint64_t data[DP_PACKET_CONTEXT_SIZE / 8]; ++ }; ++}; ++ ++#if HAVE_AF_XDP ++struct dp_packet_afxdp { ++ struct umem_pool *mpool; ++ struct dp_packet packet; ++}; ++#endif ++ ++static inline void *dp_packet_data(const struct dp_packet *); ++static inline void dp_packet_set_data(struct dp_packet *, void *); ++static inline void *dp_packet_base(const struct dp_packet *); ++static inline void dp_packet_set_base(struct dp_packet *, void *); ++ ++static inline uint32_t dp_packet_size(const struct dp_packet *); ++static inline void dp_packet_set_size(struct dp_packet *, uint32_t); ++ ++static inline uint16_t dp_packet_get_allocated(const struct dp_packet *); ++static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t); ++ ++void *dp_packet_resize_l2(struct dp_packet *, int increment); ++void *dp_packet_resize_l2_5(struct dp_packet *, int increment); ++static inline void *dp_packet_eth(const struct dp_packet *); ++static inline void dp_packet_reset_offsets(struct dp_packet *); ++static inline uint16_t dp_packet_l2_pad_size(const struct dp_packet *); ++static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint16_t); ++static inline void *dp_packet_l2_5(const struct dp_packet *); ++static inline void dp_packet_set_l2_5(struct dp_packet *, void *); ++static inline void *dp_packet_l3(const struct dp_packet *); ++static inline void dp_packet_set_l3(struct dp_packet *, void *); ++static inline void *dp_packet_l4(const struct dp_packet *); ++static inline void dp_packet_set_l4(struct dp_packet *, void *); ++static inline size_t dp_packet_l4_size(const struct dp_packet *); ++static inline const void *dp_packet_get_tcp_payload(const struct dp_packet *); ++static inline const void *dp_packet_get_udp_payload(const struct dp_packet *); ++static inline const void *dp_packet_get_sctp_payload(const struct dp_packet *); ++static inline const void *dp_packet_get_icmp_payload(const struct dp_packet *); ++static inline const void *dp_packet_get_nd_payload(const struct dp_packet *); ++ ++void dp_packet_use(struct dp_packet *, void *, size_t); ++void dp_packet_use_stub(struct dp_packet *, void *, size_t); ++void dp_packet_use_const(struct dp_packet *, const void *, size_t); ++#if HAVE_AF_XDP ++void dp_packet_use_afxdp(struct dp_packet *, void *, size_t, size_t); ++#endif ++void dp_packet_init_dpdk(struct dp_packet *); ++ ++void dp_packet_init(struct dp_packet *, size_t); ++void dp_packet_uninit(struct dp_packet *); ++ ++struct dp_packet *dp_packet_new(size_t); ++struct dp_packet *dp_packet_new_with_headroom(size_t, size_t headroom); ++struct dp_packet *dp_packet_clone(const struct dp_packet *); ++struct dp_packet *dp_packet_clone_with_headroom(const struct dp_packet *, ++ size_t headroom); ++struct dp_packet *dp_packet_clone_data(const void *, size_t); ++struct dp_packet *dp_packet_clone_data_with_headroom(const void *, size_t, ++ size_t headroom); ++void dp_packet_resize(struct dp_packet *b, size_t new_headroom, ++ size_t new_tailroom); ++static inline void dp_packet_delete(struct dp_packet *); ++static inline void dp_packet_swap(struct dp_packet *, struct dp_packet *); ++ ++static inline void *dp_packet_at(const struct dp_packet *, size_t offset, ++ size_t size); ++static inline void *dp_packet_at_assert(const struct dp_packet *, ++ size_t offset, size_t size); ++static inline void *dp_packet_tail(const struct dp_packet *); ++static inline void *dp_packet_end(const struct dp_packet *); ++ ++void *dp_packet_put_uninit(struct dp_packet *, size_t); ++void *dp_packet_put_zeros(struct dp_packet *, size_t); ++void *dp_packet_put(struct dp_packet *, const void *, size_t); ++char *dp_packet_put_hex(struct dp_packet *, const char *s, size_t *n); ++void dp_packet_reserve(struct dp_packet *, size_t); ++void dp_packet_reserve_with_tailroom(struct dp_packet *, size_t headroom, ++ size_t tailroom); ++void *dp_packet_push_uninit(struct dp_packet *, size_t); ++void *dp_packet_push_zeros(struct dp_packet *, size_t); ++void *dp_packet_push(struct dp_packet *, const void *, size_t); ++ ++static inline size_t dp_packet_headroom(const struct dp_packet *); ++static inline size_t dp_packet_tailroom(const struct dp_packet *); ++void dp_packet_prealloc_headroom(struct dp_packet *, size_t); ++void dp_packet_prealloc_tailroom(struct dp_packet *, size_t); ++void dp_packet_shift(struct dp_packet *, int); ++ ++static inline void dp_packet_clear(struct dp_packet *); ++static inline void *dp_packet_pull(struct dp_packet *, size_t); ++static inline void *dp_packet_try_pull(struct dp_packet *, size_t); ++ ++void *dp_packet_steal_data(struct dp_packet *); ++ ++static inline bool dp_packet_equal(const struct dp_packet *, ++ const struct dp_packet *); ++ ++ ++/* Frees memory that 'b' points to, as well as 'b' itself. */ ++static inline void ++dp_packet_delete(struct dp_packet *b) ++{ ++ if (b) { ++ if (b->source == DPBUF_DPDK) { ++ /* If this dp_packet was allocated by DPDK it must have been ++ * created as a dp_packet */ ++ free_dpdk_buf((struct dp_packet*) b); ++ return; ++ } ++ ++ if (b->source == DPBUF_AFXDP) { ++ free_afxdp_buf(b); ++ return; ++ } ++ ++ dp_packet_uninit(b); ++ free(b); ++ } ++} ++ ++/* Swaps content of two packets. */ ++static inline void ++dp_packet_swap(struct dp_packet *a, struct dp_packet *b) ++{ ++ ovs_assert(a->source == DPBUF_MALLOC || a->source == DPBUF_STUB); ++ ovs_assert(b->source == DPBUF_MALLOC || b->source == DPBUF_STUB); ++ struct dp_packet c = *a; ++ ++ *a = *b; ++ *b = c; ++} ++ ++/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to ++ * byte 'offset'. Otherwise, returns a null pointer. */ ++static inline void * ++dp_packet_at(const struct dp_packet *b, size_t offset, size_t size) ++{ ++ return offset + size <= dp_packet_size(b) ++ ? (char *) dp_packet_data(b) + offset ++ : NULL; ++} ++ ++/* Returns a pointer to byte 'offset' in 'b', which must contain at least ++ * 'offset + size' bytes of data. */ ++static inline void * ++dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size) ++{ ++ ovs_assert(offset + size <= dp_packet_size(b)); ++ return ((char *) dp_packet_data(b)) + offset; ++} ++ ++/* Returns a pointer to byte following the last byte of data in use in 'b'. */ ++static inline void * ++dp_packet_tail(const struct dp_packet *b) ++{ ++ return (char *) dp_packet_data(b) + dp_packet_size(b); ++} ++ ++/* Returns a pointer to byte following the last byte allocated for use (but ++ * not necessarily in use) in 'b'. */ ++static inline void * ++dp_packet_end(const struct dp_packet *b) ++{ ++ return (char *) dp_packet_base(b) + dp_packet_get_allocated(b); ++} ++ ++/* Returns the number of bytes of headroom in 'b', that is, the number of bytes ++ * of unused space in dp_packet 'b' before the data that is in use. (Most ++ * commonly, the data in a dp_packet is at its beginning, and thus the ++ * dp_packet's headroom is 0.) */ ++static inline size_t ++dp_packet_headroom(const struct dp_packet *b) ++{ ++ return (char *) dp_packet_data(b) - (char *) dp_packet_base(b); ++} ++ ++/* Returns the number of bytes that may be appended to the tail end of ++ * dp_packet 'b' before the dp_packet must be reallocated. */ ++static inline size_t ++dp_packet_tailroom(const struct dp_packet *b) ++{ ++ return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); ++} ++ ++/* Clears any data from 'b'. */ ++static inline void ++dp_packet_clear(struct dp_packet *b) ++{ ++ dp_packet_set_data(b, dp_packet_base(b)); ++ dp_packet_set_size(b, 0); ++} ++ ++/* Removes 'size' bytes from the head end of 'b', which must contain at least ++ * 'size' bytes of data. Returns the first byte of data removed. */ ++static inline void * ++dp_packet_pull(struct dp_packet *b, size_t size) ++{ ++ void *data = dp_packet_data(b); ++ ovs_assert(dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size); ++ dp_packet_set_data(b, (char *) dp_packet_data(b) + size); ++ dp_packet_set_size(b, dp_packet_size(b) - size); ++ return data; ++} ++ ++/* If 'b' has at least 'size' bytes of data, removes that many bytes from the ++ * head end of 'b' and returns the first byte removed. Otherwise, returns a ++ * null pointer without modifying 'b'. */ ++static inline void * ++dp_packet_try_pull(struct dp_packet *b, size_t size) ++{ ++ return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size ++ ? dp_packet_pull(b, size) : NULL; ++} ++ ++static inline bool ++dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b) ++{ ++ return dp_packet_size(a) == dp_packet_size(b) && ++ !memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a)); ++} ++ ++static inline bool ++dp_packet_is_eth(const struct dp_packet *b) ++{ ++ return b->packet_type == htonl(PT_ETH); ++} ++ ++/* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2 ++ * headers, so return NULL if it is not set. */ ++static inline void * ++dp_packet_eth(const struct dp_packet *b) ++{ ++ return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX) ++ ? dp_packet_data(b) : NULL; ++} ++ ++/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be ++ * retrieved. */ ++static inline void ++dp_packet_reset_offsets(struct dp_packet *b) ++{ ++ b->l2_pad_size = 0; ++ b->l2_5_ofs = UINT16_MAX; ++ b->l3_ofs = UINT16_MAX; ++ b->l4_ofs = UINT16_MAX; ++} ++ ++static inline uint16_t ++dp_packet_l2_pad_size(const struct dp_packet *b) ++{ ++ return b->l2_pad_size; ++} ++ ++static inline void ++dp_packet_set_l2_pad_size(struct dp_packet *b, uint16_t pad_size) ++{ ++ ovs_assert(pad_size <= dp_packet_size(b)); ++ b->l2_pad_size = pad_size; ++} ++ ++static inline void * ++dp_packet_l2_5(const struct dp_packet *b) ++{ ++ return b->l2_5_ofs != UINT16_MAX ++ ? (char *) dp_packet_data(b) + b->l2_5_ofs ++ : NULL; ++} ++ ++static inline void ++dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) ++{ ++ b->l2_5_ofs = l2_5 ++ ? (char *) l2_5 - (char *) dp_packet_data(b) ++ : UINT16_MAX; ++} ++ ++static inline void * ++dp_packet_l3(const struct dp_packet *b) ++{ ++ return b->l3_ofs != UINT16_MAX ++ ? (char *) dp_packet_data(b) + b->l3_ofs ++ : NULL; ++} ++ ++static inline void ++dp_packet_set_l3(struct dp_packet *b, void *l3) ++{ ++ b->l3_ofs = l3 ? (char *) l3 - (char *) dp_packet_data(b) : UINT16_MAX; ++} ++ ++static inline void * ++dp_packet_l4(const struct dp_packet *b) ++{ ++ return b->l4_ofs != UINT16_MAX ++ ? (char *) dp_packet_data(b) + b->l4_ofs ++ : NULL; ++} ++ ++static inline void ++dp_packet_set_l4(struct dp_packet *b, void *l4) ++{ ++ b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; ++} ++ ++/* Returns the size of the packet from the beginning of the L3 header to the ++ * end of the L3 payload. Hence L2 padding is not included. */ ++static inline size_t ++dp_packet_l3_size(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(b->l3_ofs != UINT16_MAX) ++ ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l3(b) ++ - dp_packet_l2_pad_size(b) ++ : 0; ++} ++ ++/* Returns the size of the packet from the beginning of the L4 header to the ++ * end of the L4 payload. Hence L2 padding is not included. */ ++static inline size_t ++dp_packet_l4_size(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(b->l4_ofs != UINT16_MAX) ++ ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) ++ - dp_packet_l2_pad_size(b) ++ : 0; ++} ++ ++static inline const void * ++dp_packet_get_tcp_payload(const struct dp_packet *b) ++{ ++ size_t l4_size = dp_packet_l4_size(b); ++ ++ if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { ++ struct tcp_header *tcp = dp_packet_l4(b); ++ int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; ++ ++ if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { ++ return (const char *)tcp + tcp_len; ++ } ++ } ++ return NULL; ++} ++ ++static inline uint32_t ++dp_packet_get_tcp_payload_length(const struct dp_packet *pkt) ++{ ++ const char *tcp_payload = dp_packet_get_tcp_payload(pkt); ++ if (tcp_payload) { ++ return ((char *) dp_packet_tail(pkt) - dp_packet_l2_pad_size(pkt) ++ - tcp_payload); ++ } else { ++ return 0; ++ } ++} ++ ++static inline const void * ++dp_packet_get_udp_payload(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(dp_packet_l4_size(b) >= UDP_HEADER_LEN) ++ ? (const char *)dp_packet_l4(b) + UDP_HEADER_LEN : NULL; ++} ++ ++static inline const void * ++dp_packet_get_sctp_payload(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(dp_packet_l4_size(b) >= SCTP_HEADER_LEN) ++ ? (const char *)dp_packet_l4(b) + SCTP_HEADER_LEN : NULL; ++} ++ ++static inline const void * ++dp_packet_get_icmp_payload(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(dp_packet_l4_size(b) >= ICMP_HEADER_LEN) ++ ? (const char *)dp_packet_l4(b) + ICMP_HEADER_LEN : NULL; ++} ++ ++static inline const void * ++dp_packet_get_nd_payload(const struct dp_packet *b) ++{ ++ return OVS_LIKELY(dp_packet_l4_size(b) >= ND_MSG_LEN) ++ ? (const char *)dp_packet_l4(b) + ND_MSG_LEN : NULL; ++} ++ ++#ifdef DPDK_NETDEV ++static inline uint64_t * ++dp_packet_ol_flags_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint64_t *, &b->mbuf.ol_flags); ++} ++ ++static inline uint32_t * ++dp_packet_rss_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint32_t *, &b->mbuf.hash.rss); ++} ++ ++static inline uint32_t * ++dp_packet_flow_mark_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint32_t *, &b->mbuf.hash.fdir.hi); ++} ++ ++#else ++static inline uint32_t * ++dp_packet_ol_flags_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint32_t *, &b->ol_flags); ++} ++ ++static inline uint32_t * ++dp_packet_rss_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint32_t *, &b->rss_hash); ++} ++ ++static inline uint32_t * ++dp_packet_flow_mark_ptr(const struct dp_packet *b) ++{ ++ return CONST_CAST(uint32_t *, &b->flow_mark); ++} ++#endif ++ ++#ifdef DPDK_NETDEV ++BUILD_ASSERT_DECL(offsetof(struct dp_packet, mbuf) == 0); ++ ++static inline void ++dp_packet_init_specific(struct dp_packet *p) ++{ ++ /* This initialization is needed for packets that do not come from DPDK ++ * interfaces, when vswitchd is built with --with-dpdk. */ ++ p->mbuf.ol_flags = p->mbuf.tx_offload = p->mbuf.packet_type = 0; ++ p->mbuf.nb_segs = 1; ++ p->mbuf.next = NULL; ++} ++ ++static inline void * ++dp_packet_base(const struct dp_packet *b) ++{ ++ return b->mbuf.buf_addr; ++} ++ ++static inline void ++dp_packet_set_base(struct dp_packet *b, void *d) ++{ ++ b->mbuf.buf_addr = d; ++} ++ ++static inline uint32_t ++dp_packet_size(const struct dp_packet *b) ++{ ++ return b->mbuf.pkt_len; ++} ++ ++static inline void ++dp_packet_set_size(struct dp_packet *b, uint32_t v) ++{ ++ /* netdev-dpdk does not currently support segmentation; consequently, for ++ * all intents and purposes, 'data_len' (16 bit) and 'pkt_len' (32 bit) may ++ * be used interchangably. ++ * ++ * On the datapath, it is expected that the size of packets ++ * (and thus 'v') will always be <= UINT16_MAX; this means that there is no ++ * loss of accuracy in assigning 'v' to 'data_len'. ++ */ ++ b->mbuf.data_len = (uint16_t)v; /* Current seg length. */ ++ b->mbuf.pkt_len = v; /* Total length of all segments linked to ++ * this segment. */ ++} ++ ++static inline uint16_t ++__packet_data(const struct dp_packet *b) ++{ ++ return b->mbuf.data_off; ++} ++ ++static inline void ++__packet_set_data(struct dp_packet *b, uint16_t v) ++{ ++ b->mbuf.data_off = v; ++} ++ ++static inline uint16_t ++dp_packet_get_allocated(const struct dp_packet *b) ++{ ++ return b->mbuf.buf_len; ++} ++ ++static inline void ++dp_packet_set_allocated(struct dp_packet *b, uint16_t s) ++{ ++ b->mbuf.buf_len = s; ++} ++ ++#else /* DPDK_NETDEV */ ++ ++static inline void ++dp_packet_init_specific(struct dp_packet *p OVS_UNUSED) ++{ ++ /* There are no implementation-specific fields for initialization. */ ++} ++ ++static inline void * ++dp_packet_base(const struct dp_packet *b) ++{ ++ return b->base_; ++} ++ ++static inline void ++dp_packet_set_base(struct dp_packet *b, void *d) ++{ ++ b->base_ = d; ++} ++ ++static inline uint32_t ++dp_packet_size(const struct dp_packet *b) ++{ ++ return b->size_; ++} ++ ++static inline void ++dp_packet_set_size(struct dp_packet *b, uint32_t v) ++{ ++ b->size_ = v; ++} ++ ++static inline uint16_t ++__packet_data(const struct dp_packet *b) ++{ ++ return b->data_ofs; ++} ++ ++static inline void ++__packet_set_data(struct dp_packet *b, uint16_t v) ++{ ++ b->data_ofs = v; ++} ++ ++static inline uint16_t ++dp_packet_get_allocated(const struct dp_packet *b) ++{ ++ return b->allocated_; ++} ++ ++static inline void ++dp_packet_set_allocated(struct dp_packet *b, uint16_t s) ++{ ++ b->allocated_ = s; ++} ++ ++#endif /* DPDK_NETDEV */ ++ ++static inline void ++dp_packet_reset_cutlen(struct dp_packet *b) ++{ ++ b->cutlen = 0; ++} ++ ++static inline uint32_t ++dp_packet_set_cutlen(struct dp_packet *b, uint32_t max_len) ++{ ++ if (max_len < ETH_HEADER_LEN) { ++ max_len = ETH_HEADER_LEN; ++ } ++ ++ if (max_len >= dp_packet_size(b)) { ++ b->cutlen = 0; ++ } else { ++ b->cutlen = dp_packet_size(b) - max_len; ++ } ++ return b->cutlen; ++} ++ ++static inline uint32_t ++dp_packet_get_cutlen(const struct dp_packet *b) ++{ ++ /* Always in valid range if user uses dp_packet_set_cutlen. */ ++ return b->cutlen; ++} ++ ++static inline uint32_t ++dp_packet_get_send_len(const struct dp_packet *b) ++{ ++ return dp_packet_size(b) - dp_packet_get_cutlen(b); ++} ++ ++static inline void * ++dp_packet_data(const struct dp_packet *b) ++{ ++ return __packet_data(b) != UINT16_MAX ++ ? (char *) dp_packet_base(b) + __packet_data(b) : NULL; ++} ++ ++static inline void ++dp_packet_set_data(struct dp_packet *b, void *data) ++{ ++ if (data) { ++ __packet_set_data(b, (char *) data - (char *) dp_packet_base(b)); ++ } else { ++ __packet_set_data(b, UINT16_MAX); ++ } ++} ++ ++static inline void ++dp_packet_reset_packet(struct dp_packet *b, int off) ++{ ++ dp_packet_set_size(b, dp_packet_size(b) - off); ++ dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off)); ++ dp_packet_reset_offsets(b); ++} ++ ++enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ ++ ++struct dp_packet_batch { ++ size_t count; ++ bool trunc; /* true if the batch needs truncate. */ ++ struct dp_packet *packets[NETDEV_MAX_BURST]; ++}; ++ ++static inline void ++dp_packet_batch_init(struct dp_packet_batch *batch) ++{ ++ batch->count = 0; ++ batch->trunc = false; ++} ++ ++static inline void ++dp_packet_batch_add__(struct dp_packet_batch *batch, ++ struct dp_packet *packet, size_t limit) ++{ ++ if (batch->count < limit) { ++ batch->packets[batch->count++] = packet; ++ } else { ++ dp_packet_delete(packet); ++ } ++} ++ ++/* When the batch is full, 'packet' will be dropped and freed. */ ++static inline void ++dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet) ++{ ++ dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); ++} ++ ++static inline size_t ++dp_packet_batch_size(const struct dp_packet_batch *batch) ++{ ++ return batch->count; ++} ++ ++/* Clear 'batch' for refill. Use dp_packet_batch_refill() to add ++ * packets back into the 'batch'. */ ++static inline void ++dp_packet_batch_refill_init(struct dp_packet_batch *batch) ++{ ++ batch->count = 0; ++}; ++ ++static inline void ++dp_packet_batch_refill(struct dp_packet_batch *batch, ++ struct dp_packet *packet, size_t idx) ++{ ++ dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1)); ++} ++ ++static inline void ++dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct dp_packet *p) ++{ ++ dp_packet_batch_init(batch); ++ batch->count = 1; ++ batch->packets[0] = p; ++} ++ ++static inline bool ++dp_packet_batch_is_empty(const struct dp_packet_batch *batch) ++{ ++ return !dp_packet_batch_size(batch); ++} ++ ++static inline bool ++dp_packet_batch_is_full(const struct dp_packet_batch *batch) ++{ ++ return dp_packet_batch_size(batch) == NETDEV_MAX_BURST; ++} ++ ++#define DP_PACKET_BATCH_FOR_EACH(IDX, PACKET, BATCH) \ ++ for (size_t IDX = 0; IDX < dp_packet_batch_size(BATCH); IDX++) \ ++ if (PACKET = BATCH->packets[IDX], true) ++ ++/* Use this macro for cases where some packets in the 'BATCH' may be ++ * dropped after going through each packet in the 'BATCH'. ++ * ++ * For packets to stay in the 'BATCH', they need to be refilled back ++ * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns ++ * the packets that are not refilled. ++ * ++ * Caller needs to supply 'SIZE', that stores the current number of ++ * packets in 'BATCH'. It is best to declare this variable with ++ * the 'const' modifier since it should not be modified by ++ * the iterator. */ ++#define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) \ ++ for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; IDX++) \ ++ if (PACKET = BATCH->packets[IDX], true) ++ ++static inline void ++dp_packet_batch_clone(struct dp_packet_batch *dst, ++ struct dp_packet_batch *src) ++{ ++ struct dp_packet *packet; ++ ++ dp_packet_batch_init(dst); ++ DP_PACKET_BATCH_FOR_EACH (i, packet, src) { ++ if (i + 1 < dp_packet_batch_size(src)) { ++ OVS_PREFETCH(src->packets[i + 1]); ++ } ++ ++ uint32_t headroom = dp_packet_headroom(packet); ++ struct dp_packet *pkt_clone; ++ ++ pkt_clone = dp_packet_clone_with_headroom(packet, headroom); ++ dp_packet_batch_add(dst, pkt_clone); ++ } ++ dst->trunc = src->trunc; ++} ++ ++static inline void ++dp_packet_delete_batch(struct dp_packet_batch *batch, bool should_steal) ++{ ++ if (should_steal) { ++ struct dp_packet *packet; ++ ++ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { ++ dp_packet_delete(packet); ++ } ++ dp_packet_batch_init(batch); ++ } ++} ++ ++static inline void ++dp_packet_batch_init_packet_fields(struct dp_packet_batch *batch) ++{ ++ struct dp_packet *packet; ++ ++ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { ++ dp_packet_reset_cutlen(packet); ++ packet->packet_type = htonl(PT_ETH); ++ } ++} ++ ++static inline void ++dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) ++{ ++ if (batch->trunc) { ++ struct dp_packet *packet; ++ ++ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { ++ dp_packet_set_size(packet, dp_packet_get_send_len(packet)); ++ dp_packet_reset_cutlen(packet); ++ } ++ batch->trunc = false; ++ } ++} ++ ++static inline void ++dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) ++{ ++ if (batch->trunc) { ++ struct dp_packet *packet; ++ ++ DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { ++ dp_packet_reset_cutlen(packet); ++ } ++ batch->trunc = false; ++ } ++} ++ ++/* Returns the RSS hash of the packet 'p'. Note that the returned value is ++ * correct only if 'dp_packet_rss_valid(p)' returns 'true'. */ ++static inline uint32_t ++dp_packet_get_rss_hash(const struct dp_packet *p) ++{ ++ return *dp_packet_rss_ptr(p); ++} ++ ++static inline void ++dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) ++{ ++ *dp_packet_rss_ptr(p) = hash; ++ *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_RSS_HASH; ++} ++ ++static inline bool ++dp_packet_rss_valid(const struct dp_packet *p) ++{ ++ return *dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RSS_HASH; ++} ++ ++static inline void ++dp_packet_reset_offload(struct dp_packet *p) ++{ ++ *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_SUPPORTED_MASK; ++} ++ ++static inline bool ++dp_packet_has_flow_mark(const struct dp_packet *p, uint32_t *mark) ++{ ++ if (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_FLOW_MARK) { ++ *mark = *dp_packet_flow_mark_ptr(p); ++ return true; ++ } ++ ++ return false; ++} ++ ++static inline void ++dp_packet_set_flow_mark(struct dp_packet *p, uint32_t mark) ++{ ++ *dp_packet_flow_mark_ptr(p) = mark; ++ *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_FLOW_MARK; ++} ++ ++/* Returns the L4 cksum offload bitmask. */ ++static inline uint64_t ++dp_packet_hwol_l4_mask(const struct dp_packet *b) ++{ ++ return *dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK; ++} ++ ++/* Return true if the packet 'b' requested L4 checksum offload. */ ++static inline bool ++dp_packet_hwol_tx_l4_checksum(const struct dp_packet *b) ++{ ++ return !!dp_packet_hwol_l4_mask(b); ++} ++ ++/* Returns 'true' if packet 'b' is marked for TCP segmentation offloading. */ ++static inline bool ++dp_packet_hwol_is_tso(const struct dp_packet *b) ++{ ++ return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_TCP_SEG); ++} ++ ++/* Returns 'true' if packet 'b' is marked for IPv4 checksum offloading. */ ++static inline bool ++dp_packet_hwol_is_ipv4(const struct dp_packet *b) ++{ ++ return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_IPV4); ++} ++ ++/* Returns 'true' if packet 'b' is marked for TCP checksum offloading. */ ++static inline bool ++dp_packet_hwol_l4_is_tcp(const struct dp_packet *b) ++{ ++ return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == ++ DP_PACKET_OL_TX_TCP_CKSUM; ++} ++ ++/* Returns 'true' if packet 'b' is marked for UDP checksum offloading. */ ++static inline bool ++dp_packet_hwol_l4_is_udp(struct dp_packet *b) ++{ ++ return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == ++ DP_PACKET_OL_TX_UDP_CKSUM; ++} ++ ++/* Returns 'true' if packet 'b' is marked for SCTP checksum offloading. */ ++static inline bool ++dp_packet_hwol_l4_is_sctp(struct dp_packet *b) ++{ ++ return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == ++ DP_PACKET_OL_TX_SCTP_CKSUM; ++} ++ ++/* Mark packet 'b' for IPv4 checksum offloading. */ ++static inline void ++dp_packet_hwol_set_tx_ipv4(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV4; ++} ++ ++/* Mark packet 'b' for IPv6 checksum offloading. */ ++static inline void ++dp_packet_hwol_set_tx_ipv6(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV6; ++} ++ ++/* Mark packet 'b' for TCP checksum offloading. It implies that either ++ * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ ++static inline void ++dp_packet_hwol_set_csum_tcp(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_CKSUM; ++} ++ ++/* Mark packet 'b' for UDP checksum offloading. It implies that either ++ * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ ++static inline void ++dp_packet_hwol_set_csum_udp(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_UDP_CKSUM; ++} ++ ++/* Mark packet 'b' for SCTP checksum offloading. It implies that either ++ * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ ++static inline void ++dp_packet_hwol_set_csum_sctp(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_SCTP_CKSUM; ++} ++ ++/* Mark packet 'b' for TCP segmentation offloading. It implies that ++ * either the packet 'b' is marked for IPv4 or IPv6 checksum offloading ++ * and also for TCP checksum offloading. */ ++static inline void ++dp_packet_hwol_set_tcp_seg(struct dp_packet *b) ++{ ++ *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_SEG; ++} ++ ++static inline bool ++dp_packet_ip_checksum_valid(const struct dp_packet *p) ++{ ++ return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == ++ DP_PACKET_OL_RX_IP_CKSUM_GOOD; ++} ++ ++static inline bool ++dp_packet_ip_checksum_bad(const struct dp_packet *p) ++{ ++ return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == ++ DP_PACKET_OL_RX_IP_CKSUM_BAD; ++} ++ ++static inline bool ++dp_packet_l4_checksum_valid(const struct dp_packet *p) ++{ ++ return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == ++ DP_PACKET_OL_RX_L4_CKSUM_GOOD; ++} ++ ++static inline bool ++dp_packet_l4_checksum_bad(const struct dp_packet *p) ++{ ++ return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == ++ DP_PACKET_OL_RX_L4_CKSUM_BAD; ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* dp-packet.h */ +Index: openvswitch-2.17.2/lib/flow.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/flow.h ++++ /dev/null +@@ -1,1215 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-#ifndef FLOW_H +-#define FLOW_H 1 +- +-#include +-#include +-#include +-#include +-#include +-#include -#include "bitmap.h" -#include "byte-order.h" -+#include "internal/bitmap.h" -+#include "internal/byte-order.h" - #include "openvswitch/compiler.h" - #include "openflow/nicira-ext.h" - #include "openflow/openflow.h" - #include "openvswitch/flow.h" +-#include "openvswitch/compiler.h" +-#include "openflow/nicira-ext.h" +-#include "openflow/openflow.h" +-#include "openvswitch/flow.h" -#include "packets.h" -#include "hash.h" -#include "util.h" +- +-struct dpif_flow_stats; +-struct dpif_flow_attrs; +-struct ds; +-struct flow_wildcards; +-struct minimask; +-struct dp_packet; +-struct ofputil_port_map; +-struct pkt_metadata; +-struct match; +- +-/* Some flow fields are mutually exclusive or only appear within the flow +- * pipeline. IPv6 headers are bigger than IPv4 and MPLS, and IPv6 ND packets +- * are bigger than TCP,UDP and IGMP packets. */ +-#define FLOW_MAX_PACKET_U64S (FLOW_U64S \ +- /* Unused in datapath */ - FLOW_U64_SIZE(regs) \ +- - FLOW_U64_SIZE(metadata) \ +- /* L2.5/3 */ - FLOW_U64_SIZE(nw_src) /* incl. nw_dst */ \ +- - FLOW_U64_SIZE(mpls_lse) \ +- /* L4 */ - FLOW_U64_SIZE(tp_src) \ +- ) +- +-extern const uint8_t flow_segment_u64s[]; +- +-/* Configured maximum VLAN headers. */ +-extern int flow_vlan_limit; +- +-#define FLOW_U64_OFFSET(FIELD) \ +- (offsetof(struct flow, FIELD) / sizeof(uint64_t)) +-#define FLOW_U64_OFFREM(FIELD) \ +- (offsetof(struct flow, FIELD) % sizeof(uint64_t)) +- +-/* Number of 64-bit units spanned by a 'FIELD'. */ +-#define FLOW_U64_SIZE(FIELD) \ +- DIV_ROUND_UP(FLOW_U64_OFFREM(FIELD) + MEMBER_SIZEOF(struct flow, FIELD), \ +- sizeof(uint64_t)) +- +-void flow_extract(struct dp_packet *, struct flow *); +- +-void flow_zero_wildcards(struct flow *, const struct flow_wildcards *); +-void flow_unwildcard_tp_ports(const struct flow *, struct flow_wildcards *); +-void flow_get_metadata(const struct flow *, struct match *flow_metadata); +-struct netdev *flow_get_tunnel_netdev(struct flow_tnl *tunnel); +- +-const char *ct_state_to_string(uint32_t state); +-uint32_t ct_state_from_string(const char *); +-bool parse_ct_state(const char *state_str, uint32_t default_state, +- uint32_t *ct_state, struct ds *); +-bool validate_ct_state(uint32_t state, struct ds *); +-void flow_clear_conntrack(struct flow *); +- +-char *flow_to_string(const struct flow *, const struct ofputil_port_map *); +-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, uint32_t max_mask); +-void format_packet_type_masked(struct ds *, ovs_be32 value, ovs_be32 mask); +-int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t), +- char end, const char *field_name, char **res_string, +- uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask); +- +-void flow_format(struct ds *, const struct flow *, +- const struct ofputil_port_map *); +-void flow_print(FILE *, const struct flow *, const struct ofputil_port_map *); +-static inline int flow_compare_3way(const struct flow *, const struct flow *); +-static inline bool flow_equal(const struct flow *, const struct flow *); +-static inline size_t flow_hash(const struct flow *, uint32_t basis); +- +-void flow_set_dl_vlan(struct flow *, ovs_be16 vid, int id); +-void flow_fix_vlan_tpid(struct flow *); +-void flow_set_vlan_vid(struct flow *, ovs_be16 vid); +-void flow_set_vlan_pcp(struct flow *, uint8_t pcp, int id); +- +-void flow_limit_vlans(int vlan_limit); +-int flow_count_vlan_headers(const struct flow *); +-void flow_skip_common_vlan_headers(const struct flow *a, int *p_an, +- const struct flow *b, int *p_bn); +-void flow_pop_vlan(struct flow*, struct flow_wildcards*); +-void flow_push_vlan_uninit(struct flow*, struct flow_wildcards*); +- +-int flow_count_mpls_labels(const struct flow *, struct flow_wildcards *); +-int flow_count_common_mpls_labels(const struct flow *a, int an, +- const struct flow *b, int bn, +- struct flow_wildcards *wc); +-void flow_push_mpls(struct flow *, int n, ovs_be16 mpls_eth_type, +- struct flow_wildcards *, bool clear_flow_L3); +-bool flow_pop_mpls(struct flow *, int n, ovs_be16 eth_type, +- struct flow_wildcards *); +-void flow_set_mpls_label(struct flow *, int idx, ovs_be32 label); +-void flow_set_mpls_ttl(struct flow *, int idx, uint8_t ttl); +-void flow_set_mpls_tc(struct flow *, int idx, uint8_t tc); +-void flow_set_mpls_bos(struct flow *, int idx, uint8_t stack); +-void flow_set_mpls_lse(struct flow *, int idx, ovs_be32 lse); +- +-void flow_compose(struct dp_packet *, const struct flow *, +- const void *l7, size_t l7_len); +-void packet_expand(struct dp_packet *, const struct flow *, size_t size); +- +-bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, +- uint8_t *nw_frag, +- const struct ovs_16aligned_ip6_frag **frag_hdr); +-bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); +-uint16_t parse_tcp_flags(struct dp_packet *packet, ovs_be16 *dl_type_p, +- uint8_t *nw_frag_p, ovs_be16 *first_vlan_tci_p); +- +-static inline uint64_t +-flow_get_xreg(const struct flow *flow, int idx) +-{ +- return ((uint64_t) flow->regs[idx * 2] << 32) | flow->regs[idx * 2 + 1]; +-} +- +-static inline void +-flow_set_xreg(struct flow *flow, int idx, uint64_t value) +-{ +- flow->regs[idx * 2] = value >> 32; +- flow->regs[idx * 2 + 1] = value; +-} +- +-static inline ovs_u128 +-flow_get_xxreg(const struct flow *flow, int idx) +-{ +- ovs_u128 value; +- +- value.u64.hi = (uint64_t) flow->regs[idx * 4] << 32; +- value.u64.hi |= flow->regs[idx * 4 + 1]; +- value.u64.lo = (uint64_t) flow->regs[idx * 4 + 2] << 32; +- value.u64.lo |= flow->regs[idx * 4 + 3]; +- +- return value; +-} +- +-static inline void +-flow_set_xxreg(struct flow *flow, int idx, ovs_u128 value) +-{ +- flow->regs[idx * 4] = value.u64.hi >> 32; +- flow->regs[idx * 4 + 1] = value.u64.hi; +- flow->regs[idx * 4 + 2] = value.u64.lo >> 32; +- flow->regs[idx * 4 + 3] = value.u64.lo; +-} +- +-static inline int +-flow_compare_3way(const struct flow *a, const struct flow *b) +-{ +- return memcmp(a, b, sizeof *a); +-} +- +-static inline bool +-flow_equal(const struct flow *a, const struct flow *b) +-{ +- return !flow_compare_3way(a, b); +-} +- +-static inline size_t +-flow_hash(const struct flow *flow, uint32_t basis) +-{ +- return hash_bytes64((const uint64_t *)flow, sizeof *flow, basis); +-} +- +-static inline uint16_t +-ofp_to_u16(ofp_port_t ofp_port) +-{ +- return (OVS_FORCE uint16_t) ofp_port; +-} +- +-static inline uint32_t +-odp_to_u32(odp_port_t odp_port) +-{ +- return (OVS_FORCE uint32_t) odp_port; +-} +- +-static inline uint32_t +-ofp11_to_u32(ofp11_port_t ofp11_port) +-{ +- return (OVS_FORCE uint32_t) ofp11_port; +-} +- +-static inline ofp_port_t +-u16_to_ofp(uint16_t port) +-{ +- return OFP_PORT_C(port); +-} +- +-static inline odp_port_t +-u32_to_odp(uint32_t port) +-{ +- return ODP_PORT_C(port); +-} +- +-static inline ofp11_port_t +-u32_to_ofp11(uint32_t port) +-{ +- return OFP11_PORT_C(port); +-} +- +-static inline uint32_t +-hash_ofp_port(ofp_port_t ofp_port) +-{ +- return hash_int(ofp_to_u16(ofp_port), 0); +-} +- +-static inline uint32_t +-hash_odp_port(odp_port_t odp_port) +-{ +- return hash_int(odp_to_u32(odp_port), 0); +-} +- +-uint32_t flow_hash_5tuple(const struct flow *flow, uint32_t basis); +-uint32_t flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis); +-uint32_t flow_hash_symmetric_l2(const struct flow *flow, uint32_t basis); +-uint32_t flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis, +- bool inc_udp_ports ); +-uint32_t flow_hash_symmetric_l3(const struct flow *flow, uint32_t basis); +- +-/* Initialize a flow with random fields that matter for nx_hash_fields. */ +-void flow_random_hash_fields(struct flow *); +-void flow_mask_hash_fields(const struct flow *, struct flow_wildcards *, +- enum nx_hash_fields); +-uint32_t flow_hash_fields(const struct flow *, enum nx_hash_fields, +- uint16_t basis); +-const char *flow_hash_fields_to_str(enum nx_hash_fields); +-bool flow_hash_fields_valid(enum nx_hash_fields); +- +-uint32_t flow_hash_in_wildcards(const struct flow *, +- const struct flow_wildcards *, +- uint32_t basis); +- +-bool flow_equal_except(const struct flow *a, const struct flow *b, +- const struct flow_wildcards *); +- +-/* Bitmap for flow values. For each 1-bit the corresponding flow value is +- * explicitly specified, other values are zeroes. +- * +- * map_t must be wide enough to hold any member of struct flow. */ +-typedef unsigned long long map_t; +-#define MAP_T_BITS (sizeof(map_t) * CHAR_BIT) +-#define MAP_1 (map_t)1 +-#define MAP_MAX TYPE_MAXIMUM(map_t) +- +-#define MAP_IS_SET(MAP, IDX) ((MAP) & (MAP_1 << (IDX))) +- +-/* Iterate through the indices of all 1-bits in 'MAP'. */ +-#define MAP_FOR_EACH_INDEX(IDX, MAP) \ +- ULLONG_FOR_EACH_1(IDX, MAP) +- +-#define FLOWMAP_UNITS DIV_ROUND_UP(FLOW_U64S, MAP_T_BITS) +- +-struct flowmap { +- map_t bits[FLOWMAP_UNITS]; +-}; +- +-#define FLOWMAP_EMPTY_INITIALIZER { { 0 } } +- +-static inline void flowmap_init(struct flowmap *); +-static inline bool flowmap_equal(struct flowmap, struct flowmap); +-static inline bool flowmap_is_set(const struct flowmap *, size_t idx); +-static inline bool flowmap_are_set(const struct flowmap *, size_t idx, +- unsigned int n_bits); +-static inline void flowmap_set(struct flowmap *, size_t idx, +- unsigned int n_bits); +-static inline void flowmap_clear(struct flowmap *, size_t idx, +- unsigned int n_bits); +-static inline struct flowmap flowmap_or(struct flowmap, struct flowmap); +-static inline struct flowmap flowmap_and(struct flowmap, struct flowmap); +-static inline bool flowmap_is_empty(struct flowmap); +-static inline unsigned int flowmap_n_1bits(struct flowmap); +- +-#define FLOWMAP_HAS_FIELD(FM, FIELD) \ +- flowmap_are_set(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) +- +-#define FLOWMAP_SET(FM, FIELD) \ +- flowmap_set(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) +- +-#define FLOWMAP_SET__(FM, FIELD, SIZE) \ +- flowmap_set(FM, FLOW_U64_OFFSET(FIELD), \ +- DIV_ROUND_UP(SIZE, sizeof(uint64_t))) +- +-/* XXX: Only works for full 64-bit units. */ +-#define FLOWMAP_CLEAR(FM, FIELD) \ +- BUILD_ASSERT_DECL(FLOW_U64_OFFREM(FIELD) == 0); \ +- BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->FIELD) % sizeof(uint64_t) == 0); \ +- flowmap_clear(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) +- +-/* Iterate through all units in 'FMAP'. */ +-#define FLOWMAP_FOR_EACH_UNIT(UNIT) \ +- for ((UNIT) = 0; (UNIT) < FLOWMAP_UNITS; (UNIT)++) +- +-/* Iterate through all map units in 'FMAP'. */ +-#define FLOWMAP_FOR_EACH_MAP(MAP, FLOWMAP) \ +- for (size_t unit__ = 0; \ +- unit__ < FLOWMAP_UNITS && ((MAP) = (FLOWMAP).bits[unit__], true); \ +- unit__++) +- +-struct flowmap_aux; +-static inline bool flowmap_next_index(struct flowmap_aux *, size_t *idx); +- +-#define FLOWMAP_AUX_INITIALIZER(FLOWMAP) { .unit = 0, .map = (FLOWMAP) } +- +-/* Iterate through all struct flow u64 indices specified by 'MAP'. This is a +- * slower but easier version of the FLOWMAP_FOR_EACH_MAP() & +- * MAP_FOR_EACH_INDEX() combination. */ +-#define FLOWMAP_FOR_EACH_INDEX(IDX, MAP) \ +- for (struct flowmap_aux aux__ = FLOWMAP_AUX_INITIALIZER(MAP); \ +- flowmap_next_index(&aux__, &(IDX));) +- +-/* Flowmap inline implementations. */ +-static inline void +-flowmap_init(struct flowmap *fm) +-{ +- memset(fm, 0, sizeof *fm); +-} +- +-static inline bool +-flowmap_equal(struct flowmap a, struct flowmap b) +-{ +- return !memcmp(&a, &b, sizeof a); +-} +- +-static inline bool +-flowmap_is_set(const struct flowmap *fm, size_t idx) +-{ +- return (fm->bits[idx / MAP_T_BITS] & (MAP_1 << (idx % MAP_T_BITS))) != 0; +-} +- +-/* Returns 'true' if any of the 'n_bits' bits starting at 'idx' are set in +- * 'fm'. 'n_bits' can be at most MAP_T_BITS. */ +-static inline bool +-flowmap_are_set(const struct flowmap *fm, size_t idx, unsigned int n_bits) +-{ +- map_t n_bits_mask = (MAP_1 << n_bits) - 1; +- size_t unit = idx / MAP_T_BITS; +- +- idx %= MAP_T_BITS; +- +- if (fm->bits[unit] & (n_bits_mask << idx)) { +- return true; +- } +- /* The seemingly unnecessary bounds check on 'unit' is a workaround for a +- * false-positive array out of bounds error by GCC 4.9. */ +- if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { +- /* Check the remaining bits from the next unit. */ +- return fm->bits[unit + 1] & (n_bits_mask >> (MAP_T_BITS - idx)); +- } +- return false; +-} +- +-/* Set the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'. +- * 'n_bits' can be at most MAP_T_BITS. */ +-static inline void +-flowmap_set(struct flowmap *fm, size_t idx, unsigned int n_bits) +-{ +- map_t n_bits_mask = (MAP_1 << n_bits) - 1; +- size_t unit = idx / MAP_T_BITS; +- +- idx %= MAP_T_BITS; +- +- fm->bits[unit] |= n_bits_mask << idx; +- /* The seemingly unnecessary bounds check on 'unit' is a workaround for a +- * false-positive array out of bounds error by GCC 4.9. */ +- if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { +- /* 'MAP_T_BITS - idx' bits were set on 'unit', set the remaining +- * bits from the next unit. */ +- fm->bits[unit + 1] |= n_bits_mask >> (MAP_T_BITS - idx); +- } +-} +- +-/* Clears the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'. +- * 'n_bits' can be at most MAP_T_BITS. */ +-static inline void +-flowmap_clear(struct flowmap *fm, size_t idx, unsigned int n_bits) +-{ +- map_t n_bits_mask = (MAP_1 << n_bits) - 1; +- size_t unit = idx / MAP_T_BITS; +- +- idx %= MAP_T_BITS; +- +- fm->bits[unit] &= ~(n_bits_mask << idx); +- /* The seemingly unnecessary bounds check on 'unit' is a workaround for a +- * false-positive array out of bounds error by GCC 4.9. */ +- if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { +- /* 'MAP_T_BITS - idx' bits were cleared on 'unit', clear the +- * remaining bits from the next unit. */ +- fm->bits[unit + 1] &= ~(n_bits_mask >> (MAP_T_BITS - idx)); +- } +-} +- +-/* OR the bits in the flowmaps. */ +-static inline struct flowmap +-flowmap_or(struct flowmap a, struct flowmap b) +-{ +- struct flowmap map; +- size_t unit; +- +- FLOWMAP_FOR_EACH_UNIT (unit) { +- map.bits[unit] = a.bits[unit] | b.bits[unit]; +- } +- return map; +-} +- +-/* AND the bits in the flowmaps. */ +-static inline struct flowmap +-flowmap_and(struct flowmap a, struct flowmap b) +-{ +- struct flowmap map; +- size_t unit; +- +- FLOWMAP_FOR_EACH_UNIT (unit) { +- map.bits[unit] = a.bits[unit] & b.bits[unit]; +- } +- return map; +-} +- +-static inline bool +-flowmap_is_empty(struct flowmap fm) +-{ +- map_t map; +- +- FLOWMAP_FOR_EACH_MAP (map, fm) { +- if (map) { +- return false; +- } +- } +- return true; +-} +- +-static inline unsigned int +-flowmap_n_1bits(struct flowmap fm) +-{ +- unsigned int n_1bits = 0; +- size_t unit; +- +- FLOWMAP_FOR_EACH_UNIT (unit) { +- n_1bits += count_1bits(fm.bits[unit]); +- } +- return n_1bits; +-} +- +-struct flowmap_aux { +- size_t unit; +- struct flowmap map; +-}; +- +-static inline bool +-flowmap_next_index(struct flowmap_aux *aux, size_t *idx) +-{ +- for (;;) { +- map_t *map = &aux->map.bits[aux->unit]; +- if (*map) { +- *idx = aux->unit * MAP_T_BITS + raw_ctz(*map); +- *map = zero_rightmost_1bit(*map); +- return true; +- } +- if (++aux->unit >= FLOWMAP_UNITS) { +- return false; +- } +- } +-} +- +- +-/* Compressed flow. */ +- +-/* A sparse representation of a "struct flow". +- * +- * A "struct flow" is fairly large and tends to be mostly zeros. Sparse +- * representation has two advantages. First, it saves memory and, more +- * importantly, minimizes the number of accessed cache lines. Second, it saves +- * time when the goal is to iterate over only the nonzero parts of the struct. +- * +- * The map member hold one bit for each uint64_t in a "struct flow". Each +- * 0-bit indicates that the corresponding uint64_t is zero, each 1-bit that it +- * *may* be nonzero (see below how this applies to minimasks). +- * +- * The values indicated by 'map' always follow the miniflow in memory. The +- * user of the miniflow is responsible for always having enough storage after +- * the struct miniflow corresponding to the number of 1-bits in maps. +- * +- * Elements in values array are allowed to be zero. This is useful for "struct +- * minimatch", for which ensuring that the miniflow and minimask members have +- * same maps allows optimization. This allowance applies only to a miniflow +- * that is not a mask. That is, a minimask may NOT have zero elements in its +- * values. +- * +- * A miniflow is always dynamically allocated so that the maps are followed by +- * at least as many elements as there are 1-bits in maps. */ +-struct miniflow { +- struct flowmap map; +- /* Followed by: +- * uint64_t values[n]; +- * where 'n' is miniflow_n_values(miniflow). */ +-}; +-BUILD_ASSERT_DECL(sizeof(struct miniflow) % sizeof(uint64_t) == 0); +- +-#define MINIFLOW_VALUES_SIZE(COUNT) ((COUNT) * sizeof(uint64_t)) +- +-static inline uint64_t *miniflow_values(struct miniflow *mf) +-{ +- return (uint64_t *)(mf + 1); +-} +- +-static inline const uint64_t *miniflow_get_values(const struct miniflow *mf) +-{ +- return (const uint64_t *)(mf + 1); +-} +- +-struct pkt_metadata; +- +-/* The 'dst' must follow with buffer space for FLOW_U64S 64-bit units. +- * 'dst->map' is ignored on input and set on output to indicate which fields +- * were extracted. */ +-void miniflow_extract(struct dp_packet *packet, struct miniflow *dst); +-void miniflow_map_init(struct miniflow *, const struct flow *); +-void flow_wc_map(const struct flow *, struct flowmap *); +-size_t miniflow_alloc(struct miniflow *dsts[], size_t n, +- const struct miniflow *src); +-void miniflow_init(struct miniflow *, const struct flow *); +-void miniflow_clone(struct miniflow *, const struct miniflow *, +- size_t n_values); +-struct miniflow * miniflow_create(const struct flow *); +- +-void miniflow_expand(const struct miniflow *, struct flow *); +- +-static inline uint64_t flow_u64_value(const struct flow *flow, size_t index) +-{ +- return ((uint64_t *)flow)[index]; +-} +- +-static inline uint64_t *flow_u64_lvalue(struct flow *flow, size_t index) +-{ +- return &((uint64_t *)flow)[index]; +-} +- +-static inline size_t +-miniflow_n_values(const struct miniflow *flow) +-{ +- return flowmap_n_1bits(flow->map); +-} +- +-struct flow_for_each_in_maps_aux { +- const struct flow *flow; +- struct flowmap_aux map_aux; +-}; +- +-static inline bool +-flow_values_get_next_in_maps(struct flow_for_each_in_maps_aux *aux, +- uint64_t *value) +-{ +- size_t idx; +- +- if (flowmap_next_index(&aux->map_aux, &idx)) { +- *value = flow_u64_value(aux->flow, idx); +- return true; +- } +- return false; +-} +- +-/* Iterate through all flow u64 values specified by 'MAPS'. */ +-#define FLOW_FOR_EACH_IN_MAPS(VALUE, FLOW, MAPS) \ +- for (struct flow_for_each_in_maps_aux aux__ \ +- = { (FLOW), FLOWMAP_AUX_INITIALIZER(MAPS) }; \ +- flow_values_get_next_in_maps(&aux__, &(VALUE));) +- +-struct mf_for_each_in_map_aux { +- size_t unit; /* Current 64-bit unit of the flowmaps +- being processed. */ +- struct flowmap fmap; /* Remaining 1-bits corresponding to the +- 64-bit words in 'values' */ +- struct flowmap map; /* Remaining 1-bits corresponding to the +- 64-bit words of interest. */ +- const uint64_t *values; /* 64-bit words corresponding to the +- 1-bits in 'fmap'. */ +-}; +- +-/* Get the data from 'aux->values' corresponding to the next lowest 1-bit +- * in 'aux->map', given that 'aux->values' points to an array of 64-bit +- * words corresponding to the 1-bits in 'aux->fmap', starting from the +- * rightmost 1-bit. +- * +- * Returns 'true' if the traversal is incomplete, 'false' otherwise. +- * 'aux' is prepared for the next iteration after each call. +- * +- * This is used to traverse through, for example, the values in a miniflow +- * representation of a flow key selected by non-zero 64-bit words in a +- * corresponding subtable mask. */ +-static inline bool +-mf_get_next_in_map(struct mf_for_each_in_map_aux *aux, +- uint64_t *value) +-{ +- map_t *map, *fmap; +- map_t rm1bit; +- +- /* Skip empty map units. */ +- while (OVS_UNLIKELY(!*(map = &aux->map.bits[aux->unit]))) { +- /* Skip remaining data in the current unit before advancing +- * to the next. */ +- aux->values += count_1bits(aux->fmap.bits[aux->unit]); +- if (++aux->unit == FLOWMAP_UNITS) { +- return false; +- } +- } +- +- rm1bit = rightmost_1bit(*map); +- *map -= rm1bit; +- fmap = &aux->fmap.bits[aux->unit]; +- +- /* If the rightmost 1-bit found from the current unit in 'aux->map' +- * ('rm1bit') is also present in 'aux->fmap', store the corresponding +- * value from 'aux->values' to '*value', otherwise store 0. */ +- if (OVS_LIKELY(*fmap & rm1bit)) { +- /* Skip all 64-bit words in 'values' preceding the one corresponding +- * to 'rm1bit'. */ +- map_t trash = *fmap & (rm1bit - 1); +- +- /* Avoid resetting 'fmap' and calling count_1bits() when trash is +- * zero. */ +- if (trash) { +- *fmap -= trash; +- aux->values += count_1bits(trash); +- } +- +- *value = *aux->values; +- } else { +- *value = 0; +- } +- return true; +-} +- +-/* Iterate through miniflow u64 values specified by 'FLOWMAP'. */ +-#define MINIFLOW_FOR_EACH_IN_FLOWMAP(VALUE, FLOW, FLOWMAP) \ +- for (struct mf_for_each_in_map_aux aux__ = \ +- { 0, (FLOW)->map, (FLOWMAP), miniflow_get_values(FLOW) }; \ +- mf_get_next_in_map(&aux__, &(VALUE));) +- +-/* This can be used when it is known that 'idx' is set in 'map'. */ +-static inline const uint64_t * +-miniflow_values_get__(const uint64_t *values, map_t map, size_t idx) +-{ +- return values + count_1bits(map & ((MAP_1 << idx) - 1)); +-} +- +-/* This can be used when it is known that 'u64_idx' is set in +- * the map of 'mf'. */ +-static inline const uint64_t * +-miniflow_get__(const struct miniflow *mf, size_t idx) +-{ +- const uint64_t *values = miniflow_get_values(mf); +- const map_t *map = mf->map.bits; +- +- while (idx >= MAP_T_BITS) { +- idx -= MAP_T_BITS; +- values += count_1bits(*map++); +- } +- return miniflow_values_get__(values, *map, idx); +-} +- +-#define MINIFLOW_IN_MAP(MF, IDX) flowmap_is_set(&(MF)->map, IDX) +- +-/* Get the value of the struct flow 'FIELD' as up to 8 byte wide integer type +- * 'TYPE' from miniflow 'MF'. */ +-#define MINIFLOW_GET_TYPE(MF, TYPE, FIELD) \ +- (BUILD_ASSERT(sizeof(TYPE) == sizeof(((struct flow *)0)->FIELD)), \ +- BUILD_ASSERT_GCCONLY(__builtin_types_compatible_p(TYPE, typeof(((struct flow *)0)->FIELD))), \ +- MINIFLOW_GET_TYPE__(MF, TYPE, FIELD)) +- +-/* Like MINIFLOW_GET_TYPE, but without checking that TYPE is the correct width +- * for FIELD. (This is useful for deliberately reading adjacent fields in one +- * go.) */ +-#define MINIFLOW_GET_TYPE__(MF, TYPE, FIELD) \ +- (MINIFLOW_IN_MAP(MF, FLOW_U64_OFFSET(FIELD)) \ +- ? ((OVS_FORCE const TYPE *)miniflow_get__(MF, FLOW_U64_OFFSET(FIELD))) \ +- [FLOW_U64_OFFREM(FIELD) / sizeof(TYPE)] \ +- : 0) +- +-#define MINIFLOW_GET_U128(FLOW, FIELD) \ +- (ovs_u128) { .u64 = { \ +- (MINIFLOW_IN_MAP(FLOW, FLOW_U64_OFFSET(FIELD)) ? \ +- *miniflow_get__(FLOW, FLOW_U64_OFFSET(FIELD)) : 0), \ +- (MINIFLOW_IN_MAP(FLOW, FLOW_U64_OFFSET(FIELD) + 1) ? \ +- *miniflow_get__(FLOW, FLOW_U64_OFFSET(FIELD) + 1) : 0) } } +- +-#define MINIFLOW_GET_U8(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, uint8_t, FIELD) +-#define MINIFLOW_GET_U16(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, uint16_t, FIELD) +-#define MINIFLOW_GET_BE16(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, ovs_be16, FIELD) +-#define MINIFLOW_GET_U32(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, uint32_t, FIELD) +-#define MINIFLOW_GET_BE32(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, ovs_be32, FIELD) +-#define MINIFLOW_GET_U64(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, uint64_t, FIELD) +-#define MINIFLOW_GET_BE64(FLOW, FIELD) \ +- MINIFLOW_GET_TYPE(FLOW, ovs_be64, FIELD) +- +-static inline uint64_t miniflow_get(const struct miniflow *, +- unsigned int u64_ofs); +-static inline uint32_t miniflow_get_u32(const struct miniflow *, +- unsigned int u32_ofs); +-static inline ovs_be32 miniflow_get_be32(const struct miniflow *, +- unsigned int be32_ofs); +-static inline uint16_t miniflow_get_vid(const struct miniflow *, size_t); +-static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *); +-static inline ovs_be64 miniflow_get_metadata(const struct miniflow *); +-static inline uint64_t miniflow_get_tun_metadata_present_map( +- const struct miniflow *); +-static inline uint32_t miniflow_get_recirc_id(const struct miniflow *); +-static inline uint32_t miniflow_get_dp_hash(const struct miniflow *); +-static inline ovs_be32 miniflow_get_ports(const struct miniflow *); +- +-bool miniflow_equal(const struct miniflow *a, const struct miniflow *b); +-bool miniflow_equal_in_minimask(const struct miniflow *a, +- const struct miniflow *b, +- const struct minimask *); +-bool miniflow_equal_flow_in_minimask(const struct miniflow *a, +- const struct flow *b, +- const struct minimask *); +-uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis); +- +- +-/* Compressed flow wildcards. */ +- +-/* A sparse representation of a "struct flow_wildcards". +- * +- * See the large comment on struct miniflow for details. +- * +- * Note: While miniflow can have zero data for a 1-bit in the map, +- * a minimask may not! We rely on this in the implementation. */ +-struct minimask { +- struct miniflow masks; +-}; +- +-void minimask_init(struct minimask *, const struct flow_wildcards *); +-struct minimask * minimask_create(const struct flow_wildcards *); +-void minimask_combine(struct minimask *dst, +- const struct minimask *a, const struct minimask *b, +- uint64_t storage[FLOW_U64S]); +- +-void minimask_expand(const struct minimask *, struct flow_wildcards *); +- +-static inline uint32_t minimask_get_u32(const struct minimask *, +- unsigned int u32_ofs); +-static inline ovs_be32 minimask_get_be32(const struct minimask *, +- unsigned int be32_ofs); +-static inline uint16_t minimask_get_vid_mask(const struct minimask *, size_t); +-static inline ovs_be64 minimask_get_metadata_mask(const struct minimask *); +- +-bool minimask_equal(const struct minimask *a, const struct minimask *b); +-bool minimask_has_extra(const struct minimask *, const struct minimask *); +- +- +-/* Returns true if 'mask' matches every packet, false if 'mask' fixes any bits +- * or fields. */ +-static inline bool +-minimask_is_catchall(const struct minimask *mask) +-{ +- /* For every 1-bit in mask's map, the corresponding value is non-zero, +- * so the only way the mask can not fix any bits or fields is for the +- * map the be zero. */ +- return flowmap_is_empty(mask->masks.map); +-} +- +-/* Returns the uint64_t that would be at byte offset '8 * u64_ofs' if 'flow' +- * were expanded into a "struct flow". */ +-static inline uint64_t miniflow_get(const struct miniflow *flow, +- unsigned int u64_ofs) +-{ +- return MINIFLOW_IN_MAP(flow, u64_ofs) ? *miniflow_get__(flow, u64_ofs) : 0; +-} +- +-static inline uint32_t miniflow_get_u32(const struct miniflow *flow, +- unsigned int u32_ofs) +-{ +- uint64_t value = miniflow_get(flow, u32_ofs / 2); +- +-#if WORDS_BIGENDIAN +- return (u32_ofs & 1) ? value : value >> 32; +-#else +- return (u32_ofs & 1) ? value >> 32 : value; +-#endif +-} +- +-static inline ovs_be32 miniflow_get_be32(const struct miniflow *flow, +- unsigned int be32_ofs) +-{ +- return (OVS_FORCE ovs_be32)miniflow_get_u32(flow, be32_ofs); +-} +- +-/* Returns the VID within the vlan_tci member of the "struct flow" represented +- * by 'flow'. */ +-static inline uint16_t +-miniflow_get_vid(const struct miniflow *flow, size_t n) +-{ +- if (n < FLOW_MAX_VLAN_HEADERS) { +- union flow_vlan_hdr hdr = { +- .qtag = MINIFLOW_GET_BE32(flow, vlans[n].qtag) +- }; +- return vlan_tci_to_vid(hdr.tci); +- } +- return 0; +-} +- +-/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'mask' +- * were expanded into a "struct flow_wildcards". */ +-static inline uint32_t +-minimask_get_u32(const struct minimask *mask, unsigned int u32_ofs) +-{ +- return miniflow_get_u32(&mask->masks, u32_ofs); +-} +- +-static inline ovs_be32 +-minimask_get_be32(const struct minimask *mask, unsigned int be32_ofs) +-{ +- return (OVS_FORCE ovs_be32)minimask_get_u32(mask, be32_ofs); +-} +- +-/* Returns the VID mask within the vlan_tci member of the "struct +- * flow_wildcards" represented by 'mask'. */ +-static inline uint16_t +-minimask_get_vid_mask(const struct minimask *mask, size_t n) +-{ +- return miniflow_get_vid(&mask->masks, n); +-} +- +-/* Returns the value of the "tcp_flags" field in 'flow'. */ +-static inline uint16_t +-miniflow_get_tcp_flags(const struct miniflow *flow) +-{ +- return ntohs(MINIFLOW_GET_BE16(flow, tcp_flags)); +-} +- +-/* Returns the value of the OpenFlow 1.1+ "metadata" field in 'flow'. */ +-static inline ovs_be64 +-miniflow_get_metadata(const struct miniflow *flow) +-{ +- return MINIFLOW_GET_BE64(flow, metadata); +-} +- +-/* Returns the bitmap that indicates which tunnel metadata fields are present +- * in 'flow'. */ +-static inline uint64_t +-miniflow_get_tun_metadata_present_map(const struct miniflow *flow) +-{ +- return MINIFLOW_GET_U64(flow, tunnel.metadata.present.map); +-} +- +-/* Returns the recirc_id in 'flow.' */ +-static inline uint32_t +-miniflow_get_recirc_id(const struct miniflow *flow) +-{ +- return MINIFLOW_GET_U32(flow, recirc_id); +-} +- +-/* Returns the dp_hash in 'flow.' */ +-static inline uint32_t +-miniflow_get_dp_hash(const struct miniflow *flow) +-{ +- return MINIFLOW_GET_U32(flow, dp_hash); +-} +- +-/* Returns the 'tp_src' and 'tp_dst' fields together as one piece of data. */ +-static inline ovs_be32 +-miniflow_get_ports(const struct miniflow *flow) +-{ +- return MINIFLOW_GET_TYPE__(flow, ovs_be32, tp_src); +-} +- +-/* Returns the mask for the OpenFlow 1.1+ "metadata" field in 'mask'. +- * +- * The return value is all-1-bits if 'mask' matches on the whole value of the +- * metadata field, all-0-bits if 'mask' entirely wildcards the metadata field, +- * or some other value if the metadata field is partially matched, partially +- * wildcarded. */ +-static inline ovs_be64 +-minimask_get_metadata_mask(const struct minimask *mask) +-{ +- return MINIFLOW_GET_BE64(&mask->masks, metadata); +-} +- +-/* Perform a bitwise OR of miniflow 'src' flow data specified in 'subset' with +- * the equivalent fields in 'dst', storing the result in 'dst'. 'subset' must +- * be a subset of 'src's map. */ +-static inline void +-flow_union_with_miniflow_subset(struct flow *dst, const struct miniflow *src, +- struct flowmap subset) +-{ +- uint64_t *dst_u64 = (uint64_t *) dst; +- const uint64_t *p = miniflow_get_values(src); +- map_t map; +- +- FLOWMAP_FOR_EACH_MAP (map, subset) { +- size_t idx; +- +- MAP_FOR_EACH_INDEX(idx, map) { +- dst_u64[idx] |= *p++; +- } +- dst_u64 += MAP_T_BITS; +- } +-} +- +-/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent +- * fields in 'dst', storing the result in 'dst'. */ +-static inline void +-flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) +-{ +- flow_union_with_miniflow_subset(dst, src, src->map); +-} +- +-static inline bool is_ct_valid(const struct flow *flow, +- const struct flow_wildcards *mask, +- struct flow_wildcards *wc) +-{ +- /* Matches are checked with 'mask' and without 'wc'. */ +- if (mask && !wc) { +- /* Must match at least one of the bits that implies a valid +- * conntrack entry, or an explicit not-invalid. */ +- return flow->ct_state & (CS_NEW | CS_ESTABLISHED | CS_RELATED +- | CS_REPLY_DIR | CS_SRC_NAT | CS_DST_NAT) +- || (flow->ct_state & CS_TRACKED +- && mask->masks.ct_state & CS_INVALID +- && !(flow->ct_state & CS_INVALID)); +- } +- /* Else we are checking a fully extracted flow, where valid CT state always +- * has either 'new', 'established', or 'reply_dir' bit set. */ +-#define CS_VALID_MASK (CS_NEW | CS_ESTABLISHED | CS_REPLY_DIR) +- if (wc) { +- wc->masks.ct_state |= CS_VALID_MASK; +- } +- return flow->ct_state & CS_VALID_MASK; +-} +- +-static inline void +-pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow) +-{ +- /* Update this function whenever struct flow changes. */ +- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42); +- +- md->recirc_id = flow->recirc_id; +- md->dp_hash = flow->dp_hash; +- flow_tnl_copy__(&md->tunnel, &flow->tunnel); +- md->skb_priority = flow->skb_priority; +- md->pkt_mark = flow->pkt_mark; +- md->in_port = flow->in_port; +- md->ct_state = flow->ct_state; +- md->ct_zone = flow->ct_zone; +- md->ct_mark = flow->ct_mark; +- md->ct_label = flow->ct_label; +- +- md->ct_orig_tuple_ipv6 = false; +- if (flow->dl_type && is_ct_valid(flow, NULL, NULL)) { +- if (flow->dl_type == htons(ETH_TYPE_IP)) { +- md->ct_orig_tuple.ipv4 = (struct ovs_key_ct_tuple_ipv4) { +- flow->ct_nw_src, +- flow->ct_nw_dst, +- flow->ct_tp_src, +- flow->ct_tp_dst, +- flow->ct_nw_proto, +- }; +- } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { +- md->ct_orig_tuple_ipv6 = true; +- md->ct_orig_tuple.ipv6 = (struct ovs_key_ct_tuple_ipv6) { +- flow->ct_ipv6_src, +- flow->ct_ipv6_dst, +- flow->ct_tp_src, +- flow->ct_tp_dst, +- flow->ct_nw_proto, +- }; +- } else { +- /* Reset ct_orig_tuple for other types. */ +- memset(&md->ct_orig_tuple, 0, sizeof md->ct_orig_tuple); +- } +- } else { +- memset(&md->ct_orig_tuple, 0, sizeof md->ct_orig_tuple); +- } +-} +- +-/* Often, during translation we need to read a value from a flow('FLOW') and +- * unwildcard the corresponding bits in the wildcards('WC'). This macro makes +- * it easier to do that. */ +- +-#define FLOW_WC_GET_AND_MASK_WC(FLOW, WC, FIELD) \ +- (((WC) ? WC_MASK_FIELD(WC, FIELD) : NULL), ((FLOW)->FIELD)) +- +-static inline bool is_ethernet(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (wc) { +- WC_MASK_FIELD(wc, packet_type); +- } +- return flow->packet_type == htonl(PT_ETH); +-} +- +-static inline ovs_be16 get_dl_type(const struct flow *flow) +-{ +- if (flow->packet_type == htonl(PT_ETH)) { +- return flow->dl_type; +- } else if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) { +- return pt_ns_type_be(flow->packet_type); +- } else { +- return htons(FLOW_DL_TYPE_NONE); +- } +-} +- +-static inline bool is_vlan(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (!is_ethernet(flow, wc)) { +- return false; +- } +- if (wc) { +- WC_MASK_FIELD_MASK(wc, vlans[0].tci, htons(VLAN_CFI)); +- } +- return (flow->vlans[0].tci & htons(VLAN_CFI)) != 0; +-} +- +-static inline bool is_ip_any(const struct flow *flow) +-{ +- return dl_type_is_ip_any(get_dl_type(flow)); +-} +- +-static inline bool is_ip_proto(const struct flow *flow, uint8_t ip_proto, +- struct flow_wildcards *wc) +-{ +- if (is_ip_any(flow)) { +- if (wc) { +- WC_MASK_FIELD(wc, nw_proto); +- } +- return flow->nw_proto == ip_proto; +- } +- return false; +-} +- +-static inline bool is_tcp(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- return is_ip_proto(flow, IPPROTO_TCP, wc); +-} +- +-static inline bool is_udp(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- return is_ip_proto(flow, IPPROTO_UDP, wc); +-} +- +-static inline bool is_sctp(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- return is_ip_proto(flow, IPPROTO_SCTP, wc); +-} +- +-static inline bool is_icmpv4(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { +- if (wc) { +- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); +- } +- return flow->nw_proto == IPPROTO_ICMP; +- } +- return false; +-} +- +-static inline bool is_icmpv6(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (get_dl_type(flow) == htons(ETH_TYPE_IPV6)) { +- if (wc) { +- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); +- } +- return flow->nw_proto == IPPROTO_ICMPV6; +- } +- return false; +-} +- +-static inline bool is_nd(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (is_icmpv6(flow, wc)) { +- if (wc) { +- memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); +- } +- if (flow->tp_dst != htons(0)) { +- return false; +- } +- +- if (wc) { +- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); +- } +- return (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) || +- flow->tp_src == htons(ND_NEIGHBOR_ADVERT)); +- } +- return false; +-} +- +-static inline bool is_arp(const struct flow *flow) +-{ +- return (flow->dl_type == htons(ETH_TYPE_ARP)); +-} +- +-static inline bool is_garp(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (is_arp(flow)) { +- return (FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_src) == +- FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_dst)); +- } +- +- return false; +-} +- +-static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc) +-{ +- if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { +- if (wc) { +- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); +- } +- return flow->nw_proto == IPPROTO_IGMP; +- } +- return false; +-} +- +-static inline bool is_mld(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (is_icmpv6(flow, wc)) { +- if (wc) { +- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); +- } +- return (flow->tp_src == htons(MLD_QUERY) +- || flow->tp_src == htons(MLD_REPORT) +- || flow->tp_src == htons(MLD_DONE) +- || flow->tp_src == htons(MLD2_REPORT)); +- } +- return false; +-} +- +-static inline bool is_mld_query(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- if (is_icmpv6(flow, wc)) { +- if (wc) { +- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); +- } +- return flow->tp_src == htons(MLD_QUERY); +- } +- return false; +-} +- +-static inline bool is_mld_report(const struct flow *flow, +- struct flow_wildcards *wc) +-{ +- return is_mld(flow, wc) && !is_mld_query(flow, wc); +-} +- +-static inline bool is_stp(const struct flow *flow) +-{ +- return (flow->dl_type == htons(FLOW_DL_TYPE_NONE) +- && eth_addr_equals(flow->dl_dst, eth_addr_stp)); +-} +- +-/* Returns true if flow->tp_dst equals 'port'. If 'wc' is nonnull, sets +- * appropriate bits in wc->masks.tp_dst to account for the test. +- * +- * The caller must already have ensured that 'flow' is a protocol for which +- * tp_dst is relevant. */ +-static inline bool tp_dst_equals(const struct flow *flow, uint16_t port, +- struct flow_wildcards *wc) +-{ +- uint16_t diff = port ^ ntohs(flow->tp_dst); +- if (wc) { +- if (diff) { +- /* Set mask for the most significant mismatching bit. */ +- int ofs = raw_clz64((uint64_t) diff << 48); /* range [0,15] */ +- wc->masks.tp_dst |= htons(0x8000 >> ofs); +- } else { +- /* Must match all bits. */ +- wc->masks.tp_dst = OVS_BE16_MAX; +- } +- } +- return !diff; +-} +- +-#endif /* flow.h */ +Index: openvswitch-2.17.2/include/internal/flow.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/flow.h +@@ -0,0 +1,1215 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#ifndef FLOW_H ++#define FLOW_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "internal/bitmap.h" ++#include "internal/byte-order.h" ++#include "openvswitch/compiler.h" ++#include "openflow/nicira-ext.h" ++#include "openflow/openflow.h" ++#include "openvswitch/flow.h" +#include "internal/packets.h" +#include "internal/hash.h" +#include "internal/util.h" - - struct dpif_flow_stats; - struct dpif_flow_attrs; -diff --git a/lib/hash-aarch64.h b/include/internal/hash-aarch64.h -similarity index 100% -rename from lib/hash-aarch64.h -rename to include/internal/hash-aarch64.h -diff --git a/lib/hash.h b/include/internal/hash.h -similarity index 99% -rename from lib/hash.h -rename to include/internal/hash.h -index 60a39a40b..519c4ae44 100644 ---- a/lib/hash.h -+++ b/include/internal/hash.h -@@ -20,7 +20,7 @@ - #include - #include - #include ++ ++struct dpif_flow_stats; ++struct dpif_flow_attrs; ++struct ds; ++struct flow_wildcards; ++struct minimask; ++struct dp_packet; ++struct ofputil_port_map; ++struct pkt_metadata; ++struct match; ++ ++/* Some flow fields are mutually exclusive or only appear within the flow ++ * pipeline. IPv6 headers are bigger than IPv4 and MPLS, and IPv6 ND packets ++ * are bigger than TCP,UDP and IGMP packets. */ ++#define FLOW_MAX_PACKET_U64S (FLOW_U64S \ ++ /* Unused in datapath */ - FLOW_U64_SIZE(regs) \ ++ - FLOW_U64_SIZE(metadata) \ ++ /* L2.5/3 */ - FLOW_U64_SIZE(nw_src) /* incl. nw_dst */ \ ++ - FLOW_U64_SIZE(mpls_lse) \ ++ /* L4 */ - FLOW_U64_SIZE(tp_src) \ ++ ) ++ ++extern const uint8_t flow_segment_u64s[]; ++ ++/* Configured maximum VLAN headers. */ ++extern int flow_vlan_limit; ++ ++#define FLOW_U64_OFFSET(FIELD) \ ++ (offsetof(struct flow, FIELD) / sizeof(uint64_t)) ++#define FLOW_U64_OFFREM(FIELD) \ ++ (offsetof(struct flow, FIELD) % sizeof(uint64_t)) ++ ++/* Number of 64-bit units spanned by a 'FIELD'. */ ++#define FLOW_U64_SIZE(FIELD) \ ++ DIV_ROUND_UP(FLOW_U64_OFFREM(FIELD) + MEMBER_SIZEOF(struct flow, FIELD), \ ++ sizeof(uint64_t)) ++ ++void flow_extract(struct dp_packet *, struct flow *); ++ ++void flow_zero_wildcards(struct flow *, const struct flow_wildcards *); ++void flow_unwildcard_tp_ports(const struct flow *, struct flow_wildcards *); ++void flow_get_metadata(const struct flow *, struct match *flow_metadata); ++struct netdev *flow_get_tunnel_netdev(struct flow_tnl *tunnel); ++ ++const char *ct_state_to_string(uint32_t state); ++uint32_t ct_state_from_string(const char *); ++bool parse_ct_state(const char *state_str, uint32_t default_state, ++ uint32_t *ct_state, struct ds *); ++bool validate_ct_state(uint32_t state, struct ds *); ++void flow_clear_conntrack(struct flow *); ++ ++char *flow_to_string(const struct flow *, const struct ofputil_port_map *); ++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, uint32_t max_mask); ++void format_packet_type_masked(struct ds *, ovs_be32 value, ovs_be32 mask); ++int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t), ++ char end, const char *field_name, char **res_string, ++ uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask); ++ ++void flow_format(struct ds *, const struct flow *, ++ const struct ofputil_port_map *); ++void flow_print(FILE *, const struct flow *, const struct ofputil_port_map *); ++static inline int flow_compare_3way(const struct flow *, const struct flow *); ++static inline bool flow_equal(const struct flow *, const struct flow *); ++static inline size_t flow_hash(const struct flow *, uint32_t basis); ++ ++void flow_set_dl_vlan(struct flow *, ovs_be16 vid, int id); ++void flow_fix_vlan_tpid(struct flow *); ++void flow_set_vlan_vid(struct flow *, ovs_be16 vid); ++void flow_set_vlan_pcp(struct flow *, uint8_t pcp, int id); ++ ++void flow_limit_vlans(int vlan_limit); ++int flow_count_vlan_headers(const struct flow *); ++void flow_skip_common_vlan_headers(const struct flow *a, int *p_an, ++ const struct flow *b, int *p_bn); ++void flow_pop_vlan(struct flow*, struct flow_wildcards*); ++void flow_push_vlan_uninit(struct flow*, struct flow_wildcards*); ++ ++int flow_count_mpls_labels(const struct flow *, struct flow_wildcards *); ++int flow_count_common_mpls_labels(const struct flow *a, int an, ++ const struct flow *b, int bn, ++ struct flow_wildcards *wc); ++void flow_push_mpls(struct flow *, int n, ovs_be16 mpls_eth_type, ++ struct flow_wildcards *, bool clear_flow_L3); ++bool flow_pop_mpls(struct flow *, int n, ovs_be16 eth_type, ++ struct flow_wildcards *); ++void flow_set_mpls_label(struct flow *, int idx, ovs_be32 label); ++void flow_set_mpls_ttl(struct flow *, int idx, uint8_t ttl); ++void flow_set_mpls_tc(struct flow *, int idx, uint8_t tc); ++void flow_set_mpls_bos(struct flow *, int idx, uint8_t stack); ++void flow_set_mpls_lse(struct flow *, int idx, ovs_be32 lse); ++ ++void flow_compose(struct dp_packet *, const struct flow *, ++ const void *l7, size_t l7_len); ++void packet_expand(struct dp_packet *, const struct flow *, size_t size); ++ ++bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, ++ uint8_t *nw_frag, ++ const struct ovs_16aligned_ip6_frag **frag_hdr); ++bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); ++uint16_t parse_tcp_flags(struct dp_packet *packet, ovs_be16 *dl_type_p, ++ uint8_t *nw_frag_p, ovs_be16 *first_vlan_tci_p); ++ ++static inline uint64_t ++flow_get_xreg(const struct flow *flow, int idx) ++{ ++ return ((uint64_t) flow->regs[idx * 2] << 32) | flow->regs[idx * 2 + 1]; ++} ++ ++static inline void ++flow_set_xreg(struct flow *flow, int idx, uint64_t value) ++{ ++ flow->regs[idx * 2] = value >> 32; ++ flow->regs[idx * 2 + 1] = value; ++} ++ ++static inline ovs_u128 ++flow_get_xxreg(const struct flow *flow, int idx) ++{ ++ ovs_u128 value; ++ ++ value.u64.hi = (uint64_t) flow->regs[idx * 4] << 32; ++ value.u64.hi |= flow->regs[idx * 4 + 1]; ++ value.u64.lo = (uint64_t) flow->regs[idx * 4 + 2] << 32; ++ value.u64.lo |= flow->regs[idx * 4 + 3]; ++ ++ return value; ++} ++ ++static inline void ++flow_set_xxreg(struct flow *flow, int idx, ovs_u128 value) ++{ ++ flow->regs[idx * 4] = value.u64.hi >> 32; ++ flow->regs[idx * 4 + 1] = value.u64.hi; ++ flow->regs[idx * 4 + 2] = value.u64.lo >> 32; ++ flow->regs[idx * 4 + 3] = value.u64.lo; ++} ++ ++static inline int ++flow_compare_3way(const struct flow *a, const struct flow *b) ++{ ++ return memcmp(a, b, sizeof *a); ++} ++ ++static inline bool ++flow_equal(const struct flow *a, const struct flow *b) ++{ ++ return !flow_compare_3way(a, b); ++} ++ ++static inline size_t ++flow_hash(const struct flow *flow, uint32_t basis) ++{ ++ return hash_bytes64((const uint64_t *)flow, sizeof *flow, basis); ++} ++ ++static inline uint16_t ++ofp_to_u16(ofp_port_t ofp_port) ++{ ++ return (OVS_FORCE uint16_t) ofp_port; ++} ++ ++static inline uint32_t ++odp_to_u32(odp_port_t odp_port) ++{ ++ return (OVS_FORCE uint32_t) odp_port; ++} ++ ++static inline uint32_t ++ofp11_to_u32(ofp11_port_t ofp11_port) ++{ ++ return (OVS_FORCE uint32_t) ofp11_port; ++} ++ ++static inline ofp_port_t ++u16_to_ofp(uint16_t port) ++{ ++ return OFP_PORT_C(port); ++} ++ ++static inline odp_port_t ++u32_to_odp(uint32_t port) ++{ ++ return ODP_PORT_C(port); ++} ++ ++static inline ofp11_port_t ++u32_to_ofp11(uint32_t port) ++{ ++ return OFP11_PORT_C(port); ++} ++ ++static inline uint32_t ++hash_ofp_port(ofp_port_t ofp_port) ++{ ++ return hash_int(ofp_to_u16(ofp_port), 0); ++} ++ ++static inline uint32_t ++hash_odp_port(odp_port_t odp_port) ++{ ++ return hash_int(odp_to_u32(odp_port), 0); ++} ++ ++uint32_t flow_hash_5tuple(const struct flow *flow, uint32_t basis); ++uint32_t flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis); ++uint32_t flow_hash_symmetric_l2(const struct flow *flow, uint32_t basis); ++uint32_t flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis, ++ bool inc_udp_ports ); ++uint32_t flow_hash_symmetric_l3(const struct flow *flow, uint32_t basis); ++ ++/* Initialize a flow with random fields that matter for nx_hash_fields. */ ++void flow_random_hash_fields(struct flow *); ++void flow_mask_hash_fields(const struct flow *, struct flow_wildcards *, ++ enum nx_hash_fields); ++uint32_t flow_hash_fields(const struct flow *, enum nx_hash_fields, ++ uint16_t basis); ++const char *flow_hash_fields_to_str(enum nx_hash_fields); ++bool flow_hash_fields_valid(enum nx_hash_fields); ++ ++uint32_t flow_hash_in_wildcards(const struct flow *, ++ const struct flow_wildcards *, ++ uint32_t basis); ++ ++bool flow_equal_except(const struct flow *a, const struct flow *b, ++ const struct flow_wildcards *); ++ ++/* Bitmap for flow values. For each 1-bit the corresponding flow value is ++ * explicitly specified, other values are zeroes. ++ * ++ * map_t must be wide enough to hold any member of struct flow. */ ++typedef unsigned long long map_t; ++#define MAP_T_BITS (sizeof(map_t) * CHAR_BIT) ++#define MAP_1 (map_t)1 ++#define MAP_MAX TYPE_MAXIMUM(map_t) ++ ++#define MAP_IS_SET(MAP, IDX) ((MAP) & (MAP_1 << (IDX))) ++ ++/* Iterate through the indices of all 1-bits in 'MAP'. */ ++#define MAP_FOR_EACH_INDEX(IDX, MAP) \ ++ ULLONG_FOR_EACH_1(IDX, MAP) ++ ++#define FLOWMAP_UNITS DIV_ROUND_UP(FLOW_U64S, MAP_T_BITS) ++ ++struct flowmap { ++ map_t bits[FLOWMAP_UNITS]; ++}; ++ ++#define FLOWMAP_EMPTY_INITIALIZER { { 0 } } ++ ++static inline void flowmap_init(struct flowmap *); ++static inline bool flowmap_equal(struct flowmap, struct flowmap); ++static inline bool flowmap_is_set(const struct flowmap *, size_t idx); ++static inline bool flowmap_are_set(const struct flowmap *, size_t idx, ++ unsigned int n_bits); ++static inline void flowmap_set(struct flowmap *, size_t idx, ++ unsigned int n_bits); ++static inline void flowmap_clear(struct flowmap *, size_t idx, ++ unsigned int n_bits); ++static inline struct flowmap flowmap_or(struct flowmap, struct flowmap); ++static inline struct flowmap flowmap_and(struct flowmap, struct flowmap); ++static inline bool flowmap_is_empty(struct flowmap); ++static inline unsigned int flowmap_n_1bits(struct flowmap); ++ ++#define FLOWMAP_HAS_FIELD(FM, FIELD) \ ++ flowmap_are_set(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) ++ ++#define FLOWMAP_SET(FM, FIELD) \ ++ flowmap_set(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) ++ ++#define FLOWMAP_SET__(FM, FIELD, SIZE) \ ++ flowmap_set(FM, FLOW_U64_OFFSET(FIELD), \ ++ DIV_ROUND_UP(SIZE, sizeof(uint64_t))) ++ ++/* XXX: Only works for full 64-bit units. */ ++#define FLOWMAP_CLEAR(FM, FIELD) \ ++ BUILD_ASSERT_DECL(FLOW_U64_OFFREM(FIELD) == 0); \ ++ BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->FIELD) % sizeof(uint64_t) == 0); \ ++ flowmap_clear(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD)) ++ ++/* Iterate through all units in 'FMAP'. */ ++#define FLOWMAP_FOR_EACH_UNIT(UNIT) \ ++ for ((UNIT) = 0; (UNIT) < FLOWMAP_UNITS; (UNIT)++) ++ ++/* Iterate through all map units in 'FMAP'. */ ++#define FLOWMAP_FOR_EACH_MAP(MAP, FLOWMAP) \ ++ for (size_t unit__ = 0; \ ++ unit__ < FLOWMAP_UNITS && ((MAP) = (FLOWMAP).bits[unit__], true); \ ++ unit__++) ++ ++struct flowmap_aux; ++static inline bool flowmap_next_index(struct flowmap_aux *, size_t *idx); ++ ++#define FLOWMAP_AUX_INITIALIZER(FLOWMAP) { .unit = 0, .map = (FLOWMAP) } ++ ++/* Iterate through all struct flow u64 indices specified by 'MAP'. This is a ++ * slower but easier version of the FLOWMAP_FOR_EACH_MAP() & ++ * MAP_FOR_EACH_INDEX() combination. */ ++#define FLOWMAP_FOR_EACH_INDEX(IDX, MAP) \ ++ for (struct flowmap_aux aux__ = FLOWMAP_AUX_INITIALIZER(MAP); \ ++ flowmap_next_index(&aux__, &(IDX));) ++ ++/* Flowmap inline implementations. */ ++static inline void ++flowmap_init(struct flowmap *fm) ++{ ++ memset(fm, 0, sizeof *fm); ++} ++ ++static inline bool ++flowmap_equal(struct flowmap a, struct flowmap b) ++{ ++ return !memcmp(&a, &b, sizeof a); ++} ++ ++static inline bool ++flowmap_is_set(const struct flowmap *fm, size_t idx) ++{ ++ return (fm->bits[idx / MAP_T_BITS] & (MAP_1 << (idx % MAP_T_BITS))) != 0; ++} ++ ++/* Returns 'true' if any of the 'n_bits' bits starting at 'idx' are set in ++ * 'fm'. 'n_bits' can be at most MAP_T_BITS. */ ++static inline bool ++flowmap_are_set(const struct flowmap *fm, size_t idx, unsigned int n_bits) ++{ ++ map_t n_bits_mask = (MAP_1 << n_bits) - 1; ++ size_t unit = idx / MAP_T_BITS; ++ ++ idx %= MAP_T_BITS; ++ ++ if (fm->bits[unit] & (n_bits_mask << idx)) { ++ return true; ++ } ++ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a ++ * false-positive array out of bounds error by GCC 4.9. */ ++ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { ++ /* Check the remaining bits from the next unit. */ ++ return fm->bits[unit + 1] & (n_bits_mask >> (MAP_T_BITS - idx)); ++ } ++ return false; ++} ++ ++/* Set the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'. ++ * 'n_bits' can be at most MAP_T_BITS. */ ++static inline void ++flowmap_set(struct flowmap *fm, size_t idx, unsigned int n_bits) ++{ ++ map_t n_bits_mask = (MAP_1 << n_bits) - 1; ++ size_t unit = idx / MAP_T_BITS; ++ ++ idx %= MAP_T_BITS; ++ ++ fm->bits[unit] |= n_bits_mask << idx; ++ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a ++ * false-positive array out of bounds error by GCC 4.9. */ ++ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { ++ /* 'MAP_T_BITS - idx' bits were set on 'unit', set the remaining ++ * bits from the next unit. */ ++ fm->bits[unit + 1] |= n_bits_mask >> (MAP_T_BITS - idx); ++ } ++} ++ ++/* Clears the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'. ++ * 'n_bits' can be at most MAP_T_BITS. */ ++static inline void ++flowmap_clear(struct flowmap *fm, size_t idx, unsigned int n_bits) ++{ ++ map_t n_bits_mask = (MAP_1 << n_bits) - 1; ++ size_t unit = idx / MAP_T_BITS; ++ ++ idx %= MAP_T_BITS; ++ ++ fm->bits[unit] &= ~(n_bits_mask << idx); ++ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a ++ * false-positive array out of bounds error by GCC 4.9. */ ++ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) { ++ /* 'MAP_T_BITS - idx' bits were cleared on 'unit', clear the ++ * remaining bits from the next unit. */ ++ fm->bits[unit + 1] &= ~(n_bits_mask >> (MAP_T_BITS - idx)); ++ } ++} ++ ++/* OR the bits in the flowmaps. */ ++static inline struct flowmap ++flowmap_or(struct flowmap a, struct flowmap b) ++{ ++ struct flowmap map; ++ size_t unit; ++ ++ FLOWMAP_FOR_EACH_UNIT (unit) { ++ map.bits[unit] = a.bits[unit] | b.bits[unit]; ++ } ++ return map; ++} ++ ++/* AND the bits in the flowmaps. */ ++static inline struct flowmap ++flowmap_and(struct flowmap a, struct flowmap b) ++{ ++ struct flowmap map; ++ size_t unit; ++ ++ FLOWMAP_FOR_EACH_UNIT (unit) { ++ map.bits[unit] = a.bits[unit] & b.bits[unit]; ++ } ++ return map; ++} ++ ++static inline bool ++flowmap_is_empty(struct flowmap fm) ++{ ++ map_t map; ++ ++ FLOWMAP_FOR_EACH_MAP (map, fm) { ++ if (map) { ++ return false; ++ } ++ } ++ return true; ++} ++ ++static inline unsigned int ++flowmap_n_1bits(struct flowmap fm) ++{ ++ unsigned int n_1bits = 0; ++ size_t unit; ++ ++ FLOWMAP_FOR_EACH_UNIT (unit) { ++ n_1bits += count_1bits(fm.bits[unit]); ++ } ++ return n_1bits; ++} ++ ++struct flowmap_aux { ++ size_t unit; ++ struct flowmap map; ++}; ++ ++static inline bool ++flowmap_next_index(struct flowmap_aux *aux, size_t *idx) ++{ ++ for (;;) { ++ map_t *map = &aux->map.bits[aux->unit]; ++ if (*map) { ++ *idx = aux->unit * MAP_T_BITS + raw_ctz(*map); ++ *map = zero_rightmost_1bit(*map); ++ return true; ++ } ++ if (++aux->unit >= FLOWMAP_UNITS) { ++ return false; ++ } ++ } ++} ++ ++ ++/* Compressed flow. */ ++ ++/* A sparse representation of a "struct flow". ++ * ++ * A "struct flow" is fairly large and tends to be mostly zeros. Sparse ++ * representation has two advantages. First, it saves memory and, more ++ * importantly, minimizes the number of accessed cache lines. Second, it saves ++ * time when the goal is to iterate over only the nonzero parts of the struct. ++ * ++ * The map member hold one bit for each uint64_t in a "struct flow". Each ++ * 0-bit indicates that the corresponding uint64_t is zero, each 1-bit that it ++ * *may* be nonzero (see below how this applies to minimasks). ++ * ++ * The values indicated by 'map' always follow the miniflow in memory. The ++ * user of the miniflow is responsible for always having enough storage after ++ * the struct miniflow corresponding to the number of 1-bits in maps. ++ * ++ * Elements in values array are allowed to be zero. This is useful for "struct ++ * minimatch", for which ensuring that the miniflow and minimask members have ++ * same maps allows optimization. This allowance applies only to a miniflow ++ * that is not a mask. That is, a minimask may NOT have zero elements in its ++ * values. ++ * ++ * A miniflow is always dynamically allocated so that the maps are followed by ++ * at least as many elements as there are 1-bits in maps. */ ++struct miniflow { ++ struct flowmap map; ++ /* Followed by: ++ * uint64_t values[n]; ++ * where 'n' is miniflow_n_values(miniflow). */ ++}; ++BUILD_ASSERT_DECL(sizeof(struct miniflow) % sizeof(uint64_t) == 0); ++ ++#define MINIFLOW_VALUES_SIZE(COUNT) ((COUNT) * sizeof(uint64_t)) ++ ++static inline uint64_t *miniflow_values(struct miniflow *mf) ++{ ++ return (uint64_t *)(mf + 1); ++} ++ ++static inline const uint64_t *miniflow_get_values(const struct miniflow *mf) ++{ ++ return (const uint64_t *)(mf + 1); ++} ++ ++struct pkt_metadata; ++ ++/* The 'dst' must follow with buffer space for FLOW_U64S 64-bit units. ++ * 'dst->map' is ignored on input and set on output to indicate which fields ++ * were extracted. */ ++void miniflow_extract(struct dp_packet *packet, struct miniflow *dst); ++void miniflow_map_init(struct miniflow *, const struct flow *); ++void flow_wc_map(const struct flow *, struct flowmap *); ++size_t miniflow_alloc(struct miniflow *dsts[], size_t n, ++ const struct miniflow *src); ++void miniflow_init(struct miniflow *, const struct flow *); ++void miniflow_clone(struct miniflow *, const struct miniflow *, ++ size_t n_values); ++struct miniflow * miniflow_create(const struct flow *); ++ ++void miniflow_expand(const struct miniflow *, struct flow *); ++ ++static inline uint64_t flow_u64_value(const struct flow *flow, size_t index) ++{ ++ return ((uint64_t *)flow)[index]; ++} ++ ++static inline uint64_t *flow_u64_lvalue(struct flow *flow, size_t index) ++{ ++ return &((uint64_t *)flow)[index]; ++} ++ ++static inline size_t ++miniflow_n_values(const struct miniflow *flow) ++{ ++ return flowmap_n_1bits(flow->map); ++} ++ ++struct flow_for_each_in_maps_aux { ++ const struct flow *flow; ++ struct flowmap_aux map_aux; ++}; ++ ++static inline bool ++flow_values_get_next_in_maps(struct flow_for_each_in_maps_aux *aux, ++ uint64_t *value) ++{ ++ size_t idx; ++ ++ if (flowmap_next_index(&aux->map_aux, &idx)) { ++ *value = flow_u64_value(aux->flow, idx); ++ return true; ++ } ++ return false; ++} ++ ++/* Iterate through all flow u64 values specified by 'MAPS'. */ ++#define FLOW_FOR_EACH_IN_MAPS(VALUE, FLOW, MAPS) \ ++ for (struct flow_for_each_in_maps_aux aux__ \ ++ = { (FLOW), FLOWMAP_AUX_INITIALIZER(MAPS) }; \ ++ flow_values_get_next_in_maps(&aux__, &(VALUE));) ++ ++struct mf_for_each_in_map_aux { ++ size_t unit; /* Current 64-bit unit of the flowmaps ++ being processed. */ ++ struct flowmap fmap; /* Remaining 1-bits corresponding to the ++ 64-bit words in 'values' */ ++ struct flowmap map; /* Remaining 1-bits corresponding to the ++ 64-bit words of interest. */ ++ const uint64_t *values; /* 64-bit words corresponding to the ++ 1-bits in 'fmap'. */ ++}; ++ ++/* Get the data from 'aux->values' corresponding to the next lowest 1-bit ++ * in 'aux->map', given that 'aux->values' points to an array of 64-bit ++ * words corresponding to the 1-bits in 'aux->fmap', starting from the ++ * rightmost 1-bit. ++ * ++ * Returns 'true' if the traversal is incomplete, 'false' otherwise. ++ * 'aux' is prepared for the next iteration after each call. ++ * ++ * This is used to traverse through, for example, the values in a miniflow ++ * representation of a flow key selected by non-zero 64-bit words in a ++ * corresponding subtable mask. */ ++static inline bool ++mf_get_next_in_map(struct mf_for_each_in_map_aux *aux, ++ uint64_t *value) ++{ ++ map_t *map, *fmap; ++ map_t rm1bit; ++ ++ /* Skip empty map units. */ ++ while (OVS_UNLIKELY(!*(map = &aux->map.bits[aux->unit]))) { ++ /* Skip remaining data in the current unit before advancing ++ * to the next. */ ++ aux->values += count_1bits(aux->fmap.bits[aux->unit]); ++ if (++aux->unit == FLOWMAP_UNITS) { ++ return false; ++ } ++ } ++ ++ rm1bit = rightmost_1bit(*map); ++ *map -= rm1bit; ++ fmap = &aux->fmap.bits[aux->unit]; ++ ++ /* If the rightmost 1-bit found from the current unit in 'aux->map' ++ * ('rm1bit') is also present in 'aux->fmap', store the corresponding ++ * value from 'aux->values' to '*value', otherwise store 0. */ ++ if (OVS_LIKELY(*fmap & rm1bit)) { ++ /* Skip all 64-bit words in 'values' preceding the one corresponding ++ * to 'rm1bit'. */ ++ map_t trash = *fmap & (rm1bit - 1); ++ ++ /* Avoid resetting 'fmap' and calling count_1bits() when trash is ++ * zero. */ ++ if (trash) { ++ *fmap -= trash; ++ aux->values += count_1bits(trash); ++ } ++ ++ *value = *aux->values; ++ } else { ++ *value = 0; ++ } ++ return true; ++} ++ ++/* Iterate through miniflow u64 values specified by 'FLOWMAP'. */ ++#define MINIFLOW_FOR_EACH_IN_FLOWMAP(VALUE, FLOW, FLOWMAP) \ ++ for (struct mf_for_each_in_map_aux aux__ = \ ++ { 0, (FLOW)->map, (FLOWMAP), miniflow_get_values(FLOW) }; \ ++ mf_get_next_in_map(&aux__, &(VALUE));) ++ ++/* This can be used when it is known that 'idx' is set in 'map'. */ ++static inline const uint64_t * ++miniflow_values_get__(const uint64_t *values, map_t map, size_t idx) ++{ ++ return values + count_1bits(map & ((MAP_1 << idx) - 1)); ++} ++ ++/* This can be used when it is known that 'u64_idx' is set in ++ * the map of 'mf'. */ ++static inline const uint64_t * ++miniflow_get__(const struct miniflow *mf, size_t idx) ++{ ++ const uint64_t *values = miniflow_get_values(mf); ++ const map_t *map = mf->map.bits; ++ ++ while (idx >= MAP_T_BITS) { ++ idx -= MAP_T_BITS; ++ values += count_1bits(*map++); ++ } ++ return miniflow_values_get__(values, *map, idx); ++} ++ ++#define MINIFLOW_IN_MAP(MF, IDX) flowmap_is_set(&(MF)->map, IDX) ++ ++/* Get the value of the struct flow 'FIELD' as up to 8 byte wide integer type ++ * 'TYPE' from miniflow 'MF'. */ ++#define MINIFLOW_GET_TYPE(MF, TYPE, FIELD) \ ++ (BUILD_ASSERT(sizeof(TYPE) == sizeof(((struct flow *)0)->FIELD)), \ ++ BUILD_ASSERT_GCCONLY(__builtin_types_compatible_p(TYPE, typeof(((struct flow *)0)->FIELD))), \ ++ MINIFLOW_GET_TYPE__(MF, TYPE, FIELD)) ++ ++/* Like MINIFLOW_GET_TYPE, but without checking that TYPE is the correct width ++ * for FIELD. (This is useful for deliberately reading adjacent fields in one ++ * go.) */ ++#define MINIFLOW_GET_TYPE__(MF, TYPE, FIELD) \ ++ (MINIFLOW_IN_MAP(MF, FLOW_U64_OFFSET(FIELD)) \ ++ ? ((OVS_FORCE const TYPE *)miniflow_get__(MF, FLOW_U64_OFFSET(FIELD))) \ ++ [FLOW_U64_OFFREM(FIELD) / sizeof(TYPE)] \ ++ : 0) ++ ++#define MINIFLOW_GET_U128(FLOW, FIELD) \ ++ (ovs_u128) { .u64 = { \ ++ (MINIFLOW_IN_MAP(FLOW, FLOW_U64_OFFSET(FIELD)) ? \ ++ *miniflow_get__(FLOW, FLOW_U64_OFFSET(FIELD)) : 0), \ ++ (MINIFLOW_IN_MAP(FLOW, FLOW_U64_OFFSET(FIELD) + 1) ? \ ++ *miniflow_get__(FLOW, FLOW_U64_OFFSET(FIELD) + 1) : 0) } } ++ ++#define MINIFLOW_GET_U8(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, uint8_t, FIELD) ++#define MINIFLOW_GET_U16(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, uint16_t, FIELD) ++#define MINIFLOW_GET_BE16(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, ovs_be16, FIELD) ++#define MINIFLOW_GET_U32(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, uint32_t, FIELD) ++#define MINIFLOW_GET_BE32(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, ovs_be32, FIELD) ++#define MINIFLOW_GET_U64(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, uint64_t, FIELD) ++#define MINIFLOW_GET_BE64(FLOW, FIELD) \ ++ MINIFLOW_GET_TYPE(FLOW, ovs_be64, FIELD) ++ ++static inline uint64_t miniflow_get(const struct miniflow *, ++ unsigned int u64_ofs); ++static inline uint32_t miniflow_get_u32(const struct miniflow *, ++ unsigned int u32_ofs); ++static inline ovs_be32 miniflow_get_be32(const struct miniflow *, ++ unsigned int be32_ofs); ++static inline uint16_t miniflow_get_vid(const struct miniflow *, size_t); ++static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *); ++static inline ovs_be64 miniflow_get_metadata(const struct miniflow *); ++static inline uint64_t miniflow_get_tun_metadata_present_map( ++ const struct miniflow *); ++static inline uint32_t miniflow_get_recirc_id(const struct miniflow *); ++static inline uint32_t miniflow_get_dp_hash(const struct miniflow *); ++static inline ovs_be32 miniflow_get_ports(const struct miniflow *); ++ ++bool miniflow_equal(const struct miniflow *a, const struct miniflow *b); ++bool miniflow_equal_in_minimask(const struct miniflow *a, ++ const struct miniflow *b, ++ const struct minimask *); ++bool miniflow_equal_flow_in_minimask(const struct miniflow *a, ++ const struct flow *b, ++ const struct minimask *); ++uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis); ++ ++ ++/* Compressed flow wildcards. */ ++ ++/* A sparse representation of a "struct flow_wildcards". ++ * ++ * See the large comment on struct miniflow for details. ++ * ++ * Note: While miniflow can have zero data for a 1-bit in the map, ++ * a minimask may not! We rely on this in the implementation. */ ++struct minimask { ++ struct miniflow masks; ++}; ++ ++void minimask_init(struct minimask *, const struct flow_wildcards *); ++struct minimask * minimask_create(const struct flow_wildcards *); ++void minimask_combine(struct minimask *dst, ++ const struct minimask *a, const struct minimask *b, ++ uint64_t storage[FLOW_U64S]); ++ ++void minimask_expand(const struct minimask *, struct flow_wildcards *); ++ ++static inline uint32_t minimask_get_u32(const struct minimask *, ++ unsigned int u32_ofs); ++static inline ovs_be32 minimask_get_be32(const struct minimask *, ++ unsigned int be32_ofs); ++static inline uint16_t minimask_get_vid_mask(const struct minimask *, size_t); ++static inline ovs_be64 minimask_get_metadata_mask(const struct minimask *); ++ ++bool minimask_equal(const struct minimask *a, const struct minimask *b); ++bool minimask_has_extra(const struct minimask *, const struct minimask *); ++ ++ ++/* Returns true if 'mask' matches every packet, false if 'mask' fixes any bits ++ * or fields. */ ++static inline bool ++minimask_is_catchall(const struct minimask *mask) ++{ ++ /* For every 1-bit in mask's map, the corresponding value is non-zero, ++ * so the only way the mask can not fix any bits or fields is for the ++ * map the be zero. */ ++ return flowmap_is_empty(mask->masks.map); ++} ++ ++/* Returns the uint64_t that would be at byte offset '8 * u64_ofs' if 'flow' ++ * were expanded into a "struct flow". */ ++static inline uint64_t miniflow_get(const struct miniflow *flow, ++ unsigned int u64_ofs) ++{ ++ return MINIFLOW_IN_MAP(flow, u64_ofs) ? *miniflow_get__(flow, u64_ofs) : 0; ++} ++ ++static inline uint32_t miniflow_get_u32(const struct miniflow *flow, ++ unsigned int u32_ofs) ++{ ++ uint64_t value = miniflow_get(flow, u32_ofs / 2); ++ ++#if WORDS_BIGENDIAN ++ return (u32_ofs & 1) ? value : value >> 32; ++#else ++ return (u32_ofs & 1) ? value >> 32 : value; ++#endif ++} ++ ++static inline ovs_be32 miniflow_get_be32(const struct miniflow *flow, ++ unsigned int be32_ofs) ++{ ++ return (OVS_FORCE ovs_be32)miniflow_get_u32(flow, be32_ofs); ++} ++ ++/* Returns the VID within the vlan_tci member of the "struct flow" represented ++ * by 'flow'. */ ++static inline uint16_t ++miniflow_get_vid(const struct miniflow *flow, size_t n) ++{ ++ if (n < FLOW_MAX_VLAN_HEADERS) { ++ union flow_vlan_hdr hdr = { ++ .qtag = MINIFLOW_GET_BE32(flow, vlans[n].qtag) ++ }; ++ return vlan_tci_to_vid(hdr.tci); ++ } ++ return 0; ++} ++ ++/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'mask' ++ * were expanded into a "struct flow_wildcards". */ ++static inline uint32_t ++minimask_get_u32(const struct minimask *mask, unsigned int u32_ofs) ++{ ++ return miniflow_get_u32(&mask->masks, u32_ofs); ++} ++ ++static inline ovs_be32 ++minimask_get_be32(const struct minimask *mask, unsigned int be32_ofs) ++{ ++ return (OVS_FORCE ovs_be32)minimask_get_u32(mask, be32_ofs); ++} ++ ++/* Returns the VID mask within the vlan_tci member of the "struct ++ * flow_wildcards" represented by 'mask'. */ ++static inline uint16_t ++minimask_get_vid_mask(const struct minimask *mask, size_t n) ++{ ++ return miniflow_get_vid(&mask->masks, n); ++} ++ ++/* Returns the value of the "tcp_flags" field in 'flow'. */ ++static inline uint16_t ++miniflow_get_tcp_flags(const struct miniflow *flow) ++{ ++ return ntohs(MINIFLOW_GET_BE16(flow, tcp_flags)); ++} ++ ++/* Returns the value of the OpenFlow 1.1+ "metadata" field in 'flow'. */ ++static inline ovs_be64 ++miniflow_get_metadata(const struct miniflow *flow) ++{ ++ return MINIFLOW_GET_BE64(flow, metadata); ++} ++ ++/* Returns the bitmap that indicates which tunnel metadata fields are present ++ * in 'flow'. */ ++static inline uint64_t ++miniflow_get_tun_metadata_present_map(const struct miniflow *flow) ++{ ++ return MINIFLOW_GET_U64(flow, tunnel.metadata.present.map); ++} ++ ++/* Returns the recirc_id in 'flow.' */ ++static inline uint32_t ++miniflow_get_recirc_id(const struct miniflow *flow) ++{ ++ return MINIFLOW_GET_U32(flow, recirc_id); ++} ++ ++/* Returns the dp_hash in 'flow.' */ ++static inline uint32_t ++miniflow_get_dp_hash(const struct miniflow *flow) ++{ ++ return MINIFLOW_GET_U32(flow, dp_hash); ++} ++ ++/* Returns the 'tp_src' and 'tp_dst' fields together as one piece of data. */ ++static inline ovs_be32 ++miniflow_get_ports(const struct miniflow *flow) ++{ ++ return MINIFLOW_GET_TYPE__(flow, ovs_be32, tp_src); ++} ++ ++/* Returns the mask for the OpenFlow 1.1+ "metadata" field in 'mask'. ++ * ++ * The return value is all-1-bits if 'mask' matches on the whole value of the ++ * metadata field, all-0-bits if 'mask' entirely wildcards the metadata field, ++ * or some other value if the metadata field is partially matched, partially ++ * wildcarded. */ ++static inline ovs_be64 ++minimask_get_metadata_mask(const struct minimask *mask) ++{ ++ return MINIFLOW_GET_BE64(&mask->masks, metadata); ++} ++ ++/* Perform a bitwise OR of miniflow 'src' flow data specified in 'subset' with ++ * the equivalent fields in 'dst', storing the result in 'dst'. 'subset' must ++ * be a subset of 'src's map. */ ++static inline void ++flow_union_with_miniflow_subset(struct flow *dst, const struct miniflow *src, ++ struct flowmap subset) ++{ ++ uint64_t *dst_u64 = (uint64_t *) dst; ++ const uint64_t *p = miniflow_get_values(src); ++ map_t map; ++ ++ FLOWMAP_FOR_EACH_MAP (map, subset) { ++ size_t idx; ++ ++ MAP_FOR_EACH_INDEX(idx, map) { ++ dst_u64[idx] |= *p++; ++ } ++ dst_u64 += MAP_T_BITS; ++ } ++} ++ ++/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent ++ * fields in 'dst', storing the result in 'dst'. */ ++static inline void ++flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) ++{ ++ flow_union_with_miniflow_subset(dst, src, src->map); ++} ++ ++static inline bool is_ct_valid(const struct flow *flow, ++ const struct flow_wildcards *mask, ++ struct flow_wildcards *wc) ++{ ++ /* Matches are checked with 'mask' and without 'wc'. */ ++ if (mask && !wc) { ++ /* Must match at least one of the bits that implies a valid ++ * conntrack entry, or an explicit not-invalid. */ ++ return flow->ct_state & (CS_NEW | CS_ESTABLISHED | CS_RELATED ++ | CS_REPLY_DIR | CS_SRC_NAT | CS_DST_NAT) ++ || (flow->ct_state & CS_TRACKED ++ && mask->masks.ct_state & CS_INVALID ++ && !(flow->ct_state & CS_INVALID)); ++ } ++ /* Else we are checking a fully extracted flow, where valid CT state always ++ * has either 'new', 'established', or 'reply_dir' bit set. */ ++#define CS_VALID_MASK (CS_NEW | CS_ESTABLISHED | CS_REPLY_DIR) ++ if (wc) { ++ wc->masks.ct_state |= CS_VALID_MASK; ++ } ++ return flow->ct_state & CS_VALID_MASK; ++} ++ ++static inline void ++pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow) ++{ ++ /* Update this function whenever struct flow changes. */ ++ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42); ++ ++ md->recirc_id = flow->recirc_id; ++ md->dp_hash = flow->dp_hash; ++ flow_tnl_copy__(&md->tunnel, &flow->tunnel); ++ md->skb_priority = flow->skb_priority; ++ md->pkt_mark = flow->pkt_mark; ++ md->in_port = flow->in_port; ++ md->ct_state = flow->ct_state; ++ md->ct_zone = flow->ct_zone; ++ md->ct_mark = flow->ct_mark; ++ md->ct_label = flow->ct_label; ++ ++ md->ct_orig_tuple_ipv6 = false; ++ if (flow->dl_type && is_ct_valid(flow, NULL, NULL)) { ++ if (flow->dl_type == htons(ETH_TYPE_IP)) { ++ md->ct_orig_tuple.ipv4 = (struct ovs_key_ct_tuple_ipv4) { ++ flow->ct_nw_src, ++ flow->ct_nw_dst, ++ flow->ct_tp_src, ++ flow->ct_tp_dst, ++ flow->ct_nw_proto, ++ }; ++ } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { ++ md->ct_orig_tuple_ipv6 = true; ++ md->ct_orig_tuple.ipv6 = (struct ovs_key_ct_tuple_ipv6) { ++ flow->ct_ipv6_src, ++ flow->ct_ipv6_dst, ++ flow->ct_tp_src, ++ flow->ct_tp_dst, ++ flow->ct_nw_proto, ++ }; ++ } else { ++ /* Reset ct_orig_tuple for other types. */ ++ memset(&md->ct_orig_tuple, 0, sizeof md->ct_orig_tuple); ++ } ++ } else { ++ memset(&md->ct_orig_tuple, 0, sizeof md->ct_orig_tuple); ++ } ++} ++ ++/* Often, during translation we need to read a value from a flow('FLOW') and ++ * unwildcard the corresponding bits in the wildcards('WC'). This macro makes ++ * it easier to do that. */ ++ ++#define FLOW_WC_GET_AND_MASK_WC(FLOW, WC, FIELD) \ ++ (((WC) ? WC_MASK_FIELD(WC, FIELD) : NULL), ((FLOW)->FIELD)) ++ ++static inline bool is_ethernet(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (wc) { ++ WC_MASK_FIELD(wc, packet_type); ++ } ++ return flow->packet_type == htonl(PT_ETH); ++} ++ ++static inline ovs_be16 get_dl_type(const struct flow *flow) ++{ ++ if (flow->packet_type == htonl(PT_ETH)) { ++ return flow->dl_type; ++ } else if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) { ++ return pt_ns_type_be(flow->packet_type); ++ } else { ++ return htons(FLOW_DL_TYPE_NONE); ++ } ++} ++ ++static inline bool is_vlan(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (!is_ethernet(flow, wc)) { ++ return false; ++ } ++ if (wc) { ++ WC_MASK_FIELD_MASK(wc, vlans[0].tci, htons(VLAN_CFI)); ++ } ++ return (flow->vlans[0].tci & htons(VLAN_CFI)) != 0; ++} ++ ++static inline bool is_ip_any(const struct flow *flow) ++{ ++ return dl_type_is_ip_any(get_dl_type(flow)); ++} ++ ++static inline bool is_ip_proto(const struct flow *flow, uint8_t ip_proto, ++ struct flow_wildcards *wc) ++{ ++ if (is_ip_any(flow)) { ++ if (wc) { ++ WC_MASK_FIELD(wc, nw_proto); ++ } ++ return flow->nw_proto == ip_proto; ++ } ++ return false; ++} ++ ++static inline bool is_tcp(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ return is_ip_proto(flow, IPPROTO_TCP, wc); ++} ++ ++static inline bool is_udp(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ return is_ip_proto(flow, IPPROTO_UDP, wc); ++} ++ ++static inline bool is_sctp(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ return is_ip_proto(flow, IPPROTO_SCTP, wc); ++} ++ ++static inline bool is_icmpv4(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { ++ if (wc) { ++ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ++ } ++ return flow->nw_proto == IPPROTO_ICMP; ++ } ++ return false; ++} ++ ++static inline bool is_icmpv6(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (get_dl_type(flow) == htons(ETH_TYPE_IPV6)) { ++ if (wc) { ++ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ++ } ++ return flow->nw_proto == IPPROTO_ICMPV6; ++ } ++ return false; ++} ++ ++static inline bool is_nd(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (is_icmpv6(flow, wc)) { ++ if (wc) { ++ memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); ++ } ++ if (flow->tp_dst != htons(0)) { ++ return false; ++ } ++ ++ if (wc) { ++ memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); ++ } ++ return (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) || ++ flow->tp_src == htons(ND_NEIGHBOR_ADVERT)); ++ } ++ return false; ++} ++ ++static inline bool is_arp(const struct flow *flow) ++{ ++ return (flow->dl_type == htons(ETH_TYPE_ARP)); ++} ++ ++static inline bool is_garp(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (is_arp(flow)) { ++ return (FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_src) == ++ FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_dst)); ++ } ++ ++ return false; ++} ++ ++static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc) ++{ ++ if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { ++ if (wc) { ++ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ++ } ++ return flow->nw_proto == IPPROTO_IGMP; ++ } ++ return false; ++} ++ ++static inline bool is_mld(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (is_icmpv6(flow, wc)) { ++ if (wc) { ++ memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); ++ } ++ return (flow->tp_src == htons(MLD_QUERY) ++ || flow->tp_src == htons(MLD_REPORT) ++ || flow->tp_src == htons(MLD_DONE) ++ || flow->tp_src == htons(MLD2_REPORT)); ++ } ++ return false; ++} ++ ++static inline bool is_mld_query(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ if (is_icmpv6(flow, wc)) { ++ if (wc) { ++ memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); ++ } ++ return flow->tp_src == htons(MLD_QUERY); ++ } ++ return false; ++} ++ ++static inline bool is_mld_report(const struct flow *flow, ++ struct flow_wildcards *wc) ++{ ++ return is_mld(flow, wc) && !is_mld_query(flow, wc); ++} ++ ++static inline bool is_stp(const struct flow *flow) ++{ ++ return (flow->dl_type == htons(FLOW_DL_TYPE_NONE) ++ && eth_addr_equals(flow->dl_dst, eth_addr_stp)); ++} ++ ++/* Returns true if flow->tp_dst equals 'port'. If 'wc' is nonnull, sets ++ * appropriate bits in wc->masks.tp_dst to account for the test. ++ * ++ * The caller must already have ensured that 'flow' is a protocol for which ++ * tp_dst is relevant. */ ++static inline bool tp_dst_equals(const struct flow *flow, uint16_t port, ++ struct flow_wildcards *wc) ++{ ++ uint16_t diff = port ^ ntohs(flow->tp_dst); ++ if (wc) { ++ if (diff) { ++ /* Set mask for the most significant mismatching bit. */ ++ int ofs = raw_clz64((uint64_t) diff << 48); /* range [0,15] */ ++ wc->masks.tp_dst |= htons(0x8000 >> ofs); ++ } else { ++ /* Must match all bits. */ ++ wc->masks.tp_dst = OVS_BE16_MAX; ++ } ++ } ++ return !diff; ++} ++ ++#endif /* flow.h */ +Index: openvswitch-2.17.2/lib/hash.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/hash.h ++++ /dev/null +@@ -1,398 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-#ifndef HASH_H +-#define HASH_H 1 +- +-#include +-#include +-#include +-#include -#include "util.h" -+#include "internal/util.h" - - #ifdef __cplusplus - extern "C" { -@@ -99,7 +99,7 @@ static inline uint32_t hash_add_bytes32(uint32_t, const uint32_t *, size_t); - static inline uint32_t hash_add_bytes64(uint32_t, const uint64_t *, size_t); - - #if (defined(__ARM_FEATURE_CRC32) && defined(__aarch64__)) +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-static inline uint32_t +-hash_rot(uint32_t x, int k) +-{ +- return (x << k) | (x >> (32 - k)); +-} +- +-uint32_t hash_bytes(const void *, size_t n_bytes, uint32_t basis); +-/* The hash input must be a word larger than 128 bits. */ +-void hash_bytes128(const void *_, size_t n_bytes, uint32_t basis, +- ovs_u128 *out); +- +-static inline uint32_t hash_int(uint32_t x, uint32_t basis); +-static inline uint32_t hash_2words(uint32_t, uint32_t); +-static inline uint32_t hash_uint64(const uint64_t); +-static inline uint32_t hash_uint64_basis(const uint64_t x, +- const uint32_t basis); +-uint32_t hash_3words(uint32_t, uint32_t, uint32_t); +- +-static inline uint32_t hash_boolean(bool x, uint32_t basis); +-uint32_t hash_double(double, uint32_t basis); +- +-static inline uint32_t hash_pointer(const void *, uint32_t basis); +-static inline uint32_t hash_string(const char *, uint32_t basis); +- +-/* Murmurhash by Austin Appleby, +- * from https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp +- * +- * The upstream license there says: +- * +- * MurmurHash3 was written by Austin Appleby, and is placed in the public +- * domain. The author hereby disclaims copyright to this source code. +- * +- * See hash_words() for sample usage. */ +- +-static inline uint32_t mhash_add__(uint32_t hash, uint32_t data) +-{ +- /* zero-valued 'data' will not change the 'hash' value */ +- if (!data) { +- return hash; +- } +- +- data *= 0xcc9e2d51; +- data = hash_rot(data, 15); +- data *= 0x1b873593; +- return hash ^ data; +-} +- +-static inline uint32_t mhash_add(uint32_t hash, uint32_t data) +-{ +- hash = mhash_add__(hash, data); +- hash = hash_rot(hash, 13); +- return hash * 5 + 0xe6546b64; +-} +- +-static inline uint32_t mhash_finish(uint32_t hash) +-{ +- hash ^= hash >> 16; +- hash *= 0x85ebca6b; +- hash ^= hash >> 13; +- hash *= 0xc2b2ae35; +- hash ^= hash >> 16; +- return hash; +-} +- +-static inline uint32_t hash_add(uint32_t hash, uint32_t data); +-static inline uint32_t hash_add64(uint32_t hash, uint64_t data); +- +-static inline uint32_t hash_add_words(uint32_t, const uint32_t *, size_t); +-static inline uint32_t hash_add_words64(uint32_t, const uint64_t *, size_t); +-static inline uint32_t hash_add_bytes32(uint32_t, const uint32_t *, size_t); +-static inline uint32_t hash_add_bytes64(uint32_t, const uint64_t *, size_t); +- +-#if (defined(__ARM_FEATURE_CRC32) && defined(__aarch64__)) -#include "hash-aarch64.h" +- +-#elif !(defined(__SSE4_2__) && defined(__x86_64__)) +-/* Mhash-based implementation. */ +- +-static inline uint32_t hash_add(uint32_t hash, uint32_t data) +-{ +- return mhash_add(hash, data); +-} +- +-static inline uint32_t hash_add64(uint32_t hash, uint64_t data) +-{ +- return hash_add(hash_add(hash, data), data >> 32); +-} +- +-static inline uint32_t hash_finish(uint32_t hash, uint32_t final) +-{ +- return mhash_finish(hash ^ final); +-} +- +-/* Returns the hash of the 'n' 32-bit words at 'p', starting from 'basis'. +- * 'p' must be properly aligned. +- * +- * This is inlined for the compiler to have access to the 'n_words', which +- * in many cases is a constant. */ +-static inline uint32_t +-hash_words_inline(const uint32_t *p, size_t n_words, uint32_t basis) +-{ +- return hash_finish(hash_add_words(basis, p, n_words), n_words * 4); +-} +- +-static inline uint32_t +-hash_words64_inline(const uint64_t *p, size_t n_words, uint32_t basis) +-{ +- return hash_finish(hash_add_words64(basis, p, n_words), n_words * 8); +-} +- +-static inline uint32_t hash_pointer(const void *p, uint32_t basis) +-{ +- /* Often pointers are hashed simply by casting to integer type, but that +- * has pitfalls since the lower bits of a pointer are often all 0 for +- * alignment reasons. It's hard to guess where the entropy really is, so +- * we give up here and just use a high-quality hash function. +- * +- * The double cast suppresses a warning on 64-bit systems about casting to +- * an integer to different size. That's OK in this case, since most of the +- * entropy in the pointer is almost certainly in the lower 32 bits. */ +- return hash_int((uint32_t) (uintptr_t) p, basis); +-} +- +-static inline uint32_t hash_2words(uint32_t x, uint32_t y) +-{ +- return hash_finish(hash_add(hash_add(x, 0), y), 8); +-} +- +-static inline uint32_t hash_uint64_basis(const uint64_t x, +- const uint32_t basis) +-{ +- return hash_finish(hash_add64(basis, x), 8); +-} +- +-static inline uint32_t hash_uint64(const uint64_t x) +-{ +- return hash_uint64_basis(x, 0); +-} +- +-#else /* __SSE4_2__ && __x86_64__ */ +-#include +- +-static inline uint32_t hash_add(uint32_t hash, uint32_t data) +-{ +- return _mm_crc32_u32(hash, data); +-} +- +-/* Add the halves of 'data' in the memory order. */ +-static inline uint32_t hash_add64(uint32_t hash, uint64_t data) +-{ +- return _mm_crc32_u64(hash, data); +-} +- +-static inline uint32_t hash_finish(uint64_t hash, uint64_t final) +-{ +- /* The finishing multiplier 0x805204f3 has been experimentally +- * derived to pass the testsuite hash tests. */ +- hash = _mm_crc32_u64(hash, final) * 0x805204f3; +- return hash ^ (uint32_t)hash >> 16; /* Increase entropy in LSBs. */ +-} +- +-/* Returns the hash of the 'n' 32-bit words at 'p_', starting from 'basis'. +- * We access 'p_' as a uint64_t pointer, which is fine for __SSE_4_2__. +- * +- * This is inlined for the compiler to have access to the 'n_words', which +- * in many cases is a constant. */ +-static inline uint32_t +-hash_words_inline(const uint32_t p_[], size_t n_words, uint32_t basis) +-{ +- const uint64_t *p = (const void *)p_; +- uint64_t hash1 = basis; +- uint64_t hash2 = 0; +- uint64_t hash3 = n_words; +- const uint32_t *endp = (const uint32_t *)p + n_words; +- const uint64_t *limit = p + n_words / 2 - 3; +- +- while (p <= limit) { +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u64(hash2, p[1]); +- hash3 = _mm_crc32_u64(hash3, p[2]); +- p += 3; +- } +- switch (endp - (const uint32_t *)p) { +- case 1: +- hash1 = _mm_crc32_u32(hash1, *(const uint32_t *)&p[0]); +- break; +- case 2: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- break; +- case 3: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u32(hash2, *(const uint32_t *)&p[1]); +- break; +- case 4: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u64(hash2, p[1]); +- break; +- case 5: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u64(hash2, p[1]); +- hash3 = _mm_crc32_u32(hash3, *(const uint32_t *)&p[2]); +- break; +- } +- return hash_finish(hash1, hash2 << 32 | hash3); +-} +- +-/* A simpler version for 64-bit data. +- * 'n_words' is the count of 64-bit words, basis is 64 bits. */ +-static inline uint32_t +-hash_words64_inline(const uint64_t *p, size_t n_words, uint32_t basis) +-{ +- uint64_t hash1 = basis; +- uint64_t hash2 = 0; +- uint64_t hash3 = n_words; +- const uint64_t *endp = p + n_words; +- const uint64_t *limit = endp - 3; +- +- while (p <= limit) { +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u64(hash2, p[1]); +- hash3 = _mm_crc32_u64(hash3, p[2]); +- p += 3; +- } +- switch (endp - p) { +- case 1: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- break; +- case 2: +- hash1 = _mm_crc32_u64(hash1, p[0]); +- hash2 = _mm_crc32_u64(hash2, p[1]); +- break; +- } +- return hash_finish(hash1, hash2 << 32 | hash3); +-} +- +-static inline uint32_t hash_uint64_basis(const uint64_t x, +- const uint32_t basis) +-{ +- /* '23' chosen to mix bits enough for the test-hash to pass. */ +- return hash_finish(hash_add64(basis, x), 23); +-} +- +-static inline uint32_t hash_uint64(const uint64_t x) +-{ +- return hash_uint64_basis(x, 0); +-} +- +-static inline uint32_t hash_2words(uint32_t x, uint32_t y) +-{ +- return hash_uint64((uint64_t)y << 32 | x); +-} +- +-static inline uint32_t hash_pointer(const void *p, uint32_t basis) +-{ +- return hash_uint64_basis((uint64_t) (uintptr_t) p, basis); +-} +-#endif +- +-uint32_t hash_words__(const uint32_t *p, size_t n_words, uint32_t basis); +-uint32_t hash_words64__(const uint64_t *p, size_t n_words, uint32_t basis); +- +-/* Inline the larger hash functions only when 'n_words' is known to be +- * compile-time constant. */ +-#if __GNUC__ >= 4 +-static inline uint32_t +-hash_words(const uint32_t *p, size_t n_words, uint32_t basis) +-{ +- if (__builtin_constant_p(n_words)) { +- return hash_words_inline(p, n_words, basis); +- } else { +- return hash_words__(p, n_words, basis); +- } +-} +- +-static inline uint32_t +-hash_words64(const uint64_t *p, size_t n_words, uint32_t basis) +-{ +- if (__builtin_constant_p(n_words)) { +- return hash_words64_inline(p, n_words, basis); +- } else { +- return hash_words64__(p, n_words, basis); +- } +-} +- +-#else +- +-static inline uint32_t +-hash_words(const uint32_t *p, size_t n_words, uint32_t basis) +-{ +- return hash_words__(p, n_words, basis); +-} +- +-static inline uint32_t +-hash_words64(const uint64_t *p, size_t n_words, uint32_t basis) +-{ +- return hash_words64__(p, n_words, basis); +-} +-#endif +- +-static inline uint32_t +-hash_bytes32(const uint32_t *p, size_t n_bytes, uint32_t basis) +-{ +- return hash_words(p, n_bytes / 4, basis); +-} +- +-static inline uint32_t +-hash_bytes64(const uint64_t *p, size_t n_bytes, uint32_t basis) +-{ +- return hash_words64(p, n_bytes / 8, basis); +-} +- +-static inline uint32_t hash_string(const char *s, uint32_t basis) +-{ +- return hash_bytes(s, strlen(s), basis); +-} +- +-static inline uint32_t hash_int(uint32_t x, uint32_t basis) +-{ +- return hash_2words(x, basis); +-} +- +-/* An attempt at a useful 1-bit hash function. Has not been analyzed for +- * quality. */ +-static inline uint32_t hash_boolean(bool x, uint32_t basis) +-{ +- const uint32_t P0 = 0xc2b73583; /* This is hash_int(1, 0). */ +- const uint32_t P1 = 0xe90f1258; /* This is hash_int(2, 0). */ +- return (x ? P0 : P1) ^ hash_rot(basis, 1); +-} +- +-/* Helper functions for calling hash_add() for several 32- or 64-bit words in a +- * buffer. These are not hash functions by themselves, since they need +- * hash_finish() to be called, so if you are looking for a full hash function +- * see hash_words(), etc. */ +- +-static inline uint32_t +-hash_add_words(uint32_t hash, const uint32_t *p, size_t n_words) +-{ +- for (size_t i = 0; i < n_words; i++) { +- hash = hash_add(hash, p[i]); +- } +- return hash; +-} +- +-static inline uint32_t +-hash_add_words64(uint32_t hash, const uint64_t *p, size_t n_words) +-{ +- for (size_t i = 0; i < n_words; i++) { +- hash = hash_add64(hash, p[i]); +- } +- return hash; +-} +- +-static inline uint32_t +-hash_add_bytes32(uint32_t hash, const uint32_t *p, size_t n_bytes) +-{ +- return hash_add_words(hash, p, n_bytes / 4); +-} +- +-static inline uint32_t +-hash_add_bytes64(uint32_t hash, const uint64_t *p, size_t n_bytes) +-{ +- return hash_add_words64(hash, p, n_bytes / 8); +-} +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* hash.h */ +Index: openvswitch-2.17.2/include/internal/hash.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/hash.h +@@ -0,0 +1,398 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#ifndef HASH_H ++#define HASH_H 1 ++ ++#include ++#include ++#include ++#include ++#include "internal/util.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++static inline uint32_t ++hash_rot(uint32_t x, int k) ++{ ++ return (x << k) | (x >> (32 - k)); ++} ++ ++uint32_t hash_bytes(const void *, size_t n_bytes, uint32_t basis); ++/* The hash input must be a word larger than 128 bits. */ ++void hash_bytes128(const void *_, size_t n_bytes, uint32_t basis, ++ ovs_u128 *out); ++ ++static inline uint32_t hash_int(uint32_t x, uint32_t basis); ++static inline uint32_t hash_2words(uint32_t, uint32_t); ++static inline uint32_t hash_uint64(const uint64_t); ++static inline uint32_t hash_uint64_basis(const uint64_t x, ++ const uint32_t basis); ++uint32_t hash_3words(uint32_t, uint32_t, uint32_t); ++ ++static inline uint32_t hash_boolean(bool x, uint32_t basis); ++uint32_t hash_double(double, uint32_t basis); ++ ++static inline uint32_t hash_pointer(const void *, uint32_t basis); ++static inline uint32_t hash_string(const char *, uint32_t basis); ++ ++/* Murmurhash by Austin Appleby, ++ * from https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp ++ * ++ * The upstream license there says: ++ * ++ * MurmurHash3 was written by Austin Appleby, and is placed in the public ++ * domain. The author hereby disclaims copyright to this source code. ++ * ++ * See hash_words() for sample usage. */ ++ ++static inline uint32_t mhash_add__(uint32_t hash, uint32_t data) ++{ ++ /* zero-valued 'data' will not change the 'hash' value */ ++ if (!data) { ++ return hash; ++ } ++ ++ data *= 0xcc9e2d51; ++ data = hash_rot(data, 15); ++ data *= 0x1b873593; ++ return hash ^ data; ++} ++ ++static inline uint32_t mhash_add(uint32_t hash, uint32_t data) ++{ ++ hash = mhash_add__(hash, data); ++ hash = hash_rot(hash, 13); ++ return hash * 5 + 0xe6546b64; ++} ++ ++static inline uint32_t mhash_finish(uint32_t hash) ++{ ++ hash ^= hash >> 16; ++ hash *= 0x85ebca6b; ++ hash ^= hash >> 13; ++ hash *= 0xc2b2ae35; ++ hash ^= hash >> 16; ++ return hash; ++} ++ ++static inline uint32_t hash_add(uint32_t hash, uint32_t data); ++static inline uint32_t hash_add64(uint32_t hash, uint64_t data); ++ ++static inline uint32_t hash_add_words(uint32_t, const uint32_t *, size_t); ++static inline uint32_t hash_add_words64(uint32_t, const uint64_t *, size_t); ++static inline uint32_t hash_add_bytes32(uint32_t, const uint32_t *, size_t); ++static inline uint32_t hash_add_bytes64(uint32_t, const uint64_t *, size_t); ++ ++#if (defined(__ARM_FEATURE_CRC32) && defined(__aarch64__)) +#include "internal/hash-aarch64.h" - - #elif !(defined(__SSE4_2__) && defined(__x86_64__)) - /* Mhash-based implementation. */ -diff --git a/lib/hindex.h b/include/internal/hindex.h -similarity index 99% -rename from lib/hindex.h -rename to include/internal/hindex.h -index 876c5a9e3..d0c14a91c 100644 ---- a/lib/hindex.h -+++ b/include/internal/hindex.h -@@ -25,7 +25,7 @@ - - #include - #include ++ ++#elif !(defined(__SSE4_2__) && defined(__x86_64__)) ++/* Mhash-based implementation. */ ++ ++static inline uint32_t hash_add(uint32_t hash, uint32_t data) ++{ ++ return mhash_add(hash, data); ++} ++ ++static inline uint32_t hash_add64(uint32_t hash, uint64_t data) ++{ ++ return hash_add(hash_add(hash, data), data >> 32); ++} ++ ++static inline uint32_t hash_finish(uint32_t hash, uint32_t final) ++{ ++ return mhash_finish(hash ^ final); ++} ++ ++/* Returns the hash of the 'n' 32-bit words at 'p', starting from 'basis'. ++ * 'p' must be properly aligned. ++ * ++ * This is inlined for the compiler to have access to the 'n_words', which ++ * in many cases is a constant. */ ++static inline uint32_t ++hash_words_inline(const uint32_t *p, size_t n_words, uint32_t basis) ++{ ++ return hash_finish(hash_add_words(basis, p, n_words), n_words * 4); ++} ++ ++static inline uint32_t ++hash_words64_inline(const uint64_t *p, size_t n_words, uint32_t basis) ++{ ++ return hash_finish(hash_add_words64(basis, p, n_words), n_words * 8); ++} ++ ++static inline uint32_t hash_pointer(const void *p, uint32_t basis) ++{ ++ /* Often pointers are hashed simply by casting to integer type, but that ++ * has pitfalls since the lower bits of a pointer are often all 0 for ++ * alignment reasons. It's hard to guess where the entropy really is, so ++ * we give up here and just use a high-quality hash function. ++ * ++ * The double cast suppresses a warning on 64-bit systems about casting to ++ * an integer to different size. That's OK in this case, since most of the ++ * entropy in the pointer is almost certainly in the lower 32 bits. */ ++ return hash_int((uint32_t) (uintptr_t) p, basis); ++} ++ ++static inline uint32_t hash_2words(uint32_t x, uint32_t y) ++{ ++ return hash_finish(hash_add(hash_add(x, 0), y), 8); ++} ++ ++static inline uint32_t hash_uint64_basis(const uint64_t x, ++ const uint32_t basis) ++{ ++ return hash_finish(hash_add64(basis, x), 8); ++} ++ ++static inline uint32_t hash_uint64(const uint64_t x) ++{ ++ return hash_uint64_basis(x, 0); ++} ++ ++#else /* __SSE4_2__ && __x86_64__ */ ++#include ++ ++static inline uint32_t hash_add(uint32_t hash, uint32_t data) ++{ ++ return _mm_crc32_u32(hash, data); ++} ++ ++/* Add the halves of 'data' in the memory order. */ ++static inline uint32_t hash_add64(uint32_t hash, uint64_t data) ++{ ++ return _mm_crc32_u64(hash, data); ++} ++ ++static inline uint32_t hash_finish(uint64_t hash, uint64_t final) ++{ ++ /* The finishing multiplier 0x805204f3 has been experimentally ++ * derived to pass the testsuite hash tests. */ ++ hash = _mm_crc32_u64(hash, final) * 0x805204f3; ++ return hash ^ (uint32_t)hash >> 16; /* Increase entropy in LSBs. */ ++} ++ ++/* Returns the hash of the 'n' 32-bit words at 'p_', starting from 'basis'. ++ * We access 'p_' as a uint64_t pointer, which is fine for __SSE_4_2__. ++ * ++ * This is inlined for the compiler to have access to the 'n_words', which ++ * in many cases is a constant. */ ++static inline uint32_t ++hash_words_inline(const uint32_t p_[], size_t n_words, uint32_t basis) ++{ ++ const uint64_t *p = (const void *)p_; ++ uint64_t hash1 = basis; ++ uint64_t hash2 = 0; ++ uint64_t hash3 = n_words; ++ const uint32_t *endp = (const uint32_t *)p + n_words; ++ const uint64_t *limit = p + n_words / 2 - 3; ++ ++ while (p <= limit) { ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u64(hash2, p[1]); ++ hash3 = _mm_crc32_u64(hash3, p[2]); ++ p += 3; ++ } ++ switch (endp - (const uint32_t *)p) { ++ case 1: ++ hash1 = _mm_crc32_u32(hash1, *(const uint32_t *)&p[0]); ++ break; ++ case 2: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ break; ++ case 3: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u32(hash2, *(const uint32_t *)&p[1]); ++ break; ++ case 4: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u64(hash2, p[1]); ++ break; ++ case 5: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u64(hash2, p[1]); ++ hash3 = _mm_crc32_u32(hash3, *(const uint32_t *)&p[2]); ++ break; ++ } ++ return hash_finish(hash1, hash2 << 32 | hash3); ++} ++ ++/* A simpler version for 64-bit data. ++ * 'n_words' is the count of 64-bit words, basis is 64 bits. */ ++static inline uint32_t ++hash_words64_inline(const uint64_t *p, size_t n_words, uint32_t basis) ++{ ++ uint64_t hash1 = basis; ++ uint64_t hash2 = 0; ++ uint64_t hash3 = n_words; ++ const uint64_t *endp = p + n_words; ++ const uint64_t *limit = endp - 3; ++ ++ while (p <= limit) { ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u64(hash2, p[1]); ++ hash3 = _mm_crc32_u64(hash3, p[2]); ++ p += 3; ++ } ++ switch (endp - p) { ++ case 1: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ break; ++ case 2: ++ hash1 = _mm_crc32_u64(hash1, p[0]); ++ hash2 = _mm_crc32_u64(hash2, p[1]); ++ break; ++ } ++ return hash_finish(hash1, hash2 << 32 | hash3); ++} ++ ++static inline uint32_t hash_uint64_basis(const uint64_t x, ++ const uint32_t basis) ++{ ++ /* '23' chosen to mix bits enough for the test-hash to pass. */ ++ return hash_finish(hash_add64(basis, x), 23); ++} ++ ++static inline uint32_t hash_uint64(const uint64_t x) ++{ ++ return hash_uint64_basis(x, 0); ++} ++ ++static inline uint32_t hash_2words(uint32_t x, uint32_t y) ++{ ++ return hash_uint64((uint64_t)y << 32 | x); ++} ++ ++static inline uint32_t hash_pointer(const void *p, uint32_t basis) ++{ ++ return hash_uint64_basis((uint64_t) (uintptr_t) p, basis); ++} ++#endif ++ ++uint32_t hash_words__(const uint32_t *p, size_t n_words, uint32_t basis); ++uint32_t hash_words64__(const uint64_t *p, size_t n_words, uint32_t basis); ++ ++/* Inline the larger hash functions only when 'n_words' is known to be ++ * compile-time constant. */ ++#if __GNUC__ >= 4 ++static inline uint32_t ++hash_words(const uint32_t *p, size_t n_words, uint32_t basis) ++{ ++ if (__builtin_constant_p(n_words)) { ++ return hash_words_inline(p, n_words, basis); ++ } else { ++ return hash_words__(p, n_words, basis); ++ } ++} ++ ++static inline uint32_t ++hash_words64(const uint64_t *p, size_t n_words, uint32_t basis) ++{ ++ if (__builtin_constant_p(n_words)) { ++ return hash_words64_inline(p, n_words, basis); ++ } else { ++ return hash_words64__(p, n_words, basis); ++ } ++} ++ ++#else ++ ++static inline uint32_t ++hash_words(const uint32_t *p, size_t n_words, uint32_t basis) ++{ ++ return hash_words__(p, n_words, basis); ++} ++ ++static inline uint32_t ++hash_words64(const uint64_t *p, size_t n_words, uint32_t basis) ++{ ++ return hash_words64__(p, n_words, basis); ++} ++#endif ++ ++static inline uint32_t ++hash_bytes32(const uint32_t *p, size_t n_bytes, uint32_t basis) ++{ ++ return hash_words(p, n_bytes / 4, basis); ++} ++ ++static inline uint32_t ++hash_bytes64(const uint64_t *p, size_t n_bytes, uint32_t basis) ++{ ++ return hash_words64(p, n_bytes / 8, basis); ++} ++ ++static inline uint32_t hash_string(const char *s, uint32_t basis) ++{ ++ return hash_bytes(s, strlen(s), basis); ++} ++ ++static inline uint32_t hash_int(uint32_t x, uint32_t basis) ++{ ++ return hash_2words(x, basis); ++} ++ ++/* An attempt at a useful 1-bit hash function. Has not been analyzed for ++ * quality. */ ++static inline uint32_t hash_boolean(bool x, uint32_t basis) ++{ ++ const uint32_t P0 = 0xc2b73583; /* This is hash_int(1, 0). */ ++ const uint32_t P1 = 0xe90f1258; /* This is hash_int(2, 0). */ ++ return (x ? P0 : P1) ^ hash_rot(basis, 1); ++} ++ ++/* Helper functions for calling hash_add() for several 32- or 64-bit words in a ++ * buffer. These are not hash functions by themselves, since they need ++ * hash_finish() to be called, so if you are looking for a full hash function ++ * see hash_words(), etc. */ ++ ++static inline uint32_t ++hash_add_words(uint32_t hash, const uint32_t *p, size_t n_words) ++{ ++ for (size_t i = 0; i < n_words; i++) { ++ hash = hash_add(hash, p[i]); ++ } ++ return hash; ++} ++ ++static inline uint32_t ++hash_add_words64(uint32_t hash, const uint64_t *p, size_t n_words) ++{ ++ for (size_t i = 0; i < n_words; i++) { ++ hash = hash_add64(hash, p[i]); ++ } ++ return hash; ++} ++ ++static inline uint32_t ++hash_add_bytes32(uint32_t hash, const uint32_t *p, size_t n_bytes) ++{ ++ return hash_add_words(hash, p, n_bytes / 4); ++} ++ ++static inline uint32_t ++hash_add_bytes64(uint32_t hash, const uint64_t *p, size_t n_bytes) ++{ ++ return hash_add_words64(hash, p, n_bytes / 8); ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* hash.h */ +Index: openvswitch-2.17.2/lib/hindex.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/hindex.h ++++ /dev/null +@@ -1,222 +0,0 @@ +-/* +- * Copyright (c) 2013, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef HINDEX_H +-#define HINDEX_H 1 +- +-/* Hashed multimap. +- * +- * hindex is a hash table data structure that gracefully handles duplicates. +- * With a high-quality hash function, insertion, deletion, and search are O(1) +- * expected time, regardless of the number of duplicates for a given key. */ +- +-#include +-#include -#include "util.h" +- +-/* A hash index node, to embed inside the data structure being indexed. +- * +- * Nodes are linked together like this (the boxes are labeled with hash +- * values): +- * +- * +--------+ d +--------+ d +--------+ d +- * bucket---> | 6 |---->| 20 |---->| 15 |---->null +- * +-|------+ +-|------+ +-|------+ +- * | ^ | | ^ +- * s| |d |s s| |d +- * V | V V | +- * +------|-+ null +------|-+ +- * | 6 | | 15 | +- * +-|------+ +-|------+ +- * | ^ | +- * s| |d s| +- * V | V +- * +------|-+ null +- * | 6 | +- * +-|------+ +- * | +- * s| +- * V +- * null +- * +- * The basic usage is: +- * +- * - To visit the unique hash values in the hindex, follow the 'd' +- * ("different") pointers starting from each bucket. The nodes visited +- * this way are called "head" nodes, because they are at the head of the +- * vertical chains. +- * +- * - To visit the nodes with hash value H, follow the 'd' pointers in the +- * appropriate bucket until you find one with hash H, then follow the 's' +- * ("same") pointers until you hit a null pointer. The non-head nodes +- * visited this way are called "body" nodes. +- * +- * - The 'd' pointers in body nodes point back to the previous body node +- * or, for the first body node, to the head node. (This makes it +- * possible to remove a body node without traversing all the way downward +- * from the head). +- */ +-struct hindex_node { +- /* Hash value. */ +- size_t hash; +- +- /* In a head node, the next head node (with a hash different from this +- * node), or NULL if this is the last node in this bucket. +- * +- * In a body node, the previous head or body node (with the same hash as +- * this node). Never null. */ +- struct hindex_node *d; +- +- /* In a head or a body node, the next body node with the same hash as this +- * node. NULL if this is the last node with this hash. */ +- struct hindex_node *s; +-}; +- +-/* A hash index. */ +-struct hindex { +- struct hindex_node **buckets; /* Must point to 'one' iff 'mask' == 0. */ +- struct hindex_node *one; +- size_t mask; /* 0 or more lowest-order bits set, others cleared. */ +- size_t n_unique; /* Number of unique hashes (the number of head nodes). */ +-}; +- +-/* Initializer for an empty hash index. */ +-#define HINDEX_INITIALIZER(HINDEX) \ +- { (struct hindex_node **const) &(HINDEX)->one, NULL, 0, 0 } +- +-/* Initialization. */ +-void hindex_init(struct hindex *); +-void hindex_destroy(struct hindex *); +-void hindex_clear(struct hindex *); +-void hindex_swap(struct hindex *a, struct hindex *b); +-void hindex_moved(struct hindex *hindex); +-static inline bool hindex_is_empty(const struct hindex *); +- +-/* Adjusting capacity. */ +-void hindex_expand(struct hindex *); +-void hindex_shrink(struct hindex *); +-void hindex_reserve(struct hindex *, size_t capacity); +- +-/* Insertion and deletion. */ +-void hindex_insert_fast(struct hindex *, struct hindex_node *, size_t hash); +-void hindex_insert(struct hindex *, struct hindex_node *, size_t hash); +-void hindex_remove(struct hindex *, struct hindex_node *); +- +-/* Search. +- * +- * HINDEX_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HINDEX that +- * have hash value equal to HASH. MEMBER must be the name of the 'struct +- * hindex_node' member within NODE. +- * +- * The loop should not change NODE to point to a different node or insert or +- * delete nodes in HINDEX (unless it "break"s out of the loop to terminate +- * iteration). +- * +- * Evaluates HASH only once. +- */ +-#define HINDEX_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HINDEX) \ +- for (INIT_MULTIVAR(NODE, MEMBER, hindex_node_with_hash(HINDEX, HASH), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ +- UPDATE_MULTIVAR(NODE, ITER_VAR(NODE)->s)) +- +-/* Safe when NODE may be freed (not needed when NODE may be removed from the +- * hash map but its members remain accessible and intact). */ +-#define HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG(NODE, NEXT, MEMBER, HASH, HINDEX) \ +- for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ +- hindex_node_with_hash(HINDEX, HASH), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ +- ITER_VAR(NODE) != NULL, \ +- ITER_VAR(NEXT) = ITER_VAR(NODE)->s, \ +- ITER_VAR(NEXT) != NULL); \ +- UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT)) +- +-/* Short version of HINDEX_FOR_EACH_WITH_HASH_SAFE. */ +-#define HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT(NODE, MEMBER, HASH, HINDEX) \ +- for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ +- hindex_node_with_hash(HINDEX, HASH), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ +- ITER_VAR(NODE) != NULL, \ +- ITER_NEXT_VAR(NODE) = ITER_VAR(NODE)->s); \ +- UPDATE_MULTIVAR_SAFE_SHORT(NODE)) +- +-#define HINDEX_FOR_EACH_WITH_HASH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG, \ +- HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT, \ +- 5, __VA_ARGS__) +- +- +-/* Returns the head node in 'hindex' with the given 'hash', or a null pointer +- * if no nodes have that hash value. */ +-static inline struct hindex_node * +-hindex_node_with_hash(const struct hindex *hindex, size_t hash) +-{ +- struct hindex_node *node = hindex->buckets[hash & hindex->mask]; +- +- while (node && node->hash != hash) { +- node = node->d; +- } +- return node; +-} +- +-/* Iteration. */ +- +-/* Iterates through every node in HINDEX. */ +-#define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX) \ +- for (INIT_MULTIVAR(NODE, MEMBER, hindex_first(HINDEX), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ +- UPDATE_MULTIVAR(NODE, hindex_next(HINDEX, ITER_VAR(NODE)))) +- +-/* Safe when NODE may be freed (not needed when NODE may be removed from the +- * hash index but its members remain accessible and intact). */ +-#define HINDEX_FOR_EACH_SAFE_LONG(NODE, NEXT, MEMBER, HINDEX) \ +- for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, hindex_first(HINDEX), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ +- ITER_VAR(NODE) != NULL, \ +- ITER_VAR(NEXT) = hindex_next(HINDEX, ITER_VAR(NODE)), \ +- ITER_VAR(NEXT) != NULL); \ +- UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT)) +- +-/* Short version of HINDEX_FOR_EACH_SAFE. */ +-#define HINDEX_FOR_EACH_SAFE_SHORT(NODE, MEMBER, HINDEX) \ +- for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER, hindex_first(HINDEX), \ +- struct hindex_node); \ +- CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ +- ITER_VAR(NODE) != NULL, \ +- ITER_NEXT_VAR(NODE) = hindex_next(HINDEX, ITER_VAR(NODE))); \ +- UPDATE_MULTIVAR_SAFE_SHORT(NODE)) +- +-#define HINDEX_FOR_EACH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_SAFE_LONG, \ +- HINDEX_FOR_EACH_SAFE_SHORT, \ +- 4, __VA_ARGS__) +- +-struct hindex_node *hindex_first(const struct hindex *); +-struct hindex_node *hindex_next(const struct hindex *, +- const struct hindex_node *); +- +-/* Returns true if 'hindex' currently contains no nodes, false otherwise. */ +-static inline bool +-hindex_is_empty(const struct hindex *hindex) +-{ +- return hindex->n_unique == 0; +-} +- +-#endif /* hindex.h */ +Index: openvswitch-2.17.2/include/internal/hindex.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/hindex.h +@@ -0,0 +1,222 @@ ++/* ++ * Copyright (c) 2013, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef HINDEX_H ++#define HINDEX_H 1 ++ ++/* Hashed multimap. ++ * ++ * hindex is a hash table data structure that gracefully handles duplicates. ++ * With a high-quality hash function, insertion, deletion, and search are O(1) ++ * expected time, regardless of the number of duplicates for a given key. */ ++ ++#include ++#include +#include "internal/util.h" - - /* A hash index node, to embed inside the data structure being indexed. - * -diff --git a/lib/hmapx.h b/include/internal/hmapx.h -similarity index 100% -rename from lib/hmapx.h -rename to include/internal/hmapx.h -diff --git a/lib/id-pool.h b/include/internal/id-pool.h -similarity index 100% -rename from lib/id-pool.h -rename to include/internal/id-pool.h -diff --git a/lib/jsonrpc.h b/include/internal/jsonrpc.h -similarity index 100% -rename from lib/jsonrpc.h -rename to include/internal/jsonrpc.h -diff --git a/lib/latch.h b/include/internal/latch.h -similarity index 97% -rename from lib/latch.h -rename to include/internal/latch.h -index 3c0b842a1..c0b8aa6f1 100644 ---- a/lib/latch.h -+++ b/include/internal/latch.h -@@ -23,7 +23,7 @@ - * other that an event has occurred in a signal-safe way */ - - #include ++ ++/* A hash index node, to embed inside the data structure being indexed. ++ * ++ * Nodes are linked together like this (the boxes are labeled with hash ++ * values): ++ * ++ * +--------+ d +--------+ d +--------+ d ++ * bucket---> | 6 |---->| 20 |---->| 15 |---->null ++ * +-|------+ +-|------+ +-|------+ ++ * | ^ | | ^ ++ * s| |d |s s| |d ++ * V | V V | ++ * +------|-+ null +------|-+ ++ * | 6 | | 15 | ++ * +-|------+ +-|------+ ++ * | ^ | ++ * s| |d s| ++ * V | V ++ * +------|-+ null ++ * | 6 | ++ * +-|------+ ++ * | ++ * s| ++ * V ++ * null ++ * ++ * The basic usage is: ++ * ++ * - To visit the unique hash values in the hindex, follow the 'd' ++ * ("different") pointers starting from each bucket. The nodes visited ++ * this way are called "head" nodes, because they are at the head of the ++ * vertical chains. ++ * ++ * - To visit the nodes with hash value H, follow the 'd' pointers in the ++ * appropriate bucket until you find one with hash H, then follow the 's' ++ * ("same") pointers until you hit a null pointer. The non-head nodes ++ * visited this way are called "body" nodes. ++ * ++ * - The 'd' pointers in body nodes point back to the previous body node ++ * or, for the first body node, to the head node. (This makes it ++ * possible to remove a body node without traversing all the way downward ++ * from the head). ++ */ ++struct hindex_node { ++ /* Hash value. */ ++ size_t hash; ++ ++ /* In a head node, the next head node (with a hash different from this ++ * node), or NULL if this is the last node in this bucket. ++ * ++ * In a body node, the previous head or body node (with the same hash as ++ * this node). Never null. */ ++ struct hindex_node *d; ++ ++ /* In a head or a body node, the next body node with the same hash as this ++ * node. NULL if this is the last node with this hash. */ ++ struct hindex_node *s; ++}; ++ ++/* A hash index. */ ++struct hindex { ++ struct hindex_node **buckets; /* Must point to 'one' iff 'mask' == 0. */ ++ struct hindex_node *one; ++ size_t mask; /* 0 or more lowest-order bits set, others cleared. */ ++ size_t n_unique; /* Number of unique hashes (the number of head nodes). */ ++}; ++ ++/* Initializer for an empty hash index. */ ++#define HINDEX_INITIALIZER(HINDEX) \ ++ { (struct hindex_node **const) &(HINDEX)->one, NULL, 0, 0 } ++ ++/* Initialization. */ ++void hindex_init(struct hindex *); ++void hindex_destroy(struct hindex *); ++void hindex_clear(struct hindex *); ++void hindex_swap(struct hindex *a, struct hindex *b); ++void hindex_moved(struct hindex *hindex); ++static inline bool hindex_is_empty(const struct hindex *); ++ ++/* Adjusting capacity. */ ++void hindex_expand(struct hindex *); ++void hindex_shrink(struct hindex *); ++void hindex_reserve(struct hindex *, size_t capacity); ++ ++/* Insertion and deletion. */ ++void hindex_insert_fast(struct hindex *, struct hindex_node *, size_t hash); ++void hindex_insert(struct hindex *, struct hindex_node *, size_t hash); ++void hindex_remove(struct hindex *, struct hindex_node *); ++ ++/* Search. ++ * ++ * HINDEX_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HINDEX that ++ * have hash value equal to HASH. MEMBER must be the name of the 'struct ++ * hindex_node' member within NODE. ++ * ++ * The loop should not change NODE to point to a different node or insert or ++ * delete nodes in HINDEX (unless it "break"s out of the loop to terminate ++ * iteration). ++ * ++ * Evaluates HASH only once. ++ */ ++#define HINDEX_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HINDEX) \ ++ for (INIT_MULTIVAR(NODE, MEMBER, hindex_node_with_hash(HINDEX, HASH), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ ++ UPDATE_MULTIVAR(NODE, ITER_VAR(NODE)->s)) ++ ++/* Safe when NODE may be freed (not needed when NODE may be removed from the ++ * hash map but its members remain accessible and intact). */ ++#define HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG(NODE, NEXT, MEMBER, HASH, HINDEX) \ ++ for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ ++ hindex_node_with_hash(HINDEX, HASH), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ ++ ITER_VAR(NODE) != NULL, \ ++ ITER_VAR(NEXT) = ITER_VAR(NODE)->s, \ ++ ITER_VAR(NEXT) != NULL); \ ++ UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT)) ++ ++/* Short version of HINDEX_FOR_EACH_WITH_HASH_SAFE. */ ++#define HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT(NODE, MEMBER, HASH, HINDEX) \ ++ for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ ++ hindex_node_with_hash(HINDEX, HASH), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ ++ ITER_VAR(NODE) != NULL, \ ++ ITER_NEXT_VAR(NODE) = ITER_VAR(NODE)->s); \ ++ UPDATE_MULTIVAR_SAFE_SHORT(NODE)) ++ ++#define HINDEX_FOR_EACH_WITH_HASH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG, \ ++ HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT, \ ++ 5, __VA_ARGS__) ++ ++ ++/* Returns the head node in 'hindex' with the given 'hash', or a null pointer ++ * if no nodes have that hash value. */ ++static inline struct hindex_node * ++hindex_node_with_hash(const struct hindex *hindex, size_t hash) ++{ ++ struct hindex_node *node = hindex->buckets[hash & hindex->mask]; ++ ++ while (node && node->hash != hash) { ++ node = node->d; ++ } ++ return node; ++} ++ ++/* Iteration. */ ++ ++/* Iterates through every node in HINDEX. */ ++#define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX) \ ++ for (INIT_MULTIVAR(NODE, MEMBER, hindex_first(HINDEX), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ ++ UPDATE_MULTIVAR(NODE, hindex_next(HINDEX, ITER_VAR(NODE)))) ++ ++/* Safe when NODE may be freed (not needed when NODE may be removed from the ++ * hash index but its members remain accessible and intact). */ ++#define HINDEX_FOR_EACH_SAFE_LONG(NODE, NEXT, MEMBER, HINDEX) \ ++ for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, hindex_first(HINDEX), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, \ ++ ITER_VAR(NODE) != NULL, \ ++ ITER_VAR(NEXT) = hindex_next(HINDEX, ITER_VAR(NODE)), \ ++ ITER_VAR(NEXT) != NULL); \ ++ UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT)) ++ ++/* Short version of HINDEX_FOR_EACH_SAFE. */ ++#define HINDEX_FOR_EACH_SAFE_SHORT(NODE, MEMBER, HINDEX) \ ++ for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER, hindex_first(HINDEX), \ ++ struct hindex_node); \ ++ CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER, \ ++ ITER_VAR(NODE) != NULL, \ ++ ITER_NEXT_VAR(NODE) = hindex_next(HINDEX, ITER_VAR(NODE))); \ ++ UPDATE_MULTIVAR_SAFE_SHORT(NODE)) ++ ++#define HINDEX_FOR_EACH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_SAFE_LONG, \ ++ HINDEX_FOR_EACH_SAFE_SHORT, \ ++ 4, __VA_ARGS__) ++ ++struct hindex_node *hindex_first(const struct hindex *); ++struct hindex_node *hindex_next(const struct hindex *, ++ const struct hindex_node *); ++ ++/* Returns true if 'hindex' currently contains no nodes, false otherwise. */ ++static inline bool ++hindex_is_empty(const struct hindex *hindex) ++{ ++ return hindex->n_unique == 0; ++} ++ ++#endif /* hindex.h */ +Index: openvswitch-2.17.2/lib/latch.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/latch.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * Copyright (c) 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef LATCH_H +-#define LATCH_H 1 +- +-/* A thread-safe, signal-safe, pollable doorbell. +- * +- * This is a thin wrapper around a pipe that allows threads to notify each +- * other that an event has occurred in a signal-safe way */ +- +-#include -#include "util.h" +- +-struct latch { +-#ifndef _WIN32 +- int fds[2]; +-#else +- HANDLE wevent; +- bool is_set; +-#endif +-}; +- +-void latch_init(struct latch *); +-void latch_destroy(struct latch *); +- +-bool latch_poll(struct latch *); +-void latch_set(struct latch *); +- +-bool latch_is_set(const struct latch *); +-void latch_wait_at(const struct latch *, const char *where); +-#define latch_wait(latch) latch_wait_at(latch, OVS_SOURCE_LOCATOR) +- +-#endif /* latch.h */ +Index: openvswitch-2.17.2/include/internal/latch.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/latch.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef LATCH_H ++#define LATCH_H 1 ++ ++/* A thread-safe, signal-safe, pollable doorbell. ++ * ++ * This is a thin wrapper around a pipe that allows threads to notify each ++ * other that an event has occurred in a signal-safe way */ ++ ++#include +#include "internal/util.h" - - struct latch { - #ifndef _WIN32 -diff --git a/lib/mcast-snooping.h b/include/internal/mcast-snooping.h -similarity index 97% -rename from lib/mcast-snooping.h -rename to include/internal/mcast-snooping.h -index f120405da..babdcffe9 100644 ---- a/lib/mcast-snooping.h -+++ b/include/internal/mcast-snooping.h -@@ -20,13 +20,13 @@ - #define MCAST_SNOOPING_H 1 - - #include ++ ++struct latch { ++#ifndef _WIN32 ++ int fds[2]; ++#else ++ HANDLE wevent; ++ bool is_set; ++#endif ++}; ++ ++void latch_init(struct latch *); ++void latch_destroy(struct latch *); ++ ++bool latch_poll(struct latch *); ++void latch_set(struct latch *); ++ ++bool latch_is_set(const struct latch *); ++void latch_wait_at(const struct latch *, const char *where); ++#define latch_wait(latch) latch_wait_at(latch, OVS_SOURCE_LOCATOR) ++ ++#endif /* latch.h */ +Index: openvswitch-2.17.2/lib/mcast-snooping.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/mcast-snooping.h ++++ /dev/null +@@ -1,219 +0,0 @@ +-/* +- * Copyright (c) 2014 Red Hat, Inc. +- * +- * Based on mac-learning implementation. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef MCAST_SNOOPING_H +-#define MCAST_SNOOPING_H 1 +- +-#include -#include "dp-packet.h" -+#include "internal/dp-packet.h" - #include "openvswitch/hmap.h" - #include "openvswitch/list.h" +-#include "openvswitch/hmap.h" +-#include "openvswitch/list.h" -#include "ovs-atomic.h" -#include "ovs-thread.h" -#include "packets.h" -#include "timeval.h" +- +-struct mcast_snooping; +- +-/* Default maximum size of a mcast snooping table, in entries. */ +-#define MCAST_DEFAULT_MAX_ENTRIES 2048 +- +-/* Time, in seconds, before expiring a mcast_group due to inactivity. */ +-#define MCAST_ENTRY_DEFAULT_IDLE_TIME 300 +- +-/* Time, in seconds, before expiring a mrouter_port due to inactivity. */ +-#define MCAST_MROUTER_PORT_IDLE_TIME 180 +- +-/* Multicast group entry. +- * Guarded by owning 'mcast_snooping''s rwlock. */ +-struct mcast_group { +- /* Node in parent struct mcast_snooping hmap. */ +- struct hmap_node hmap_node; +- +- /* Multicast group IPv6/IPv4 address. */ +- struct in6_addr addr; +- +- /* VLAN tag. */ +- uint16_t vlan; +- +- /* Node in parent struct mcast_snooping group_lru. */ +- struct ovs_list group_node OVS_GUARDED; +- +- /* Contains struct mcast_group_bundle (ports), least recently used +- * at the front, most recently used at the back. */ +- struct ovs_list bundle_lru OVS_GUARDED; +-}; +- +-/* The bundle associated to the multicast group. +- * Guarded by owning 'mcast_snooping''s rwlock. */ +-struct mcast_group_bundle { +- /* Node in parent struct mcast_group bundle_lru list. */ +- struct ovs_list bundle_node OVS_GUARDED; +- +- /* When this node expires. */ +- time_t expires; +- +- /* Learned port. */ +- void *port OVS_GUARDED; +-}; +- +-/* The bundle connected to a multicast router. +- * Guarded by owning 'mcast_snooping''s rwlock. */ +-struct mcast_mrouter_bundle { +- /* Node in parent struct mcast_group mrouter_lru list. */ +- struct ovs_list mrouter_node OVS_GUARDED; +- +- /* When this node expires. */ +- time_t expires; +- +- /* VLAN tag. */ +- uint16_t vlan; +- +- /* Learned port. */ +- void *port OVS_GUARDED; +-}; +- +-/* The bundle to send multicast traffic or Reports. +- * Guarded by owning 'mcast_snooping''s rwlock */ +-struct mcast_port_bundle { +- /* Node in parent struct mcast_snooping. */ +- struct ovs_list node; +- +- /* VLAN tag. */ +- uint16_t vlan; +- +- /* Learned port. */ +- void *port; +-}; +- +-/* Multicast snooping table. */ +-struct mcast_snooping { +- /* Snooping/learning table. */ +- struct hmap table; +- +- /* Contains struct mcast_group, least recently used at the front, +- * most recently used at the back. */ +- struct ovs_list group_lru OVS_GUARDED; +- +- /* Contains struct mcast_mrouter_bundle, least recently used at the +- * front, most recently used at the back. */ +- struct ovs_list mrouter_lru OVS_GUARDED; +- +- /* Contains struct mcast_port_bundle to be flooded with multicast +- * packets in no special order. */ +- struct ovs_list fport_list OVS_GUARDED; +- +- /* Contains struct mcast_port_bundle to forward Reports in +- * no special order. */ +- struct ovs_list rport_list OVS_GUARDED; +- +- /* Secret for randomizing hash table. */ +- uint32_t secret; +- +- /* Maximum age before deleting an entry. */ +- unsigned int idle_time; +- +- /* Maximum number of multicast groups learned. */ +- size_t max_entries; +- +- /* True if flow revalidation is needed. */ +- bool need_revalidate; +- +- /* True if unregistered multicast packets should be flooded to all +- * ports, otherwise send them to ports connected to multicast routers. */ +- bool flood_unreg; +- +- struct ovs_refcount ref_cnt; +- struct ovs_rwlock rwlock; +-}; +- +-/* Basics. */ +-bool mcast_snooping_enabled(const struct mcast_snooping *ms); +-bool mcast_snooping_flood_unreg(const struct mcast_snooping *ms); +-int mcast_mrouter_age(const struct mcast_snooping *ms, +- const struct mcast_mrouter_bundle *m); +-int mcast_bundle_age(const struct mcast_snooping *ms, +- const struct mcast_group_bundle *b); +-struct mcast_snooping *mcast_snooping_create(void); +-struct mcast_snooping *mcast_snooping_ref(const struct mcast_snooping *); +-void mcast_snooping_unref(struct mcast_snooping *); +-bool mcast_snooping_run(struct mcast_snooping *ms); +-void mcast_snooping_wait(struct mcast_snooping *ms); +- +-/* Configuration. */ +-void mcast_snooping_set_idle_time(struct mcast_snooping *ms, +- unsigned int idle_time) +- OVS_REQ_WRLOCK(ms->rwlock); +-void mcast_snooping_set_max_entries(struct mcast_snooping *ms, +- size_t max_entries) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool +-mcast_snooping_set_flood_unreg(struct mcast_snooping *ms, bool enable) +- OVS_REQ_WRLOCK(ms->rwlock); +-void mcast_snooping_set_port_flood(struct mcast_snooping *ms, void *port, +- bool flood) +- OVS_REQ_WRLOCK(ms->rwlock); +-void mcast_snooping_set_port_flood_reports(struct mcast_snooping *ms, +- void *port, bool flood) +- OVS_REQ_WRLOCK(ms->rwlock); +- +-/* Lookup. */ +-struct mcast_group * +-mcast_snooping_lookup(const struct mcast_snooping *ms, +- const struct in6_addr *dip, uint16_t vlan) +- OVS_REQ_RDLOCK(ms->rwlock); +-struct mcast_group * +-mcast_snooping_lookup4(const struct mcast_snooping *ms, ovs_be32 ip4, +- uint16_t vlan) +- OVS_REQ_RDLOCK(ms->rwlock); +- +-/* Learning. */ +-bool mcast_snooping_add_group(struct mcast_snooping *ms, +- const struct in6_addr *addr, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool mcast_snooping_add_group4(struct mcast_snooping *ms, ovs_be32 ip4, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-int mcast_snooping_add_report(struct mcast_snooping *ms, +- const struct dp_packet *p, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-int mcast_snooping_add_mld(struct mcast_snooping *ms, +- const struct dp_packet *p, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool mcast_snooping_leave_group(struct mcast_snooping *ms, +- const struct in6_addr *addr, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool mcast_snooping_leave_group4(struct mcast_snooping *ms, ovs_be32 ip4, +- uint16_t vlan, void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool mcast_snooping_add_mrouter(struct mcast_snooping *ms, uint16_t vlan, +- void *port) +- OVS_REQ_WRLOCK(ms->rwlock); +-bool mcast_snooping_is_query(ovs_be16 igmp_type); +-bool mcast_snooping_is_membership(ovs_be16 igmp_type); +- +-/* Flush. */ +-void mcast_snooping_mdb_flush(struct mcast_snooping *ms); +-void mcast_snooping_flush(struct mcast_snooping *ms); +-void mcast_snooping_flush_bundle(struct mcast_snooping *ms, void *port); +- +-#endif /* mcast-snooping.h */ +Index: openvswitch-2.17.2/include/internal/mcast-snooping.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/mcast-snooping.h +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (c) 2014 Red Hat, Inc. ++ * ++ * Based on mac-learning implementation. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef MCAST_SNOOPING_H ++#define MCAST_SNOOPING_H 1 ++ ++#include ++#include "internal/dp-packet.h" ++#include "openvswitch/hmap.h" ++#include "openvswitch/list.h" +#include "openvswitch/ovs-atomic.h" +#include "openvswitch/ovs-thread.h" +#include "internal/packets.h" +#include "internal/timeval.h" - - struct mcast_snooping; - -diff --git a/lib/memory.h b/include/internal/memory.h -similarity index 100% -rename from lib/memory.h -rename to include/internal/memory.h -diff --git a/lib/netdev-afxdp.h b/include/internal/netdev-afxdp.h -similarity index 100% -rename from lib/netdev-afxdp.h -rename to include/internal/netdev-afxdp.h -diff --git a/lib/netdev-dpdk.h b/include/internal/netdev-dpdk.h -similarity index 100% -rename from lib/netdev-dpdk.h -rename to include/internal/netdev-dpdk.h -diff --git a/lib/netdev.h b/include/internal/netdev.h -similarity index 99% -rename from lib/netdev.h -rename to include/internal/netdev.h -index acf174927..9da79e39f 100644 ---- a/lib/netdev.h -+++ b/include/internal/netdev.h -@@ -19,8 +19,8 @@ - - #include "openvswitch/netdev.h" - #include "openvswitch/types.h" ++ ++struct mcast_snooping; ++ ++/* Default maximum size of a mcast snooping table, in entries. */ ++#define MCAST_DEFAULT_MAX_ENTRIES 2048 ++ ++/* Time, in seconds, before expiring a mcast_group due to inactivity. */ ++#define MCAST_ENTRY_DEFAULT_IDLE_TIME 300 ++ ++/* Time, in seconds, before expiring a mrouter_port due to inactivity. */ ++#define MCAST_MROUTER_PORT_IDLE_TIME 180 ++ ++/* Multicast group entry. ++ * Guarded by owning 'mcast_snooping''s rwlock. */ ++struct mcast_group { ++ /* Node in parent struct mcast_snooping hmap. */ ++ struct hmap_node hmap_node; ++ ++ /* Multicast group IPv6/IPv4 address. */ ++ struct in6_addr addr; ++ ++ /* VLAN tag. */ ++ uint16_t vlan; ++ ++ /* Node in parent struct mcast_snooping group_lru. */ ++ struct ovs_list group_node OVS_GUARDED; ++ ++ /* Contains struct mcast_group_bundle (ports), least recently used ++ * at the front, most recently used at the back. */ ++ struct ovs_list bundle_lru OVS_GUARDED; ++}; ++ ++/* The bundle associated to the multicast group. ++ * Guarded by owning 'mcast_snooping''s rwlock. */ ++struct mcast_group_bundle { ++ /* Node in parent struct mcast_group bundle_lru list. */ ++ struct ovs_list bundle_node OVS_GUARDED; ++ ++ /* When this node expires. */ ++ time_t expires; ++ ++ /* Learned port. */ ++ void *port OVS_GUARDED; ++}; ++ ++/* The bundle connected to a multicast router. ++ * Guarded by owning 'mcast_snooping''s rwlock. */ ++struct mcast_mrouter_bundle { ++ /* Node in parent struct mcast_group mrouter_lru list. */ ++ struct ovs_list mrouter_node OVS_GUARDED; ++ ++ /* When this node expires. */ ++ time_t expires; ++ ++ /* VLAN tag. */ ++ uint16_t vlan; ++ ++ /* Learned port. */ ++ void *port OVS_GUARDED; ++}; ++ ++/* The bundle to send multicast traffic or Reports. ++ * Guarded by owning 'mcast_snooping''s rwlock */ ++struct mcast_port_bundle { ++ /* Node in parent struct mcast_snooping. */ ++ struct ovs_list node; ++ ++ /* VLAN tag. */ ++ uint16_t vlan; ++ ++ /* Learned port. */ ++ void *port; ++}; ++ ++/* Multicast snooping table. */ ++struct mcast_snooping { ++ /* Snooping/learning table. */ ++ struct hmap table; ++ ++ /* Contains struct mcast_group, least recently used at the front, ++ * most recently used at the back. */ ++ struct ovs_list group_lru OVS_GUARDED; ++ ++ /* Contains struct mcast_mrouter_bundle, least recently used at the ++ * front, most recently used at the back. */ ++ struct ovs_list mrouter_lru OVS_GUARDED; ++ ++ /* Contains struct mcast_port_bundle to be flooded with multicast ++ * packets in no special order. */ ++ struct ovs_list fport_list OVS_GUARDED; ++ ++ /* Contains struct mcast_port_bundle to forward Reports in ++ * no special order. */ ++ struct ovs_list rport_list OVS_GUARDED; ++ ++ /* Secret for randomizing hash table. */ ++ uint32_t secret; ++ ++ /* Maximum age before deleting an entry. */ ++ unsigned int idle_time; ++ ++ /* Maximum number of multicast groups learned. */ ++ size_t max_entries; ++ ++ /* True if flow revalidation is needed. */ ++ bool need_revalidate; ++ ++ /* True if unregistered multicast packets should be flooded to all ++ * ports, otherwise send them to ports connected to multicast routers. */ ++ bool flood_unreg; ++ ++ struct ovs_refcount ref_cnt; ++ struct ovs_rwlock rwlock; ++}; ++ ++/* Basics. */ ++bool mcast_snooping_enabled(const struct mcast_snooping *ms); ++bool mcast_snooping_flood_unreg(const struct mcast_snooping *ms); ++int mcast_mrouter_age(const struct mcast_snooping *ms, ++ const struct mcast_mrouter_bundle *m); ++int mcast_bundle_age(const struct mcast_snooping *ms, ++ const struct mcast_group_bundle *b); ++struct mcast_snooping *mcast_snooping_create(void); ++struct mcast_snooping *mcast_snooping_ref(const struct mcast_snooping *); ++void mcast_snooping_unref(struct mcast_snooping *); ++bool mcast_snooping_run(struct mcast_snooping *ms); ++void mcast_snooping_wait(struct mcast_snooping *ms); ++ ++/* Configuration. */ ++void mcast_snooping_set_idle_time(struct mcast_snooping *ms, ++ unsigned int idle_time) ++ OVS_REQ_WRLOCK(ms->rwlock); ++void mcast_snooping_set_max_entries(struct mcast_snooping *ms, ++ size_t max_entries) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool ++mcast_snooping_set_flood_unreg(struct mcast_snooping *ms, bool enable) ++ OVS_REQ_WRLOCK(ms->rwlock); ++void mcast_snooping_set_port_flood(struct mcast_snooping *ms, void *port, ++ bool flood) ++ OVS_REQ_WRLOCK(ms->rwlock); ++void mcast_snooping_set_port_flood_reports(struct mcast_snooping *ms, ++ void *port, bool flood) ++ OVS_REQ_WRLOCK(ms->rwlock); ++ ++/* Lookup. */ ++struct mcast_group * ++mcast_snooping_lookup(const struct mcast_snooping *ms, ++ const struct in6_addr *dip, uint16_t vlan) ++ OVS_REQ_RDLOCK(ms->rwlock); ++struct mcast_group * ++mcast_snooping_lookup4(const struct mcast_snooping *ms, ovs_be32 ip4, ++ uint16_t vlan) ++ OVS_REQ_RDLOCK(ms->rwlock); ++ ++/* Learning. */ ++bool mcast_snooping_add_group(struct mcast_snooping *ms, ++ const struct in6_addr *addr, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool mcast_snooping_add_group4(struct mcast_snooping *ms, ovs_be32 ip4, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++int mcast_snooping_add_report(struct mcast_snooping *ms, ++ const struct dp_packet *p, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++int mcast_snooping_add_mld(struct mcast_snooping *ms, ++ const struct dp_packet *p, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool mcast_snooping_leave_group(struct mcast_snooping *ms, ++ const struct in6_addr *addr, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool mcast_snooping_leave_group4(struct mcast_snooping *ms, ovs_be32 ip4, ++ uint16_t vlan, void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool mcast_snooping_add_mrouter(struct mcast_snooping *ms, uint16_t vlan, ++ void *port) ++ OVS_REQ_WRLOCK(ms->rwlock); ++bool mcast_snooping_is_query(ovs_be16 igmp_type); ++bool mcast_snooping_is_membership(ovs_be16 igmp_type); ++ ++/* Flush. */ ++void mcast_snooping_mdb_flush(struct mcast_snooping *ms); ++void mcast_snooping_flush(struct mcast_snooping *ms); ++void mcast_snooping_flush_bundle(struct mcast_snooping *ms, void *port); ++ ++#endif /* mcast-snooping.h */ +Index: openvswitch-2.17.2/lib/netdev.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev.h ++++ /dev/null +@@ -1,364 +0,0 @@ +-/* +- * 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NETDEV_H +-#define NETDEV_H 1 +- +-#include "openvswitch/netdev.h" +-#include "openvswitch/types.h" -#include "packets.h" -#include "flow.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* Generic interface to network devices ("netdev"s). +- * +- * Every port on a switch must have a corresponding netdev that must minimally +- * support a few operations, such as the ability to read the netdev's MTU. +- * The Porting section of the documentation has more information in the +- * "Writing a netdev Provider" section. +- * +- * Thread-safety +- * ============= +- * +- * Most of the netdev functions are fully thread-safe: they may be called from +- * any number of threads on the same or different netdev objects. The +- * exceptions are: +- * +- * netdev_rxq_recv() +- * netdev_rxq_wait() +- * netdev_rxq_drain() +- * +- * These functions are conditionally thread-safe: they may be called from +- * different threads only on different netdev_rxq objects. (The client may +- * create multiple netdev_rxq objects for a single netdev and access each +- * of those from a different thread.) +- * +- * NETDEV_QUEUE_FOR_EACH +- * netdev_queue_dump_next() +- * netdev_queue_dump_done() +- * +- * These functions are conditionally thread-safe: they may be called from +- * different threads only on different netdev_queue_dump objects. (The +- * client may create multiple netdev_queue_dump objects for a single +- * netdev and access each of those from a different thread.) +- */ +- +-struct dp_packet_batch; +-struct dp_packet; +-struct netdev_class; +-struct netdev_rxq; +-struct netdev_saved_flags; +-struct ofpbuf; +-struct in_addr; +-struct in6_addr; +-struct smap; +-struct sset; +-struct ovs_action_push_tnl; +- +-enum netdev_pt_mode { +- /* The netdev is packet type aware. It can potentially carry any kind of +- * packet. This "modern" mode is appropriate for both netdevs that handle +- * only a single kind of packet (such as a virtual or physical Ethernet +- * interface) and for those that can handle multiple (such as VXLAN-GPE or +- * Geneve). */ +- NETDEV_PT_AWARE, +- +- /* The netdev sends and receives only Ethernet frames. The netdev cannot +- * carry packets other than Ethernet frames. This is a legacy mode for +- * backward compability with controllers that are not prepared to handle +- * OpenFlow 1.5+ "packet_type". */ +- NETDEV_PT_LEGACY_L2, +- +- /* The netdev sends and receives only IPv4 and IPv6 packets. The netdev +- * cannot carry Ethernet frames or other kinds of packets. +- * +- * IPv4 and IPv6 packets carried over the netdev are treated as Ethernet: +- * when they are received, they are converted to Ethernet by adding a dummy +- * header with the proper Ethertype; on tranmission, the Ethernet header is +- * stripped. This is a legacy mode for backward compability with +- * controllers that are not prepared to handle OpenFlow 1.5+ +- * "packet_type". */ +- NETDEV_PT_LEGACY_L3, +-}; +- +-/* Configuration specific to tunnels. */ +-struct netdev_tunnel_config { +- ovs_be64 in_key; +- bool in_key_present; +- bool in_key_flow; +- +- bool out_key_present; +- bool out_key_flow; +- ovs_be64 out_key; +- +- ovs_be16 payload_ethertype; +- ovs_be16 dst_port; +- +- bool ip_src_flow; +- bool ip_dst_flow; +- struct in6_addr ipv6_src; +- struct in6_addr ipv6_dst; +- +- uint32_t exts; +- uint32_t egress_pkt_mark; +- bool set_egress_pkt_mark; +- +- uint8_t ttl; +- bool ttl_inherit; +- +- uint8_t tos; +- bool tos_inherit; +- +- bool csum; +- bool dont_fragment; +- enum netdev_pt_mode pt_mode; +- +- bool set_seq; +- uint32_t seqno; +- uint32_t erspan_idx; +- uint8_t erspan_ver; +- uint8_t erspan_dir; +- uint8_t erspan_hwid; +- +- bool erspan_ver_flow; +- bool erspan_idx_flow; +- bool erspan_dir_flow; +- bool erspan_hwid_flow; +-}; +- +-void netdev_run(void); +-void netdev_wait(void); +- +-void netdev_enumerate_types(struct sset *types); +-bool netdev_is_reserved_name(const char *name); +- +-int netdev_n_txq(const struct netdev *netdev); +-int netdev_n_rxq(const struct netdev *netdev); +-bool netdev_is_pmd(const struct netdev *netdev); +-bool netdev_has_tunnel_push_pop(const struct netdev *netdev); +- +-/* Open and close. */ +-int netdev_open(const char *name, const char *type, struct netdev **netdevp); +- +-struct netdev *netdev_ref(const struct netdev *); +-void netdev_remove(struct netdev *); +-void netdev_close(struct netdev *); +- +-void netdev_parse_name(const char *netdev_name, char **name, char **type); +- +-/* Options. */ +-int netdev_set_config(struct netdev *, const struct smap *args, char **errp); +-int netdev_get_config(const struct netdev *, struct smap *); +-const struct netdev_tunnel_config * +- netdev_get_tunnel_config(const struct netdev *); +-int netdev_get_numa_id(const struct netdev *); +- +-/* Basic properties. */ +-const char *netdev_get_name(const struct netdev *); +-const char *netdev_get_type(const struct netdev *); +-const char *netdev_get_type_from_name(const char *); +-int netdev_get_mtu(const struct netdev *, int *mtup); +-int netdev_set_mtu(struct netdev *, int mtu); +-void netdev_mtu_user_config(struct netdev *, bool); +-bool netdev_mtu_is_user_config(struct netdev *); +-int netdev_get_ifindex(const struct netdev *); +-int netdev_set_tx_multiq(struct netdev *, unsigned int n_txq); +-enum netdev_pt_mode netdev_get_pt_mode(const struct netdev *); +-void netdev_set_dpif_type(struct netdev *, const char *); +-const char *netdev_get_dpif_type(const struct netdev *); +- +-/* Packet reception. */ +-int netdev_rxq_open(struct netdev *, struct netdev_rxq **, int id); +-void netdev_rxq_close(struct netdev_rxq *); +-bool netdev_rxq_enabled(struct netdev_rxq *); +- +-const char *netdev_rxq_get_name(const struct netdev_rxq *); +-int netdev_rxq_get_queue_id(const struct netdev_rxq *); +- +-int netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet_batch *, +- int *qfill); +-void netdev_rxq_wait(struct netdev_rxq *); +-int netdev_rxq_drain(struct netdev_rxq *); +- +-/* Packet transmission. */ +-int netdev_send(struct netdev *, int qid, struct dp_packet_batch *, +- bool concurrent_txq); +-void netdev_send_wait(struct netdev *, int qid); +- +-/* native tunnel APIs */ +-/* Structure to pass parameters required to build a tunnel header. */ +-struct netdev_tnl_build_header_params { +- const struct flow *flow; +- const struct in6_addr *s_ip; +- struct eth_addr dmac; +- struct eth_addr smac; +- bool is_ipv6; +-}; +- +-void +-netdev_init_tnl_build_header_params(struct netdev_tnl_build_header_params *params, +- const struct flow *tnl_flow, +- const struct in6_addr *src, +- struct eth_addr dmac, +- struct eth_addr smac); +- +-int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data, +- const struct netdev_tnl_build_header_params *params); +- +-int netdev_push_header(const struct netdev *netdev, +- struct dp_packet_batch *, +- const struct ovs_action_push_tnl *data); +-void netdev_pop_header(struct netdev *netdev, struct dp_packet_batch *); +- +-/* Hardware address. */ +-int netdev_set_etheraddr(struct netdev *, const struct eth_addr mac); +-int netdev_get_etheraddr(const struct netdev *, struct eth_addr *mac); +- +-/* PHY interface. */ +-bool netdev_get_carrier(const struct netdev *); +-long long int netdev_get_carrier_resets(const struct netdev *); +-int netdev_set_miimon_interval(struct netdev *, long long int interval); +- +-/* Flags. */ +-enum netdev_flags { +- NETDEV_UP = 0x0001, /* Device enabled? */ +- NETDEV_PROMISC = 0x0002, /* Promiscuous mode? */ +- NETDEV_LOOPBACK = 0x0004 /* This is a loopback device. */ +-}; +- +-int netdev_get_flags(const struct netdev *, enum netdev_flags *); +-int netdev_set_flags(struct netdev *, enum netdev_flags, +- struct netdev_saved_flags **); +-int netdev_turn_flags_on(struct netdev *, enum netdev_flags, +- struct netdev_saved_flags **); +-int netdev_turn_flags_off(struct netdev *, enum netdev_flags, +- struct netdev_saved_flags **); +- +-void netdev_restore_flags(struct netdev_saved_flags *); +- +-/* TCP/IP stack interface. */ +-int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask); +-int netdev_get_in4_by_name(const char *device_name, struct in_addr *in4); +-int netdev_get_ip_by_name(const char *device_name, struct in6_addr *); +-int netdev_get_addr_list(const struct netdev *netdev, struct in6_addr **addr, +- struct in6_addr **mask, int *n_in6); +- +-int netdev_add_router(struct netdev *, struct in_addr router); +-int netdev_get_next_hop(const struct netdev *, const struct in_addr *host, +- struct in_addr *next_hop, char **); +-int netdev_get_status(const struct netdev *, struct smap *); +-int netdev_arp_lookup(const struct netdev *, ovs_be32 ip, +- struct eth_addr *mac); +- +-struct netdev *netdev_find_dev_by_in4(const struct in_addr *); +- +-/* Statistics. */ +-int netdev_get_stats(const struct netdev *, struct netdev_stats *); +-int netdev_get_custom_stats(const struct netdev *, +- struct netdev_custom_stats *); +- +-/* Quality of service. */ +-struct netdev_qos_capabilities { +- unsigned int n_queues; +-}; +- +-struct netdev_queue_stats { +- /* Values of unsupported statistics are set to all-1-bits (UINT64_MAX). */ +- uint64_t tx_bytes; +- uint64_t tx_packets; +- uint64_t tx_errors; +- +- /* Time at which the queue was created, in msecs, LLONG_MIN if unknown. */ +- long long int created; +-}; +- +-int netdev_set_policing(struct netdev *, uint32_t kbits_rate, +- uint32_t kbits_burst, uint32_t kpkts_rate, +- uint32_t kpkts_burst); +- +-int netdev_get_qos_types(const struct netdev *, struct sset *types); +-int netdev_get_qos_capabilities(const struct netdev *, +- const char *type, +- struct netdev_qos_capabilities *); +-int netdev_get_n_queues(const struct netdev *, +- const char *type, unsigned int *n_queuesp); +- +-int netdev_get_qos(const struct netdev *, +- const char **typep, struct smap *details); +-int netdev_set_qos(struct netdev *, +- const char *type, const struct smap *details); +- +-int netdev_get_queue(const struct netdev *, +- unsigned int queue_id, struct smap *details); +-int netdev_set_queue(struct netdev *, +- unsigned int queue_id, const struct smap *details); +-int netdev_delete_queue(struct netdev *, unsigned int queue_id); +-int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id, +- struct netdev_queue_stats *); +-uint64_t netdev_get_change_seq(const struct netdev *); +- +-int netdev_reconfigure(struct netdev *netdev); +-void netdev_wait_reconf_required(struct netdev *netdev); +-bool netdev_is_reconf_required(struct netdev *netdev); +- +-struct netdev_queue_dump { +- struct netdev *netdev; +- int error; +- void *state; +-}; +-void netdev_queue_dump_start(struct netdev_queue_dump *, +- const struct netdev *); +-bool netdev_queue_dump_next(struct netdev_queue_dump *, +- unsigned int *queue_id, struct smap *details); +-int netdev_queue_dump_done(struct netdev_queue_dump *); +- +-/* Iterates through each queue in NETDEV, using DUMP as state. Fills QUEUE_ID +- * and DETAILS with information about queues. The client must initialize and +- * destroy DETAILS. +- * +- * Arguments all have pointer type. +- * +- * If you break out of the loop, then you need to free the dump structure by +- * hand using netdev_queue_dump_done(). */ +-#define NETDEV_QUEUE_FOR_EACH(QUEUE_ID, DETAILS, DUMP, NETDEV) \ +- for (netdev_queue_dump_start(DUMP, NETDEV); \ +- (netdev_queue_dump_next(DUMP, QUEUE_ID, DETAILS) \ +- ? true \ +- : (netdev_queue_dump_done(DUMP), false)); \ +- ) +- +-typedef void netdev_dump_queue_stats_cb(unsigned int queue_id, +- struct netdev_queue_stats *, +- void *aux); +-int netdev_dump_queue_stats(const struct netdev *, +- netdev_dump_queue_stats_cb *, void *aux); +- +-extern struct seq *tnl_conf_seq; +- +-#ifndef _WIN32 +-void netdev_get_addrs_list_flush(void); +-int netdev_get_addrs(const char dev[], struct in6_addr **paddr, +- struct in6_addr **pmask, int *n_in6); +-#endif +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* netdev.h */ +Index: openvswitch-2.17.2/include/internal/netdev.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/netdev.h +@@ -0,0 +1,364 @@ ++/* ++ * 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NETDEV_H ++#define NETDEV_H 1 ++ ++#include "openvswitch/netdev.h" ++#include "openvswitch/types.h" +#include "internal/packets.h" +#include "internal/flow.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/netlink-protocol.h b/include/internal/netlink-protocol.h -similarity index 99% -rename from lib/netlink-protocol.h -rename to include/internal/netlink-protocol.h -index 6eaa7035a..50bbf3049 100644 ---- a/lib/netlink-protocol.h -+++ b/include/internal/netlink-protocol.h -@@ -31,7 +31,7 @@ - - #include - #include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Generic interface to network devices ("netdev"s). ++ * ++ * Every port on a switch must have a corresponding netdev that must minimally ++ * support a few operations, such as the ability to read the netdev's MTU. ++ * The Porting section of the documentation has more information in the ++ * "Writing a netdev Provider" section. ++ * ++ * Thread-safety ++ * ============= ++ * ++ * Most of the netdev functions are fully thread-safe: they may be called from ++ * any number of threads on the same or different netdev objects. The ++ * exceptions are: ++ * ++ * netdev_rxq_recv() ++ * netdev_rxq_wait() ++ * netdev_rxq_drain() ++ * ++ * These functions are conditionally thread-safe: they may be called from ++ * different threads only on different netdev_rxq objects. (The client may ++ * create multiple netdev_rxq objects for a single netdev and access each ++ * of those from a different thread.) ++ * ++ * NETDEV_QUEUE_FOR_EACH ++ * netdev_queue_dump_next() ++ * netdev_queue_dump_done() ++ * ++ * These functions are conditionally thread-safe: they may be called from ++ * different threads only on different netdev_queue_dump objects. (The ++ * client may create multiple netdev_queue_dump objects for a single ++ * netdev and access each of those from a different thread.) ++ */ ++ ++struct dp_packet_batch; ++struct dp_packet; ++struct netdev_class; ++struct netdev_rxq; ++struct netdev_saved_flags; ++struct ofpbuf; ++struct in_addr; ++struct in6_addr; ++struct smap; ++struct sset; ++struct ovs_action_push_tnl; ++ ++enum netdev_pt_mode { ++ /* The netdev is packet type aware. It can potentially carry any kind of ++ * packet. This "modern" mode is appropriate for both netdevs that handle ++ * only a single kind of packet (such as a virtual or physical Ethernet ++ * interface) and for those that can handle multiple (such as VXLAN-GPE or ++ * Geneve). */ ++ NETDEV_PT_AWARE, ++ ++ /* The netdev sends and receives only Ethernet frames. The netdev cannot ++ * carry packets other than Ethernet frames. This is a legacy mode for ++ * backward compability with controllers that are not prepared to handle ++ * OpenFlow 1.5+ "packet_type". */ ++ NETDEV_PT_LEGACY_L2, ++ ++ /* The netdev sends and receives only IPv4 and IPv6 packets. The netdev ++ * cannot carry Ethernet frames or other kinds of packets. ++ * ++ * IPv4 and IPv6 packets carried over the netdev are treated as Ethernet: ++ * when they are received, they are converted to Ethernet by adding a dummy ++ * header with the proper Ethertype; on tranmission, the Ethernet header is ++ * stripped. This is a legacy mode for backward compability with ++ * controllers that are not prepared to handle OpenFlow 1.5+ ++ * "packet_type". */ ++ NETDEV_PT_LEGACY_L3, ++}; ++ ++/* Configuration specific to tunnels. */ ++struct netdev_tunnel_config { ++ ovs_be64 in_key; ++ bool in_key_present; ++ bool in_key_flow; ++ ++ bool out_key_present; ++ bool out_key_flow; ++ ovs_be64 out_key; ++ ++ ovs_be16 payload_ethertype; ++ ovs_be16 dst_port; ++ ++ bool ip_src_flow; ++ bool ip_dst_flow; ++ struct in6_addr ipv6_src; ++ struct in6_addr ipv6_dst; ++ ++ uint32_t exts; ++ uint32_t egress_pkt_mark; ++ bool set_egress_pkt_mark; ++ ++ uint8_t ttl; ++ bool ttl_inherit; ++ ++ uint8_t tos; ++ bool tos_inherit; ++ ++ bool csum; ++ bool dont_fragment; ++ enum netdev_pt_mode pt_mode; ++ ++ bool set_seq; ++ uint32_t seqno; ++ uint32_t erspan_idx; ++ uint8_t erspan_ver; ++ uint8_t erspan_dir; ++ uint8_t erspan_hwid; ++ ++ bool erspan_ver_flow; ++ bool erspan_idx_flow; ++ bool erspan_dir_flow; ++ bool erspan_hwid_flow; ++}; ++ ++void netdev_run(void); ++void netdev_wait(void); ++ ++void netdev_enumerate_types(struct sset *types); ++bool netdev_is_reserved_name(const char *name); ++ ++int netdev_n_txq(const struct netdev *netdev); ++int netdev_n_rxq(const struct netdev *netdev); ++bool netdev_is_pmd(const struct netdev *netdev); ++bool netdev_has_tunnel_push_pop(const struct netdev *netdev); ++ ++/* Open and close. */ ++int netdev_open(const char *name, const char *type, struct netdev **netdevp); ++ ++struct netdev *netdev_ref(const struct netdev *); ++void netdev_remove(struct netdev *); ++void netdev_close(struct netdev *); ++ ++void netdev_parse_name(const char *netdev_name, char **name, char **type); ++ ++/* Options. */ ++int netdev_set_config(struct netdev *, const struct smap *args, char **errp); ++int netdev_get_config(const struct netdev *, struct smap *); ++const struct netdev_tunnel_config * ++ netdev_get_tunnel_config(const struct netdev *); ++int netdev_get_numa_id(const struct netdev *); ++ ++/* Basic properties. */ ++const char *netdev_get_name(const struct netdev *); ++const char *netdev_get_type(const struct netdev *); ++const char *netdev_get_type_from_name(const char *); ++int netdev_get_mtu(const struct netdev *, int *mtup); ++int netdev_set_mtu(struct netdev *, int mtu); ++void netdev_mtu_user_config(struct netdev *, bool); ++bool netdev_mtu_is_user_config(struct netdev *); ++int netdev_get_ifindex(const struct netdev *); ++int netdev_set_tx_multiq(struct netdev *, unsigned int n_txq); ++enum netdev_pt_mode netdev_get_pt_mode(const struct netdev *); ++void netdev_set_dpif_type(struct netdev *, const char *); ++const char *netdev_get_dpif_type(const struct netdev *); ++ ++/* Packet reception. */ ++int netdev_rxq_open(struct netdev *, struct netdev_rxq **, int id); ++void netdev_rxq_close(struct netdev_rxq *); ++bool netdev_rxq_enabled(struct netdev_rxq *); ++ ++const char *netdev_rxq_get_name(const struct netdev_rxq *); ++int netdev_rxq_get_queue_id(const struct netdev_rxq *); ++ ++int netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet_batch *, ++ int *qfill); ++void netdev_rxq_wait(struct netdev_rxq *); ++int netdev_rxq_drain(struct netdev_rxq *); ++ ++/* Packet transmission. */ ++int netdev_send(struct netdev *, int qid, struct dp_packet_batch *, ++ bool concurrent_txq); ++void netdev_send_wait(struct netdev *, int qid); ++ ++/* native tunnel APIs */ ++/* Structure to pass parameters required to build a tunnel header. */ ++struct netdev_tnl_build_header_params { ++ const struct flow *flow; ++ const struct in6_addr *s_ip; ++ struct eth_addr dmac; ++ struct eth_addr smac; ++ bool is_ipv6; ++}; ++ ++void ++netdev_init_tnl_build_header_params(struct netdev_tnl_build_header_params *params, ++ const struct flow *tnl_flow, ++ const struct in6_addr *src, ++ struct eth_addr dmac, ++ struct eth_addr smac); ++ ++int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data, ++ const struct netdev_tnl_build_header_params *params); ++ ++int netdev_push_header(const struct netdev *netdev, ++ struct dp_packet_batch *, ++ const struct ovs_action_push_tnl *data); ++void netdev_pop_header(struct netdev *netdev, struct dp_packet_batch *); ++ ++/* Hardware address. */ ++int netdev_set_etheraddr(struct netdev *, const struct eth_addr mac); ++int netdev_get_etheraddr(const struct netdev *, struct eth_addr *mac); ++ ++/* PHY interface. */ ++bool netdev_get_carrier(const struct netdev *); ++long long int netdev_get_carrier_resets(const struct netdev *); ++int netdev_set_miimon_interval(struct netdev *, long long int interval); ++ ++/* Flags. */ ++enum netdev_flags { ++ NETDEV_UP = 0x0001, /* Device enabled? */ ++ NETDEV_PROMISC = 0x0002, /* Promiscuous mode? */ ++ NETDEV_LOOPBACK = 0x0004 /* This is a loopback device. */ ++}; ++ ++int netdev_get_flags(const struct netdev *, enum netdev_flags *); ++int netdev_set_flags(struct netdev *, enum netdev_flags, ++ struct netdev_saved_flags **); ++int netdev_turn_flags_on(struct netdev *, enum netdev_flags, ++ struct netdev_saved_flags **); ++int netdev_turn_flags_off(struct netdev *, enum netdev_flags, ++ struct netdev_saved_flags **); ++ ++void netdev_restore_flags(struct netdev_saved_flags *); ++ ++/* TCP/IP stack interface. */ ++int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask); ++int netdev_get_in4_by_name(const char *device_name, struct in_addr *in4); ++int netdev_get_ip_by_name(const char *device_name, struct in6_addr *); ++int netdev_get_addr_list(const struct netdev *netdev, struct in6_addr **addr, ++ struct in6_addr **mask, int *n_in6); ++ ++int netdev_add_router(struct netdev *, struct in_addr router); ++int netdev_get_next_hop(const struct netdev *, const struct in_addr *host, ++ struct in_addr *next_hop, char **); ++int netdev_get_status(const struct netdev *, struct smap *); ++int netdev_arp_lookup(const struct netdev *, ovs_be32 ip, ++ struct eth_addr *mac); ++ ++struct netdev *netdev_find_dev_by_in4(const struct in_addr *); ++ ++/* Statistics. */ ++int netdev_get_stats(const struct netdev *, struct netdev_stats *); ++int netdev_get_custom_stats(const struct netdev *, ++ struct netdev_custom_stats *); ++ ++/* Quality of service. */ ++struct netdev_qos_capabilities { ++ unsigned int n_queues; ++}; ++ ++struct netdev_queue_stats { ++ /* Values of unsupported statistics are set to all-1-bits (UINT64_MAX). */ ++ uint64_t tx_bytes; ++ uint64_t tx_packets; ++ uint64_t tx_errors; ++ ++ /* Time at which the queue was created, in msecs, LLONG_MIN if unknown. */ ++ long long int created; ++}; ++ ++int netdev_set_policing(struct netdev *, uint32_t kbits_rate, ++ uint32_t kbits_burst, uint32_t kpkts_rate, ++ uint32_t kpkts_burst); ++ ++int netdev_get_qos_types(const struct netdev *, struct sset *types); ++int netdev_get_qos_capabilities(const struct netdev *, ++ const char *type, ++ struct netdev_qos_capabilities *); ++int netdev_get_n_queues(const struct netdev *, ++ const char *type, unsigned int *n_queuesp); ++ ++int netdev_get_qos(const struct netdev *, ++ const char **typep, struct smap *details); ++int netdev_set_qos(struct netdev *, ++ const char *type, const struct smap *details); ++ ++int netdev_get_queue(const struct netdev *, ++ unsigned int queue_id, struct smap *details); ++int netdev_set_queue(struct netdev *, ++ unsigned int queue_id, const struct smap *details); ++int netdev_delete_queue(struct netdev *, unsigned int queue_id); ++int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id, ++ struct netdev_queue_stats *); ++uint64_t netdev_get_change_seq(const struct netdev *); ++ ++int netdev_reconfigure(struct netdev *netdev); ++void netdev_wait_reconf_required(struct netdev *netdev); ++bool netdev_is_reconf_required(struct netdev *netdev); ++ ++struct netdev_queue_dump { ++ struct netdev *netdev; ++ int error; ++ void *state; ++}; ++void netdev_queue_dump_start(struct netdev_queue_dump *, ++ const struct netdev *); ++bool netdev_queue_dump_next(struct netdev_queue_dump *, ++ unsigned int *queue_id, struct smap *details); ++int netdev_queue_dump_done(struct netdev_queue_dump *); ++ ++/* Iterates through each queue in NETDEV, using DUMP as state. Fills QUEUE_ID ++ * and DETAILS with information about queues. The client must initialize and ++ * destroy DETAILS. ++ * ++ * Arguments all have pointer type. ++ * ++ * If you break out of the loop, then you need to free the dump structure by ++ * hand using netdev_queue_dump_done(). */ ++#define NETDEV_QUEUE_FOR_EACH(QUEUE_ID, DETAILS, DUMP, NETDEV) \ ++ for (netdev_queue_dump_start(DUMP, NETDEV); \ ++ (netdev_queue_dump_next(DUMP, QUEUE_ID, DETAILS) \ ++ ? true \ ++ : (netdev_queue_dump_done(DUMP), false)); \ ++ ) ++ ++typedef void netdev_dump_queue_stats_cb(unsigned int queue_id, ++ struct netdev_queue_stats *, ++ void *aux); ++int netdev_dump_queue_stats(const struct netdev *, ++ netdev_dump_queue_stats_cb *, void *aux); ++ ++extern struct seq *tnl_conf_seq; ++ ++#ifndef _WIN32 ++void netdev_get_addrs_list_flush(void); ++int netdev_get_addrs(const char dev[], struct in6_addr **paddr, ++ struct in6_addr **pmask, int *n_in6); ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* netdev.h */ +Index: openvswitch-2.17.2/lib/netlink-protocol.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-protocol.h ++++ /dev/null +@@ -1,208 +0,0 @@ +-/* +- * Copyright (c) 2008, 2010, 2011, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NETLINK_PROTOCOL_H +-#define NETLINK_PROTOCOL_H 1 +- +-/* Netlink protocol definitions. +- * +- * Netlink is a message framing format described in RFC 3549 and used heavily +- * in Linux to access the network stack. Open vSwitch uses AF_NETLINK sockets +- * for this purpose on Linux. But on all platforms, Open vSwitch uses Netlink +- * message framing internally for certain purposes. +- * +- * This header provides access to the Netlink message framing definitions +- * regardless of platform. On Linux, it includes the proper headers directly; +- * on other platforms it directly defines the structures and macros itself. +- */ +- +-#include +-#include -#include "util.h" +- +-#ifdef HAVE_NETLINK +-#include +-#include +- +-#else +-#define NETLINK_NETFILTER 12 +-#define NETLINK_GENERIC 16 +- +-/* nlmsg_flags bits. */ +-#define NLM_F_REQUEST 0x001 +-#define NLM_F_MULTI 0x002 +-#define NLM_F_ACK 0x004 +-#define NLM_F_ECHO 0x008 +- +-/* GET request flag.*/ +-#define NLM_F_ROOT 0x100 +-#define NLM_F_MATCH 0x200 +-#define NLM_F_ATOMIC 0x400 +-#define NLM_F_DUMP (NLM_F_ROOT | NLM_F_MATCH) +- +-/* NEW request flags. */ +-#define NLM_F_REPLACE 0x100 +-#define NLM_F_EXCL 0x200 +-#define NLM_F_CREATE 0x400 +- +-/* nlmsg_type values. */ +-#define NLMSG_NOOP 1 +-#define NLMSG_ERROR 2 +-#define NLMSG_DONE 3 +-#define NLMSG_OVERRUN 4 +- +-#define NLMSG_MIN_TYPE 0x10 +- +-#define MAX_LINKS 32 +- +-struct nlmsghdr { +- uint32_t nlmsg_len; +- uint16_t nlmsg_type; +- uint16_t nlmsg_flags; +- uint32_t nlmsg_seq; +- uint32_t nlmsg_pid; +-}; +-BUILD_ASSERT_DECL(sizeof(struct nlmsghdr) == 16); +- +-#define NLMSG_ALIGNTO 4 +-#define NLMSG_ALIGN(SIZE) ROUND_UP(SIZE, NLMSG_ALIGNTO) +-#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +- +-struct nlmsgerr +-{ +- int error; +- struct nlmsghdr msg; +-}; +-BUILD_ASSERT_DECL(sizeof(struct nlmsgerr) == 20); +- +-struct genlmsghdr { +- uint8_t cmd; +- uint8_t version; +- uint16_t reserved; +-}; +-BUILD_ASSERT_DECL(sizeof(struct genlmsghdr) == 4); +- +-#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) +- +-struct nlattr { +- uint16_t nla_len; +- uint16_t nla_type; +-}; +-BUILD_ASSERT_DECL(sizeof(struct nlattr) == 4); +- +-#define NLA_ALIGNTO 4 +-#define NLA_ALIGN(SIZE) ROUND_UP(SIZE, NLA_ALIGNTO) +-#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) +- +-#define GENL_MIN_ID NLMSG_MIN_TYPE +-#define GENL_MAX_ID 1023 +- +-#define GENL_ID_CTRL NLMSG_MIN_TYPE +- +-enum { +- CTRL_CMD_UNSPEC, +- CTRL_CMD_NEWFAMILY, +- CTRL_CMD_DELFAMILY, +- CTRL_CMD_GETFAMILY, +- CTRL_CMD_NEWOPS, +- CTRL_CMD_DELOPS, +- CTRL_CMD_GETOPS, +- __CTRL_CMD_MAX, +-}; +- +-#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) +- +-enum { +- CTRL_ATTR_UNSPEC, +- CTRL_ATTR_FAMILY_ID, +- CTRL_ATTR_FAMILY_NAME, +- CTRL_ATTR_VERSION, +- CTRL_ATTR_HDRSIZE, +- CTRL_ATTR_MAXATTR, +- CTRL_ATTR_OPS, +- __CTRL_ATTR_MAX, +-}; +- +-#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) +- +-enum { +- CTRL_ATTR_OP_UNSPEC, +- CTRL_ATTR_OP_ID, +- CTRL_ATTR_OP_FLAGS, +- __CTRL_ATTR_OP_MAX, +-}; +- +-#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) +-#endif /* !HAVE_NETLINK */ +- +-/* These were introduced all together in 2.6.24. */ +-#ifndef NLA_TYPE_MASK +-#define NLA_F_NESTED (1 << 15) +-#define NLA_F_NET_BYTEORDER (1 << 14) +-#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) +-#endif +- +-/* These were introduced all together in 2.6.14. (We want our programs to +- * support the newer kernel features even if compiled with older headers.) */ +-#ifndef NETLINK_ADD_MEMBERSHIP +-#define NETLINK_ADD_MEMBERSHIP 1 +-#define NETLINK_DROP_MEMBERSHIP 2 +-#endif +- +-/* This was introduced in v4.2. (We want our programs to support the newer +- * kernel features even if compiled with older headers.) */ +-#ifndef NETLINK_LISTEN_ALL_NSID +-#define NETLINK_LISTEN_ALL_NSID 8 +-#endif +- +-/* These were introduced all together in 2.6.23. (We want our programs to +- * support the newer kernel features even if compiled with older headers.) */ +-#ifndef CTRL_ATTR_MCAST_GRP_MAX +- +-#undef CTRL_ATTR_MAX +-#define CTRL_ATTR_MAX 7 +-#define CTRL_ATTR_MCAST_GROUPS 7 +- +-enum { +- CTRL_ATTR_MCAST_GRP_UNSPEC, +- CTRL_ATTR_MCAST_GRP_NAME, +- CTRL_ATTR_MCAST_GRP_ID, +- __CTRL_ATTR_MCAST_GRP_MAX, +-}; +- +-#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) +-#endif /* CTRL_ATTR_MCAST_GRP_MAX */ +- +-#ifndef NETLINK_EXT_ACK +- +-#define NETLINK_CAP_ACK 10 +-#define NETLINK_EXT_ACK 11 +- +-/* ACK message flags. */ +-#define NLM_F_CAPPED 0x100 +-#define NLM_F_ACK_TLVS 0x200 +- +-enum { +- NLMSGERR_ATTR_UNUSED, +- NLMSGERR_ATTR_MSG, +- NLMSGERR_ATTR_OFFS, +- __NLMSGERR_ATTR_MAX, +- NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 +-}; +- +-#endif /* NLM_F_ACK_TLVS */ +- +-#endif /* netlink-protocol.h */ +Index: openvswitch-2.17.2/include/internal/netlink-protocol.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/netlink-protocol.h +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (c) 2008, 2010, 2011, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NETLINK_PROTOCOL_H ++#define NETLINK_PROTOCOL_H 1 ++ ++/* Netlink protocol definitions. ++ * ++ * Netlink is a message framing format described in RFC 3549 and used heavily ++ * in Linux to access the network stack. Open vSwitch uses AF_NETLINK sockets ++ * for this purpose on Linux. But on all platforms, Open vSwitch uses Netlink ++ * message framing internally for certain purposes. ++ * ++ * This header provides access to the Netlink message framing definitions ++ * regardless of platform. On Linux, it includes the proper headers directly; ++ * on other platforms it directly defines the structures and macros itself. ++ */ ++ ++#include ++#include +#include "internal/util.h" - - #ifdef HAVE_NETLINK - #include -diff --git a/lib/netlink.h b/include/internal/netlink.h -similarity index 99% -rename from lib/netlink.h -rename to include/internal/netlink.h -index b97470743..0163285a9 100644 ---- a/lib/netlink.h -+++ b/include/internal/netlink.h -@@ -36,7 +36,7 @@ - #include - #include - #include ++ ++#ifdef HAVE_NETLINK ++#include ++#include ++ ++#else ++#define NETLINK_NETFILTER 12 ++#define NETLINK_GENERIC 16 ++ ++/* nlmsg_flags bits. */ ++#define NLM_F_REQUEST 0x001 ++#define NLM_F_MULTI 0x002 ++#define NLM_F_ACK 0x004 ++#define NLM_F_ECHO 0x008 ++ ++/* GET request flag.*/ ++#define NLM_F_ROOT 0x100 ++#define NLM_F_MATCH 0x200 ++#define NLM_F_ATOMIC 0x400 ++#define NLM_F_DUMP (NLM_F_ROOT | NLM_F_MATCH) ++ ++/* NEW request flags. */ ++#define NLM_F_REPLACE 0x100 ++#define NLM_F_EXCL 0x200 ++#define NLM_F_CREATE 0x400 ++ ++/* nlmsg_type values. */ ++#define NLMSG_NOOP 1 ++#define NLMSG_ERROR 2 ++#define NLMSG_DONE 3 ++#define NLMSG_OVERRUN 4 ++ ++#define NLMSG_MIN_TYPE 0x10 ++ ++#define MAX_LINKS 32 ++ ++struct nlmsghdr { ++ uint32_t nlmsg_len; ++ uint16_t nlmsg_type; ++ uint16_t nlmsg_flags; ++ uint32_t nlmsg_seq; ++ uint32_t nlmsg_pid; ++}; ++BUILD_ASSERT_DECL(sizeof(struct nlmsghdr) == 16); ++ ++#define NLMSG_ALIGNTO 4 ++#define NLMSG_ALIGN(SIZE) ROUND_UP(SIZE, NLMSG_ALIGNTO) ++#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) ++ ++struct nlmsgerr ++{ ++ int error; ++ struct nlmsghdr msg; ++}; ++BUILD_ASSERT_DECL(sizeof(struct nlmsgerr) == 20); ++ ++struct genlmsghdr { ++ uint8_t cmd; ++ uint8_t version; ++ uint16_t reserved; ++}; ++BUILD_ASSERT_DECL(sizeof(struct genlmsghdr) == 4); ++ ++#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) ++ ++struct nlattr { ++ uint16_t nla_len; ++ uint16_t nla_type; ++}; ++BUILD_ASSERT_DECL(sizeof(struct nlattr) == 4); ++ ++#define NLA_ALIGNTO 4 ++#define NLA_ALIGN(SIZE) ROUND_UP(SIZE, NLA_ALIGNTO) ++#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) ++ ++#define GENL_MIN_ID NLMSG_MIN_TYPE ++#define GENL_MAX_ID 1023 ++ ++#define GENL_ID_CTRL NLMSG_MIN_TYPE ++ ++enum { ++ CTRL_CMD_UNSPEC, ++ CTRL_CMD_NEWFAMILY, ++ CTRL_CMD_DELFAMILY, ++ CTRL_CMD_GETFAMILY, ++ CTRL_CMD_NEWOPS, ++ CTRL_CMD_DELOPS, ++ CTRL_CMD_GETOPS, ++ __CTRL_CMD_MAX, ++}; ++ ++#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) ++ ++enum { ++ CTRL_ATTR_UNSPEC, ++ CTRL_ATTR_FAMILY_ID, ++ CTRL_ATTR_FAMILY_NAME, ++ CTRL_ATTR_VERSION, ++ CTRL_ATTR_HDRSIZE, ++ CTRL_ATTR_MAXATTR, ++ CTRL_ATTR_OPS, ++ __CTRL_ATTR_MAX, ++}; ++ ++#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) ++ ++enum { ++ CTRL_ATTR_OP_UNSPEC, ++ CTRL_ATTR_OP_ID, ++ CTRL_ATTR_OP_FLAGS, ++ __CTRL_ATTR_OP_MAX, ++}; ++ ++#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) ++#endif /* !HAVE_NETLINK */ ++ ++/* These were introduced all together in 2.6.24. */ ++#ifndef NLA_TYPE_MASK ++#define NLA_F_NESTED (1 << 15) ++#define NLA_F_NET_BYTEORDER (1 << 14) ++#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) ++#endif ++ ++/* These were introduced all together in 2.6.14. (We want our programs to ++ * support the newer kernel features even if compiled with older headers.) */ ++#ifndef NETLINK_ADD_MEMBERSHIP ++#define NETLINK_ADD_MEMBERSHIP 1 ++#define NETLINK_DROP_MEMBERSHIP 2 ++#endif ++ ++/* This was introduced in v4.2. (We want our programs to support the newer ++ * kernel features even if compiled with older headers.) */ ++#ifndef NETLINK_LISTEN_ALL_NSID ++#define NETLINK_LISTEN_ALL_NSID 8 ++#endif ++ ++/* These were introduced all together in 2.6.23. (We want our programs to ++ * support the newer kernel features even if compiled with older headers.) */ ++#ifndef CTRL_ATTR_MCAST_GRP_MAX ++ ++#undef CTRL_ATTR_MAX ++#define CTRL_ATTR_MAX 7 ++#define CTRL_ATTR_MCAST_GROUPS 7 ++ ++enum { ++ CTRL_ATTR_MCAST_GRP_UNSPEC, ++ CTRL_ATTR_MCAST_GRP_NAME, ++ CTRL_ATTR_MCAST_GRP_ID, ++ __CTRL_ATTR_MCAST_GRP_MAX, ++}; ++ ++#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) ++#endif /* CTRL_ATTR_MCAST_GRP_MAX */ ++ ++#ifndef NETLINK_EXT_ACK ++ ++#define NETLINK_CAP_ACK 10 ++#define NETLINK_EXT_ACK 11 ++ ++/* ACK message flags. */ ++#define NLM_F_CAPPED 0x100 ++#define NLM_F_ACK_TLVS 0x200 ++ ++enum { ++ NLMSGERR_ATTR_UNUSED, ++ NLMSGERR_ATTR_MSG, ++ NLMSGERR_ATTR_OFFS, ++ __NLMSGERR_ATTR_MAX, ++ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 ++}; ++ ++#endif /* NLM_F_ACK_TLVS */ ++ ++#endif /* netlink-protocol.h */ +Index: openvswitch-2.17.2/lib/netlink.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink.h ++++ /dev/null +@@ -1,251 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2015 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NETLINK_H +-#define NETLINK_H 1 +- +-/* Netlink message helpers. +- * +- * Netlink is a datagram-based network protocol primarily for communication +- * between user processes and the kernel, and mainly on Linux. Netlink is +- * specified in RFC 3549, "Linux Netlink as an IP Services Protocol". +- * +- * Netlink is not suitable for use in physical networks of heterogeneous +- * machines because host byte order is used throughout. +- * +- * This header file defines helper functions for working with Netlink messages. +- * For Netlink protocol definitions, see netlink-protocol.h. For +- * Linux-specific definitions for Netlink sockets, see netlink-socket.h. +- */ +- +-#include +-#include +-#include +-#include +-#include -#include "netlink-protocol.h" +-#include "openvswitch/types.h" +- +-struct ofpbuf; +-struct nlattr; +- +-/* Accessing headers and data. */ +-struct nlmsghdr *nl_msg_nlmsghdr(const struct ofpbuf *); +-struct genlmsghdr *nl_msg_genlmsghdr(const struct ofpbuf *); +-bool nl_msg_nlmsgerr(const struct ofpbuf *, int *error, const char **attr_msg); +-void nl_msg_reserve(struct ofpbuf *, size_t); +- +-/* Appending and prepending headers and raw data. */ +-void nl_msg_put_nlmsghdr(struct ofpbuf *, size_t expected_payload, +- uint32_t type, uint32_t flags); +-void nl_msg_put_genlmsghdr(struct ofpbuf *, size_t expected_payload, +- int family, uint32_t flags, +- uint8_t cmd, uint8_t version); +-void nl_msg_put(struct ofpbuf *, const void *, size_t); +-void *nl_msg_put_uninit(struct ofpbuf *, size_t); +-void nl_msg_push(struct ofpbuf *, const void *, size_t); +-void *nl_msg_push_uninit(struct ofpbuf *, size_t); +- +-/* Appending attributes. */ +-void *nl_msg_put_unspec_uninit(struct ofpbuf *, uint16_t type, size_t); +-void *nl_msg_put_unspec_zero(struct ofpbuf *, uint16_t type, size_t); +-void nl_msg_put_unspec(struct ofpbuf *, uint16_t type, const void *, size_t); +-void nl_msg_put_flag(struct ofpbuf *, uint16_t type); +-void nl_msg_put_u8(struct ofpbuf *, uint16_t type, uint8_t value); +-void nl_msg_put_u16(struct ofpbuf *, uint16_t type, uint16_t value); +-void nl_msg_put_u32(struct ofpbuf *, uint16_t type, uint32_t value); +-void nl_msg_put_u64(struct ofpbuf *, uint16_t type, uint64_t value); +-void nl_msg_put_u128(struct ofpbuf *, uint16_t type, ovs_u128 value); +-void nl_msg_put_be16(struct ofpbuf *, uint16_t type, ovs_be16 value); +-void nl_msg_put_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); +-void nl_msg_put_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); +-void nl_msg_put_be128(struct ofpbuf *, uint16_t type, ovs_be128 value); +-void nl_msg_put_in6_addr(struct ofpbuf *msg, uint16_t type, +- const struct in6_addr *value); +-void nl_msg_put_odp_port(struct ofpbuf *, uint16_t type, odp_port_t value); +-void nl_msg_put_string__(struct ofpbuf *, uint16_t type, const char *value, +- size_t len); +-void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value); +- +-size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type); +-void nl_msg_end_nested(struct ofpbuf *, size_t offset); +-void nl_msg_cancel_nested(struct ofpbuf *, size_t offset); +-bool nl_msg_end_non_empty_nested(struct ofpbuf *, size_t offset); +-void nl_msg_put_nested(struct ofpbuf *, uint16_t type, +- const void *data, size_t size); +- +-/* Prepending attributes. */ +-void *nl_msg_push_unspec_uninit(struct ofpbuf *, uint16_t type, size_t); +-void nl_msg_push_unspec(struct ofpbuf *, uint16_t type, const void *, size_t); +-void nl_msg_push_flag(struct ofpbuf *, uint16_t type); +-void nl_msg_push_u8(struct ofpbuf *, uint16_t type, uint8_t value); +-void nl_msg_push_u16(struct ofpbuf *, uint16_t type, uint16_t value); +-void nl_msg_push_u32(struct ofpbuf *, uint16_t type, uint32_t value); +-void nl_msg_push_u64(struct ofpbuf *, uint16_t type, uint64_t value); +-void nl_msg_push_u128(struct ofpbuf *, uint16_t type, ovs_u128 value); +-void nl_msg_push_be16(struct ofpbuf *, uint16_t type, ovs_be16 value); +-void nl_msg_push_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); +-void nl_msg_push_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); +-void nl_msg_push_be128(struct ofpbuf *, uint16_t type, ovs_be128 value); +-void nl_msg_push_string(struct ofpbuf *, uint16_t type, const char *value); +- +-/* Separating buffers into individual messages. */ +-struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg); +- +-/* Sizes of various attribute types, in bytes, including the attribute header +- * and padding. +- * +- * A minimum-size attribute is 4 bytes long: 4 bytes of header, no bytes of +- * payload, no padding. +- * +- * A maximum-size attribute is 65536 bytes long: 4 bytes of header, 65531 bytes +- * of payload, 1 byte of padding. (Thus, NL_ATTR_SIZE() of a maximum length +- * attribute payload does not fit in 16 bits.) */ +-#define NL_ATTR_SIZE(PAYLOAD_SIZE) (NLA_HDRLEN + NLA_ALIGN(PAYLOAD_SIZE)) +-#define NL_A_U8_SIZE NL_ATTR_SIZE(sizeof(uint8_t)) +-#define NL_A_U16_SIZE NL_ATTR_SIZE(sizeof(uint16_t)) +-#define NL_A_U32_SIZE NL_ATTR_SIZE(sizeof(uint32_t)) +-#define NL_A_U64_SIZE NL_ATTR_SIZE(sizeof(uint64_t)) +-#define NL_A_U128_SIZE NL_ATTR_SIZE(sizeof(ovs_u128)) +-#define NL_A_BE16_SIZE NL_ATTR_SIZE(sizeof(ovs_be16)) +-#define NL_A_BE32_SIZE NL_ATTR_SIZE(sizeof(ovs_be32)) +-#define NL_A_BE64_SIZE NL_ATTR_SIZE(sizeof(ovs_be64)) +-#define NL_A_BE128_SIZE NL_ATTR_SIZE(sizeof(ovs_be128)) +-#define NL_A_FLAG_SIZE NL_ATTR_SIZE(0) +-#define NL_A_IPV6_SIZE NL_ATTR_SIZE(sizeof(struct in6_addr)) +-#define NL_A_LL_ADDR_ETH_SIZE NL_ATTR_SIZE(sizeof(struct eth_addr)) +-#define NL_A_LL_ADDR_IB_SIZE NL_ATTR_SIZE(sizeof(struct ib_addr)) +- +-bool nl_attr_oversized(size_t payload_size); +- +-/* Netlink attribute types. */ +-enum nl_attr_type +-{ +- NL_A_NO_ATTR = 0, +- NL_A_UNSPEC, +- NL_A_U8, +- NL_A_U16, +- NL_A_BE16 = NL_A_U16, +- NL_A_U32, +- NL_A_BE32 = NL_A_U32, +- NL_A_U64, +- NL_A_BE64 = NL_A_U64, +- NL_A_U128, +- NL_A_BE128 = NL_A_U128, +- NL_A_STRING, +- NL_A_FLAG, +- NL_A_IPV6, +- NL_A_NESTED, +- NL_A_LL_ADDR, +- N_NL_ATTR_TYPES +-}; +- +-/* Netlink attribute iteration. */ +-static inline struct nlattr * +-nl_attr_next(const struct nlattr *nla) +-{ +- return ALIGNED_CAST(struct nlattr *, +- ((uint8_t *) nla + NLA_ALIGN(nla->nla_len))); +-} +- +-static inline bool +-nl_attr_is_valid(const struct nlattr *nla, size_t maxlen) +-{ +- return (maxlen >= sizeof *nla +- && nla->nla_len >= sizeof *nla +- && nla->nla_len <= maxlen); +-} +- +-static inline size_t +-nl_attr_len_pad(const struct nlattr *nla, size_t maxlen) +-{ +- size_t len = NLA_ALIGN(nla->nla_len); +- +- return len <= maxlen ? len : nla->nla_len; +-} +- +-/* This macro is careful to check for attributes with bad lengths. */ +-#define NL_ATTR_FOR_EACH(ITER, LEFT, ATTRS, ATTRS_LEN) \ +- for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN); \ +- nl_attr_is_valid(ITER, LEFT); \ +- (LEFT) -= nl_attr_len_pad(ITER, LEFT), (ITER) = nl_attr_next(ITER)) +- +- +-/* This macro does not check for attributes with bad lengths. It should only +- * be used with messages from trusted sources or with messages that have +- * already been validated (e.g. with NL_ATTR_FOR_EACH). */ +-#define NL_ATTR_FOR_EACH_UNSAFE(ITER, LEFT, ATTRS, ATTRS_LEN) \ +- for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN); \ +- (LEFT) > 0; \ +- (LEFT) -= nl_attr_len_pad(ITER, LEFT), (ITER) = nl_attr_next(ITER)) +- +-/* These variants are convenient for iterating nested attributes. */ +-#define NL_NESTED_FOR_EACH(ITER, LEFT, A) \ +- NL_ATTR_FOR_EACH(ITER, LEFT, nl_attr_get(A), nl_attr_get_size(A)) +-#define NL_NESTED_FOR_EACH_UNSAFE(ITER, LEFT, A) \ +- NL_ATTR_FOR_EACH_UNSAFE(ITER, LEFT, nl_attr_get(A), nl_attr_get_size(A)) +- +-/* Netlink attribute parsing. */ +-int nl_attr_type(const struct nlattr *); +-const void *nl_attr_get(const struct nlattr *); +-size_t nl_attr_get_size(const struct nlattr *); +-const void *nl_attr_get_unspec(const struct nlattr *, size_t size); +-bool nl_attr_get_flag(const struct nlattr *); +-uint8_t nl_attr_get_u8(const struct nlattr *); +-uint16_t nl_attr_get_u16(const struct nlattr *); +-uint32_t nl_attr_get_u32(const struct nlattr *); +-uint64_t nl_attr_get_u64(const struct nlattr *); +-ovs_u128 nl_attr_get_u128(const struct nlattr *); +-ovs_be16 nl_attr_get_be16(const struct nlattr *); +-ovs_be32 nl_attr_get_be32(const struct nlattr *); +-ovs_be64 nl_attr_get_be64(const struct nlattr *); +-ovs_be128 nl_attr_get_be128(const struct nlattr *); +-struct in6_addr nl_attr_get_in6_addr(const struct nlattr *nla); +-odp_port_t nl_attr_get_odp_port(const struct nlattr *); +-const char *nl_attr_get_string(const struct nlattr *); +-void nl_attr_get_nested(const struct nlattr *, struct ofpbuf *); +-struct eth_addr nl_attr_get_eth_addr(const struct nlattr *nla); +-struct ib_addr nl_attr_get_ib_addr(const struct nlattr *nla); +- +-/* Netlink attribute policy. +- * +- * Specifies how to parse a single attribute from a Netlink message payload. +- */ +-struct nl_policy +-{ +- enum nl_attr_type type; +- size_t min_len, max_len; +- bool optional; +-}; +- +-#define NL_POLICY_FOR(TYPE) \ +- .type = NL_A_UNSPEC, .min_len = sizeof(TYPE), .max_len = sizeof(TYPE) +- +-bool nl_attr_validate(const struct nlattr *, const struct nl_policy *); +- +-bool nl_policy_parse(const struct ofpbuf *, size_t offset, +- const struct nl_policy[], +- struct nlattr *[], size_t n_attrs); +-bool nl_parse_nested(const struct nlattr *, const struct nl_policy[], +- struct nlattr *[], size_t n_attrs); +- +-const struct nlattr *nl_attr_find(const struct ofpbuf *, size_t hdr_len, +- uint16_t type); +-const struct nlattr *nl_attr_find_nested(const struct nlattr *, uint16_t type); +-const struct nlattr *nl_attr_find__(const struct nlattr *attrs, size_t size, +- uint16_t type); +- +-#endif /* netlink.h */ +Index: openvswitch-2.17.2/include/internal/netlink.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/netlink.h +@@ -0,0 +1,251 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NETLINK_H ++#define NETLINK_H 1 ++ ++/* Netlink message helpers. ++ * ++ * Netlink is a datagram-based network protocol primarily for communication ++ * between user processes and the kernel, and mainly on Linux. Netlink is ++ * specified in RFC 3549, "Linux Netlink as an IP Services Protocol". ++ * ++ * Netlink is not suitable for use in physical networks of heterogeneous ++ * machines because host byte order is used throughout. ++ * ++ * This header file defines helper functions for working with Netlink messages. ++ * For Netlink protocol definitions, see netlink-protocol.h. For ++ * Linux-specific definitions for Netlink sockets, see netlink-socket.h. ++ */ ++ ++#include ++#include ++#include ++#include ++#include +#include "internal/netlink-protocol.h" - #include "openvswitch/types.h" - - struct ofpbuf; -diff --git a/lib/nx-match.h b/include/internal/nx-match.h -similarity index 99% -rename from lib/nx-match.h -rename to include/internal/nx-match.h -index 967c8d93f..07f8639a3 100644 ---- a/lib/nx-match.h -+++ b/include/internal/nx-match.h -@@ -21,7 +21,7 @@ - #include - #include - #include "openvswitch/compiler.h" ++#include "openvswitch/types.h" ++ ++struct ofpbuf; ++struct nlattr; ++ ++/* Accessing headers and data. */ ++struct nlmsghdr *nl_msg_nlmsghdr(const struct ofpbuf *); ++struct genlmsghdr *nl_msg_genlmsghdr(const struct ofpbuf *); ++bool nl_msg_nlmsgerr(const struct ofpbuf *, int *error, const char **attr_msg); ++void nl_msg_reserve(struct ofpbuf *, size_t); ++ ++/* Appending and prepending headers and raw data. */ ++void nl_msg_put_nlmsghdr(struct ofpbuf *, size_t expected_payload, ++ uint32_t type, uint32_t flags); ++void nl_msg_put_genlmsghdr(struct ofpbuf *, size_t expected_payload, ++ int family, uint32_t flags, ++ uint8_t cmd, uint8_t version); ++void nl_msg_put(struct ofpbuf *, const void *, size_t); ++void *nl_msg_put_uninit(struct ofpbuf *, size_t); ++void nl_msg_push(struct ofpbuf *, const void *, size_t); ++void *nl_msg_push_uninit(struct ofpbuf *, size_t); ++ ++/* Appending attributes. */ ++void *nl_msg_put_unspec_uninit(struct ofpbuf *, uint16_t type, size_t); ++void *nl_msg_put_unspec_zero(struct ofpbuf *, uint16_t type, size_t); ++void nl_msg_put_unspec(struct ofpbuf *, uint16_t type, const void *, size_t); ++void nl_msg_put_flag(struct ofpbuf *, uint16_t type); ++void nl_msg_put_u8(struct ofpbuf *, uint16_t type, uint8_t value); ++void nl_msg_put_u16(struct ofpbuf *, uint16_t type, uint16_t value); ++void nl_msg_put_u32(struct ofpbuf *, uint16_t type, uint32_t value); ++void nl_msg_put_u64(struct ofpbuf *, uint16_t type, uint64_t value); ++void nl_msg_put_u128(struct ofpbuf *, uint16_t type, ovs_u128 value); ++void nl_msg_put_be16(struct ofpbuf *, uint16_t type, ovs_be16 value); ++void nl_msg_put_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); ++void nl_msg_put_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); ++void nl_msg_put_be128(struct ofpbuf *, uint16_t type, ovs_be128 value); ++void nl_msg_put_in6_addr(struct ofpbuf *msg, uint16_t type, ++ const struct in6_addr *value); ++void nl_msg_put_odp_port(struct ofpbuf *, uint16_t type, odp_port_t value); ++void nl_msg_put_string__(struct ofpbuf *, uint16_t type, const char *value, ++ size_t len); ++void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value); ++ ++size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type); ++void nl_msg_end_nested(struct ofpbuf *, size_t offset); ++void nl_msg_cancel_nested(struct ofpbuf *, size_t offset); ++bool nl_msg_end_non_empty_nested(struct ofpbuf *, size_t offset); ++void nl_msg_put_nested(struct ofpbuf *, uint16_t type, ++ const void *data, size_t size); ++ ++/* Prepending attributes. */ ++void *nl_msg_push_unspec_uninit(struct ofpbuf *, uint16_t type, size_t); ++void nl_msg_push_unspec(struct ofpbuf *, uint16_t type, const void *, size_t); ++void nl_msg_push_flag(struct ofpbuf *, uint16_t type); ++void nl_msg_push_u8(struct ofpbuf *, uint16_t type, uint8_t value); ++void nl_msg_push_u16(struct ofpbuf *, uint16_t type, uint16_t value); ++void nl_msg_push_u32(struct ofpbuf *, uint16_t type, uint32_t value); ++void nl_msg_push_u64(struct ofpbuf *, uint16_t type, uint64_t value); ++void nl_msg_push_u128(struct ofpbuf *, uint16_t type, ovs_u128 value); ++void nl_msg_push_be16(struct ofpbuf *, uint16_t type, ovs_be16 value); ++void nl_msg_push_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); ++void nl_msg_push_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); ++void nl_msg_push_be128(struct ofpbuf *, uint16_t type, ovs_be128 value); ++void nl_msg_push_string(struct ofpbuf *, uint16_t type, const char *value); ++ ++/* Separating buffers into individual messages. */ ++struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg); ++ ++/* Sizes of various attribute types, in bytes, including the attribute header ++ * and padding. ++ * ++ * A minimum-size attribute is 4 bytes long: 4 bytes of header, no bytes of ++ * payload, no padding. ++ * ++ * A maximum-size attribute is 65536 bytes long: 4 bytes of header, 65531 bytes ++ * of payload, 1 byte of padding. (Thus, NL_ATTR_SIZE() of a maximum length ++ * attribute payload does not fit in 16 bits.) */ ++#define NL_ATTR_SIZE(PAYLOAD_SIZE) (NLA_HDRLEN + NLA_ALIGN(PAYLOAD_SIZE)) ++#define NL_A_U8_SIZE NL_ATTR_SIZE(sizeof(uint8_t)) ++#define NL_A_U16_SIZE NL_ATTR_SIZE(sizeof(uint16_t)) ++#define NL_A_U32_SIZE NL_ATTR_SIZE(sizeof(uint32_t)) ++#define NL_A_U64_SIZE NL_ATTR_SIZE(sizeof(uint64_t)) ++#define NL_A_U128_SIZE NL_ATTR_SIZE(sizeof(ovs_u128)) ++#define NL_A_BE16_SIZE NL_ATTR_SIZE(sizeof(ovs_be16)) ++#define NL_A_BE32_SIZE NL_ATTR_SIZE(sizeof(ovs_be32)) ++#define NL_A_BE64_SIZE NL_ATTR_SIZE(sizeof(ovs_be64)) ++#define NL_A_BE128_SIZE NL_ATTR_SIZE(sizeof(ovs_be128)) ++#define NL_A_FLAG_SIZE NL_ATTR_SIZE(0) ++#define NL_A_IPV6_SIZE NL_ATTR_SIZE(sizeof(struct in6_addr)) ++#define NL_A_LL_ADDR_ETH_SIZE NL_ATTR_SIZE(sizeof(struct eth_addr)) ++#define NL_A_LL_ADDR_IB_SIZE NL_ATTR_SIZE(sizeof(struct ib_addr)) ++ ++bool nl_attr_oversized(size_t payload_size); ++ ++/* Netlink attribute types. */ ++enum nl_attr_type ++{ ++ NL_A_NO_ATTR = 0, ++ NL_A_UNSPEC, ++ NL_A_U8, ++ NL_A_U16, ++ NL_A_BE16 = NL_A_U16, ++ NL_A_U32, ++ NL_A_BE32 = NL_A_U32, ++ NL_A_U64, ++ NL_A_BE64 = NL_A_U64, ++ NL_A_U128, ++ NL_A_BE128 = NL_A_U128, ++ NL_A_STRING, ++ NL_A_FLAG, ++ NL_A_IPV6, ++ NL_A_NESTED, ++ NL_A_LL_ADDR, ++ N_NL_ATTR_TYPES ++}; ++ ++/* Netlink attribute iteration. */ ++static inline struct nlattr * ++nl_attr_next(const struct nlattr *nla) ++{ ++ return ALIGNED_CAST(struct nlattr *, ++ ((uint8_t *) nla + NLA_ALIGN(nla->nla_len))); ++} ++ ++static inline bool ++nl_attr_is_valid(const struct nlattr *nla, size_t maxlen) ++{ ++ return (maxlen >= sizeof *nla ++ && nla->nla_len >= sizeof *nla ++ && nla->nla_len <= maxlen); ++} ++ ++static inline size_t ++nl_attr_len_pad(const struct nlattr *nla, size_t maxlen) ++{ ++ size_t len = NLA_ALIGN(nla->nla_len); ++ ++ return len <= maxlen ? len : nla->nla_len; ++} ++ ++/* This macro is careful to check for attributes with bad lengths. */ ++#define NL_ATTR_FOR_EACH(ITER, LEFT, ATTRS, ATTRS_LEN) \ ++ for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN); \ ++ nl_attr_is_valid(ITER, LEFT); \ ++ (LEFT) -= nl_attr_len_pad(ITER, LEFT), (ITER) = nl_attr_next(ITER)) ++ ++ ++/* This macro does not check for attributes with bad lengths. It should only ++ * be used with messages from trusted sources or with messages that have ++ * already been validated (e.g. with NL_ATTR_FOR_EACH). */ ++#define NL_ATTR_FOR_EACH_UNSAFE(ITER, LEFT, ATTRS, ATTRS_LEN) \ ++ for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN); \ ++ (LEFT) > 0; \ ++ (LEFT) -= nl_attr_len_pad(ITER, LEFT), (ITER) = nl_attr_next(ITER)) ++ ++/* These variants are convenient for iterating nested attributes. */ ++#define NL_NESTED_FOR_EACH(ITER, LEFT, A) \ ++ NL_ATTR_FOR_EACH(ITER, LEFT, nl_attr_get(A), nl_attr_get_size(A)) ++#define NL_NESTED_FOR_EACH_UNSAFE(ITER, LEFT, A) \ ++ NL_ATTR_FOR_EACH_UNSAFE(ITER, LEFT, nl_attr_get(A), nl_attr_get_size(A)) ++ ++/* Netlink attribute parsing. */ ++int nl_attr_type(const struct nlattr *); ++const void *nl_attr_get(const struct nlattr *); ++size_t nl_attr_get_size(const struct nlattr *); ++const void *nl_attr_get_unspec(const struct nlattr *, size_t size); ++bool nl_attr_get_flag(const struct nlattr *); ++uint8_t nl_attr_get_u8(const struct nlattr *); ++uint16_t nl_attr_get_u16(const struct nlattr *); ++uint32_t nl_attr_get_u32(const struct nlattr *); ++uint64_t nl_attr_get_u64(const struct nlattr *); ++ovs_u128 nl_attr_get_u128(const struct nlattr *); ++ovs_be16 nl_attr_get_be16(const struct nlattr *); ++ovs_be32 nl_attr_get_be32(const struct nlattr *); ++ovs_be64 nl_attr_get_be64(const struct nlattr *); ++ovs_be128 nl_attr_get_be128(const struct nlattr *); ++struct in6_addr nl_attr_get_in6_addr(const struct nlattr *nla); ++odp_port_t nl_attr_get_odp_port(const struct nlattr *); ++const char *nl_attr_get_string(const struct nlattr *); ++void nl_attr_get_nested(const struct nlattr *, struct ofpbuf *); ++struct eth_addr nl_attr_get_eth_addr(const struct nlattr *nla); ++struct ib_addr nl_attr_get_ib_addr(const struct nlattr *nla); ++ ++/* Netlink attribute policy. ++ * ++ * Specifies how to parse a single attribute from a Netlink message payload. ++ */ ++struct nl_policy ++{ ++ enum nl_attr_type type; ++ size_t min_len, max_len; ++ bool optional; ++}; ++ ++#define NL_POLICY_FOR(TYPE) \ ++ .type = NL_A_UNSPEC, .min_len = sizeof(TYPE), .max_len = sizeof(TYPE) ++ ++bool nl_attr_validate(const struct nlattr *, const struct nl_policy *); ++ ++bool nl_policy_parse(const struct ofpbuf *, size_t offset, ++ const struct nl_policy[], ++ struct nlattr *[], size_t n_attrs); ++bool nl_parse_nested(const struct nlattr *, const struct nl_policy[], ++ struct nlattr *[], size_t n_attrs); ++ ++const struct nlattr *nl_attr_find(const struct ofpbuf *, size_t hdr_len, ++ uint16_t type); ++const struct nlattr *nl_attr_find_nested(const struct nlattr *, uint16_t type); ++const struct nlattr *nl_attr_find__(const struct nlattr *attrs, size_t size, ++ uint16_t type); ++ ++#endif /* netlink.h */ +Index: openvswitch-2.17.2/lib/nx-match.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/nx-match.h ++++ /dev/null +@@ -1,181 +0,0 @@ +-/* +- * Copyright (c) 2010-2017, 2020 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NX_MATCH_H +-#define NX_MATCH_H 1 +- +-#include +-#include +-#include +-#include "openvswitch/compiler.h" -#include "flow.h" +-#include "openvswitch/meta-flow.h" +-#include "openvswitch/ofp-errors.h" +-#include "openvswitch/types.h" +- +-struct ds; +-struct match; +-struct ofpact_reg_move; +-struct ofpact_reg_load; +-struct ofpact_stack; +-struct ofpbuf; +-struct nx_action_reg_load; +-struct nx_action_reg_move; +-struct vl_mff_map; +- +- +-/* Nicira Extended Match (NXM) flexible flow match helper functions. +- * +- * See include/openflow/nicira-ext.h for NXM specification. +- */ +- +-char * mf_parse_field(const struct mf_field **field, const char *s) +- OVS_WARN_UNUSED_RESULT; +-void mf_format_subfield(const struct mf_subfield *, struct ds *); +-char *mf_parse_subfield__(struct mf_subfield *sf, const char **s) +- OVS_WARN_UNUSED_RESULT; +-char *mf_parse_subfield(struct mf_subfield *, const char *s) +- OVS_WARN_UNUSED_RESULT; +- +-/* Decoding matches. */ +-enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len, +- struct match *, ovs_be64 *cookie, +- ovs_be64 *cookie_mask, bool pipeline_fields_only, +- const struct tun_table *, const struct vl_mff_map *); +-enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, +- struct match *, ovs_be64 *cookie, +- ovs_be64 *cookie_mask, +- bool pipeline_fields_only, +- const struct tun_table *); +-enum ofperr oxm_pull_match(struct ofpbuf *, bool pipeline_fields_only, +- const struct tun_table *, const struct vl_mff_map *, +- struct match *); +-enum ofperr oxm_pull_match_loose(struct ofpbuf *, bool pipeline_fields_only, +- const struct tun_table *, struct match *); +-enum ofperr oxm_decode_match(const void *, size_t, bool, +- const struct tun_table *, +- const struct vl_mff_map *, struct match *); +-enum ofperr oxm_pull_field_array(const void *, size_t fields_len, +- struct field_array *); +- +-/* Encoding matches. */ +-int nx_put_match(struct ofpbuf *, const struct match *, +- ovs_be64 cookie, ovs_be64 cookie_mask); +-int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); +-void oxm_put_raw(struct ofpbuf *, const struct match *, enum ofp_version); +-void oxm_format_field_array(struct ds *, const struct field_array *); +-int oxm_put_field_array(struct ofpbuf *, const struct field_array *, +- enum ofp_version version); +- +-/* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field +- * ID followed by a value and possibly a mask). */ +-enum ofperr nx_pull_entry(struct ofpbuf *, const struct vl_mff_map *, +- const struct mf_field **, union mf_value *value, +- union mf_value *mask, bool is_action); +-enum ofperr nx_pull_header(struct ofpbuf *, const struct vl_mff_map *, +- const struct mf_field **, bool *masked); +-void nxm_put_entry_raw(struct ofpbuf *, enum mf_field_id field, +- enum ofp_version version, const void *value, +- const void *mask, size_t n_bytes); +-void nx_put_entry(struct ofpbuf *, const struct mf_field *, enum ofp_version, +- const union mf_value *value, const union mf_value *mask); +-void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version, +- bool masked); +-void nx_put_mff_header(struct ofpbuf *, const struct mf_field *, +- enum ofp_version, bool); +- +-/* NXM and OXM protocol headers values. +- * +- * These are often alternatives to nx_pull_entry/header() and +- * nx_put_entry/header() for decoding and encoding OXM/NXM. In those cases, +- * the nx_*() functions should be preferred because they can support the 64-bit +- * "experimenter" OXM format (even though it is not yet implemented). */ +-uint32_t mf_nxm_header(enum mf_field_id); +-uint32_t nxm_header_from_mff(const struct mf_field *); +-const struct mf_field *mf_from_nxm_header(uint32_t nxm_header, +- const struct vl_mff_map *); +- +-char *nx_match_to_string(const uint8_t *, unsigned int match_len); +-char *oxm_match_to_string(const struct ofpbuf *, unsigned int match_len); +-int nx_match_from_string(const char *, struct ofpbuf *); +-int oxm_match_from_string(const char *, struct ofpbuf *); +- +-void nx_format_field_name(enum mf_field_id, enum ofp_version, struct ds *); +- +-char *nxm_parse_reg_move(struct ofpact_reg_move *, const char *) +- OVS_WARN_UNUSED_RESULT; +- +-void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *); +- +-enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *, +- const struct match *); +- +-void nxm_reg_load(const struct mf_subfield *, uint64_t src_data, +- struct flow *, struct flow_wildcards *); +- +-char *nxm_parse_stack_action(struct ofpact_stack *, const char *) +- OVS_WARN_UNUSED_RESULT; +- +-void nxm_format_stack_push(const struct ofpact_stack *, struct ds *); +-void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *); +- +-enum ofperr nxm_stack_push_check(const struct ofpact_stack *, +- const struct match *); +-enum ofperr nxm_stack_pop_check(const struct ofpact_stack *, +- const struct match *); +-void nx_stack_push(struct ofpbuf *stack, const void *v, uint8_t bytes); +-void nx_stack_push_bottom(struct ofpbuf *stack, const void *v, uint8_t bytes); +-void *nx_stack_pop(struct ofpbuf *stack, uint8_t *bytes); +- +-void nxm_execute_stack_push(const struct ofpact_stack *, +- const struct flow *, struct flow_wildcards *, +- struct ofpbuf *); +-bool nxm_execute_stack_pop(const struct ofpact_stack *, +- struct flow *, struct flow_wildcards *, +- struct ofpbuf *); +- +-ovs_be64 oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *, enum ofp_version); +-struct mf_bitmap oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap, +- enum ofp_version); +-struct mf_bitmap oxm_writable_fields(void); +-struct mf_bitmap oxm_matchable_fields(void); +-struct mf_bitmap oxm_maskable_fields(void); +- +-/* Dealing with the 'ofs_nbits' members in several Nicira extensions. */ +- +-static inline ovs_be16 +-nxm_encode_ofs_nbits(int ofs, int n_bits) +-{ +- return htons((ofs << 6) | (n_bits - 1)); +-} +- +-static inline int +-nxm_decode_ofs(ovs_be16 ofs_nbits) +-{ +- return ntohs(ofs_nbits) >> 6; +-} +- +-static inline int +-nxm_decode_n_bits(ovs_be16 ofs_nbits) +-{ +- return (ntohs(ofs_nbits) & 0x3f) + 1; +-} +- +-/* This is my guess at the length of a "typical" nx_match, for use in +- * predicting space requirements. */ +-#define NXM_TYPICAL_LEN 64 +- +-#endif /* nx-match.h */ +Index: openvswitch-2.17.2/include/internal/nx-match.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/nx-match.h +@@ -0,0 +1,181 @@ ++/* ++ * Copyright (c) 2010-2017, 2020 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NX_MATCH_H ++#define NX_MATCH_H 1 ++ ++#include ++#include ++#include ++#include "openvswitch/compiler.h" +#include "internal/flow.h" - #include "openvswitch/meta-flow.h" - #include "openvswitch/ofp-errors.h" - #include "openvswitch/types.h" -diff --git a/lib/ovs-atomic-c++.h b/include/internal/ovs-atomic-c++.h -similarity index 100% -rename from lib/ovs-atomic-c++.h -rename to include/internal/ovs-atomic-c++.h -diff --git a/lib/ovs-atomic-c11.h b/include/internal/ovs-atomic-c11.h -similarity index 100% -rename from lib/ovs-atomic-c11.h -rename to include/internal/ovs-atomic-c11.h -diff --git a/lib/ovs-atomic-clang.h b/include/internal/ovs-atomic-clang.h -similarity index 98% -rename from lib/ovs-atomic-clang.h -rename to include/internal/ovs-atomic-clang.h -index cdf02a512..77e0db1e9 100644 ---- a/lib/ovs-atomic-clang.h -+++ b/include/internal/ovs-atomic-clang.h -@@ -94,4 +94,4 @@ typedef enum { - #define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ - (*(ORIG) = __c11_atomic_fetch_and(RMW, ARG, ORDER), (void) 0) - ++#include "openvswitch/meta-flow.h" ++#include "openvswitch/ofp-errors.h" ++#include "openvswitch/types.h" ++ ++struct ds; ++struct match; ++struct ofpact_reg_move; ++struct ofpact_reg_load; ++struct ofpact_stack; ++struct ofpbuf; ++struct nx_action_reg_load; ++struct nx_action_reg_move; ++struct vl_mff_map; ++ ++ ++/* Nicira Extended Match (NXM) flexible flow match helper functions. ++ * ++ * See include/openflow/nicira-ext.h for NXM specification. ++ */ ++ ++char * mf_parse_field(const struct mf_field **field, const char *s) ++ OVS_WARN_UNUSED_RESULT; ++void mf_format_subfield(const struct mf_subfield *, struct ds *); ++char *mf_parse_subfield__(struct mf_subfield *sf, const char **s) ++ OVS_WARN_UNUSED_RESULT; ++char *mf_parse_subfield(struct mf_subfield *, const char *s) ++ OVS_WARN_UNUSED_RESULT; ++ ++/* Decoding matches. */ ++enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len, ++ struct match *, ovs_be64 *cookie, ++ ovs_be64 *cookie_mask, bool pipeline_fields_only, ++ const struct tun_table *, const struct vl_mff_map *); ++enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, ++ struct match *, ovs_be64 *cookie, ++ ovs_be64 *cookie_mask, ++ bool pipeline_fields_only, ++ const struct tun_table *); ++enum ofperr oxm_pull_match(struct ofpbuf *, bool pipeline_fields_only, ++ const struct tun_table *, const struct vl_mff_map *, ++ struct match *); ++enum ofperr oxm_pull_match_loose(struct ofpbuf *, bool pipeline_fields_only, ++ const struct tun_table *, struct match *); ++enum ofperr oxm_decode_match(const void *, size_t, bool, ++ const struct tun_table *, ++ const struct vl_mff_map *, struct match *); ++enum ofperr oxm_pull_field_array(const void *, size_t fields_len, ++ struct field_array *); ++ ++/* Encoding matches. */ ++int nx_put_match(struct ofpbuf *, const struct match *, ++ ovs_be64 cookie, ovs_be64 cookie_mask); ++int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); ++void oxm_put_raw(struct ofpbuf *, const struct match *, enum ofp_version); ++void oxm_format_field_array(struct ds *, const struct field_array *); ++int oxm_put_field_array(struct ofpbuf *, const struct field_array *, ++ enum ofp_version version); ++ ++/* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field ++ * ID followed by a value and possibly a mask). */ ++enum ofperr nx_pull_entry(struct ofpbuf *, const struct vl_mff_map *, ++ const struct mf_field **, union mf_value *value, ++ union mf_value *mask, bool is_action); ++enum ofperr nx_pull_header(struct ofpbuf *, const struct vl_mff_map *, ++ const struct mf_field **, bool *masked); ++void nxm_put_entry_raw(struct ofpbuf *, enum mf_field_id field, ++ enum ofp_version version, const void *value, ++ const void *mask, size_t n_bytes); ++void nx_put_entry(struct ofpbuf *, const struct mf_field *, enum ofp_version, ++ const union mf_value *value, const union mf_value *mask); ++void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version, ++ bool masked); ++void nx_put_mff_header(struct ofpbuf *, const struct mf_field *, ++ enum ofp_version, bool); ++ ++/* NXM and OXM protocol headers values. ++ * ++ * These are often alternatives to nx_pull_entry/header() and ++ * nx_put_entry/header() for decoding and encoding OXM/NXM. In those cases, ++ * the nx_*() functions should be preferred because they can support the 64-bit ++ * "experimenter" OXM format (even though it is not yet implemented). */ ++uint32_t mf_nxm_header(enum mf_field_id); ++uint32_t nxm_header_from_mff(const struct mf_field *); ++const struct mf_field *mf_from_nxm_header(uint32_t nxm_header, ++ const struct vl_mff_map *); ++ ++char *nx_match_to_string(const uint8_t *, unsigned int match_len); ++char *oxm_match_to_string(const struct ofpbuf *, unsigned int match_len); ++int nx_match_from_string(const char *, struct ofpbuf *); ++int oxm_match_from_string(const char *, struct ofpbuf *); ++ ++void nx_format_field_name(enum mf_field_id, enum ofp_version, struct ds *); ++ ++char *nxm_parse_reg_move(struct ofpact_reg_move *, const char *) ++ OVS_WARN_UNUSED_RESULT; ++ ++void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *); ++ ++enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *, ++ const struct match *); ++ ++void nxm_reg_load(const struct mf_subfield *, uint64_t src_data, ++ struct flow *, struct flow_wildcards *); ++ ++char *nxm_parse_stack_action(struct ofpact_stack *, const char *) ++ OVS_WARN_UNUSED_RESULT; ++ ++void nxm_format_stack_push(const struct ofpact_stack *, struct ds *); ++void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *); ++ ++enum ofperr nxm_stack_push_check(const struct ofpact_stack *, ++ const struct match *); ++enum ofperr nxm_stack_pop_check(const struct ofpact_stack *, ++ const struct match *); ++void nx_stack_push(struct ofpbuf *stack, const void *v, uint8_t bytes); ++void nx_stack_push_bottom(struct ofpbuf *stack, const void *v, uint8_t bytes); ++void *nx_stack_pop(struct ofpbuf *stack, uint8_t *bytes); ++ ++void nxm_execute_stack_push(const struct ofpact_stack *, ++ const struct flow *, struct flow_wildcards *, ++ struct ofpbuf *); ++bool nxm_execute_stack_pop(const struct ofpact_stack *, ++ struct flow *, struct flow_wildcards *, ++ struct ofpbuf *); ++ ++ovs_be64 oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *, enum ofp_version); ++struct mf_bitmap oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap, ++ enum ofp_version); ++struct mf_bitmap oxm_writable_fields(void); ++struct mf_bitmap oxm_matchable_fields(void); ++struct mf_bitmap oxm_maskable_fields(void); ++ ++/* Dealing with the 'ofs_nbits' members in several Nicira extensions. */ ++ ++static inline ovs_be16 ++nxm_encode_ofs_nbits(int ofs, int n_bits) ++{ ++ return htons((ofs << 6) | (n_bits - 1)); ++} ++ ++static inline int ++nxm_decode_ofs(ovs_be16 ofs_nbits) ++{ ++ return ntohs(ofs_nbits) >> 6; ++} ++ ++static inline int ++nxm_decode_n_bits(ovs_be16 ofs_nbits) ++{ ++ return (ntohs(ofs_nbits) & 0x3f) + 1; ++} ++ ++/* This is my guess at the length of a "typical" nx_match, for use in ++ * predicting space requirements. */ ++#define NXM_TYPICAL_LEN 64 ++ ++#endif /* nx-match.h */ +Index: openvswitch-2.17.2/lib/ovs-atomic-clang.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-clang.h ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on Clang. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#define OVS_ATOMIC_CLANG_IMPL 1 +- +-#define ATOMIC(TYPE) _Atomic(TYPE) +- +-#define ATOMIC_VAR_INIT(VALUE) (VALUE) +- +-#define atomic_init(OBJECT, VALUE) __c11_atomic_init(OBJECT, VALUE) +- +-/* Clang hard-codes these exact values internally but does not appear to +- * export any names for them. */ +-typedef enum { +- memory_order_relaxed = 0, +- memory_order_consume = 1, +- memory_order_acquire = 2, +- memory_order_release = 3, +- memory_order_acq_rel = 4, +- memory_order_seq_cst = 5 +-} memory_order; +- +-#define atomic_thread_fence(ORDER) __c11_atomic_thread_fence(ORDER) +-#define atomic_signal_fence(ORDER) __c11_atomic_signal_fence(ORDER) +- +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- __c11_atomic_store(DST, SRC, ORDER) +- +- +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- (*(DST) = __c11_atomic_load(SRC, ORDER), \ +- (void) 0) +- +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- __c11_atomic_compare_exchange_strong(DST, EXP, SRC, ORD1, ORD2) +- +-#define atomic_compare_exchange_weak(DST, EXP, SRC) \ +- atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- __c11_atomic_compare_exchange_weak(DST, EXP, SRC, ORD1, ORD2) +- +-#define atomic_exchange(RMW, ARG) \ +- atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) +-#define atomic_exchange_explicit(RMW, ARG, ORDER) \ +- __c11_atomic_exchange(RMW, ARG, ORDER) +- +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = __c11_atomic_fetch_add(RMW, ARG, ORDER), (void) 0) +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = __c11_atomic_fetch_sub(RMW, ARG, ORDER), (void) 0) +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = __c11_atomic_fetch_or(RMW, ARG, ORDER), (void) 0) +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = __c11_atomic_fetch_xor(RMW, ARG, ORDER), (void) 0) +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = __c11_atomic_fetch_and(RMW, ARG, ORDER), (void) 0) +- -#include "ovs-atomic-flag-gcc4.7+.h" +Index: openvswitch-2.17.2/include/internal/ovs-atomic-clang.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-clang.h +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on Clang. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#define OVS_ATOMIC_CLANG_IMPL 1 ++ ++#define ATOMIC(TYPE) _Atomic(TYPE) ++ ++#define ATOMIC_VAR_INIT(VALUE) (VALUE) ++ ++#define atomic_init(OBJECT, VALUE) __c11_atomic_init(OBJECT, VALUE) ++ ++/* Clang hard-codes these exact values internally but does not appear to ++ * export any names for them. */ ++typedef enum { ++ memory_order_relaxed = 0, ++ memory_order_consume = 1, ++ memory_order_acquire = 2, ++ memory_order_release = 3, ++ memory_order_acq_rel = 4, ++ memory_order_seq_cst = 5 ++} memory_order; ++ ++#define atomic_thread_fence(ORDER) __c11_atomic_thread_fence(ORDER) ++#define atomic_signal_fence(ORDER) __c11_atomic_signal_fence(ORDER) ++ ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ __c11_atomic_store(DST, SRC, ORDER) ++ ++ ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ (*(DST) = __c11_atomic_load(SRC, ORDER), \ ++ (void) 0) ++ ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ __c11_atomic_compare_exchange_strong(DST, EXP, SRC, ORD1, ORD2) ++ ++#define atomic_compare_exchange_weak(DST, EXP, SRC) \ ++ atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ __c11_atomic_compare_exchange_weak(DST, EXP, SRC, ORD1, ORD2) ++ ++#define atomic_exchange(RMW, ARG) \ ++ atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) ++#define atomic_exchange_explicit(RMW, ARG, ORDER) \ ++ __c11_atomic_exchange(RMW, ARG, ORDER) ++ ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = __c11_atomic_fetch_add(RMW, ARG, ORDER), (void) 0) ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = __c11_atomic_fetch_sub(RMW, ARG, ORDER), (void) 0) ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = __c11_atomic_fetch_or(RMW, ARG, ORDER), (void) 0) ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = __c11_atomic_fetch_xor(RMW, ARG, ORDER), (void) 0) ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = __c11_atomic_fetch_and(RMW, ARG, ORDER), (void) 0) ++ +#include "internal/ovs-atomic-flag-gcc4.7+.h" -diff --git a/lib/ovs-atomic-flag-gcc4.7+.h b/include/internal/ovs-atomic-flag-gcc4.7+.h -similarity index 100% -rename from lib/ovs-atomic-flag-gcc4.7+.h -rename to include/internal/ovs-atomic-flag-gcc4.7+.h -diff --git a/lib/ovs-atomic-gcc4+.h b/include/internal/ovs-atomic-gcc4+.h -similarity index 99% -rename from lib/ovs-atomic-gcc4+.h -rename to include/internal/ovs-atomic-gcc4+.h -index f9accde1a..cff986311 100644 ---- a/lib/ovs-atomic-gcc4+.h -+++ b/include/internal/ovs-atomic-gcc4+.h -@@ -19,7 +19,7 @@ - #error "This header should only be included indirectly via ovs-atomic.h." - #endif - +Index: openvswitch-2.17.2/lib/ovs-atomic-gcc4+.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-gcc4+.h ++++ /dev/null +@@ -1,208 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on GCC 4.x. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- -#include "ovs-atomic-locked.h" +-#define OVS_ATOMIC_GCC4P_IMPL 1 +- +-#define ATOMIC(TYPE) TYPE +- +-#define ATOMIC_BOOL_LOCK_FREE 2 +-#define ATOMIC_CHAR_LOCK_FREE 2 +-#define ATOMIC_SHORT_LOCK_FREE 2 +-#define ATOMIC_INT_LOCK_FREE 2 +-#define ATOMIC_LONG_LOCK_FREE (ULONG_MAX <= UINTPTR_MAX ? 2 : 0) +-#define ATOMIC_LLONG_LOCK_FREE (ULLONG_MAX <= UINTPTR_MAX ? 2 : 0) +-#define ATOMIC_POINTER_LOCK_FREE 2 +- +-typedef enum { +- memory_order_relaxed, +- memory_order_consume, +- memory_order_acquire, +- memory_order_release, +- memory_order_acq_rel, +- memory_order_seq_cst +-} memory_order; +- +-#define IS_LOCKLESS_ATOMIC(OBJECT) (sizeof(OBJECT) <= sizeof(void *)) +- +-#define ATOMIC_VAR_INIT(VALUE) VALUE +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-static inline void +-atomic_thread_fence(memory_order order) +-{ +- if (order != memory_order_relaxed) { +- __sync_synchronize(); +- } +-} +- +-static inline void +-atomic_thread_fence_if_seq_cst(memory_order order) +-{ +- if (order == memory_order_seq_cst) { +- __sync_synchronize(); +- } +-} +- +-static inline void +-atomic_signal_fence(memory_order order) +-{ +- if (order != memory_order_relaxed) { +- asm volatile("" : : : "memory"); +- } +-} +- +-#define atomic_is_lock_free(OBJ) \ +- ((void) *(OBJ), \ +- IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) +- +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(SRC) src__ = (SRC); \ +- \ +- if (IS_LOCKLESS_ATOMIC(*dst__)) { \ +- atomic_thread_fence(ORDER); \ +- *(typeof(*(DST)) volatile *)dst__ = src__; \ +- atomic_thread_fence_if_seq_cst(ORDER); \ +- } else { \ +- atomic_store_locked(dst__, src__); \ +- } \ +- (void) 0; \ +- }) +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(SRC) src__ = (SRC); \ +- \ +- if (IS_LOCKLESS_ATOMIC(*src__)) { \ +- atomic_thread_fence_if_seq_cst(ORDER); \ +- *dst__ = *(typeof(*(SRC)) volatile *)src__; \ +- } else { \ +- atomic_read_locked(src__, dst__); \ +- } \ +- (void) 0; \ +- }) +- +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(EXP) expp__ = (EXP); \ +- typeof(SRC) src__ = (SRC); \ +- typeof(SRC) exp__ = *expp__; \ +- typeof(SRC) ret__; \ +- \ +- ret__ = __sync_val_compare_and_swap(dst__, exp__, src__); \ +- if (ret__ != exp__) { \ +- *expp__ = ret__; \ +- } \ +- ret__ == exp__; \ +- }) +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- ((void) (ORD1), (void) (ORD2), \ +- atomic_compare_exchange_strong(DST, EXP, SRC)) +-#define atomic_compare_exchange_weak \ +- atomic_compare_exchange_strong +-#define atomic_compare_exchange_weak_explicit \ +- atomic_compare_exchange_strong_explicit +- +-#define atomic_exchange_explicit(DST, SRC, ORDER) \ +- __sync_lock_test_and_set(DST, SRC) +-#define atomic_exchange(DST, SRC) \ +- atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) +- +-#define atomic_op__(RMW, OP, ARG, ORIG) \ +- ({ \ +- typeof(RMW) rmw__ = (RMW); \ +- typeof(ARG) arg__ = (ARG); \ +- typeof(ORIG) orig__ = (ORIG); \ +- \ +- if (IS_LOCKLESS_ATOMIC(*rmw__)) { \ +- *orig__ = __sync_fetch_and_##OP(rmw__, arg__); \ +- } else { \ +- atomic_op_locked(rmw__, OP, arg__, orig__); \ +- } \ +- (void) 0; \ +- }) +- +-#define atomic_add(RMW, ARG, ORIG) atomic_op__(RMW, add, ARG, ORIG) +-#define atomic_sub(RMW, ARG, ORIG) atomic_op__(RMW, sub, ARG, ORIG) +-#define atomic_or(RMW, ARG, ORIG) atomic_op__(RMW, or, ARG, ORIG) +-#define atomic_xor(RMW, ARG, ORIG) atomic_op__(RMW, xor, ARG, ORIG) +-#define atomic_and(RMW, ARG, ORIG) atomic_op__(RMW, and, ARG, ORIG) +- +-#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER) \ +- ((void) (ORDER), atomic_add(RMW, OPERAND, ORIG)) +-#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER) \ +- ((void) (ORDER), atomic_sub(RMW, OPERAND, ORIG)) +-#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER) \ +- ((void) (ORDER), atomic_or(RMW, OPERAND, ORIG)) +-#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER) \ +- ((void) (ORDER), atomic_xor(RMW, OPERAND, ORIG)) +-#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER) \ +- ((void) (ORDER), atomic_and(RMW, OPERAND, ORIG)) +- +-/* atomic_flag */ +- +-typedef struct { +- int b; +-} atomic_flag; +-#define ATOMIC_FLAG_INIT { false } +- +-static inline bool +-atomic_flag_test_and_set_explicit(volatile atomic_flag *object, +- memory_order order) +-{ +- bool old; +- +- /* __sync_lock_test_and_set() by itself is an acquire barrier. +- * For anything higher additional barriers are needed. */ +- if (order > memory_order_acquire) { +- atomic_thread_fence(order); +- } +- old = __sync_lock_test_and_set(&object->b, 1); +- atomic_thread_fence_if_seq_cst(order); +- +- return old; +-} +- +-#define atomic_flag_test_and_set(FLAG) \ +- atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) +- +-static inline void +-atomic_flag_clear_explicit(volatile atomic_flag *object, +- memory_order order) +-{ +- /* __sync_lock_release() by itself is a release barrier. For +- * anything else additional barrier may be needed. */ +- if (order != memory_order_release) { +- atomic_thread_fence(order); +- } +- __sync_lock_release(&object->b); +- atomic_thread_fence_if_seq_cst(order); +-} +- +-#define atomic_flag_clear(FLAG) \ +- atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/include/internal/ovs-atomic-gcc4+.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-gcc4+.h +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on GCC 4.x. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ +#include "internal/ovs-atomic-locked.h" - #define OVS_ATOMIC_GCC4P_IMPL 1 - - #define ATOMIC(TYPE) TYPE -diff --git a/lib/ovs-atomic-gcc4.7+.h b/include/internal/ovs-atomic-gcc4.7+.h -similarity index 98% -rename from lib/ovs-atomic-gcc4.7+.h -rename to include/internal/ovs-atomic-gcc4.7+.h -index 846e05775..9bcb0efe5 100644 ---- a/lib/ovs-atomic-gcc4.7+.h -+++ b/include/internal/ovs-atomic-gcc4.7+.h -@@ -88,4 +88,4 @@ typedef enum { - #define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER) \ - (*(ORIG) = __atomic_fetch_and(RMW, OPERAND, ORDER), (void) 0) - ++#define OVS_ATOMIC_GCC4P_IMPL 1 ++ ++#define ATOMIC(TYPE) TYPE ++ ++#define ATOMIC_BOOL_LOCK_FREE 2 ++#define ATOMIC_CHAR_LOCK_FREE 2 ++#define ATOMIC_SHORT_LOCK_FREE 2 ++#define ATOMIC_INT_LOCK_FREE 2 ++#define ATOMIC_LONG_LOCK_FREE (ULONG_MAX <= UINTPTR_MAX ? 2 : 0) ++#define ATOMIC_LLONG_LOCK_FREE (ULLONG_MAX <= UINTPTR_MAX ? 2 : 0) ++#define ATOMIC_POINTER_LOCK_FREE 2 ++ ++typedef enum { ++ memory_order_relaxed, ++ memory_order_consume, ++ memory_order_acquire, ++ memory_order_release, ++ memory_order_acq_rel, ++ memory_order_seq_cst ++} memory_order; ++ ++#define IS_LOCKLESS_ATOMIC(OBJECT) (sizeof(OBJECT) <= sizeof(void *)) ++ ++#define ATOMIC_VAR_INIT(VALUE) VALUE ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++static inline void ++atomic_thread_fence(memory_order order) ++{ ++ if (order != memory_order_relaxed) { ++ __sync_synchronize(); ++ } ++} ++ ++static inline void ++atomic_thread_fence_if_seq_cst(memory_order order) ++{ ++ if (order == memory_order_seq_cst) { ++ __sync_synchronize(); ++ } ++} ++ ++static inline void ++atomic_signal_fence(memory_order order) ++{ ++ if (order != memory_order_relaxed) { ++ asm volatile("" : : : "memory"); ++ } ++} ++ ++#define atomic_is_lock_free(OBJ) \ ++ ((void) *(OBJ), \ ++ IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) ++ ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(SRC) src__ = (SRC); \ ++ \ ++ if (IS_LOCKLESS_ATOMIC(*dst__)) { \ ++ atomic_thread_fence(ORDER); \ ++ *(typeof(*(DST)) volatile *)dst__ = src__; \ ++ atomic_thread_fence_if_seq_cst(ORDER); \ ++ } else { \ ++ atomic_store_locked(dst__, src__); \ ++ } \ ++ (void) 0; \ ++ }) ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(SRC) src__ = (SRC); \ ++ \ ++ if (IS_LOCKLESS_ATOMIC(*src__)) { \ ++ atomic_thread_fence_if_seq_cst(ORDER); \ ++ *dst__ = *(typeof(*(SRC)) volatile *)src__; \ ++ } else { \ ++ atomic_read_locked(src__, dst__); \ ++ } \ ++ (void) 0; \ ++ }) ++ ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(EXP) expp__ = (EXP); \ ++ typeof(SRC) src__ = (SRC); \ ++ typeof(SRC) exp__ = *expp__; \ ++ typeof(SRC) ret__; \ ++ \ ++ ret__ = __sync_val_compare_and_swap(dst__, exp__, src__); \ ++ if (ret__ != exp__) { \ ++ *expp__ = ret__; \ ++ } \ ++ ret__ == exp__; \ ++ }) ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ ((void) (ORD1), (void) (ORD2), \ ++ atomic_compare_exchange_strong(DST, EXP, SRC)) ++#define atomic_compare_exchange_weak \ ++ atomic_compare_exchange_strong ++#define atomic_compare_exchange_weak_explicit \ ++ atomic_compare_exchange_strong_explicit ++ ++#define atomic_exchange_explicit(DST, SRC, ORDER) \ ++ __sync_lock_test_and_set(DST, SRC) ++#define atomic_exchange(DST, SRC) \ ++ atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) ++ ++#define atomic_op__(RMW, OP, ARG, ORIG) \ ++ ({ \ ++ typeof(RMW) rmw__ = (RMW); \ ++ typeof(ARG) arg__ = (ARG); \ ++ typeof(ORIG) orig__ = (ORIG); \ ++ \ ++ if (IS_LOCKLESS_ATOMIC(*rmw__)) { \ ++ *orig__ = __sync_fetch_and_##OP(rmw__, arg__); \ ++ } else { \ ++ atomic_op_locked(rmw__, OP, arg__, orig__); \ ++ } \ ++ (void) 0; \ ++ }) ++ ++#define atomic_add(RMW, ARG, ORIG) atomic_op__(RMW, add, ARG, ORIG) ++#define atomic_sub(RMW, ARG, ORIG) atomic_op__(RMW, sub, ARG, ORIG) ++#define atomic_or(RMW, ARG, ORIG) atomic_op__(RMW, or, ARG, ORIG) ++#define atomic_xor(RMW, ARG, ORIG) atomic_op__(RMW, xor, ARG, ORIG) ++#define atomic_and(RMW, ARG, ORIG) atomic_op__(RMW, and, ARG, ORIG) ++ ++#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_add(RMW, OPERAND, ORIG)) ++#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_sub(RMW, OPERAND, ORIG)) ++#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_or(RMW, OPERAND, ORIG)) ++#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_xor(RMW, OPERAND, ORIG)) ++#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_and(RMW, OPERAND, ORIG)) ++ ++/* atomic_flag */ ++ ++typedef struct { ++ int b; ++} atomic_flag; ++#define ATOMIC_FLAG_INIT { false } ++ ++static inline bool ++atomic_flag_test_and_set_explicit(volatile atomic_flag *object, ++ memory_order order) ++{ ++ bool old; ++ ++ /* __sync_lock_test_and_set() by itself is an acquire barrier. ++ * For anything higher additional barriers are needed. */ ++ if (order > memory_order_acquire) { ++ atomic_thread_fence(order); ++ } ++ old = __sync_lock_test_and_set(&object->b, 1); ++ atomic_thread_fence_if_seq_cst(order); ++ ++ return old; ++} ++ ++#define atomic_flag_test_and_set(FLAG) \ ++ atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) ++ ++static inline void ++atomic_flag_clear_explicit(volatile atomic_flag *object, ++ memory_order order) ++{ ++ /* __sync_lock_release() by itself is a release barrier. For ++ * anything else additional barrier may be needed. */ ++ if (order != memory_order_release) { ++ atomic_thread_fence(order); ++ } ++ __sync_lock_release(&object->b); ++ atomic_thread_fence_if_seq_cst(order); ++} ++ ++#define atomic_flag_clear(FLAG) \ ++ atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/lib/ovs-atomic-gcc4.7+.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-gcc4.7+.h ++++ /dev/null +@@ -1,91 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on GCC 4.7 and later. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#define ATOMIC(TYPE) TYPE +- +-typedef enum { +- memory_order_relaxed = __ATOMIC_RELAXED, +- memory_order_consume = __ATOMIC_CONSUME, +- memory_order_acquire = __ATOMIC_ACQUIRE, +- memory_order_release = __ATOMIC_RELEASE, +- memory_order_acq_rel = __ATOMIC_ACQ_REL, +- memory_order_seq_cst = __ATOMIC_SEQ_CST +-} memory_order; +- +-#define ATOMIC_VAR_INIT(VALUE) (VALUE) +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-#define atomic_thread_fence __atomic_thread_fence +-#define atomic_signal_fence __atomic_signal_fence +-#define atomic_is_lock_free __atomic_is_lock_free +- +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +-#define atomic_store_explicit __atomic_store_n +- +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- (*(DST) = __atomic_load_n(SRC, ORDER), \ +- (void) 0) +- +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- __atomic_compare_exchange_n(DST, EXP, SRC, false, ORD1, ORD2) +- +-#define atomic_compare_exchange_weak(DST, EXP, SRC) \ +- atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- __atomic_compare_exchange_n(DST, EXP, SRC, true, ORD1, ORD2) +- +-#define atomic_exchange_explicit(DST, SRC, ORDER) \ +- __atomic_exchange_n(DST, SRC, ORDER) +-#define atomic_exchange(DST, SRC) \ +- atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) +- +-#define atomic_add(RMW, OPERAND, ORIG) \ +- atomic_add_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) +-#define atomic_sub(RMW, OPERAND, ORIG) \ +- atomic_sub_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) +-#define atomic_or(RMW, OPERAND, ORIG) \ +- atomic_or_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) +-#define atomic_xor(RMW, OPERAND, ORIG) \ +- atomic_xor_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) +-#define atomic_and(RMW, OPERAND, ORIG) \ +- atomic_and_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) +- +-#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER) \ +- (*(ORIG) = __atomic_fetch_add(RMW, OPERAND, ORDER), (void) 0) +-#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER) \ +- (*(ORIG) = __atomic_fetch_sub(RMW, OPERAND, ORDER), (void) 0) +-#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER) \ +- (*(ORIG) = __atomic_fetch_or(RMW, OPERAND, ORDER), (void) 0) +-#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER) \ +- (*(ORIG) = __atomic_fetch_xor(RMW, OPERAND, ORDER), (void) 0) +-#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER) \ +- (*(ORIG) = __atomic_fetch_and(RMW, OPERAND, ORDER), (void) 0) +- -#include "ovs-atomic-flag-gcc4.7+.h" +Index: openvswitch-2.17.2/include/internal/ovs-atomic-gcc4.7+.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-gcc4.7+.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on GCC 4.7 and later. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#define ATOMIC(TYPE) TYPE ++ ++typedef enum { ++ memory_order_relaxed = __ATOMIC_RELAXED, ++ memory_order_consume = __ATOMIC_CONSUME, ++ memory_order_acquire = __ATOMIC_ACQUIRE, ++ memory_order_release = __ATOMIC_RELEASE, ++ memory_order_acq_rel = __ATOMIC_ACQ_REL, ++ memory_order_seq_cst = __ATOMIC_SEQ_CST ++} memory_order; ++ ++#define ATOMIC_VAR_INIT(VALUE) (VALUE) ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++#define atomic_thread_fence __atomic_thread_fence ++#define atomic_signal_fence __atomic_signal_fence ++#define atomic_is_lock_free __atomic_is_lock_free ++ ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++#define atomic_store_explicit __atomic_store_n ++ ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ (*(DST) = __atomic_load_n(SRC, ORDER), \ ++ (void) 0) ++ ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ __atomic_compare_exchange_n(DST, EXP, SRC, false, ORD1, ORD2) ++ ++#define atomic_compare_exchange_weak(DST, EXP, SRC) \ ++ atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ __atomic_compare_exchange_n(DST, EXP, SRC, true, ORD1, ORD2) ++ ++#define atomic_exchange_explicit(DST, SRC, ORDER) \ ++ __atomic_exchange_n(DST, SRC, ORDER) ++#define atomic_exchange(DST, SRC) \ ++ atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) ++ ++#define atomic_add(RMW, OPERAND, ORIG) \ ++ atomic_add_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) ++#define atomic_sub(RMW, OPERAND, ORIG) \ ++ atomic_sub_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) ++#define atomic_or(RMW, OPERAND, ORIG) \ ++ atomic_or_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) ++#define atomic_xor(RMW, OPERAND, ORIG) \ ++ atomic_xor_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) ++#define atomic_and(RMW, OPERAND, ORIG) \ ++ atomic_and_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) ++ ++#define atomic_add_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ (*(ORIG) = __atomic_fetch_add(RMW, OPERAND, ORDER), (void) 0) ++#define atomic_sub_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ (*(ORIG) = __atomic_fetch_sub(RMW, OPERAND, ORDER), (void) 0) ++#define atomic_or_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ (*(ORIG) = __atomic_fetch_or(RMW, OPERAND, ORDER), (void) 0) ++#define atomic_xor_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ (*(ORIG) = __atomic_fetch_xor(RMW, OPERAND, ORDER), (void) 0) ++#define atomic_and_explicit(RMW, OPERAND, ORIG, ORDER) \ ++ (*(ORIG) = __atomic_fetch_and(RMW, OPERAND, ORDER), (void) 0) ++ +#include "internal/ovs-atomic-flag-gcc4.7+.h" -diff --git a/lib/ovs-atomic-i586.h b/include/internal/ovs-atomic-i586.h -similarity index 100% -rename from lib/ovs-atomic-i586.h -rename to include/internal/ovs-atomic-i586.h -diff --git a/lib/ovs-atomic-locked.c b/include/internal/ovs-atomic-locked.c -similarity index 94% -rename from lib/ovs-atomic-locked.c -rename to include/internal/ovs-atomic-locked.c -index dc2a4356c..3e8f8199f 100644 ---- a/lib/ovs-atomic-locked.c -+++ b/include/internal/ovs-atomic-locked.c -@@ -16,9 +16,9 @@ - - #include - +Index: openvswitch-2.17.2/lib/ovs-atomic-locked.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-locked.c ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#include +- -#include "ovs-atomic.h" -#include "hash.h" -#include "ovs-thread.h" +- +-#ifdef OVS_ATOMIC_LOCKED_IMPL +-static struct ovs_mutex * +-mutex_for_pointer(void *p) +-{ +- OVS_ALIGNED_STRUCT(CACHE_LINE_SIZE, aligned_mutex) { +- struct ovs_mutex mutex; +- char pad[PAD_SIZE(sizeof(struct ovs_mutex), CACHE_LINE_SIZE)]; +- }; +- +- static struct aligned_mutex atomic_mutexes[] = { +-#define MUTEX_INIT { .mutex = OVS_MUTEX_INITIALIZER } +-#define MUTEX_INIT4 MUTEX_INIT, MUTEX_INIT, MUTEX_INIT, MUTEX_INIT +-#define MUTEX_INIT16 MUTEX_INIT4, MUTEX_INIT4, MUTEX_INIT4, MUTEX_INIT4 +- MUTEX_INIT16, MUTEX_INIT16, +- }; +- BUILD_ASSERT_DECL(IS_POW2(ARRAY_SIZE(atomic_mutexes))); +- +- uint32_t hash = hash_pointer(p, 0); +- uint32_t indx = hash & (ARRAY_SIZE(atomic_mutexes) - 1); +- return &atomic_mutexes[indx].mutex; +-} +- +-void +-atomic_lock__(void *p) +- OVS_ACQUIRES(mutex_for_pointer(p)) +-{ +- ovs_mutex_lock(mutex_for_pointer(p)); +-} +- +-void +-atomic_unlock__(void *p) +- OVS_RELEASES(mutex_for_pointer(p)) +-{ +- ovs_mutex_unlock(mutex_for_pointer(p)); +-} +-#endif /* OVS_ATOMIC_LOCKED_IMPL */ +Index: openvswitch-2.17.2/include/internal/ovs-atomic-locked.c +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-locked.c +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++ +#include "openvswitch/ovs-atomic.h" +#include "internal/hash.h" +#include "openvswitch/ovs-thread.h" - - #ifdef OVS_ATOMIC_LOCKED_IMPL - static struct ovs_mutex * -diff --git a/lib/ovs-atomic-locked.h b/include/internal/ovs-atomic-locked.h -similarity index 100% -rename from lib/ovs-atomic-locked.h -rename to include/internal/ovs-atomic-locked.h -diff --git a/lib/ovs-atomic-msvc.h b/include/internal/ovs-atomic-msvc.h -similarity index 100% -rename from lib/ovs-atomic-msvc.h -rename to include/internal/ovs-atomic-msvc.h -diff --git a/lib/ovs-atomic-pthreads.h b/include/internal/ovs-atomic-pthreads.h -similarity index 99% -rename from lib/ovs-atomic-pthreads.h -rename to include/internal/ovs-atomic-pthreads.h -index 570a67fe4..3bd6cfb99 100644 ---- a/lib/ovs-atomic-pthreads.h -+++ b/include/internal/ovs-atomic-pthreads.h -@@ -19,7 +19,7 @@ - #error "This header should only be included indirectly via ovs-atomic.h." - #endif - ++ ++#ifdef OVS_ATOMIC_LOCKED_IMPL ++static struct ovs_mutex * ++mutex_for_pointer(void *p) ++{ ++ OVS_ALIGNED_STRUCT(CACHE_LINE_SIZE, aligned_mutex) { ++ struct ovs_mutex mutex; ++ char pad[PAD_SIZE(sizeof(struct ovs_mutex), CACHE_LINE_SIZE)]; ++ }; ++ ++ static struct aligned_mutex atomic_mutexes[] = { ++#define MUTEX_INIT { .mutex = OVS_MUTEX_INITIALIZER } ++#define MUTEX_INIT4 MUTEX_INIT, MUTEX_INIT, MUTEX_INIT, MUTEX_INIT ++#define MUTEX_INIT16 MUTEX_INIT4, MUTEX_INIT4, MUTEX_INIT4, MUTEX_INIT4 ++ MUTEX_INIT16, MUTEX_INIT16, ++ }; ++ BUILD_ASSERT_DECL(IS_POW2(ARRAY_SIZE(atomic_mutexes))); ++ ++ uint32_t hash = hash_pointer(p, 0); ++ uint32_t indx = hash & (ARRAY_SIZE(atomic_mutexes) - 1); ++ return &atomic_mutexes[indx].mutex; ++} ++ ++void ++atomic_lock__(void *p) ++ OVS_ACQUIRES(mutex_for_pointer(p)) ++{ ++ ovs_mutex_lock(mutex_for_pointer(p)); ++} ++ ++void ++atomic_unlock__(void *p) ++ OVS_RELEASES(mutex_for_pointer(p)) ++{ ++ ovs_mutex_unlock(mutex_for_pointer(p)); ++} ++#endif /* OVS_ATOMIC_LOCKED_IMPL */ +Index: openvswitch-2.17.2/lib/ovs-atomic-pthreads.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-pthreads.h ++++ /dev/null +@@ -1,145 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives using pthreads. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- -#include "ovs-atomic-locked.h" +- +-#define OVS_ATOMIC_PTHREADS_IMPL 1 +- +-#define ATOMIC(TYPE) TYPE +- +-#define ATOMIC_BOOL_LOCK_FREE 0 +-#define ATOMIC_CHAR_LOCK_FREE 0 +-#define ATOMIC_SHORT_LOCK_FREE 0 +-#define ATOMIC_INT_LOCK_FREE 0 +-#define ATOMIC_LONG_LOCK_FREE 0 +-#define ATOMIC_LLONG_LOCK_FREE 0 +-#define ATOMIC_POINTER_LOCK_FREE 0 +- +-typedef enum { +- memory_order_relaxed, +- memory_order_consume, +- memory_order_acquire, +- memory_order_release, +- memory_order_acq_rel, +- memory_order_seq_cst +-} memory_order; +- +-#define ATOMIC_VAR_INIT(VALUE) (VALUE) +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-static inline void +-atomic_thread_fence(memory_order order OVS_UNUSED) +-{ +- /* Nothing to do. */ +-} +- +-static inline void +-atomic_signal_fence(memory_order order OVS_UNUSED) +-{ +- /* Nothing to do. */ +-} +- +-#define atomic_is_lock_free(OBJ) false +- +-#define atomic_store(DST, SRC) atomic_store_locked(DST, SRC) +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- ((void) (ORDER), atomic_store(DST, SRC)) +- +-#define atomic_read(SRC, DST) atomic_read_locked(SRC, DST) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- ((void) (ORDER), atomic_read(SRC, DST)) +- +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_locked(DST, EXP, SRC) +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- ((void) (ORD1), (void) (ORD2), \ +- atomic_compare_exchange_strong(DST, EXP, SRC)) +-#define atomic_compare_exchange_weak \ +- atomic_compare_exchange_strong +-#define atomic_compare_exchange_weak_explicit \ +- atomic_compare_exchange_strong_explicit +- +-#define atomic_exchange(DST, SRC) \ +- atomic_exchange_locked(DST, SRC) +-#define atomic_exchange_explicit(DST, SRC, ORDER) \ +- ((void) (ORDER), atomic_exchange(DST, SRC)) +- +-#define atomic_add(RMW, ARG, ORIG) atomic_op_locked(RMW, add, ARG, ORIG) +-#define atomic_sub(RMW, ARG, ORIG) atomic_op_locked(RMW, sub, ARG, ORIG) +-#define atomic_or( RMW, ARG, ORIG) atomic_op_locked(RMW, or, ARG, ORIG) +-#define atomic_xor(RMW, ARG, ORIG) atomic_op_locked(RMW, xor, ARG, ORIG) +-#define atomic_and(RMW, ARG, ORIG) atomic_op_locked(RMW, and, ARG, ORIG) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- ((void) (ORDER), atomic_add(RMW, ARG, ORIG)) +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- ((void) (ORDER), atomic_sub(RMW, ARG, ORIG)) +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- ((void) (ORDER), atomic_or(RMW, ARG, ORIG)) +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- ((void) (ORDER), atomic_xor(RMW, ARG, ORIG)) +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- ((void) (ORDER), atomic_and(RMW, ARG, ORIG)) +- +-/* atomic_flag */ +- +-typedef struct { +- bool b; +-} atomic_flag; +-#define ATOMIC_FLAG_INIT { false } +- +-static inline bool +-atomic_flag_test_and_set(volatile atomic_flag *flag_) +-{ +- atomic_flag *flag = CONST_CAST(atomic_flag *, flag_); +- bool old_value; +- +- atomic_lock__(flag); +- old_value = flag->b; +- flag->b = true; +- atomic_unlock__(flag); +- +- return old_value; +-} +- +-static inline bool +-atomic_flag_test_and_set_explicit(volatile atomic_flag *flag, +- memory_order order OVS_UNUSED) +-{ +- return atomic_flag_test_and_set(flag); +-} +- +-static inline void +-atomic_flag_clear(volatile atomic_flag *flag_) +-{ +- atomic_flag *flag = CONST_CAST(atomic_flag *, flag_); +- +- atomic_lock__(flag); +- flag->b = false; +- atomic_unlock__(flag); +-} +- +-static inline void +-atomic_flag_clear_explicit(volatile atomic_flag *flag, +- memory_order order OVS_UNUSED) +-{ +- atomic_flag_clear(flag); +-} +Index: openvswitch-2.17.2/include/internal/ovs-atomic-pthreads.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-pthreads.h +@@ -0,0 +1,145 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives using pthreads. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ +#include "internal/ovs-atomic-locked.h" - - #define OVS_ATOMIC_PTHREADS_IMPL 1 - -diff --git a/lib/ovs-atomic-x86_64.h b/include/internal/ovs-atomic-x86_64.h -similarity index 100% -rename from lib/ovs-atomic-x86_64.h -rename to include/internal/ovs-atomic-x86_64.h -diff --git a/lib/packets.h b/include/internal/packets.h -similarity index 99% -rename from lib/packets.h -rename to include/internal/packets.h -index ee4d96542..75225583c 100644 ---- a/lib/packets.h -+++ b/include/internal/packets.h -@@ -27,12 +27,12 @@ - #include "openvswitch/types.h" - #include "openvswitch/nsh.h" - #include "odp-netlink.h" ++ ++#define OVS_ATOMIC_PTHREADS_IMPL 1 ++ ++#define ATOMIC(TYPE) TYPE ++ ++#define ATOMIC_BOOL_LOCK_FREE 0 ++#define ATOMIC_CHAR_LOCK_FREE 0 ++#define ATOMIC_SHORT_LOCK_FREE 0 ++#define ATOMIC_INT_LOCK_FREE 0 ++#define ATOMIC_LONG_LOCK_FREE 0 ++#define ATOMIC_LLONG_LOCK_FREE 0 ++#define ATOMIC_POINTER_LOCK_FREE 0 ++ ++typedef enum { ++ memory_order_relaxed, ++ memory_order_consume, ++ memory_order_acquire, ++ memory_order_release, ++ memory_order_acq_rel, ++ memory_order_seq_cst ++} memory_order; ++ ++#define ATOMIC_VAR_INIT(VALUE) (VALUE) ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++static inline void ++atomic_thread_fence(memory_order order OVS_UNUSED) ++{ ++ /* Nothing to do. */ ++} ++ ++static inline void ++atomic_signal_fence(memory_order order OVS_UNUSED) ++{ ++ /* Nothing to do. */ ++} ++ ++#define atomic_is_lock_free(OBJ) false ++ ++#define atomic_store(DST, SRC) atomic_store_locked(DST, SRC) ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ ((void) (ORDER), atomic_store(DST, SRC)) ++ ++#define atomic_read(SRC, DST) atomic_read_locked(SRC, DST) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ ((void) (ORDER), atomic_read(SRC, DST)) ++ ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_locked(DST, EXP, SRC) ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ ((void) (ORD1), (void) (ORD2), \ ++ atomic_compare_exchange_strong(DST, EXP, SRC)) ++#define atomic_compare_exchange_weak \ ++ atomic_compare_exchange_strong ++#define atomic_compare_exchange_weak_explicit \ ++ atomic_compare_exchange_strong_explicit ++ ++#define atomic_exchange(DST, SRC) \ ++ atomic_exchange_locked(DST, SRC) ++#define atomic_exchange_explicit(DST, SRC, ORDER) \ ++ ((void) (ORDER), atomic_exchange(DST, SRC)) ++ ++#define atomic_add(RMW, ARG, ORIG) atomic_op_locked(RMW, add, ARG, ORIG) ++#define atomic_sub(RMW, ARG, ORIG) atomic_op_locked(RMW, sub, ARG, ORIG) ++#define atomic_or( RMW, ARG, ORIG) atomic_op_locked(RMW, or, ARG, ORIG) ++#define atomic_xor(RMW, ARG, ORIG) atomic_op_locked(RMW, xor, ARG, ORIG) ++#define atomic_and(RMW, ARG, ORIG) atomic_op_locked(RMW, and, ARG, ORIG) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_add(RMW, ARG, ORIG)) ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_sub(RMW, ARG, ORIG)) ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_or(RMW, ARG, ORIG)) ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_xor(RMW, ARG, ORIG)) ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ ((void) (ORDER), atomic_and(RMW, ARG, ORIG)) ++ ++/* atomic_flag */ ++ ++typedef struct { ++ bool b; ++} atomic_flag; ++#define ATOMIC_FLAG_INIT { false } ++ ++static inline bool ++atomic_flag_test_and_set(volatile atomic_flag *flag_) ++{ ++ atomic_flag *flag = CONST_CAST(atomic_flag *, flag_); ++ bool old_value; ++ ++ atomic_lock__(flag); ++ old_value = flag->b; ++ flag->b = true; ++ atomic_unlock__(flag); ++ ++ return old_value; ++} ++ ++static inline bool ++atomic_flag_test_and_set_explicit(volatile atomic_flag *flag, ++ memory_order order OVS_UNUSED) ++{ ++ return atomic_flag_test_and_set(flag); ++} ++ ++static inline void ++atomic_flag_clear(volatile atomic_flag *flag_) ++{ ++ atomic_flag *flag = CONST_CAST(atomic_flag *, flag_); ++ ++ atomic_lock__(flag); ++ flag->b = false; ++ atomic_unlock__(flag); ++} ++ ++static inline void ++atomic_flag_clear_explicit(volatile atomic_flag *flag, ++ memory_order order OVS_UNUSED) ++{ ++ atomic_flag_clear(flag); ++} +Index: openvswitch-2.17.2/lib/packets.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/packets.h ++++ /dev/null +@@ -1,1671 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef PACKETS_H +-#define PACKETS_H 1 +- +-#include +-#include +-#include +-#include +-#include "openvswitch/compiler.h" +-#include "openvswitch/geneve.h" +-#include "openvswitch/packets.h" +-#include "openvswitch/types.h" +-#include "openvswitch/nsh.h" +-#include "odp-netlink.h" -#include "random.h" -#include "hash.h" -#include "tun-metadata.h" -#include "unaligned.h" -#include "util.h" -#include "timeval.h" +- +-struct dp_packet; +-struct conn; +-struct ds; +- +-/* Purely internal to OVS userspace. These flags should never be exposed to +- * the outside world and so aren't included in the flags mask. */ +- +-/* Tunnel information is in userspace datapath format. */ +-#define FLOW_TNL_F_UDPIF (1 << 4) +- +-static inline bool ipv6_addr_is_set(const struct in6_addr *addr); +- +-static inline bool +-flow_tnl_dst_is_set(const struct flow_tnl *tnl) +-{ +- return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst); +-} +- +-static inline bool +-flow_tnl_src_is_set(const struct flow_tnl *tnl) +-{ +- return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src); +-} +- +-struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl); +-struct in6_addr flow_tnl_src(const struct flow_tnl *tnl); +- +-/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */ +-static inline size_t +-flow_tnl_size(const struct flow_tnl *src) +-{ +- if (!flow_tnl_dst_is_set(src)) { +- /* Covers ip_dst and ipv6_dst only. */ +- return offsetof(struct flow_tnl, ip_src); +- } +- if (src->flags & FLOW_TNL_F_UDPIF) { +- /* Datapath format, cover all options we have. */ +- return offsetof(struct flow_tnl, metadata.opts) +- + src->metadata.present.len; +- } +- if (!src->metadata.present.map) { +- /* No TLVs, opts is irrelevant. */ +- return offsetof(struct flow_tnl, metadata.opts); +- } +- /* Have decoded TLVs, opts is relevant. */ +- return sizeof *src; +-} +- +-/* Copy flow_tnl, but avoid copying unused portions of tun_metadata. Unused +- * data in 'dst' is NOT cleared, so this must not be used in cases where the +- * uninitialized portion may be hashed over. */ +-static inline void +-flow_tnl_copy__(struct flow_tnl *dst, const struct flow_tnl *src) +-{ +- memcpy(dst, src, flow_tnl_size(src)); +-} +- +-static inline bool +-flow_tnl_equal(const struct flow_tnl *a, const struct flow_tnl *b) +-{ +- size_t a_size = flow_tnl_size(a); +- +- return a_size == flow_tnl_size(b) && !memcmp(a, b, a_size); +-} +- +-/* Datapath packet metadata */ +-struct pkt_metadata { +-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0, +- uint32_t recirc_id; /* Recirculation id carried with the +- recirculating packets. 0 for packets +- received from the wire. */ +- uint32_t dp_hash; /* hash value computed by the recirculation +- action. */ +- uint32_t skb_priority; /* Packet priority for QoS. */ +- uint32_t pkt_mark; /* Packet mark. */ +- uint8_t ct_state; /* Connection state. */ +- bool ct_orig_tuple_ipv6; +- uint16_t ct_zone; /* Connection zone. */ +- uint32_t ct_mark; /* Connection mark. */ +- ovs_u128 ct_label; /* Connection label. */ +- union flow_in_port in_port; /* Input port. */ +- odp_port_t orig_in_port; /* Originating in_port for tunneled packets */ +- struct conn *conn; /* Cached conntrack connection. */ +- bool reply; /* True if reply direction. */ +- bool icmp_related; /* True if ICMP related. */ +-); +- +-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1, +- union { /* Populated only for non-zero 'ct_state'. */ +- struct ovs_key_ct_tuple_ipv4 ipv4; +- struct ovs_key_ct_tuple_ipv6 ipv6; /* Used only if */ +- } ct_orig_tuple; /* 'ct_orig_tuple_ipv6' is set */ +-); +- +-PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline2, +- struct flow_tnl tunnel; /* Encapsulating tunnel parameters. Note that +- * if 'ip_dst' == 0, the rest of the fields may +- * be uninitialized. */ +-); +-}; +- +-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline0) == 0); +-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline1) == +- CACHE_LINE_SIZE); +-BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline2) == +- 2 * CACHE_LINE_SIZE); +- +-static inline void +-pkt_metadata_init_tnl(struct pkt_metadata *md) +-{ +- odp_port_t orig_in_port; +- +- /* Zero up through the tunnel metadata options. The length and table +- * are before this and as long as they are empty, the options won't +- * be looked at. Keep the orig_in_port field. */ +- orig_in_port = md->in_port.odp_port; +- memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts)); +- md->orig_in_port = orig_in_port; +-} +- +-static inline void +-pkt_metadata_init_conn(struct pkt_metadata *md) +-{ +- md->conn = NULL; +-} +- +-static inline void +-pkt_metadata_init(struct pkt_metadata *md, odp_port_t port) +-{ +- /* This is called for every packet in userspace datapath and affects +- * performance if all the metadata is initialized. Hence, fields should +- * only be zeroed out when necessary. +- * +- * Initialize only till ct_state. Once the ct_state is zeroed out rest +- * of ct fields will not be looked at unless ct_state != 0. +- */ +- memset(md, 0, offsetof(struct pkt_metadata, ct_orig_tuple_ipv6)); +- +- /* It can be expensive to zero out all of the tunnel metadata. However, +- * we can just zero out ip_dst and the rest of the data will never be +- * looked at. */ +- md->tunnel.ip_dst = 0; +- md->tunnel.ipv6_dst = in6addr_any; +- md->in_port.odp_port = port; +- md->orig_in_port = port; +- md->conn = NULL; +-} +- +-/* This function prefetches the cachelines touched by pkt_metadata_init() +- * and pkt_metadata_init_tnl(). For performance reasons the two functions +- * should be kept in sync. */ +-static inline void +-pkt_metadata_prefetch_init(struct pkt_metadata *md) +-{ +- /* Prefetch cacheline0 as members till ct_state and odp_port will +- * be initialized later in pkt_metadata_init(). */ +- OVS_PREFETCH(md->cacheline0); +- +- /* Prefetch cacheline1 as members of this cacheline will be zeroed out +- * in pkt_metadata_init_tnl(). */ +- OVS_PREFETCH(md->cacheline1); +- +- /* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */ +- OVS_PREFETCH(md->cacheline2); +-} +- +-bool dpid_from_string(const char *s, uint64_t *dpidp); +- +-#define ETH_ADDR_LEN 6 +- +-static const struct eth_addr eth_addr_broadcast OVS_UNUSED +- = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); +- +-static const struct eth_addr eth_addr_exact OVS_UNUSED +- = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); +- +-static const struct eth_addr eth_addr_zero OVS_UNUSED +- = ETH_ADDR_C(00,00,00,00,00,00); +-static const struct eth_addr64 eth_addr64_zero OVS_UNUSED +- = ETH_ADDR64_C(00,00,00,00,00,00,00,00); +- +-static const struct eth_addr eth_addr_stp OVS_UNUSED +- = ETH_ADDR_C(01,80,c2,00,00,00); +- +-static const struct eth_addr eth_addr_lacp OVS_UNUSED +- = ETH_ADDR_C(01,80,c2,00,00,02); +- +-static const struct eth_addr eth_addr_bfd OVS_UNUSED +- = ETH_ADDR_C(00,23,20,00,00,01); +- +-static inline bool eth_addr_is_broadcast(const struct eth_addr a) +-{ +- return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); +-} +- +-static inline bool eth_addr_is_multicast(const struct eth_addr a) +-{ +- return a.ea[0] & 1; +-} +- +-static inline bool eth_addr_is_local(const struct eth_addr a) +-{ +- /* Local if it is either a locally administered address or a Nicira random +- * address. */ +- return a.ea[0] & 2 +- || (a.be16[0] == htons(0x0023) +- && (a.be16[1] & htons(0xff80)) == htons(0x2080)); +-} +-static inline bool eth_addr_is_zero(const struct eth_addr a) +-{ +- return !(a.be16[0] | a.be16[1] | a.be16[2]); +-} +-static inline bool eth_addr64_is_zero(const struct eth_addr64 a) +-{ +- return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]); +-} +- +-static inline int eth_mask_is_exact(const struct eth_addr a) +-{ +- return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); +-} +- +-static inline int eth_addr_compare_3way(const struct eth_addr a, +- const struct eth_addr b) +-{ +- return memcmp(&a, &b, sizeof a); +-} +-static inline int eth_addr64_compare_3way(const struct eth_addr64 a, +- const struct eth_addr64 b) +-{ +- return memcmp(&a, &b, sizeof a); +-} +- +-static inline bool eth_addr_equals(const struct eth_addr a, +- const struct eth_addr b) +-{ +- return !eth_addr_compare_3way(a, b); +-} +-static inline bool eth_addr64_equals(const struct eth_addr64 a, +- const struct eth_addr64 b) +-{ +- return !eth_addr64_compare_3way(a, b); +-} +- +-static inline bool eth_addr_equal_except(const struct eth_addr a, +- const struct eth_addr b, +- const struct eth_addr mask) +-{ +- return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0]) +- || ((a.be16[1] ^ b.be16[1]) & mask.be16[1]) +- || ((a.be16[2] ^ b.be16[2]) & mask.be16[2])); +-} +- +-uint64_t eth_addr_to_uint64(const struct eth_addr ea); +- +-static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea, +- uint16_t vlan) +-{ +- return (((uint64_t)vlan << 48) | eth_addr_to_uint64(ea)); +-} +- +-void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea); +- +-static inline struct eth_addr eth_addr_invert(const struct eth_addr src) +-{ +- struct eth_addr dst; +- +- for (int i = 0; i < ARRAY_SIZE(src.be16); i++) { +- dst.be16[i] = ~src.be16[i]; +- } +- +- return dst; +-} +- +-void eth_addr_mark_random(struct eth_addr *ea); +- +-static inline void eth_addr_random(struct eth_addr *ea) +-{ +- random_bytes((uint8_t *)ea, sizeof *ea); +- eth_addr_mark_random(ea); +-} +- +-static inline void eth_addr_nicira_random(struct eth_addr *ea) +-{ +- eth_addr_random(ea); +- +- /* Set the OUI to the Nicira one. */ +- ea->ea[0] = 0x00; +- ea->ea[1] = 0x23; +- ea->ea[2] = 0x20; +- +- /* Set the top bit to indicate random Nicira address. */ +- ea->ea[3] |= 0x80; +-} +-static inline uint32_t hash_mac(const struct eth_addr ea, +- const uint16_t vlan, const uint32_t basis) +-{ +- return hash_uint64_basis(eth_addr_vlan_to_uint64(ea, vlan), basis); +-} +- +-bool eth_addr_is_reserved(const struct eth_addr); +-bool eth_addr_from_string(const char *, struct eth_addr *); +- +-void compose_rarp(struct dp_packet *, const struct eth_addr); +- +-void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci); +-void eth_pop_vlan(struct dp_packet *); +- +-const char *eth_from_hex(const char *hex, struct dp_packet **packetp); +-void eth_format_masked(const struct eth_addr ea, +- const struct eth_addr *mask, struct ds *s); +- +-void set_mpls_lse(struct dp_packet *, ovs_be32 label); +-void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse); +-void pop_mpls(struct dp_packet *, ovs_be16 ethtype); +- +-void set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl); +-void set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc); +-void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label); +-void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos); +-ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, +- ovs_be32 label); +-void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse, +- bool l3_encap); +- +-/* Example: +- * +- * struct eth_addr mac; +- * [...] +- * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac)); +- * +- */ +-#define ETH_ADDR_FMT \ +- "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 +-#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea) +-#define ETH_ADDR_BYTES_ARGS(EAB) \ +- (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5] +-#define ETH_ADDR_STRLEN 17 +- +-/* Example: +- * +- * struct eth_addr64 eui64; +- * [...] +- * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac)); +- * +- */ +-#define ETH_ADDR64_FMT \ +- "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \ +- "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 +-#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64) +-#define ETH_ADDR64_BYTES_ARGS(EAB) \ +- (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \ +- (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7] +-#define ETH_ADDR64_STRLEN 23 +- +-/* Example: +- * +- * char *string = "1 00:11:22:33:44:55 2"; +- * struct eth_addr mac; +- * int a, b; +- * +- * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d", +- * &a, ETH_ADDR_SCAN_ARGS(mac), &b)) { +- * ... +- * } +- */ +-#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8 +-#define ETH_ADDR_SCAN_ARGS(EA) \ +- &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], &(EA).ea[3], &(EA).ea[4], &(EA).ea[5] +- +-#define ETH_TYPE_IP 0x0800 +-#define ETH_TYPE_ARP 0x0806 +-#define ETH_TYPE_TEB 0x6558 +-#define ETH_TYPE_VLAN_8021Q 0x8100 +-#define ETH_TYPE_VLAN ETH_TYPE_VLAN_8021Q +-#define ETH_TYPE_VLAN_8021AD 0x88a8 +-#define ETH_TYPE_IPV6 0x86dd +-#define ETH_TYPE_LACP 0x8809 +-#define ETH_TYPE_RARP 0x8035 +-#define ETH_TYPE_MPLS 0x8847 +-#define ETH_TYPE_MPLS_MCAST 0x8848 +-#define ETH_TYPE_NSH 0x894f +-#define ETH_TYPE_ERSPAN1 0x88be /* version 1 type II */ +-#define ETH_TYPE_ERSPAN2 0x22eb /* version 2 type III */ +- +-static inline bool eth_type_mpls(ovs_be16 eth_type) +-{ +- return eth_type == htons(ETH_TYPE_MPLS) || +- eth_type == htons(ETH_TYPE_MPLS_MCAST); +-} +- +-static inline bool eth_type_vlan(ovs_be16 eth_type) +-{ +- return eth_type == htons(ETH_TYPE_VLAN_8021Q) || +- eth_type == htons(ETH_TYPE_VLAN_8021AD); +-} +- +- +-/* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame +- * lengths. */ +-#define ETH_TYPE_MIN 0x600 +- +-#define ETH_HEADER_LEN 14 +-#define ETH_PAYLOAD_MIN 46 +-#define ETH_PAYLOAD_MAX 1500 +-#define ETH_TOTAL_MIN (ETH_HEADER_LEN + ETH_PAYLOAD_MIN) +-#define ETH_TOTAL_MAX (ETH_HEADER_LEN + ETH_PAYLOAD_MAX) +-#define ETH_VLAN_TOTAL_MAX (ETH_HEADER_LEN + VLAN_HEADER_LEN + ETH_PAYLOAD_MAX) +-struct eth_header { +- struct eth_addr eth_dst; +- struct eth_addr eth_src; +- ovs_be16 eth_type; +-}; +-BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header)); +- +-void push_eth(struct dp_packet *packet, const struct eth_addr *dst, +- const struct eth_addr *src); +-void pop_eth(struct dp_packet *packet); +- +-void push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src); +-bool pop_nsh(struct dp_packet *packet); +- +-#define LLC_DSAP_SNAP 0xaa +-#define LLC_SSAP_SNAP 0xaa +-#define LLC_CNTL_SNAP 3 +- +-#define LLC_HEADER_LEN 3 +-struct llc_header { +- uint8_t llc_dsap; +- uint8_t llc_ssap; +- uint8_t llc_cntl; +-}; +-BUILD_ASSERT_DECL(LLC_HEADER_LEN == sizeof(struct llc_header)); +- +-/* LLC field values used for STP frames. */ +-#define STP_LLC_SSAP 0x42 +-#define STP_LLC_DSAP 0x42 +-#define STP_LLC_CNTL 0x03 +- +-#define SNAP_ORG_ETHERNET "\0\0" /* The compiler adds a null byte, so +- sizeof(SNAP_ORG_ETHERNET) == 3. */ +-#define SNAP_HEADER_LEN 5 +-OVS_PACKED( +-struct snap_header { +- uint8_t snap_org[3]; +- ovs_be16 snap_type; +-}); +-BUILD_ASSERT_DECL(SNAP_HEADER_LEN == sizeof(struct snap_header)); +- +-#define LLC_SNAP_HEADER_LEN (LLC_HEADER_LEN + SNAP_HEADER_LEN) +-OVS_PACKED( +-struct llc_snap_header { +- struct llc_header llc; +- struct snap_header snap; +-}); +-BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header)); +- +-#define VLAN_VID_MASK 0x0fff +-#define VLAN_VID_SHIFT 0 +- +-#define VLAN_PCP_MASK 0xe000 +-#define VLAN_PCP_SHIFT 13 +- +-#define VLAN_CFI 0x1000 +-#define VLAN_CFI_SHIFT 12 +- +-/* Given the vlan_tci field from an 802.1Q header, in network byte order, +- * returns the VLAN ID in host byte order. */ +-static inline uint16_t +-vlan_tci_to_vid(ovs_be16 vlan_tci) +-{ +- return (ntohs(vlan_tci) & VLAN_VID_MASK) >> VLAN_VID_SHIFT; +-} +- +-/* Given the vlan_tci field from an 802.1Q header, in network byte order, +- * returns the priority code point (PCP) in host byte order. */ +-static inline int +-vlan_tci_to_pcp(ovs_be16 vlan_tci) +-{ +- return (ntohs(vlan_tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; +-} +- +-/* Given the vlan_tci field from an 802.1Q header, in network byte order, +- * returns the Canonical Format Indicator (CFI). */ +-static inline int +-vlan_tci_to_cfi(ovs_be16 vlan_tci) +-{ +- return (vlan_tci & htons(VLAN_CFI)) != 0; +-} +- +-#define VLAN_HEADER_LEN 4 +-struct vlan_header { +- ovs_be16 vlan_tci; /* Lowest 12 bits are VLAN ID. */ +- ovs_be16 vlan_next_type; +-}; +-BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header)); +- +-#define VLAN_ETH_HEADER_LEN (ETH_HEADER_LEN + VLAN_HEADER_LEN) +-struct vlan_eth_header { +- struct eth_addr veth_dst; +- struct eth_addr veth_src; +- ovs_be16 veth_type; /* Always htons(ETH_TYPE_VLAN). */ +- ovs_be16 veth_tci; /* Lowest 12 bits are VLAN ID. */ +- ovs_be16 veth_next_type; +-}; +-BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); +- +-/* MPLS related definitions */ +-#define MPLS_TTL_MASK 0x000000ff +-#define MPLS_TTL_SHIFT 0 +- +-#define MPLS_BOS_MASK 0x00000100 +-#define MPLS_BOS_SHIFT 8 +- +-#define MPLS_TC_MASK 0x00000e00 +-#define MPLS_TC_SHIFT 9 +- +-#define MPLS_LABEL_MASK 0xfffff000 +-#define MPLS_LABEL_SHIFT 12 +- +-#define MPLS_HLEN 4 +- +-struct mpls_hdr { +- ovs_16aligned_be32 mpls_lse; +-}; +-BUILD_ASSERT_DECL(MPLS_HLEN == sizeof(struct mpls_hdr)); +- +-/* Given a mpls label stack entry in network byte order +- * return mpls label in host byte order */ +-static inline uint32_t +-mpls_lse_to_label(ovs_be32 mpls_lse) +-{ +- return (ntohl(mpls_lse) & MPLS_LABEL_MASK) >> MPLS_LABEL_SHIFT; +-} +- +-/* Given a mpls label stack entry in network byte order +- * return mpls tc */ +-static inline uint8_t +-mpls_lse_to_tc(ovs_be32 mpls_lse) +-{ +- return (ntohl(mpls_lse) & MPLS_TC_MASK) >> MPLS_TC_SHIFT; +-} +- +-/* Given a mpls label stack entry in network byte order +- * return mpls ttl */ +-static inline uint8_t +-mpls_lse_to_ttl(ovs_be32 mpls_lse) +-{ +- return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; +-} +- +-/* Set label in mpls lse. */ +-static inline void +-flow_set_mpls_lse_label(ovs_be32 *mpls_lse, uint32_t label) +-{ +- *mpls_lse &= ~htonl(MPLS_LABEL_MASK); +- *mpls_lse |= htonl(label << MPLS_LABEL_SHIFT); +-} +- +-/* Set TC in mpls lse. */ +-static inline void +-flow_set_mpls_lse_tc(ovs_be32 *mpls_lse, uint8_t tc) +-{ +- *mpls_lse &= ~htonl(MPLS_TC_MASK); +- *mpls_lse |= htonl((tc & 0x7) << MPLS_TC_SHIFT); +-} +- +-/* Set BOS in mpls lse. */ +-static inline void +-flow_set_mpls_lse_bos(ovs_be32 *mpls_lse, uint8_t bos) +-{ +- *mpls_lse &= ~htonl(MPLS_BOS_MASK); +- *mpls_lse |= htonl((bos & 0x1) << MPLS_BOS_SHIFT); +-} +- +-/* Set TTL in mpls lse. */ +-static inline void +-flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl) +-{ +- *mpls_lse &= ~htonl(MPLS_TTL_MASK); +- *mpls_lse |= htonl(ttl << MPLS_TTL_SHIFT); +-} +- +-/* Given a mpls label stack entry in network byte order +- * return mpls BoS bit */ +-static inline uint8_t +-mpls_lse_to_bos(ovs_be32 mpls_lse) +-{ +- return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0; +-} +- +-#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32 +-#define IP_ARGS(ip) \ +- ntohl(ip) >> 24, \ +- (ntohl(ip) >> 16) & 0xff, \ +- (ntohl(ip) >> 8) & 0xff, \ +- ntohl(ip) & 0xff +- +-/* Example: +- * +- * char *string = "1 33.44.55.66 2"; +- * ovs_be32 ip; +- * int a, b; +- * +- * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) { +- * ... +- * } +- */ +-#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8 +-#define IP_SCAN_ARGS(ip) \ +- ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ +- &((uint8_t *) ip)[1], \ +- &((uint8_t *) ip)[2], \ +- &((uint8_t *) ip)[3] +- +-#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16 +-#define IP_PORT_SCAN_ARGS(ip, port) \ +- ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ +- &((uint8_t *) ip)[1], \ +- &((uint8_t *) ip)[2], \ +- &((uint8_t *) ip)[3], \ +- ((void) (ovs_be16) *(port), (uint16_t *) port) +- +-/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N +- * high-order 1-bits and 32-N low-order 0-bits. */ +-static inline bool +-ip_is_cidr(ovs_be32 netmask) +-{ +- uint32_t x = ~ntohl(netmask); +- return !(x & (x + 1)); +-} +-static inline bool +-ip_is_multicast(ovs_be32 ip) +-{ +- return (ip & htonl(0xf0000000)) == htonl(0xe0000000); +-} +-static inline bool +-ip_is_local_multicast(ovs_be32 ip) +-{ +- return (ip & htonl(0xffffff00)) == htonl(0xe0000000); +-} +-int ip_count_cidr_bits(ovs_be32 netmask); +-void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *); +-bool ip_parse(const char *s, ovs_be32 *ip); +-char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) +- OVS_WARN_UNUSED_RESULT; +-char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) +- OVS_WARN_UNUSED_RESULT; +-char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) +- OVS_WARN_UNUSED_RESULT; +-char *ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, ovs_be32 *mask) +- OVS_WARN_UNUSED_RESULT; +-char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, +- unsigned int *plen) +- OVS_WARN_UNUSED_RESULT; +- +-#define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4) +-#define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15) +-#define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl)) +- +-#ifndef IPPROTO_SCTP +-#define IPPROTO_SCTP 132 +-#endif +- +-#ifndef IPPROTO_DCCP +-#define IPPROTO_DCCP 33 +-#endif +- +-#ifndef IPPROTO_IGMP +-#define IPPROTO_IGMP 2 +-#endif +- +-#ifndef IPPROTO_UDPLITE +-#define IPPROTO_UDPLITE 136 +-#endif +- +-/* TOS fields. */ +-#define IP_ECN_NOT_ECT 0x0 +-#define IP_ECN_ECT_1 0x01 +-#define IP_ECN_ECT_0 0x02 +-#define IP_ECN_CE 0x03 +-#define IP_ECN_MASK 0x03 +-#define IP_DSCP_CS6 0xc0 +-#define IP_DSCP_MASK 0xfc +- +-static inline int +-IP_ECN_is_ce(uint8_t dsfield) +-{ +- return (dsfield & IP_ECN_MASK) == IP_ECN_CE; +-} +- +-#define IP_VERSION 4 +- +-#define IP_DONT_FRAGMENT 0x4000 /* Don't fragment. */ +-#define IP_MORE_FRAGMENTS 0x2000 /* More fragments. */ +-#define IP_FRAG_OFF_MASK 0x1fff /* Fragment offset. */ +-#define IP_IS_FRAGMENT(ip_frag_off) \ +- ((ip_frag_off) & htons(IP_MORE_FRAGMENTS | IP_FRAG_OFF_MASK)) +- +-#define IP_HEADER_LEN 20 +-struct ip_header { +- uint8_t ip_ihl_ver; +- uint8_t ip_tos; +- ovs_be16 ip_tot_len; +- ovs_be16 ip_id; +- ovs_be16 ip_frag_off; +- uint8_t ip_ttl; +- uint8_t ip_proto; +- ovs_be16 ip_csum; +- ovs_16aligned_be32 ip_src; +- ovs_16aligned_be32 ip_dst; +-}; +-BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); +- +-/* ICMPv4 types. */ +-#define ICMP4_ECHO_REPLY 0 +-#define ICMP4_DST_UNREACH 3 +-#define ICMP4_SOURCEQUENCH 4 +-#define ICMP4_REDIRECT 5 +-#define ICMP4_ECHO_REQUEST 8 +-#define ICMP4_TIME_EXCEEDED 11 +-#define ICMP4_PARAM_PROB 12 +-#define ICMP4_TIMESTAMP 13 +-#define ICMP4_TIMESTAMPREPLY 14 +-#define ICMP4_INFOREQUEST 15 +-#define ICMP4_INFOREPLY 16 +- +-#define ICMP_HEADER_LEN 8 +-struct icmp_header { +- uint8_t icmp_type; +- uint8_t icmp_code; +- ovs_be16 icmp_csum; +- union { +- struct { +- ovs_be16 id; +- ovs_be16 seq; +- } echo; +- struct { +- ovs_be16 empty; +- ovs_be16 mtu; +- } frag; +- ovs_16aligned_be32 gateway; +- } icmp_fields; +-}; +-BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header)); +- +-/* ICMPV4 */ +-#define ICMP_ERROR_DATA_L4_LEN 8 +- +-#define IGMP_HEADER_LEN 8 +-struct igmp_header { +- uint8_t igmp_type; +- uint8_t igmp_code; +- ovs_be16 igmp_csum; +- ovs_16aligned_be32 group; +-}; +-BUILD_ASSERT_DECL(IGMP_HEADER_LEN == sizeof(struct igmp_header)); +- +-#define IGMPV3_HEADER_LEN 8 +-struct igmpv3_header { +- uint8_t type; +- uint8_t rsvr1; +- ovs_be16 csum; +- ovs_be16 rsvr2; +- ovs_be16 ngrp; +-}; +-BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header)); +- +-#define IGMPV3_QUERY_HEADER_LEN 12 +-struct igmpv3_query_header { +- uint8_t type; +- uint8_t max_resp; +- ovs_be16 csum; +- ovs_16aligned_be32 group; +- uint8_t srs_qrv; +- uint8_t qqic; +- ovs_be16 nsrcs; +-}; +-BUILD_ASSERT_DECL( +- IGMPV3_QUERY_HEADER_LEN == sizeof(struct igmpv3_query_header +-)); +- +-#define IGMPV3_RECORD_LEN 8 +-struct igmpv3_record { +- uint8_t type; +- uint8_t aux_len; +- ovs_be16 nsrcs; +- ovs_16aligned_be32 maddr; +-}; +-BUILD_ASSERT_DECL(IGMPV3_RECORD_LEN == sizeof(struct igmpv3_record)); +- +-#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ +-#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ +-#define IGMPV2_HOST_MEMBERSHIP_REPORT 0x16 /* V2 version of 0x12 */ +-#define IGMP_HOST_LEAVE_MESSAGE 0x17 +-#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */ +- +-/* +- * IGMPv3 and MLDv2 use the same codes. +- */ +-#define IGMPV3_MODE_IS_INCLUDE 1 +-#define IGMPV3_MODE_IS_EXCLUDE 2 +-#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3 +-#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 4 +-#define IGMPV3_ALLOW_NEW_SOURCES 5 +-#define IGMPV3_BLOCK_OLD_SOURCES 6 +- +-#define SCTP_HEADER_LEN 12 +-struct sctp_header { +- ovs_be16 sctp_src; +- ovs_be16 sctp_dst; +- ovs_16aligned_be32 sctp_vtag; +- ovs_16aligned_be32 sctp_csum; +-}; +-BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header)); +- +-#define UDP_HEADER_LEN 8 +-struct udp_header { +- ovs_be16 udp_src; +- ovs_be16 udp_dst; +- ovs_be16 udp_len; +- ovs_be16 udp_csum; +-}; +-BUILD_ASSERT_DECL(UDP_HEADER_LEN == sizeof(struct udp_header)); +- +-#define ESP_HEADER_LEN 8 +-struct esp_header { +- ovs_be32 spi; +- ovs_be32 seq_no; +-}; +-BUILD_ASSERT_DECL(ESP_HEADER_LEN == sizeof(struct esp_header)); +- +-#define ESP_TRAILER_LEN 2 +-struct esp_trailer { +- uint8_t pad_len; +- uint8_t next_hdr; +-}; +-BUILD_ASSERT_DECL(ESP_TRAILER_LEN == sizeof(struct esp_trailer)); +- +-#define TCP_FIN 0x001 +-#define TCP_SYN 0x002 +-#define TCP_RST 0x004 +-#define TCP_PSH 0x008 +-#define TCP_ACK 0x010 +-#define TCP_URG 0x020 +-#define TCP_ECE 0x040 +-#define TCP_CWR 0x080 +-#define TCP_NS 0x100 +- +-#define TCP_CTL(flags, offset) (htons((flags) | ((offset) << 12))) +-#define TCP_FLAGS(tcp_ctl) (ntohs(tcp_ctl) & 0x0fff) +-#define TCP_FLAGS_BE16(tcp_ctl) ((tcp_ctl) & htons(0x0fff)) +-#define TCP_OFFSET(tcp_ctl) (ntohs(tcp_ctl) >> 12) +- +-#define TCP_HEADER_LEN 20 +-struct tcp_header { +- ovs_be16 tcp_src; +- ovs_be16 tcp_dst; +- ovs_16aligned_be32 tcp_seq; +- ovs_16aligned_be32 tcp_ack; +- ovs_be16 tcp_ctl; +- ovs_be16 tcp_winsz; +- ovs_be16 tcp_csum; +- ovs_be16 tcp_urg; +-}; +-BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header)); +- +-/* Connection states. +- * +- * Names like CS_RELATED are bit values, e.g. 1 << 2. +- * Names like CS_RELATED_BIT are bit indexes, e.g. 2. */ +-#define CS_STATES \ +- CS_STATE(NEW, 0, "new") \ +- CS_STATE(ESTABLISHED, 1, "est") \ +- CS_STATE(RELATED, 2, "rel") \ +- CS_STATE(REPLY_DIR, 3, "rpl") \ +- CS_STATE(INVALID, 4, "inv") \ +- CS_STATE(TRACKED, 5, "trk") \ +- CS_STATE(SRC_NAT, 6, "snat") \ +- CS_STATE(DST_NAT, 7, "dnat") +- +-enum { +-#define CS_STATE(ENUM, INDEX, NAME) \ +- CS_##ENUM = 1 << INDEX, \ +- CS_##ENUM##_BIT = INDEX, +- CS_STATES +-#undef CS_STATE +-}; +- +-/* Undefined connection state bits. */ +-enum { +-#define CS_STATE(ENUM, INDEX, NAME) +CS_##ENUM +- CS_SUPPORTED_MASK = CS_STATES +-#undef CS_STATE +-}; +-#define CS_UNSUPPORTED_MASK (~(uint32_t)CS_SUPPORTED_MASK) +- +-#define ARP_HRD_ETHERNET 1 +-#define ARP_PRO_IP 0x0800 +-#define ARP_OP_REQUEST 1 +-#define ARP_OP_REPLY 2 +-#define ARP_OP_RARP 3 +- +-#define ARP_ETH_HEADER_LEN 28 +-struct arp_eth_header { +- /* Generic members. */ +- ovs_be16 ar_hrd; /* Hardware type. */ +- ovs_be16 ar_pro; /* Protocol type. */ +- uint8_t ar_hln; /* Hardware address length. */ +- uint8_t ar_pln; /* Protocol address length. */ +- ovs_be16 ar_op; /* Opcode. */ +- +- /* Ethernet+IPv4 specific members. */ +- struct eth_addr ar_sha; /* Sender hardware address. */ +- ovs_16aligned_be32 ar_spa; /* Sender protocol address. */ +- struct eth_addr ar_tha; /* Target hardware address. */ +- ovs_16aligned_be32 ar_tpa; /* Target protocol address. */ +-}; +-BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header)); +- +-#define IPV6_HEADER_LEN 40 +- +-/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on +- * most implementations, this one only requires 16-bit alignment. */ +-union ovs_16aligned_in6_addr { +- ovs_be16 be16[8]; +- ovs_16aligned_be32 be32[4]; +-}; +- +-/* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this +- * one only requires 16-bit alignment. */ +-struct ovs_16aligned_ip6_hdr { +- union { +- struct ovs_16aligned_ip6_hdrctl { +- ovs_16aligned_be32 ip6_un1_flow; +- ovs_be16 ip6_un1_plen; +- uint8_t ip6_un1_nxt; +- uint8_t ip6_un1_hlim; +- } ip6_un1; +- uint8_t ip6_un2_vfc; +- } ip6_ctlun; +- union ovs_16aligned_in6_addr ip6_src; +- union ovs_16aligned_in6_addr ip6_dst; +-}; +- +-/* Like struct in6_frag, but whereas that struct requires 32-bit alignment, +- * this one only requires 16-bit alignment. */ +-struct ovs_16aligned_ip6_frag { +- uint8_t ip6f_nxt; +- uint8_t ip6f_reserved; +- ovs_be16 ip6f_offlg; +- ovs_16aligned_be32 ip6f_ident; +-}; +- +-#define ICMP6_HEADER_LEN 4 +-struct icmp6_header { +- uint8_t icmp6_type; +- uint8_t icmp6_code; +- ovs_be16 icmp6_cksum; +-}; +-BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header)); +- +-#define ICMP6_DATA_HEADER_LEN 8 +-struct icmp6_data_header { +- struct icmp6_header icmp6_base; +- union { +- ovs_16aligned_be32 be32[1]; +- ovs_be16 be16[2]; +- uint8_t u8[4]; +- } icmp6_data; +-}; +-BUILD_ASSERT_DECL(ICMP6_DATA_HEADER_LEN == sizeof(struct icmp6_data_header)); +- +-uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *); +-ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *, +- const void *, uint8_t, uint16_t); +- +-/* Neighbor Discovery option field. +- * ND options are always a multiple of 8 bytes in size. */ +-#define ND_LLA_OPT_LEN 8 +-struct ovs_nd_lla_opt { +- uint8_t type; /* One of ND_OPT_*_LINKADDR. */ +- uint8_t len; +- struct eth_addr mac; +-}; +-BUILD_ASSERT_DECL(ND_LLA_OPT_LEN == sizeof(struct ovs_nd_lla_opt)); +- +-/* Neighbor Discovery option: Prefix Information. */ +-#define ND_PREFIX_OPT_LEN 32 +-struct ovs_nd_prefix_opt { +- uint8_t type; /* ND_OPT_PREFIX_INFORMATION. */ +- uint8_t len; /* Always 4. */ +- uint8_t prefix_len; +- uint8_t la_flags; /* ND_PREFIX_* flags. */ +- ovs_16aligned_be32 valid_lifetime; +- ovs_16aligned_be32 preferred_lifetime; +- ovs_16aligned_be32 reserved; /* Always 0. */ +- union ovs_16aligned_in6_addr prefix; +-}; +-BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt)); +- +-/* Neighbor Discovery option: MTU. */ +-#define ND_MTU_OPT_LEN 8 +-#define ND_MTU_DEFAULT 0 +-struct ovs_nd_mtu_opt { +- uint8_t type; /* ND_OPT_MTU */ +- uint8_t len; /* Always 1. */ +- ovs_be16 reserved; /* Always 0. */ +- ovs_16aligned_be32 mtu; +-}; +-BUILD_ASSERT_DECL(ND_MTU_OPT_LEN == sizeof(struct ovs_nd_mtu_opt)); +- +-/* Like struct nd_msg (from ndisc.h), but whereas that struct requires 32-bit +- * alignment, this one only requires 16-bit alignment. */ +-#define ND_MSG_LEN 24 +-struct ovs_nd_msg { +- struct icmp6_header icmph; +- ovs_16aligned_be32 rso_flags; +- union ovs_16aligned_in6_addr target; +- struct ovs_nd_lla_opt options[0]; +-}; +-BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg)); +- +-/* Neighbor Discovery packet flags. */ +-#define ND_RSO_ROUTER 0x80000000 +-#define ND_RSO_SOLICITED 0x40000000 +-#define ND_RSO_OVERRIDE 0x20000000 +- +-#define RA_MSG_LEN 16 +-struct ovs_ra_msg { +- struct icmp6_header icmph; +- uint8_t cur_hop_limit; +- uint8_t mo_flags; /* ND_RA_MANAGED_ADDRESS and ND_RA_OTHER_CONFIG flags. */ +- ovs_be16 router_lifetime; +- ovs_be32 reachable_time; +- ovs_be32 retrans_timer; +- struct ovs_nd_lla_opt options[0]; +-}; +-BUILD_ASSERT_DECL(RA_MSG_LEN == sizeof(struct ovs_ra_msg)); +- +-#define ND_RA_MANAGED_ADDRESS 0x80 +-#define ND_RA_OTHER_CONFIG 0x40 +- +-/* Defaults based on MaxRtrInterval and MinRtrInterval from RFC 4861 section +- * 6.2.1 +- */ +-#define ND_RA_MAX_INTERVAL_DEFAULT 600 +- +-static inline int +-nd_ra_min_interval_default(int max) +-{ +- return max >= 9 ? max / 3 : max * 3 / 4; +-} +- +-/* +- * Use the same struct for MLD and MLD2, naming members as the defined fields in +- * in the corresponding version of the protocol, though they are reserved in the +- * other one. +- */ +-#define MLD_HEADER_LEN 8 +-struct mld_header { +- uint8_t type; +- uint8_t code; +- ovs_be16 csum; +- ovs_be16 mrd; +- ovs_be16 ngrp; +-}; +-BUILD_ASSERT_DECL(MLD_HEADER_LEN == sizeof(struct mld_header)); +- +-#define MLD2_RECORD_LEN 20 +-struct mld2_record { +- uint8_t type; +- uint8_t aux_len; +- ovs_be16 nsrcs; +- union ovs_16aligned_in6_addr maddr; +-}; +-BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct mld2_record)); +- +-#define MLD_QUERY 130 +-#define MLD_REPORT 131 +-#define MLD_DONE 132 +-#define MLD2_REPORT 143 +- +-/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */ +-#define IPV6_LABEL_MASK 0x000fffff +- +-/* Example: +- * +- * char *string = "1 ::1 2"; +- * char ipv6_s[IPV6_SCAN_LEN + 1]; +- * struct in6_addr ipv6; +- * +- * if (ovs_scan(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b) +- * && inet_pton(AF_INET6, ipv6_s, &ipv6) == 1) { +- * ... +- * } +- */ +-#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]" +-#define IPV6_SCAN_LEN 46 +- +-extern const struct in6_addr in6addr_exact; +-#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \ +- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } } +- +-extern const struct in6_addr in6addr_all_hosts; +-#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ +- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } } +- +-extern const struct in6_addr in6addr_all_routers; +-#define IN6ADDR_ALL_ROUTERS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ +- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } +- +-static inline bool ipv6_addr_equals(const struct in6_addr *a, +- const struct in6_addr *b) +-{ +-#ifdef IN6_ARE_ADDR_EQUAL +- return IN6_ARE_ADDR_EQUAL(a, b); +-#else +- return !memcmp(a, b, sizeof(*a)); +-#endif +-} +- +-/* Checks the IPv6 address in 'mask' for all zeroes. */ +-static inline bool ipv6_mask_is_any(const struct in6_addr *mask) { +- return ipv6_addr_equals(mask, &in6addr_any); +-} +- +-static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) { +- return ipv6_addr_equals(mask, &in6addr_exact); +-} +- +-static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) { +- return ipv6_addr_equals(addr, &in6addr_all_hosts); +-} +- +-static inline bool ipv6_addr_is_set(const struct in6_addr *addr) { +- return !ipv6_addr_equals(addr, &in6addr_any); +-} +- +-static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) { +- return ip->s6_addr[0] == 0xff; +-} +- +-static inline struct in6_addr +-in6_addr_mapped_ipv4(ovs_be32 ip4) +-{ +- struct in6_addr ip6; +- memset(&ip6, 0, sizeof(ip6)); +- ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff; +- memcpy(&ip6.s6_addr[12], &ip4, 4); +- return ip6; +-} +- +-static inline void +-in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4) +-{ +- *ip6 = in6_addr_mapped_ipv4(ip4); +-} +- +-static inline ovs_be32 +-in6_addr_get_mapped_ipv4(const struct in6_addr *addr) +-{ +- union ovs_16aligned_in6_addr *taddr = +- (union ovs_16aligned_in6_addr *) addr; +- if (IN6_IS_ADDR_V4MAPPED(addr)) { +- return get_16aligned_be32(&taddr->be32[3]); +- } else { +- return INADDR_ANY; +- } +-} +- +-void in6_addr_solicited_node(struct in6_addr *addr, +- const struct in6_addr *ip6); +- +-void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, +- struct in6_addr *lla); +- +-void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla); +- +-/* Returns true if 'addr' is a link local address. Otherwise, false. */ +-bool in6_is_lla(struct in6_addr *addr); +- +-void ipv6_multicast_to_ethernet(struct eth_addr *eth, +- const struct in6_addr *ip6); +- +-static inline bool dl_type_is_ip_any(ovs_be16 dl_type) +-{ +- return dl_type == htons(ETH_TYPE_IP) +- || dl_type == htons(ETH_TYPE_IPV6); +-} +- +-/* Tunnel header */ +- +-/* GRE protocol header */ +-struct gre_base_hdr { +- ovs_be16 flags; +- ovs_be16 protocol; +-}; +- +-#define GRE_CSUM 0x8000 +-#define GRE_ROUTING 0x4000 +-#define GRE_KEY 0x2000 +-#define GRE_SEQ 0x1000 +-#define GRE_STRICT 0x0800 +-#define GRE_REC 0x0700 +-#define GRE_FLAGS 0x00F8 +-#define GRE_VERSION 0x0007 +- +-/* +- * ERSPAN protocol header and metadata +- * +- * Version 1 (Type II) header (8 octets [42:49]) +- * 0 1 2 3 +- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Ver | VLAN | COS | En|T| Session ID | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Reserved | Index | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * +- * +- * ERSPAN Version 2 (Type III) header (12 octets [42:49]) +- * 0 1 2 3 +- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Ver | VLAN | COS |BSO|T| Session ID | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Timestamp | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | SGT |P| FT | Hw ID |D|Gra|O| +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * +- */ +- +-/* ERSPAN has fixed 8-byte GRE header */ +-#define ERSPAN_GREHDR_LEN 8 +-#define ERSPAN_HDR(gre_base_hdr) \ +- ((struct erspan_base_hdr *)((char *)gre_base_hdr + ERSPAN_GREHDR_LEN)) +- +-#define ERSPAN_V1_MDSIZE 4 +-#define ERSPAN_V2_MDSIZE 8 +- +-#define ERSPAN_SID_MASK 0x03ff /* 10-bit Session ID. */ +-#define ERSPAN_IDX_MASK 0xfffff /* v1 Index */ +-#define ERSPAN_HWID_MASK 0x03f0 +-#define ERSPAN_DIR_MASK 0x0008 +- +-struct erspan_base_hdr { +-#ifdef WORDS_BIGENDIAN +- uint8_t ver:4, +- vlan_upper:4; +- uint8_t vlan:8; +- uint8_t cos:3, +- en:2, +- t:1, +- session_id_upper:2; +- uint8_t session_id:8; +-#else +- uint8_t vlan_upper:4, +- ver:4; +- uint8_t vlan:8; +- uint8_t session_id_upper:2, +- t:1, +- en:2, +- cos:3; +- uint8_t session_id:8; +-#endif +-}; +- +-struct erspan_md2 { +- ovs_16aligned_be32 timestamp; +- ovs_be16 sgt; +-#ifdef WORDS_BIGENDIAN +- uint8_t p:1, +- ft:5, +- hwid_upper:2; +- uint8_t hwid:4, +- dir:1, +- gra:2, +- o:1; +-#else +- uint8_t hwid_upper:2, +- ft:5, +- p:1; +- uint8_t o:1, +- gra:2, +- dir:1, +- hwid:4; +-#endif +-}; +- +-struct erspan_metadata { +- int version; +- union { +- ovs_be32 index; /* Version 1 (type II)*/ +- struct erspan_md2 md2; /* Version 2 (type III) */ +- } u; +-}; +- +-static inline uint16_t get_sid(const struct erspan_base_hdr *ershdr) +-{ +- return (ershdr->session_id_upper << 8) + ershdr->session_id; +-} +- +-static inline void set_sid(struct erspan_base_hdr *ershdr, uint16_t id) +-{ +- ershdr->session_id = id & 0xff; +- ershdr->session_id_upper = (id >> 8) &0x3; +-} +- +-static inline uint8_t get_hwid(const struct erspan_md2 *md2) +-{ +- return (md2->hwid_upper << 4) + md2->hwid; +-} +- +-static inline void set_hwid(struct erspan_md2 *md2, uint8_t hwid) +-{ +- md2->hwid = hwid & 0xf; +- md2->hwid_upper = (hwid >> 4) & 0x3; +-} +- +-/* ERSPAN timestamp granularity +- * 00b --> granularity = 100 microseconds +- * 01b --> granularity = 100 nanoseconds +- * 10b --> granularity = IEEE 1588 +- * Here we only support 100 microseconds. +- */ +-enum erspan_ts_gra { +- ERSPAN_100US, +- ERSPAN_100NS, +- ERSPAN_IEEE1588, +-}; +- +-static inline ovs_be32 get_erspan_ts(enum erspan_ts_gra gra) +-{ +- ovs_be32 ts = 0; +- +- switch (gra) { +- case ERSPAN_100US: +- ts = htonl((uint32_t)(time_wall_usec() / 100)); +- break; +- case ERSPAN_100NS: +- /* fall back */ +- case ERSPAN_IEEE1588: +- /* fall back */ +- default: +- OVS_NOT_REACHED(); +- break; +- } +- return ts; +-} +- +-/* +- * GTP-U protocol header and metadata +- * See: +- * User Plane Protocol and Architectural Analysis on 3GPP 5G System +- * draft-hmm-dmm-5g-uplane-analysis-00 +- * +- * 0 1 2 3 +- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Ver |P|R|E|S|N| Message Type| Length | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Tunnel Endpoint Identifier | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | Sequence Number | N-PDU Number | Next-Ext-Hdr | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * +- * GTP-U Flags: +- * P: Protocol Type (Set to '1') +- * R: Reserved Bit (Set to '0') +- * E: Extension Header Flag (Set to '1' if extension header exists) +- * S: Sequence Number Flag (Set to '1' if sequence number exists) +- * N: N-PDU Number Flag (Set to '1' if N-PDU number exists) +- * +- * GTP-U Message Type: +- * Indicates the type of GTP-U message. +- * +- * GTP-U Length: +- * Indicates the length in octets of the payload. +- * +- * User payload is transmitted in G-PDU packets. +- */ +- +-#define GTPU_VER_MASK 0xe0 +-#define GTPU_P_MASK 0x10 +-#define GTPU_E_MASK 0x04 +-#define GTPU_S_MASK 0x02 +- +-/* GTP-U UDP port. */ +-#define GTPU_DST_PORT 2152 +- +-/* Default GTP-U flags: Ver = 1 and P = 1. */ +-#define GTPU_FLAGS_DEFAULT 0x30 +- +-/* GTP-U message type for normal user plane PDU. */ +-#define GTPU_MSGTYPE_REQ 1 /* Echo Request. */ +-#define GTPU_MSGTYPE_REPL 2 /* Echo Reply. */ +-#define GTPU_MSGTYPE_GPDU 255 /* User Payload. */ +- +-struct gtpu_metadata { +- uint8_t flags; +- uint8_t msgtype; +-}; +-BUILD_ASSERT_DECL(sizeof(struct gtpu_metadata) == 2); +- +-struct gtpuhdr { +- struct gtpu_metadata md; +- ovs_be16 len; +- ovs_16aligned_be32 teid; +-}; +-BUILD_ASSERT_DECL(sizeof(struct gtpuhdr) == 8); +- +-struct gtpuhdr_opt { +- ovs_be16 seqno; +- uint8_t pdu_number; +- uint8_t next_ext_type; +-}; +-BUILD_ASSERT_DECL(sizeof(struct gtpuhdr_opt) == 4); +- +-/* VXLAN protocol header */ +-struct vxlanhdr { +- union { +- ovs_16aligned_be32 vx_flags; /* VXLAN flags. */ +- struct { +- uint8_t flags; /* VXLAN GPE flags. */ +- uint8_t reserved[2]; /* 16 bits reserved. */ +- uint8_t next_protocol; /* Next Protocol field for VXLAN GPE. */ +- } vx_gpe; +- }; +- ovs_16aligned_be32 vx_vni; +-}; +-BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8); +- +-#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ +- +-/* +- * VXLAN Generic Protocol Extension (VXLAN_F_GPE): +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * |R|R|Ver|I|P|R|O| Reserved |Next Protocol | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * | VXLAN Network Identifier (VNI) | Reserved | +- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +- * +- * Ver = Version. Indicates VXLAN GPE protocol version. +- * +- * P = Next Protocol Bit. The P bit is set to indicate that the +- * Next Protocol field is present. +- * +- * O = OAM Flag Bit. The O bit is set to indicate that the packet +- * is an OAM packet. +- * +- * Next Protocol = This 8 bit field indicates the protocol header +- * immediately following the VXLAN GPE header. +- * +- * https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01 +- */ +- +-/* Fields in struct vxlanhdr.vx_gpe.flags */ +-#define VXLAN_GPE_FLAGS_VER 0x30 /* Version. */ +-#define VXLAN_GPE_FLAGS_P 0x04 /* Next Protocol Bit. */ +-#define VXLAN_GPE_FLAGS_O 0x01 /* OAM Bit. */ +- +-/* VXLAN-GPE header flags. */ +-#define VXLAN_HF_VER ((1U <<29) | (1U <<28)) +-#define VXLAN_HF_NP (1U <<26) +-#define VXLAN_HF_OAM (1U <<24) +- +-#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \ +- 0xff) +- +-/* VXLAN-GPE header Next Protocol. */ +-#define VXLAN_GPE_NP_IPV4 0x01 +-#define VXLAN_GPE_NP_IPV6 0x02 +-#define VXLAN_GPE_NP_ETHERNET 0x03 +-#define VXLAN_GPE_NP_NSH 0x04 +- +-#define VXLAN_F_GPE 0x4000 +-#define VXLAN_HF_GPE 0x04000000 +- +-/* Input values for PACKET_TYPE macros have to be in host byte order. +- * The _BE postfix indicates result is in network byte order. Otherwise result +- * is in host byte order. */ +-#define PACKET_TYPE(NS, NS_TYPE) ((uint32_t) ((NS) << 16 | (NS_TYPE))) +-#define PACKET_TYPE_BE(NS, NS_TYPE) (htonl((NS) << 16 | (NS_TYPE))) +- +-/* Returns the host byte ordered namespace of 'packet type'. */ +-static inline uint16_t +-pt_ns(ovs_be32 packet_type) +-{ +- return ntohl(packet_type) >> 16; +-} +- +-/* Returns the network byte ordered namespace type of 'packet type'. */ +-static inline ovs_be16 +-pt_ns_type_be(ovs_be32 packet_type) +-{ +- return be32_to_be16(packet_type); +-} +- +-/* Returns the host byte ordered namespace type of 'packet type'. */ +-static inline uint16_t +-pt_ns_type(ovs_be32 packet_type) +-{ +- return ntohs(pt_ns_type_be(packet_type)); +-} +- +-/* Well-known packet_type field values. */ +-enum packet_type { +- PT_ETH = PACKET_TYPE(OFPHTN_ONF, 0x0000), /* Default PT: Ethernet */ +- PT_USE_NEXT_PROTO = PACKET_TYPE(OFPHTN_ONF, 0xfffe), /* Pseudo PT for decap. */ +- PT_IPV4 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IP), +- PT_IPV6 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IPV6), +- PT_MPLS = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS), +- PT_MPLS_MC = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS_MCAST), +- PT_NSH = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_NSH), +- PT_UNKNOWN = PACKET_TYPE(0xffff, 0xffff), /* Unknown packet type. */ +-}; +- +- +-void ipv6_format_addr(const struct in6_addr *addr, struct ds *); +-void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *, +- bool bracket); +-void ipv6_format_mapped(const struct in6_addr *addr, struct ds *); +-void ipv6_format_masked(const struct in6_addr *addr, +- const struct in6_addr *mask, struct ds *); +-const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr); +-struct in6_addr ipv6_addr_bitand(const struct in6_addr *src, +- const struct in6_addr *mask); +-struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a, +- const struct in6_addr *b); +-bool ipv6_is_zero(const struct in6_addr *a); +-struct in6_addr ipv6_create_mask(int mask); +-int ipv6_count_cidr_bits(const struct in6_addr *netmask); +-bool ipv6_is_cidr(const struct in6_addr *netmask); +- +-bool ipv6_parse(const char *s, struct in6_addr *ip); +-char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6, +- struct in6_addr *mask); +-char *ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) +- OVS_WARN_UNUSED_RESULT; +-char *ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ipv6, +- struct in6_addr *mask); +-char *ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip, +- unsigned int *plen) +- OVS_WARN_UNUSED_RESULT; +- +-void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst, +- const struct eth_addr eth_src, uint16_t eth_type, +- size_t size); +-void *snap_compose(struct dp_packet *, const struct eth_addr eth_dst, +- const struct eth_addr eth_src, +- unsigned int oui, uint16_t snap_type, size_t size); +-void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos, +- uint8_t ttl); +-void packet_set_ipv4_addr(struct dp_packet *packet, ovs_16aligned_be32 *addr, +- ovs_be32 new_addr); +-void packet_set_ipv6(struct dp_packet *, const struct in6_addr *src, +- const struct in6_addr *dst, uint8_t tc, +- ovs_be32 fl, uint8_t hlmit); +-void packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto, +- ovs_16aligned_be32 addr[4], +- const struct in6_addr *new_addr, +- bool recalculate_csum); +-void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); +-void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); +-void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); +-void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code); +-void packet_set_nd(struct dp_packet *, const struct in6_addr *target, +- const struct eth_addr sll, const struct eth_addr tll); +-void packet_set_nd_ext(struct dp_packet *packet, +- const ovs_16aligned_be32 rso_flags, +- const uint8_t opt_type); +-void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp, +- ovs_be32 group, bool srs, uint8_t qrv, +- uint8_t qqic); +-void packet_format_tcp_flags(struct ds *, uint16_t); +-const char *packet_tcp_flag_to_string(uint32_t flag); +-void *compose_ipv6(struct dp_packet *packet, uint8_t proto, +- const struct in6_addr *src, const struct in6_addr *dst, +- uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size); +-void compose_arp__(struct dp_packet *); +-void compose_arp(struct dp_packet *, uint16_t arp_op, +- const struct eth_addr arp_sha, +- const struct eth_addr arp_tha, bool broadcast, +- ovs_be32 arp_spa, ovs_be32 arp_tpa); +-void compose_nd_ns(struct dp_packet *, const struct eth_addr eth_src, +- const struct in6_addr *ipv6_src, +- const struct in6_addr *ipv6_dst); +-void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src, +- const struct eth_addr eth_dst, +- const struct in6_addr *ipv6_src, +- const struct in6_addr *ipv6_dst, +- ovs_be32 rso_flags); +-void compose_nd_ra(struct dp_packet *, +- const struct eth_addr eth_src, +- const struct eth_addr eth_dst, +- const struct in6_addr *ipv6_src, +- const struct in6_addr *ipv6_dst, +- uint8_t cur_hop_limit, uint8_t mo_flags, +- ovs_be16 router_lt, ovs_be32 reachable_time, +- ovs_be32 retrans_timer, uint32_t mtu); +-void packet_put_ra_prefix_opt(struct dp_packet *, +- uint8_t plen, uint8_t la_flags, +- ovs_be32 valid_lifetime, +- ovs_be32 preferred_lifetime, +- const ovs_be128 router_prefix); +-uint32_t packet_csum_pseudoheader(const struct ip_header *); +-void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6); +- +-#define DNS_HEADER_LEN 12 +-struct dns_header { +- ovs_be16 id; +- uint8_t lo_flag; /* QR (1), OPCODE (4), AA (1), TC (1) and RD (1) */ +- uint8_t hi_flag; /* RA (1), Z (3) and RCODE (4) */ +- ovs_be16 qdcount; /* Num of entries in the question section. */ +- ovs_be16 ancount; /* Num of resource records in the answer section. */ +- +- /* Num of name server records in the authority record section. */ +- ovs_be16 nscount; +- +- /* Num of resource records in the additional records section. */ +- ovs_be16 arcount; +-}; +- +-BUILD_ASSERT_DECL(DNS_HEADER_LEN == sizeof(struct dns_header)); +- +-#define DNS_QUERY_TYPE_A 0x01 +-#define DNS_QUERY_TYPE_AAAA 0x1c +-#define DNS_QUERY_TYPE_ANY 0xff +- +-#define DNS_CLASS_IN 0x01 +-#define DNS_DEFAULT_RR_TTL 3600 +- +-#endif /* packets.h */ +Index: openvswitch-2.17.2/include/internal/packets.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/packets.h +@@ -0,0 +1,1671 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef PACKETS_H ++#define PACKETS_H 1 ++ ++#include ++#include ++#include ++#include ++#include "openvswitch/compiler.h" ++#include "openvswitch/geneve.h" ++#include "openvswitch/packets.h" ++#include "openvswitch/types.h" ++#include "openvswitch/nsh.h" ++#include "odp-netlink.h" +#include "internal/random.h" +#include "internal/hash.h" +#include "internal/tun-metadata-private.h" +#include "internal/unaligned.h" +#include "internal/util.h" +#include "internal/timeval.h" - - struct dp_packet; - struct conn; -diff --git a/lib/process.h b/include/internal/process.h -similarity index 100% -rename from lib/process.h -rename to include/internal/process.h -diff --git a/lib/pvector.h b/include/internal/pvector.h -similarity index 99% -rename from lib/pvector.h -rename to include/internal/pvector.h -index 6da8c5b63..cf11aced6 100644 ---- a/lib/pvector.h -+++ b/include/internal/pvector.h -@@ -20,8 +20,8 @@ - #include - #include - #include ++ ++struct dp_packet; ++struct conn; ++struct ds; ++ ++/* Purely internal to OVS userspace. These flags should never be exposed to ++ * the outside world and so aren't included in the flags mask. */ ++ ++/* Tunnel information is in userspace datapath format. */ ++#define FLOW_TNL_F_UDPIF (1 << 4) ++ ++static inline bool ipv6_addr_is_set(const struct in6_addr *addr); ++ ++static inline bool ++flow_tnl_dst_is_set(const struct flow_tnl *tnl) ++{ ++ return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst); ++} ++ ++static inline bool ++flow_tnl_src_is_set(const struct flow_tnl *tnl) ++{ ++ return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src); ++} ++ ++struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl); ++struct in6_addr flow_tnl_src(const struct flow_tnl *tnl); ++ ++/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */ ++static inline size_t ++flow_tnl_size(const struct flow_tnl *src) ++{ ++ if (!flow_tnl_dst_is_set(src)) { ++ /* Covers ip_dst and ipv6_dst only. */ ++ return offsetof(struct flow_tnl, ip_src); ++ } ++ if (src->flags & FLOW_TNL_F_UDPIF) { ++ /* Datapath format, cover all options we have. */ ++ return offsetof(struct flow_tnl, metadata.opts) ++ + src->metadata.present.len; ++ } ++ if (!src->metadata.present.map) { ++ /* No TLVs, opts is irrelevant. */ ++ return offsetof(struct flow_tnl, metadata.opts); ++ } ++ /* Have decoded TLVs, opts is relevant. */ ++ return sizeof *src; ++} ++ ++/* Copy flow_tnl, but avoid copying unused portions of tun_metadata. Unused ++ * data in 'dst' is NOT cleared, so this must not be used in cases where the ++ * uninitialized portion may be hashed over. */ ++static inline void ++flow_tnl_copy__(struct flow_tnl *dst, const struct flow_tnl *src) ++{ ++ memcpy(dst, src, flow_tnl_size(src)); ++} ++ ++static inline bool ++flow_tnl_equal(const struct flow_tnl *a, const struct flow_tnl *b) ++{ ++ size_t a_size = flow_tnl_size(a); ++ ++ return a_size == flow_tnl_size(b) && !memcmp(a, b, a_size); ++} ++ ++/* Datapath packet metadata */ ++struct pkt_metadata { ++PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0, ++ uint32_t recirc_id; /* Recirculation id carried with the ++ recirculating packets. 0 for packets ++ received from the wire. */ ++ uint32_t dp_hash; /* hash value computed by the recirculation ++ action. */ ++ uint32_t skb_priority; /* Packet priority for QoS. */ ++ uint32_t pkt_mark; /* Packet mark. */ ++ uint8_t ct_state; /* Connection state. */ ++ bool ct_orig_tuple_ipv6; ++ uint16_t ct_zone; /* Connection zone. */ ++ uint32_t ct_mark; /* Connection mark. */ ++ ovs_u128 ct_label; /* Connection label. */ ++ union flow_in_port in_port; /* Input port. */ ++ odp_port_t orig_in_port; /* Originating in_port for tunneled packets */ ++ struct conn *conn; /* Cached conntrack connection. */ ++ bool reply; /* True if reply direction. */ ++ bool icmp_related; /* True if ICMP related. */ ++); ++ ++PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1, ++ union { /* Populated only for non-zero 'ct_state'. */ ++ struct ovs_key_ct_tuple_ipv4 ipv4; ++ struct ovs_key_ct_tuple_ipv6 ipv6; /* Used only if */ ++ } ct_orig_tuple; /* 'ct_orig_tuple_ipv6' is set */ ++); ++ ++PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline2, ++ struct flow_tnl tunnel; /* Encapsulating tunnel parameters. Note that ++ * if 'ip_dst' == 0, the rest of the fields may ++ * be uninitialized. */ ++); ++}; ++ ++BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline0) == 0); ++BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline1) == ++ CACHE_LINE_SIZE); ++BUILD_ASSERT_DECL(offsetof(struct pkt_metadata, cacheline2) == ++ 2 * CACHE_LINE_SIZE); ++ ++static inline void ++pkt_metadata_init_tnl(struct pkt_metadata *md) ++{ ++ odp_port_t orig_in_port; ++ ++ /* Zero up through the tunnel metadata options. The length and table ++ * are before this and as long as they are empty, the options won't ++ * be looked at. Keep the orig_in_port field. */ ++ orig_in_port = md->in_port.odp_port; ++ memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts)); ++ md->orig_in_port = orig_in_port; ++} ++ ++static inline void ++pkt_metadata_init_conn(struct pkt_metadata *md) ++{ ++ md->conn = NULL; ++} ++ ++static inline void ++pkt_metadata_init(struct pkt_metadata *md, odp_port_t port) ++{ ++ /* This is called for every packet in userspace datapath and affects ++ * performance if all the metadata is initialized. Hence, fields should ++ * only be zeroed out when necessary. ++ * ++ * Initialize only till ct_state. Once the ct_state is zeroed out rest ++ * of ct fields will not be looked at unless ct_state != 0. ++ */ ++ memset(md, 0, offsetof(struct pkt_metadata, ct_orig_tuple_ipv6)); ++ ++ /* It can be expensive to zero out all of the tunnel metadata. However, ++ * we can just zero out ip_dst and the rest of the data will never be ++ * looked at. */ ++ md->tunnel.ip_dst = 0; ++ md->tunnel.ipv6_dst = in6addr_any; ++ md->in_port.odp_port = port; ++ md->orig_in_port = port; ++ md->conn = NULL; ++} ++ ++/* This function prefetches the cachelines touched by pkt_metadata_init() ++ * and pkt_metadata_init_tnl(). For performance reasons the two functions ++ * should be kept in sync. */ ++static inline void ++pkt_metadata_prefetch_init(struct pkt_metadata *md) ++{ ++ /* Prefetch cacheline0 as members till ct_state and odp_port will ++ * be initialized later in pkt_metadata_init(). */ ++ OVS_PREFETCH(md->cacheline0); ++ ++ /* Prefetch cacheline1 as members of this cacheline will be zeroed out ++ * in pkt_metadata_init_tnl(). */ ++ OVS_PREFETCH(md->cacheline1); ++ ++ /* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */ ++ OVS_PREFETCH(md->cacheline2); ++} ++ ++bool dpid_from_string(const char *s, uint64_t *dpidp); ++ ++#define ETH_ADDR_LEN 6 ++ ++static const struct eth_addr eth_addr_broadcast OVS_UNUSED ++ = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); ++ ++static const struct eth_addr eth_addr_exact OVS_UNUSED ++ = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); ++ ++static const struct eth_addr eth_addr_zero OVS_UNUSED ++ = ETH_ADDR_C(00,00,00,00,00,00); ++static const struct eth_addr64 eth_addr64_zero OVS_UNUSED ++ = ETH_ADDR64_C(00,00,00,00,00,00,00,00); ++ ++static const struct eth_addr eth_addr_stp OVS_UNUSED ++ = ETH_ADDR_C(01,80,c2,00,00,00); ++ ++static const struct eth_addr eth_addr_lacp OVS_UNUSED ++ = ETH_ADDR_C(01,80,c2,00,00,02); ++ ++static const struct eth_addr eth_addr_bfd OVS_UNUSED ++ = ETH_ADDR_C(00,23,20,00,00,01); ++ ++static inline bool eth_addr_is_broadcast(const struct eth_addr a) ++{ ++ return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); ++} ++ ++static inline bool eth_addr_is_multicast(const struct eth_addr a) ++{ ++ return a.ea[0] & 1; ++} ++ ++static inline bool eth_addr_is_local(const struct eth_addr a) ++{ ++ /* Local if it is either a locally administered address or a Nicira random ++ * address. */ ++ return a.ea[0] & 2 ++ || (a.be16[0] == htons(0x0023) ++ && (a.be16[1] & htons(0xff80)) == htons(0x2080)); ++} ++static inline bool eth_addr_is_zero(const struct eth_addr a) ++{ ++ return !(a.be16[0] | a.be16[1] | a.be16[2]); ++} ++static inline bool eth_addr64_is_zero(const struct eth_addr64 a) ++{ ++ return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]); ++} ++ ++static inline int eth_mask_is_exact(const struct eth_addr a) ++{ ++ return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); ++} ++ ++static inline int eth_addr_compare_3way(const struct eth_addr a, ++ const struct eth_addr b) ++{ ++ return memcmp(&a, &b, sizeof a); ++} ++static inline int eth_addr64_compare_3way(const struct eth_addr64 a, ++ const struct eth_addr64 b) ++{ ++ return memcmp(&a, &b, sizeof a); ++} ++ ++static inline bool eth_addr_equals(const struct eth_addr a, ++ const struct eth_addr b) ++{ ++ return !eth_addr_compare_3way(a, b); ++} ++static inline bool eth_addr64_equals(const struct eth_addr64 a, ++ const struct eth_addr64 b) ++{ ++ return !eth_addr64_compare_3way(a, b); ++} ++ ++static inline bool eth_addr_equal_except(const struct eth_addr a, ++ const struct eth_addr b, ++ const struct eth_addr mask) ++{ ++ return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0]) ++ || ((a.be16[1] ^ b.be16[1]) & mask.be16[1]) ++ || ((a.be16[2] ^ b.be16[2]) & mask.be16[2])); ++} ++ ++uint64_t eth_addr_to_uint64(const struct eth_addr ea); ++ ++static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea, ++ uint16_t vlan) ++{ ++ return (((uint64_t)vlan << 48) | eth_addr_to_uint64(ea)); ++} ++ ++void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea); ++ ++static inline struct eth_addr eth_addr_invert(const struct eth_addr src) ++{ ++ struct eth_addr dst; ++ ++ for (int i = 0; i < ARRAY_SIZE(src.be16); i++) { ++ dst.be16[i] = ~src.be16[i]; ++ } ++ ++ return dst; ++} ++ ++void eth_addr_mark_random(struct eth_addr *ea); ++ ++static inline void eth_addr_random(struct eth_addr *ea) ++{ ++ random_bytes((uint8_t *)ea, sizeof *ea); ++ eth_addr_mark_random(ea); ++} ++ ++static inline void eth_addr_nicira_random(struct eth_addr *ea) ++{ ++ eth_addr_random(ea); ++ ++ /* Set the OUI to the Nicira one. */ ++ ea->ea[0] = 0x00; ++ ea->ea[1] = 0x23; ++ ea->ea[2] = 0x20; ++ ++ /* Set the top bit to indicate random Nicira address. */ ++ ea->ea[3] |= 0x80; ++} ++static inline uint32_t hash_mac(const struct eth_addr ea, ++ const uint16_t vlan, const uint32_t basis) ++{ ++ return hash_uint64_basis(eth_addr_vlan_to_uint64(ea, vlan), basis); ++} ++ ++bool eth_addr_is_reserved(const struct eth_addr); ++bool eth_addr_from_string(const char *, struct eth_addr *); ++ ++void compose_rarp(struct dp_packet *, const struct eth_addr); ++ ++void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci); ++void eth_pop_vlan(struct dp_packet *); ++ ++const char *eth_from_hex(const char *hex, struct dp_packet **packetp); ++void eth_format_masked(const struct eth_addr ea, ++ const struct eth_addr *mask, struct ds *s); ++ ++void set_mpls_lse(struct dp_packet *, ovs_be32 label); ++void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse); ++void pop_mpls(struct dp_packet *, ovs_be16 ethtype); ++ ++void set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl); ++void set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc); ++void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label); ++void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos); ++ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, ++ ovs_be32 label); ++void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse, ++ bool l3_encap); ++ ++/* Example: ++ * ++ * struct eth_addr mac; ++ * [...] ++ * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac)); ++ * ++ */ ++#define ETH_ADDR_FMT \ ++ "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 ++#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea) ++#define ETH_ADDR_BYTES_ARGS(EAB) \ ++ (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5] ++#define ETH_ADDR_STRLEN 17 ++ ++/* Example: ++ * ++ * struct eth_addr64 eui64; ++ * [...] ++ * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac)); ++ * ++ */ ++#define ETH_ADDR64_FMT \ ++ "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \ ++ "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 ++#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64) ++#define ETH_ADDR64_BYTES_ARGS(EAB) \ ++ (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \ ++ (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7] ++#define ETH_ADDR64_STRLEN 23 ++ ++/* Example: ++ * ++ * char *string = "1 00:11:22:33:44:55 2"; ++ * struct eth_addr mac; ++ * int a, b; ++ * ++ * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d", ++ * &a, ETH_ADDR_SCAN_ARGS(mac), &b)) { ++ * ... ++ * } ++ */ ++#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8 ++#define ETH_ADDR_SCAN_ARGS(EA) \ ++ &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], &(EA).ea[3], &(EA).ea[4], &(EA).ea[5] ++ ++#define ETH_TYPE_IP 0x0800 ++#define ETH_TYPE_ARP 0x0806 ++#define ETH_TYPE_TEB 0x6558 ++#define ETH_TYPE_VLAN_8021Q 0x8100 ++#define ETH_TYPE_VLAN ETH_TYPE_VLAN_8021Q ++#define ETH_TYPE_VLAN_8021AD 0x88a8 ++#define ETH_TYPE_IPV6 0x86dd ++#define ETH_TYPE_LACP 0x8809 ++#define ETH_TYPE_RARP 0x8035 ++#define ETH_TYPE_MPLS 0x8847 ++#define ETH_TYPE_MPLS_MCAST 0x8848 ++#define ETH_TYPE_NSH 0x894f ++#define ETH_TYPE_ERSPAN1 0x88be /* version 1 type II */ ++#define ETH_TYPE_ERSPAN2 0x22eb /* version 2 type III */ ++ ++static inline bool eth_type_mpls(ovs_be16 eth_type) ++{ ++ return eth_type == htons(ETH_TYPE_MPLS) || ++ eth_type == htons(ETH_TYPE_MPLS_MCAST); ++} ++ ++static inline bool eth_type_vlan(ovs_be16 eth_type) ++{ ++ return eth_type == htons(ETH_TYPE_VLAN_8021Q) || ++ eth_type == htons(ETH_TYPE_VLAN_8021AD); ++} ++ ++ ++/* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame ++ * lengths. */ ++#define ETH_TYPE_MIN 0x600 ++ ++#define ETH_HEADER_LEN 14 ++#define ETH_PAYLOAD_MIN 46 ++#define ETH_PAYLOAD_MAX 1500 ++#define ETH_TOTAL_MIN (ETH_HEADER_LEN + ETH_PAYLOAD_MIN) ++#define ETH_TOTAL_MAX (ETH_HEADER_LEN + ETH_PAYLOAD_MAX) ++#define ETH_VLAN_TOTAL_MAX (ETH_HEADER_LEN + VLAN_HEADER_LEN + ETH_PAYLOAD_MAX) ++struct eth_header { ++ struct eth_addr eth_dst; ++ struct eth_addr eth_src; ++ ovs_be16 eth_type; ++}; ++BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header)); ++ ++void push_eth(struct dp_packet *packet, const struct eth_addr *dst, ++ const struct eth_addr *src); ++void pop_eth(struct dp_packet *packet); ++ ++void push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src); ++bool pop_nsh(struct dp_packet *packet); ++ ++#define LLC_DSAP_SNAP 0xaa ++#define LLC_SSAP_SNAP 0xaa ++#define LLC_CNTL_SNAP 3 ++ ++#define LLC_HEADER_LEN 3 ++struct llc_header { ++ uint8_t llc_dsap; ++ uint8_t llc_ssap; ++ uint8_t llc_cntl; ++}; ++BUILD_ASSERT_DECL(LLC_HEADER_LEN == sizeof(struct llc_header)); ++ ++/* LLC field values used for STP frames. */ ++#define STP_LLC_SSAP 0x42 ++#define STP_LLC_DSAP 0x42 ++#define STP_LLC_CNTL 0x03 ++ ++#define SNAP_ORG_ETHERNET "\0\0" /* The compiler adds a null byte, so ++ sizeof(SNAP_ORG_ETHERNET) == 3. */ ++#define SNAP_HEADER_LEN 5 ++OVS_PACKED( ++struct snap_header { ++ uint8_t snap_org[3]; ++ ovs_be16 snap_type; ++}); ++BUILD_ASSERT_DECL(SNAP_HEADER_LEN == sizeof(struct snap_header)); ++ ++#define LLC_SNAP_HEADER_LEN (LLC_HEADER_LEN + SNAP_HEADER_LEN) ++OVS_PACKED( ++struct llc_snap_header { ++ struct llc_header llc; ++ struct snap_header snap; ++}); ++BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header)); ++ ++#define VLAN_VID_MASK 0x0fff ++#define VLAN_VID_SHIFT 0 ++ ++#define VLAN_PCP_MASK 0xe000 ++#define VLAN_PCP_SHIFT 13 ++ ++#define VLAN_CFI 0x1000 ++#define VLAN_CFI_SHIFT 12 ++ ++/* Given the vlan_tci field from an 802.1Q header, in network byte order, ++ * returns the VLAN ID in host byte order. */ ++static inline uint16_t ++vlan_tci_to_vid(ovs_be16 vlan_tci) ++{ ++ return (ntohs(vlan_tci) & VLAN_VID_MASK) >> VLAN_VID_SHIFT; ++} ++ ++/* Given the vlan_tci field from an 802.1Q header, in network byte order, ++ * returns the priority code point (PCP) in host byte order. */ ++static inline int ++vlan_tci_to_pcp(ovs_be16 vlan_tci) ++{ ++ return (ntohs(vlan_tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; ++} ++ ++/* Given the vlan_tci field from an 802.1Q header, in network byte order, ++ * returns the Canonical Format Indicator (CFI). */ ++static inline int ++vlan_tci_to_cfi(ovs_be16 vlan_tci) ++{ ++ return (vlan_tci & htons(VLAN_CFI)) != 0; ++} ++ ++#define VLAN_HEADER_LEN 4 ++struct vlan_header { ++ ovs_be16 vlan_tci; /* Lowest 12 bits are VLAN ID. */ ++ ovs_be16 vlan_next_type; ++}; ++BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header)); ++ ++#define VLAN_ETH_HEADER_LEN (ETH_HEADER_LEN + VLAN_HEADER_LEN) ++struct vlan_eth_header { ++ struct eth_addr veth_dst; ++ struct eth_addr veth_src; ++ ovs_be16 veth_type; /* Always htons(ETH_TYPE_VLAN). */ ++ ovs_be16 veth_tci; /* Lowest 12 bits are VLAN ID. */ ++ ovs_be16 veth_next_type; ++}; ++BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); ++ ++/* MPLS related definitions */ ++#define MPLS_TTL_MASK 0x000000ff ++#define MPLS_TTL_SHIFT 0 ++ ++#define MPLS_BOS_MASK 0x00000100 ++#define MPLS_BOS_SHIFT 8 ++ ++#define MPLS_TC_MASK 0x00000e00 ++#define MPLS_TC_SHIFT 9 ++ ++#define MPLS_LABEL_MASK 0xfffff000 ++#define MPLS_LABEL_SHIFT 12 ++ ++#define MPLS_HLEN 4 ++ ++struct mpls_hdr { ++ ovs_16aligned_be32 mpls_lse; ++}; ++BUILD_ASSERT_DECL(MPLS_HLEN == sizeof(struct mpls_hdr)); ++ ++/* Given a mpls label stack entry in network byte order ++ * return mpls label in host byte order */ ++static inline uint32_t ++mpls_lse_to_label(ovs_be32 mpls_lse) ++{ ++ return (ntohl(mpls_lse) & MPLS_LABEL_MASK) >> MPLS_LABEL_SHIFT; ++} ++ ++/* Given a mpls label stack entry in network byte order ++ * return mpls tc */ ++static inline uint8_t ++mpls_lse_to_tc(ovs_be32 mpls_lse) ++{ ++ return (ntohl(mpls_lse) & MPLS_TC_MASK) >> MPLS_TC_SHIFT; ++} ++ ++/* Given a mpls label stack entry in network byte order ++ * return mpls ttl */ ++static inline uint8_t ++mpls_lse_to_ttl(ovs_be32 mpls_lse) ++{ ++ return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; ++} ++ ++/* Set label in mpls lse. */ ++static inline void ++flow_set_mpls_lse_label(ovs_be32 *mpls_lse, uint32_t label) ++{ ++ *mpls_lse &= ~htonl(MPLS_LABEL_MASK); ++ *mpls_lse |= htonl(label << MPLS_LABEL_SHIFT); ++} ++ ++/* Set TC in mpls lse. */ ++static inline void ++flow_set_mpls_lse_tc(ovs_be32 *mpls_lse, uint8_t tc) ++{ ++ *mpls_lse &= ~htonl(MPLS_TC_MASK); ++ *mpls_lse |= htonl((tc & 0x7) << MPLS_TC_SHIFT); ++} ++ ++/* Set BOS in mpls lse. */ ++static inline void ++flow_set_mpls_lse_bos(ovs_be32 *mpls_lse, uint8_t bos) ++{ ++ *mpls_lse &= ~htonl(MPLS_BOS_MASK); ++ *mpls_lse |= htonl((bos & 0x1) << MPLS_BOS_SHIFT); ++} ++ ++/* Set TTL in mpls lse. */ ++static inline void ++flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl) ++{ ++ *mpls_lse &= ~htonl(MPLS_TTL_MASK); ++ *mpls_lse |= htonl(ttl << MPLS_TTL_SHIFT); ++} ++ ++/* Given a mpls label stack entry in network byte order ++ * return mpls BoS bit */ ++static inline uint8_t ++mpls_lse_to_bos(ovs_be32 mpls_lse) ++{ ++ return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0; ++} ++ ++#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32 ++#define IP_ARGS(ip) \ ++ ntohl(ip) >> 24, \ ++ (ntohl(ip) >> 16) & 0xff, \ ++ (ntohl(ip) >> 8) & 0xff, \ ++ ntohl(ip) & 0xff ++ ++/* Example: ++ * ++ * char *string = "1 33.44.55.66 2"; ++ * ovs_be32 ip; ++ * int a, b; ++ * ++ * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) { ++ * ... ++ * } ++ */ ++#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8 ++#define IP_SCAN_ARGS(ip) \ ++ ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ ++ &((uint8_t *) ip)[1], \ ++ &((uint8_t *) ip)[2], \ ++ &((uint8_t *) ip)[3] ++ ++#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16 ++#define IP_PORT_SCAN_ARGS(ip, port) \ ++ ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ ++ &((uint8_t *) ip)[1], \ ++ &((uint8_t *) ip)[2], \ ++ &((uint8_t *) ip)[3], \ ++ ((void) (ovs_be16) *(port), (uint16_t *) port) ++ ++/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N ++ * high-order 1-bits and 32-N low-order 0-bits. */ ++static inline bool ++ip_is_cidr(ovs_be32 netmask) ++{ ++ uint32_t x = ~ntohl(netmask); ++ return !(x & (x + 1)); ++} ++static inline bool ++ip_is_multicast(ovs_be32 ip) ++{ ++ return (ip & htonl(0xf0000000)) == htonl(0xe0000000); ++} ++static inline bool ++ip_is_local_multicast(ovs_be32 ip) ++{ ++ return (ip & htonl(0xffffff00)) == htonl(0xe0000000); ++} ++int ip_count_cidr_bits(ovs_be32 netmask); ++void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *); ++bool ip_parse(const char *s, ovs_be32 *ip); ++char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) ++ OVS_WARN_UNUSED_RESULT; ++char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) ++ OVS_WARN_UNUSED_RESULT; ++char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) ++ OVS_WARN_UNUSED_RESULT; ++char *ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, ovs_be32 *mask) ++ OVS_WARN_UNUSED_RESULT; ++char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, ++ unsigned int *plen) ++ OVS_WARN_UNUSED_RESULT; ++ ++#define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4) ++#define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15) ++#define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl)) ++ ++#ifndef IPPROTO_SCTP ++#define IPPROTO_SCTP 132 ++#endif ++ ++#ifndef IPPROTO_DCCP ++#define IPPROTO_DCCP 33 ++#endif ++ ++#ifndef IPPROTO_IGMP ++#define IPPROTO_IGMP 2 ++#endif ++ ++#ifndef IPPROTO_UDPLITE ++#define IPPROTO_UDPLITE 136 ++#endif ++ ++/* TOS fields. */ ++#define IP_ECN_NOT_ECT 0x0 ++#define IP_ECN_ECT_1 0x01 ++#define IP_ECN_ECT_0 0x02 ++#define IP_ECN_CE 0x03 ++#define IP_ECN_MASK 0x03 ++#define IP_DSCP_CS6 0xc0 ++#define IP_DSCP_MASK 0xfc ++ ++static inline int ++IP_ECN_is_ce(uint8_t dsfield) ++{ ++ return (dsfield & IP_ECN_MASK) == IP_ECN_CE; ++} ++ ++#define IP_VERSION 4 ++ ++#define IP_DONT_FRAGMENT 0x4000 /* Don't fragment. */ ++#define IP_MORE_FRAGMENTS 0x2000 /* More fragments. */ ++#define IP_FRAG_OFF_MASK 0x1fff /* Fragment offset. */ ++#define IP_IS_FRAGMENT(ip_frag_off) \ ++ ((ip_frag_off) & htons(IP_MORE_FRAGMENTS | IP_FRAG_OFF_MASK)) ++ ++#define IP_HEADER_LEN 20 ++struct ip_header { ++ uint8_t ip_ihl_ver; ++ uint8_t ip_tos; ++ ovs_be16 ip_tot_len; ++ ovs_be16 ip_id; ++ ovs_be16 ip_frag_off; ++ uint8_t ip_ttl; ++ uint8_t ip_proto; ++ ovs_be16 ip_csum; ++ ovs_16aligned_be32 ip_src; ++ ovs_16aligned_be32 ip_dst; ++}; ++BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); ++ ++/* ICMPv4 types. */ ++#define ICMP4_ECHO_REPLY 0 ++#define ICMP4_DST_UNREACH 3 ++#define ICMP4_SOURCEQUENCH 4 ++#define ICMP4_REDIRECT 5 ++#define ICMP4_ECHO_REQUEST 8 ++#define ICMP4_TIME_EXCEEDED 11 ++#define ICMP4_PARAM_PROB 12 ++#define ICMP4_TIMESTAMP 13 ++#define ICMP4_TIMESTAMPREPLY 14 ++#define ICMP4_INFOREQUEST 15 ++#define ICMP4_INFOREPLY 16 ++ ++#define ICMP_HEADER_LEN 8 ++struct icmp_header { ++ uint8_t icmp_type; ++ uint8_t icmp_code; ++ ovs_be16 icmp_csum; ++ union { ++ struct { ++ ovs_be16 id; ++ ovs_be16 seq; ++ } echo; ++ struct { ++ ovs_be16 empty; ++ ovs_be16 mtu; ++ } frag; ++ ovs_16aligned_be32 gateway; ++ } icmp_fields; ++}; ++BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header)); ++ ++/* ICMPV4 */ ++#define ICMP_ERROR_DATA_L4_LEN 8 ++ ++#define IGMP_HEADER_LEN 8 ++struct igmp_header { ++ uint8_t igmp_type; ++ uint8_t igmp_code; ++ ovs_be16 igmp_csum; ++ ovs_16aligned_be32 group; ++}; ++BUILD_ASSERT_DECL(IGMP_HEADER_LEN == sizeof(struct igmp_header)); ++ ++#define IGMPV3_HEADER_LEN 8 ++struct igmpv3_header { ++ uint8_t type; ++ uint8_t rsvr1; ++ ovs_be16 csum; ++ ovs_be16 rsvr2; ++ ovs_be16 ngrp; ++}; ++BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header)); ++ ++#define IGMPV3_QUERY_HEADER_LEN 12 ++struct igmpv3_query_header { ++ uint8_t type; ++ uint8_t max_resp; ++ ovs_be16 csum; ++ ovs_16aligned_be32 group; ++ uint8_t srs_qrv; ++ uint8_t qqic; ++ ovs_be16 nsrcs; ++}; ++BUILD_ASSERT_DECL( ++ IGMPV3_QUERY_HEADER_LEN == sizeof(struct igmpv3_query_header ++)); ++ ++#define IGMPV3_RECORD_LEN 8 ++struct igmpv3_record { ++ uint8_t type; ++ uint8_t aux_len; ++ ovs_be16 nsrcs; ++ ovs_16aligned_be32 maddr; ++}; ++BUILD_ASSERT_DECL(IGMPV3_RECORD_LEN == sizeof(struct igmpv3_record)); ++ ++#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ ++#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ ++#define IGMPV2_HOST_MEMBERSHIP_REPORT 0x16 /* V2 version of 0x12 */ ++#define IGMP_HOST_LEAVE_MESSAGE 0x17 ++#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */ ++ ++/* ++ * IGMPv3 and MLDv2 use the same codes. ++ */ ++#define IGMPV3_MODE_IS_INCLUDE 1 ++#define IGMPV3_MODE_IS_EXCLUDE 2 ++#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3 ++#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 4 ++#define IGMPV3_ALLOW_NEW_SOURCES 5 ++#define IGMPV3_BLOCK_OLD_SOURCES 6 ++ ++#define SCTP_HEADER_LEN 12 ++struct sctp_header { ++ ovs_be16 sctp_src; ++ ovs_be16 sctp_dst; ++ ovs_16aligned_be32 sctp_vtag; ++ ovs_16aligned_be32 sctp_csum; ++}; ++BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header)); ++ ++#define UDP_HEADER_LEN 8 ++struct udp_header { ++ ovs_be16 udp_src; ++ ovs_be16 udp_dst; ++ ovs_be16 udp_len; ++ ovs_be16 udp_csum; ++}; ++BUILD_ASSERT_DECL(UDP_HEADER_LEN == sizeof(struct udp_header)); ++ ++#define ESP_HEADER_LEN 8 ++struct esp_header { ++ ovs_be32 spi; ++ ovs_be32 seq_no; ++}; ++BUILD_ASSERT_DECL(ESP_HEADER_LEN == sizeof(struct esp_header)); ++ ++#define ESP_TRAILER_LEN 2 ++struct esp_trailer { ++ uint8_t pad_len; ++ uint8_t next_hdr; ++}; ++BUILD_ASSERT_DECL(ESP_TRAILER_LEN == sizeof(struct esp_trailer)); ++ ++#define TCP_FIN 0x001 ++#define TCP_SYN 0x002 ++#define TCP_RST 0x004 ++#define TCP_PSH 0x008 ++#define TCP_ACK 0x010 ++#define TCP_URG 0x020 ++#define TCP_ECE 0x040 ++#define TCP_CWR 0x080 ++#define TCP_NS 0x100 ++ ++#define TCP_CTL(flags, offset) (htons((flags) | ((offset) << 12))) ++#define TCP_FLAGS(tcp_ctl) (ntohs(tcp_ctl) & 0x0fff) ++#define TCP_FLAGS_BE16(tcp_ctl) ((tcp_ctl) & htons(0x0fff)) ++#define TCP_OFFSET(tcp_ctl) (ntohs(tcp_ctl) >> 12) ++ ++#define TCP_HEADER_LEN 20 ++struct tcp_header { ++ ovs_be16 tcp_src; ++ ovs_be16 tcp_dst; ++ ovs_16aligned_be32 tcp_seq; ++ ovs_16aligned_be32 tcp_ack; ++ ovs_be16 tcp_ctl; ++ ovs_be16 tcp_winsz; ++ ovs_be16 tcp_csum; ++ ovs_be16 tcp_urg; ++}; ++BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header)); ++ ++/* Connection states. ++ * ++ * Names like CS_RELATED are bit values, e.g. 1 << 2. ++ * Names like CS_RELATED_BIT are bit indexes, e.g. 2. */ ++#define CS_STATES \ ++ CS_STATE(NEW, 0, "new") \ ++ CS_STATE(ESTABLISHED, 1, "est") \ ++ CS_STATE(RELATED, 2, "rel") \ ++ CS_STATE(REPLY_DIR, 3, "rpl") \ ++ CS_STATE(INVALID, 4, "inv") \ ++ CS_STATE(TRACKED, 5, "trk") \ ++ CS_STATE(SRC_NAT, 6, "snat") \ ++ CS_STATE(DST_NAT, 7, "dnat") ++ ++enum { ++#define CS_STATE(ENUM, INDEX, NAME) \ ++ CS_##ENUM = 1 << INDEX, \ ++ CS_##ENUM##_BIT = INDEX, ++ CS_STATES ++#undef CS_STATE ++}; ++ ++/* Undefined connection state bits. */ ++enum { ++#define CS_STATE(ENUM, INDEX, NAME) +CS_##ENUM ++ CS_SUPPORTED_MASK = CS_STATES ++#undef CS_STATE ++}; ++#define CS_UNSUPPORTED_MASK (~(uint32_t)CS_SUPPORTED_MASK) ++ ++#define ARP_HRD_ETHERNET 1 ++#define ARP_PRO_IP 0x0800 ++#define ARP_OP_REQUEST 1 ++#define ARP_OP_REPLY 2 ++#define ARP_OP_RARP 3 ++ ++#define ARP_ETH_HEADER_LEN 28 ++struct arp_eth_header { ++ /* Generic members. */ ++ ovs_be16 ar_hrd; /* Hardware type. */ ++ ovs_be16 ar_pro; /* Protocol type. */ ++ uint8_t ar_hln; /* Hardware address length. */ ++ uint8_t ar_pln; /* Protocol address length. */ ++ ovs_be16 ar_op; /* Opcode. */ ++ ++ /* Ethernet+IPv4 specific members. */ ++ struct eth_addr ar_sha; /* Sender hardware address. */ ++ ovs_16aligned_be32 ar_spa; /* Sender protocol address. */ ++ struct eth_addr ar_tha; /* Target hardware address. */ ++ ovs_16aligned_be32 ar_tpa; /* Target protocol address. */ ++}; ++BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header)); ++ ++#define IPV6_HEADER_LEN 40 ++ ++/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on ++ * most implementations, this one only requires 16-bit alignment. */ ++union ovs_16aligned_in6_addr { ++ ovs_be16 be16[8]; ++ ovs_16aligned_be32 be32[4]; ++}; ++ ++/* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this ++ * one only requires 16-bit alignment. */ ++struct ovs_16aligned_ip6_hdr { ++ union { ++ struct ovs_16aligned_ip6_hdrctl { ++ ovs_16aligned_be32 ip6_un1_flow; ++ ovs_be16 ip6_un1_plen; ++ uint8_t ip6_un1_nxt; ++ uint8_t ip6_un1_hlim; ++ } ip6_un1; ++ uint8_t ip6_un2_vfc; ++ } ip6_ctlun; ++ union ovs_16aligned_in6_addr ip6_src; ++ union ovs_16aligned_in6_addr ip6_dst; ++}; ++ ++/* Like struct in6_frag, but whereas that struct requires 32-bit alignment, ++ * this one only requires 16-bit alignment. */ ++struct ovs_16aligned_ip6_frag { ++ uint8_t ip6f_nxt; ++ uint8_t ip6f_reserved; ++ ovs_be16 ip6f_offlg; ++ ovs_16aligned_be32 ip6f_ident; ++}; ++ ++#define ICMP6_HEADER_LEN 4 ++struct icmp6_header { ++ uint8_t icmp6_type; ++ uint8_t icmp6_code; ++ ovs_be16 icmp6_cksum; ++}; ++BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header)); ++ ++#define ICMP6_DATA_HEADER_LEN 8 ++struct icmp6_data_header { ++ struct icmp6_header icmp6_base; ++ union { ++ ovs_16aligned_be32 be32[1]; ++ ovs_be16 be16[2]; ++ uint8_t u8[4]; ++ } icmp6_data; ++}; ++BUILD_ASSERT_DECL(ICMP6_DATA_HEADER_LEN == sizeof(struct icmp6_data_header)); ++ ++uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *); ++ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *, ++ const void *, uint8_t, uint16_t); ++ ++/* Neighbor Discovery option field. ++ * ND options are always a multiple of 8 bytes in size. */ ++#define ND_LLA_OPT_LEN 8 ++struct ovs_nd_lla_opt { ++ uint8_t type; /* One of ND_OPT_*_LINKADDR. */ ++ uint8_t len; ++ struct eth_addr mac; ++}; ++BUILD_ASSERT_DECL(ND_LLA_OPT_LEN == sizeof(struct ovs_nd_lla_opt)); ++ ++/* Neighbor Discovery option: Prefix Information. */ ++#define ND_PREFIX_OPT_LEN 32 ++struct ovs_nd_prefix_opt { ++ uint8_t type; /* ND_OPT_PREFIX_INFORMATION. */ ++ uint8_t len; /* Always 4. */ ++ uint8_t prefix_len; ++ uint8_t la_flags; /* ND_PREFIX_* flags. */ ++ ovs_16aligned_be32 valid_lifetime; ++ ovs_16aligned_be32 preferred_lifetime; ++ ovs_16aligned_be32 reserved; /* Always 0. */ ++ union ovs_16aligned_in6_addr prefix; ++}; ++BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt)); ++ ++/* Neighbor Discovery option: MTU. */ ++#define ND_MTU_OPT_LEN 8 ++#define ND_MTU_DEFAULT 0 ++struct ovs_nd_mtu_opt { ++ uint8_t type; /* ND_OPT_MTU */ ++ uint8_t len; /* Always 1. */ ++ ovs_be16 reserved; /* Always 0. */ ++ ovs_16aligned_be32 mtu; ++}; ++BUILD_ASSERT_DECL(ND_MTU_OPT_LEN == sizeof(struct ovs_nd_mtu_opt)); ++ ++/* Like struct nd_msg (from ndisc.h), but whereas that struct requires 32-bit ++ * alignment, this one only requires 16-bit alignment. */ ++#define ND_MSG_LEN 24 ++struct ovs_nd_msg { ++ struct icmp6_header icmph; ++ ovs_16aligned_be32 rso_flags; ++ union ovs_16aligned_in6_addr target; ++ struct ovs_nd_lla_opt options[0]; ++}; ++BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg)); ++ ++/* Neighbor Discovery packet flags. */ ++#define ND_RSO_ROUTER 0x80000000 ++#define ND_RSO_SOLICITED 0x40000000 ++#define ND_RSO_OVERRIDE 0x20000000 ++ ++#define RA_MSG_LEN 16 ++struct ovs_ra_msg { ++ struct icmp6_header icmph; ++ uint8_t cur_hop_limit; ++ uint8_t mo_flags; /* ND_RA_MANAGED_ADDRESS and ND_RA_OTHER_CONFIG flags. */ ++ ovs_be16 router_lifetime; ++ ovs_be32 reachable_time; ++ ovs_be32 retrans_timer; ++ struct ovs_nd_lla_opt options[0]; ++}; ++BUILD_ASSERT_DECL(RA_MSG_LEN == sizeof(struct ovs_ra_msg)); ++ ++#define ND_RA_MANAGED_ADDRESS 0x80 ++#define ND_RA_OTHER_CONFIG 0x40 ++ ++/* Defaults based on MaxRtrInterval and MinRtrInterval from RFC 4861 section ++ * 6.2.1 ++ */ ++#define ND_RA_MAX_INTERVAL_DEFAULT 600 ++ ++static inline int ++nd_ra_min_interval_default(int max) ++{ ++ return max >= 9 ? max / 3 : max * 3 / 4; ++} ++ ++/* ++ * Use the same struct for MLD and MLD2, naming members as the defined fields in ++ * in the corresponding version of the protocol, though they are reserved in the ++ * other one. ++ */ ++#define MLD_HEADER_LEN 8 ++struct mld_header { ++ uint8_t type; ++ uint8_t code; ++ ovs_be16 csum; ++ ovs_be16 mrd; ++ ovs_be16 ngrp; ++}; ++BUILD_ASSERT_DECL(MLD_HEADER_LEN == sizeof(struct mld_header)); ++ ++#define MLD2_RECORD_LEN 20 ++struct mld2_record { ++ uint8_t type; ++ uint8_t aux_len; ++ ovs_be16 nsrcs; ++ union ovs_16aligned_in6_addr maddr; ++}; ++BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct mld2_record)); ++ ++#define MLD_QUERY 130 ++#define MLD_REPORT 131 ++#define MLD_DONE 132 ++#define MLD2_REPORT 143 ++ ++/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */ ++#define IPV6_LABEL_MASK 0x000fffff ++ ++/* Example: ++ * ++ * char *string = "1 ::1 2"; ++ * char ipv6_s[IPV6_SCAN_LEN + 1]; ++ * struct in6_addr ipv6; ++ * ++ * if (ovs_scan(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b) ++ * && inet_pton(AF_INET6, ipv6_s, &ipv6) == 1) { ++ * ... ++ * } ++ */ ++#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]" ++#define IPV6_SCAN_LEN 46 ++ ++extern const struct in6_addr in6addr_exact; ++#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \ ++ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } } ++ ++extern const struct in6_addr in6addr_all_hosts; ++#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } } ++ ++extern const struct in6_addr in6addr_all_routers; ++#define IN6ADDR_ALL_ROUTERS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } ++ ++static inline bool ipv6_addr_equals(const struct in6_addr *a, ++ const struct in6_addr *b) ++{ ++#ifdef IN6_ARE_ADDR_EQUAL ++ return IN6_ARE_ADDR_EQUAL(a, b); ++#else ++ return !memcmp(a, b, sizeof(*a)); ++#endif ++} ++ ++/* Checks the IPv6 address in 'mask' for all zeroes. */ ++static inline bool ipv6_mask_is_any(const struct in6_addr *mask) { ++ return ipv6_addr_equals(mask, &in6addr_any); ++} ++ ++static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) { ++ return ipv6_addr_equals(mask, &in6addr_exact); ++} ++ ++static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) { ++ return ipv6_addr_equals(addr, &in6addr_all_hosts); ++} ++ ++static inline bool ipv6_addr_is_set(const struct in6_addr *addr) { ++ return !ipv6_addr_equals(addr, &in6addr_any); ++} ++ ++static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) { ++ return ip->s6_addr[0] == 0xff; ++} ++ ++static inline struct in6_addr ++in6_addr_mapped_ipv4(ovs_be32 ip4) ++{ ++ struct in6_addr ip6; ++ memset(&ip6, 0, sizeof(ip6)); ++ ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff; ++ memcpy(&ip6.s6_addr[12], &ip4, 4); ++ return ip6; ++} ++ ++static inline void ++in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4) ++{ ++ *ip6 = in6_addr_mapped_ipv4(ip4); ++} ++ ++static inline ovs_be32 ++in6_addr_get_mapped_ipv4(const struct in6_addr *addr) ++{ ++ union ovs_16aligned_in6_addr *taddr = ++ (union ovs_16aligned_in6_addr *) addr; ++ if (IN6_IS_ADDR_V4MAPPED(addr)) { ++ return get_16aligned_be32(&taddr->be32[3]); ++ } else { ++ return INADDR_ANY; ++ } ++} ++ ++void in6_addr_solicited_node(struct in6_addr *addr, ++ const struct in6_addr *ip6); ++ ++void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, ++ struct in6_addr *lla); ++ ++void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla); ++ ++/* Returns true if 'addr' is a link local address. Otherwise, false. */ ++bool in6_is_lla(struct in6_addr *addr); ++ ++void ipv6_multicast_to_ethernet(struct eth_addr *eth, ++ const struct in6_addr *ip6); ++ ++static inline bool dl_type_is_ip_any(ovs_be16 dl_type) ++{ ++ return dl_type == htons(ETH_TYPE_IP) ++ || dl_type == htons(ETH_TYPE_IPV6); ++} ++ ++/* Tunnel header */ ++ ++/* GRE protocol header */ ++struct gre_base_hdr { ++ ovs_be16 flags; ++ ovs_be16 protocol; ++}; ++ ++#define GRE_CSUM 0x8000 ++#define GRE_ROUTING 0x4000 ++#define GRE_KEY 0x2000 ++#define GRE_SEQ 0x1000 ++#define GRE_STRICT 0x0800 ++#define GRE_REC 0x0700 ++#define GRE_FLAGS 0x00F8 ++#define GRE_VERSION 0x0007 ++ ++/* ++ * ERSPAN protocol header and metadata ++ * ++ * Version 1 (Type II) header (8 octets [42:49]) ++ * 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Ver | VLAN | COS | En|T| Session ID | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Reserved | Index | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ * ++ * ERSPAN Version 2 (Type III) header (12 octets [42:49]) ++ * 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Ver | VLAN | COS |BSO|T| Session ID | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Timestamp | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | SGT |P| FT | Hw ID |D|Gra|O| ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ */ ++ ++/* ERSPAN has fixed 8-byte GRE header */ ++#define ERSPAN_GREHDR_LEN 8 ++#define ERSPAN_HDR(gre_base_hdr) \ ++ ((struct erspan_base_hdr *)((char *)gre_base_hdr + ERSPAN_GREHDR_LEN)) ++ ++#define ERSPAN_V1_MDSIZE 4 ++#define ERSPAN_V2_MDSIZE 8 ++ ++#define ERSPAN_SID_MASK 0x03ff /* 10-bit Session ID. */ ++#define ERSPAN_IDX_MASK 0xfffff /* v1 Index */ ++#define ERSPAN_HWID_MASK 0x03f0 ++#define ERSPAN_DIR_MASK 0x0008 ++ ++struct erspan_base_hdr { ++#ifdef WORDS_BIGENDIAN ++ uint8_t ver:4, ++ vlan_upper:4; ++ uint8_t vlan:8; ++ uint8_t cos:3, ++ en:2, ++ t:1, ++ session_id_upper:2; ++ uint8_t session_id:8; ++#else ++ uint8_t vlan_upper:4, ++ ver:4; ++ uint8_t vlan:8; ++ uint8_t session_id_upper:2, ++ t:1, ++ en:2, ++ cos:3; ++ uint8_t session_id:8; ++#endif ++}; ++ ++struct erspan_md2 { ++ ovs_16aligned_be32 timestamp; ++ ovs_be16 sgt; ++#ifdef WORDS_BIGENDIAN ++ uint8_t p:1, ++ ft:5, ++ hwid_upper:2; ++ uint8_t hwid:4, ++ dir:1, ++ gra:2, ++ o:1; ++#else ++ uint8_t hwid_upper:2, ++ ft:5, ++ p:1; ++ uint8_t o:1, ++ gra:2, ++ dir:1, ++ hwid:4; ++#endif ++}; ++ ++struct erspan_metadata { ++ int version; ++ union { ++ ovs_be32 index; /* Version 1 (type II)*/ ++ struct erspan_md2 md2; /* Version 2 (type III) */ ++ } u; ++}; ++ ++static inline uint16_t get_sid(const struct erspan_base_hdr *ershdr) ++{ ++ return (ershdr->session_id_upper << 8) + ershdr->session_id; ++} ++ ++static inline void set_sid(struct erspan_base_hdr *ershdr, uint16_t id) ++{ ++ ershdr->session_id = id & 0xff; ++ ershdr->session_id_upper = (id >> 8) &0x3; ++} ++ ++static inline uint8_t get_hwid(const struct erspan_md2 *md2) ++{ ++ return (md2->hwid_upper << 4) + md2->hwid; ++} ++ ++static inline void set_hwid(struct erspan_md2 *md2, uint8_t hwid) ++{ ++ md2->hwid = hwid & 0xf; ++ md2->hwid_upper = (hwid >> 4) & 0x3; ++} ++ ++/* ERSPAN timestamp granularity ++ * 00b --> granularity = 100 microseconds ++ * 01b --> granularity = 100 nanoseconds ++ * 10b --> granularity = IEEE 1588 ++ * Here we only support 100 microseconds. ++ */ ++enum erspan_ts_gra { ++ ERSPAN_100US, ++ ERSPAN_100NS, ++ ERSPAN_IEEE1588, ++}; ++ ++static inline ovs_be32 get_erspan_ts(enum erspan_ts_gra gra) ++{ ++ ovs_be32 ts = 0; ++ ++ switch (gra) { ++ case ERSPAN_100US: ++ ts = htonl((uint32_t)(time_wall_usec() / 100)); ++ break; ++ case ERSPAN_100NS: ++ /* fall back */ ++ case ERSPAN_IEEE1588: ++ /* fall back */ ++ default: ++ OVS_NOT_REACHED(); ++ break; ++ } ++ return ts; ++} ++ ++/* ++ * GTP-U protocol header and metadata ++ * See: ++ * User Plane Protocol and Architectural Analysis on 3GPP 5G System ++ * draft-hmm-dmm-5g-uplane-analysis-00 ++ * ++ * 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Ver |P|R|E|S|N| Message Type| Length | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Tunnel Endpoint Identifier | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Sequence Number | N-PDU Number | Next-Ext-Hdr | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ * GTP-U Flags: ++ * P: Protocol Type (Set to '1') ++ * R: Reserved Bit (Set to '0') ++ * E: Extension Header Flag (Set to '1' if extension header exists) ++ * S: Sequence Number Flag (Set to '1' if sequence number exists) ++ * N: N-PDU Number Flag (Set to '1' if N-PDU number exists) ++ * ++ * GTP-U Message Type: ++ * Indicates the type of GTP-U message. ++ * ++ * GTP-U Length: ++ * Indicates the length in octets of the payload. ++ * ++ * User payload is transmitted in G-PDU packets. ++ */ ++ ++#define GTPU_VER_MASK 0xe0 ++#define GTPU_P_MASK 0x10 ++#define GTPU_E_MASK 0x04 ++#define GTPU_S_MASK 0x02 ++ ++/* GTP-U UDP port. */ ++#define GTPU_DST_PORT 2152 ++ ++/* Default GTP-U flags: Ver = 1 and P = 1. */ ++#define GTPU_FLAGS_DEFAULT 0x30 ++ ++/* GTP-U message type for normal user plane PDU. */ ++#define GTPU_MSGTYPE_REQ 1 /* Echo Request. */ ++#define GTPU_MSGTYPE_REPL 2 /* Echo Reply. */ ++#define GTPU_MSGTYPE_GPDU 255 /* User Payload. */ ++ ++struct gtpu_metadata { ++ uint8_t flags; ++ uint8_t msgtype; ++}; ++BUILD_ASSERT_DECL(sizeof(struct gtpu_metadata) == 2); ++ ++struct gtpuhdr { ++ struct gtpu_metadata md; ++ ovs_be16 len; ++ ovs_16aligned_be32 teid; ++}; ++BUILD_ASSERT_DECL(sizeof(struct gtpuhdr) == 8); ++ ++struct gtpuhdr_opt { ++ ovs_be16 seqno; ++ uint8_t pdu_number; ++ uint8_t next_ext_type; ++}; ++BUILD_ASSERT_DECL(sizeof(struct gtpuhdr_opt) == 4); ++ ++/* VXLAN protocol header */ ++struct vxlanhdr { ++ union { ++ ovs_16aligned_be32 vx_flags; /* VXLAN flags. */ ++ struct { ++ uint8_t flags; /* VXLAN GPE flags. */ ++ uint8_t reserved[2]; /* 16 bits reserved. */ ++ uint8_t next_protocol; /* Next Protocol field for VXLAN GPE. */ ++ } vx_gpe; ++ }; ++ ovs_16aligned_be32 vx_vni; ++}; ++BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8); ++ ++#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ ++ ++/* ++ * VXLAN Generic Protocol Extension (VXLAN_F_GPE): ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * |R|R|Ver|I|P|R|O| Reserved |Next Protocol | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | VXLAN Network Identifier (VNI) | Reserved | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ * Ver = Version. Indicates VXLAN GPE protocol version. ++ * ++ * P = Next Protocol Bit. The P bit is set to indicate that the ++ * Next Protocol field is present. ++ * ++ * O = OAM Flag Bit. The O bit is set to indicate that the packet ++ * is an OAM packet. ++ * ++ * Next Protocol = This 8 bit field indicates the protocol header ++ * immediately following the VXLAN GPE header. ++ * ++ * https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01 ++ */ ++ ++/* Fields in struct vxlanhdr.vx_gpe.flags */ ++#define VXLAN_GPE_FLAGS_VER 0x30 /* Version. */ ++#define VXLAN_GPE_FLAGS_P 0x04 /* Next Protocol Bit. */ ++#define VXLAN_GPE_FLAGS_O 0x01 /* OAM Bit. */ ++ ++/* VXLAN-GPE header flags. */ ++#define VXLAN_HF_VER ((1U <<29) | (1U <<28)) ++#define VXLAN_HF_NP (1U <<26) ++#define VXLAN_HF_OAM (1U <<24) ++ ++#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \ ++ 0xff) ++ ++/* VXLAN-GPE header Next Protocol. */ ++#define VXLAN_GPE_NP_IPV4 0x01 ++#define VXLAN_GPE_NP_IPV6 0x02 ++#define VXLAN_GPE_NP_ETHERNET 0x03 ++#define VXLAN_GPE_NP_NSH 0x04 ++ ++#define VXLAN_F_GPE 0x4000 ++#define VXLAN_HF_GPE 0x04000000 ++ ++/* Input values for PACKET_TYPE macros have to be in host byte order. ++ * The _BE postfix indicates result is in network byte order. Otherwise result ++ * is in host byte order. */ ++#define PACKET_TYPE(NS, NS_TYPE) ((uint32_t) ((NS) << 16 | (NS_TYPE))) ++#define PACKET_TYPE_BE(NS, NS_TYPE) (htonl((NS) << 16 | (NS_TYPE))) ++ ++/* Returns the host byte ordered namespace of 'packet type'. */ ++static inline uint16_t ++pt_ns(ovs_be32 packet_type) ++{ ++ return ntohl(packet_type) >> 16; ++} ++ ++/* Returns the network byte ordered namespace type of 'packet type'. */ ++static inline ovs_be16 ++pt_ns_type_be(ovs_be32 packet_type) ++{ ++ return be32_to_be16(packet_type); ++} ++ ++/* Returns the host byte ordered namespace type of 'packet type'. */ ++static inline uint16_t ++pt_ns_type(ovs_be32 packet_type) ++{ ++ return ntohs(pt_ns_type_be(packet_type)); ++} ++ ++/* Well-known packet_type field values. */ ++enum packet_type { ++ PT_ETH = PACKET_TYPE(OFPHTN_ONF, 0x0000), /* Default PT: Ethernet */ ++ PT_USE_NEXT_PROTO = PACKET_TYPE(OFPHTN_ONF, 0xfffe), /* Pseudo PT for decap. */ ++ PT_IPV4 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IP), ++ PT_IPV6 = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_IPV6), ++ PT_MPLS = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS), ++ PT_MPLS_MC = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_MPLS_MCAST), ++ PT_NSH = PACKET_TYPE(OFPHTN_ETHERTYPE, ETH_TYPE_NSH), ++ PT_UNKNOWN = PACKET_TYPE(0xffff, 0xffff), /* Unknown packet type. */ ++}; ++ ++ ++void ipv6_format_addr(const struct in6_addr *addr, struct ds *); ++void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *, ++ bool bracket); ++void ipv6_format_mapped(const struct in6_addr *addr, struct ds *); ++void ipv6_format_masked(const struct in6_addr *addr, ++ const struct in6_addr *mask, struct ds *); ++const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr); ++struct in6_addr ipv6_addr_bitand(const struct in6_addr *src, ++ const struct in6_addr *mask); ++struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a, ++ const struct in6_addr *b); ++bool ipv6_is_zero(const struct in6_addr *a); ++struct in6_addr ipv6_create_mask(int mask); ++int ipv6_count_cidr_bits(const struct in6_addr *netmask); ++bool ipv6_is_cidr(const struct in6_addr *netmask); ++ ++bool ipv6_parse(const char *s, struct in6_addr *ip); ++char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6, ++ struct in6_addr *mask); ++char *ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) ++ OVS_WARN_UNUSED_RESULT; ++char *ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ipv6, ++ struct in6_addr *mask); ++char *ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip, ++ unsigned int *plen) ++ OVS_WARN_UNUSED_RESULT; ++ ++void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst, ++ const struct eth_addr eth_src, uint16_t eth_type, ++ size_t size); ++void *snap_compose(struct dp_packet *, const struct eth_addr eth_dst, ++ const struct eth_addr eth_src, ++ unsigned int oui, uint16_t snap_type, size_t size); ++void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos, ++ uint8_t ttl); ++void packet_set_ipv4_addr(struct dp_packet *packet, ovs_16aligned_be32 *addr, ++ ovs_be32 new_addr); ++void packet_set_ipv6(struct dp_packet *, const struct in6_addr *src, ++ const struct in6_addr *dst, uint8_t tc, ++ ovs_be32 fl, uint8_t hlmit); ++void packet_set_ipv6_addr(struct dp_packet *packet, uint8_t proto, ++ ovs_16aligned_be32 addr[4], ++ const struct in6_addr *new_addr, ++ bool recalculate_csum); ++void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); ++void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); ++void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); ++void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code); ++void packet_set_nd(struct dp_packet *, const struct in6_addr *target, ++ const struct eth_addr sll, const struct eth_addr tll); ++void packet_set_nd_ext(struct dp_packet *packet, ++ const ovs_16aligned_be32 rso_flags, ++ const uint8_t opt_type); ++void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp, ++ ovs_be32 group, bool srs, uint8_t qrv, ++ uint8_t qqic); ++void packet_format_tcp_flags(struct ds *, uint16_t); ++const char *packet_tcp_flag_to_string(uint32_t flag); ++void *compose_ipv6(struct dp_packet *packet, uint8_t proto, ++ const struct in6_addr *src, const struct in6_addr *dst, ++ uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size); ++void compose_arp__(struct dp_packet *); ++void compose_arp(struct dp_packet *, uint16_t arp_op, ++ const struct eth_addr arp_sha, ++ const struct eth_addr arp_tha, bool broadcast, ++ ovs_be32 arp_spa, ovs_be32 arp_tpa); ++void compose_nd_ns(struct dp_packet *, const struct eth_addr eth_src, ++ const struct in6_addr *ipv6_src, ++ const struct in6_addr *ipv6_dst); ++void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src, ++ const struct eth_addr eth_dst, ++ const struct in6_addr *ipv6_src, ++ const struct in6_addr *ipv6_dst, ++ ovs_be32 rso_flags); ++void compose_nd_ra(struct dp_packet *, ++ const struct eth_addr eth_src, ++ const struct eth_addr eth_dst, ++ const struct in6_addr *ipv6_src, ++ const struct in6_addr *ipv6_dst, ++ uint8_t cur_hop_limit, uint8_t mo_flags, ++ ovs_be16 router_lt, ovs_be32 reachable_time, ++ ovs_be32 retrans_timer, uint32_t mtu); ++void packet_put_ra_prefix_opt(struct dp_packet *, ++ uint8_t plen, uint8_t la_flags, ++ ovs_be32 valid_lifetime, ++ ovs_be32 preferred_lifetime, ++ const ovs_be128 router_prefix); ++uint32_t packet_csum_pseudoheader(const struct ip_header *); ++void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6); ++ ++#define DNS_HEADER_LEN 12 ++struct dns_header { ++ ovs_be16 id; ++ uint8_t lo_flag; /* QR (1), OPCODE (4), AA (1), TC (1) and RD (1) */ ++ uint8_t hi_flag; /* RA (1), Z (3) and RCODE (4) */ ++ ovs_be16 qdcount; /* Num of entries in the question section. */ ++ ovs_be16 ancount; /* Num of resource records in the answer section. */ ++ ++ /* Num of name server records in the authority record section. */ ++ ovs_be16 nscount; ++ ++ /* Num of resource records in the additional records section. */ ++ ovs_be16 arcount; ++}; ++ ++BUILD_ASSERT_DECL(DNS_HEADER_LEN == sizeof(struct dns_header)); ++ ++#define DNS_QUERY_TYPE_A 0x01 ++#define DNS_QUERY_TYPE_AAAA 0x1c ++#define DNS_QUERY_TYPE_ANY 0xff ++ ++#define DNS_CLASS_IN 0x01 ++#define DNS_DEFAULT_RR_TTL 3600 ++ ++#endif /* packets.h */ +Index: openvswitch-2.17.2/lib/pvector.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/pvector.h ++++ /dev/null +@@ -1,249 +0,0 @@ +-/* +- * Copyright (c) 2014, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef PVECTOR_H +-#define PVECTOR_H 1 +- +-#include +-#include +-#include -#include "ovs-rcu.h" -#include "util.h" +- +-/* Concurrent Priority Vector +- * ========================== +- * +- * Concurrent priority vector holds non-NULL pointers to objects in a +- * nondecreasing priority order and allows readers to traverse the vector +- * without being concerned about writers modifying the vector as they are +- * traversing it. +- * +- * Multiple elements of a given priority are allowed. +- * +- * The priority order is maintained as a linear vector of elements to allow +- * for efficient memory prefetching. +- * +- * Concurrency is implemented with OVS RCU so that the readers can assume +- * that once they have taken a pointer to the vector with +- * pvector_cursor_init(), the 'size' member will not decrease, so that +- * they can safely read 'size' entries from 'vector', and find that each +- * entry has a valid, non-NULL 'ptr', and the vector is in order from highest +- * to lowest 'priority'. The 'priority' values can change any time, but only +- * so that the order of the entries does not change, so readers can use +- * 'priority' values read at any time after acquisition of the vector pointer. +- * +- * Writers can concurrently add entries to the end of the vector, incrementing +- * 'size', or update the 'priority' value of an entry, but only if that does +- * not change the ordering of the entries. Writers will never change the 'ptr' +- * values, or decrement the 'size' on a copy that readers have access to. +- * +- * Most modifications are internally staged at the 'temp' vector, from which +- * they can be published at 'impl' by calling pvector_publish(). This saves +- * unnecessary memory allocations when many changes are done back-to-back. +- * 'temp' may contain NULL pointers and it may be in unsorted order. It is +- * sorted before it is published at 'impl', which also removes the NULLs from +- * the published vector. +- * +- * Since the vector is RCU protected, the entry destruction after removal must +- * be RCU postponed. Also, if it happens before changes published with +- * pvector_publish(), destruction must be double postponed, i.e., the second +- * ovsrcu_postpone() call to destruct the entry should be called from the first +- * RCU callback. This is required because readers could still obtain the +- * unmodified vector until updated version is published. +- */ +- +-struct pvector_entry { +- int priority; +- void *ptr; +-}; +- +-struct pvector_impl { +- atomic_size_t size; /* Number of entries in the vector. */ +- size_t allocated; /* Number of allocated entries. */ +- struct pvector_entry vector[]; +-}; +- +-/* Concurrent priority vector. */ +-struct pvector { +- OVSRCU_TYPE(struct pvector_impl *) impl; +- struct pvector_impl *temp; +-}; +- +-/* Initialization. */ +-void pvector_init(struct pvector *); +-void pvector_destroy(struct pvector *); +- +-/* Insertion and deletion. These work on 'temp'. */ +-void pvector_insert(struct pvector *, void *, int priority); +-void pvector_change_priority(struct pvector *, void *, int priority); +-void pvector_remove(struct pvector *, void *); +- +-/* Make the modified pvector available for iteration. */ +-static inline void pvector_publish(struct pvector *); +- +-/* Count. These operate on the published pvector. */ +-static inline size_t pvector_count(const struct pvector *); +-static inline bool pvector_is_empty(const struct pvector *); +- +-/* Iteration. +- * +- * +- * Thread-safety +- * ============= +- * +- * Iteration is safe even in a pvector that is changing concurrently. +- * Multiple writers must exclude each other via e.g., a mutex. +- * +- * Example +- * ======= +- * +- * struct my_node { +- * int data; +- * }; +- * +- * struct my_node elem1, elem2, *iter; +- * struct pvector my_pvector; +- * +- * pvector_init(&my_pvector); +- * ...add data... +- * pvector_insert(&my_pvector, &elem1, 1); +- * pvector_insert(&my_pvector, &elem2, 2); +- * ... +- * PVECTOR_FOR_EACH (iter, &my_pvector) { +- * ...operate on '*iter'... +- * ...elem2 to be seen before elem1... +- * } +- * ... +- * pvector_destroy(&my_pvector); +- * +- * There is no PVECTOR_FOR_EACH_SAFE variant as iteration is performed on RCU +- * protected instance of the priority vector. Any concurrent modifications +- * that would be disruptive for readers (such as deletions), will be performed +- * on a new instance. To see any of the modifications, a new iteration loop +- * has to be started. +- * +- * The PVECTOR_FOR_EACH_PRIORITY limits the iteration to entries with higher +- * than or equal to the given priority and allows for object lookahead. +- * +- * The iteration loop must be completed without entering the OVS RCU quiescent +- * period. That is, an old iteration loop must not be continued after any +- * blocking IO (VLOG is non-blocking, so that is OK). +- */ +-struct pvector_cursor { +- size_t size; /* Number of entries in the vector. */ +- size_t entry_idx; /* Current index. */ +- const struct pvector_entry *vector; +-}; +- +-static inline struct pvector_cursor pvector_cursor_init(const struct pvector *, +- size_t n_ahead, +- size_t obj_size); +-static inline void *pvector_cursor_next(struct pvector_cursor *, +- int lowest_priority, +- size_t n_ahead, size_t obj_size); +-static inline void pvector_cursor_lookahead(const struct pvector_cursor *, +- int n, size_t size); +- +-#define PVECTOR_FOR_EACH(PTR, PVECTOR) \ +- for (struct pvector_cursor cursor__ = pvector_cursor_init(PVECTOR, 0, 0); \ +- ((PTR) = pvector_cursor_next(&cursor__, INT_MIN, 0, 0)) != NULL; ) +- +-/* Loop while priority is higher than or equal to 'PRIORITY' and prefetch +- * objects of size 'SZ' 'N' objects ahead from the current object. */ +-#define PVECTOR_FOR_EACH_PRIORITY(PTR, PRIORITY, N, SZ, PVECTOR) \ +- for (struct pvector_cursor cursor__ = pvector_cursor_init(PVECTOR, N, SZ); \ +- ((PTR) = pvector_cursor_next(&cursor__, PRIORITY, N, SZ)) != NULL; ) +- +-#define PVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, PVECTOR) \ +- for (*(CURSOR) = pvector_cursor_init(PVECTOR, 0, 0); \ +- ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) +- +-#define PVECTOR_CURSOR_FOR_EACH_CONTINUE(PTR, CURSOR) \ +- for (; ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) +- +- +-/* Inline implementations. */ +- +-static inline struct pvector_cursor +-pvector_cursor_init(const struct pvector *pvec, +- size_t n_ahead, size_t obj_size) +-{ +- const struct pvector_impl *impl; +- struct pvector_cursor cursor; +- size_t size; +- +- impl = ovsrcu_get(struct pvector_impl *, &pvec->impl); +- +- /* Use memory_order_acquire to ensure entry access can not be +- * reordered to happen before size read. */ +- atomic_read_explicit(&CONST_CAST(struct pvector_impl *, impl)->size, +- &size, memory_order_acquire); +- ovs_prefetch_range(impl->vector, size * sizeof impl->vector[0]); +- +- cursor.size = size; +- cursor.vector = impl->vector; +- cursor.entry_idx = -1; +- +- for (size_t i = 0; i < n_ahead; i++) { +- /* Prefetch the first objects. */ +- pvector_cursor_lookahead(&cursor, i, obj_size); +- } +- return cursor; +-} +- +-static inline void *pvector_cursor_next(struct pvector_cursor *cursor, +- int lowest_priority, +- size_t n_ahead, size_t obj_size) +-{ +- if (++cursor->entry_idx < cursor->size && +- cursor->vector[cursor->entry_idx].priority >= lowest_priority) { +- if (n_ahead) { +- pvector_cursor_lookahead(cursor, n_ahead, obj_size); +- } +- return cursor->vector[cursor->entry_idx].ptr; +- } +- return NULL; +-} +- +-static inline void pvector_cursor_lookahead(const struct pvector_cursor *cursor, +- int n, size_t size) +-{ +- if (cursor->entry_idx + n < cursor->size) { +- ovs_prefetch_range(cursor->vector[cursor->entry_idx + n].ptr, size); +- } +-} +- +-static inline size_t pvector_count(const struct pvector *pvec) +-{ +- return ovsrcu_get(struct pvector_impl *, &pvec->impl)->size; +-} +- +-static inline bool pvector_is_empty(const struct pvector *pvec) +-{ +- return pvector_count(pvec) == 0; +-} +- +-void pvector_publish__(struct pvector *); +- +-/* Make the modified pvector available for iteration. */ +-static inline void pvector_publish(struct pvector *pvec) +-{ +- if (pvec->temp) { +- pvector_publish__(pvec); +- } +-} +- +-#endif /* pvector.h */ +Index: openvswitch-2.17.2/include/internal/pvector.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/pvector.h +@@ -0,0 +1,249 @@ ++/* ++ * Copyright (c) 2014, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef PVECTOR_H ++#define PVECTOR_H 1 ++ ++#include ++#include ++#include +#include "openvswitch/ovs-rcu.h" +#include "internal/util.h" - - /* Concurrent Priority Vector - * ========================== -diff --git a/lib/random.h b/include/internal/random.h -similarity index 100% -rename from lib/random.h -rename to include/internal/random.h -diff --git a/lib/rculist.h b/include/internal/rculist.h -similarity index 99% -rename from lib/rculist.h -rename to include/internal/rculist.h -index 1072b87af..850009fc2 100644 ---- a/lib/rculist.h -+++ b/include/internal/rculist.h -@@ -50,8 +50,8 @@ - - #include - #include ++ ++/* Concurrent Priority Vector ++ * ========================== ++ * ++ * Concurrent priority vector holds non-NULL pointers to objects in a ++ * nondecreasing priority order and allows readers to traverse the vector ++ * without being concerned about writers modifying the vector as they are ++ * traversing it. ++ * ++ * Multiple elements of a given priority are allowed. ++ * ++ * The priority order is maintained as a linear vector of elements to allow ++ * for efficient memory prefetching. ++ * ++ * Concurrency is implemented with OVS RCU so that the readers can assume ++ * that once they have taken a pointer to the vector with ++ * pvector_cursor_init(), the 'size' member will not decrease, so that ++ * they can safely read 'size' entries from 'vector', and find that each ++ * entry has a valid, non-NULL 'ptr', and the vector is in order from highest ++ * to lowest 'priority'. The 'priority' values can change any time, but only ++ * so that the order of the entries does not change, so readers can use ++ * 'priority' values read at any time after acquisition of the vector pointer. ++ * ++ * Writers can concurrently add entries to the end of the vector, incrementing ++ * 'size', or update the 'priority' value of an entry, but only if that does ++ * not change the ordering of the entries. Writers will never change the 'ptr' ++ * values, or decrement the 'size' on a copy that readers have access to. ++ * ++ * Most modifications are internally staged at the 'temp' vector, from which ++ * they can be published at 'impl' by calling pvector_publish(). This saves ++ * unnecessary memory allocations when many changes are done back-to-back. ++ * 'temp' may contain NULL pointers and it may be in unsorted order. It is ++ * sorted before it is published at 'impl', which also removes the NULLs from ++ * the published vector. ++ * ++ * Since the vector is RCU protected, the entry destruction after removal must ++ * be RCU postponed. Also, if it happens before changes published with ++ * pvector_publish(), destruction must be double postponed, i.e., the second ++ * ovsrcu_postpone() call to destruct the entry should be called from the first ++ * RCU callback. This is required because readers could still obtain the ++ * unmodified vector until updated version is published. ++ */ ++ ++struct pvector_entry { ++ int priority; ++ void *ptr; ++}; ++ ++struct pvector_impl { ++ atomic_size_t size; /* Number of entries in the vector. */ ++ size_t allocated; /* Number of allocated entries. */ ++ struct pvector_entry vector[]; ++}; ++ ++/* Concurrent priority vector. */ ++struct pvector { ++ OVSRCU_TYPE(struct pvector_impl *) impl; ++ struct pvector_impl *temp; ++}; ++ ++/* Initialization. */ ++void pvector_init(struct pvector *); ++void pvector_destroy(struct pvector *); ++ ++/* Insertion and deletion. These work on 'temp'. */ ++void pvector_insert(struct pvector *, void *, int priority); ++void pvector_change_priority(struct pvector *, void *, int priority); ++void pvector_remove(struct pvector *, void *); ++ ++/* Make the modified pvector available for iteration. */ ++static inline void pvector_publish(struct pvector *); ++ ++/* Count. These operate on the published pvector. */ ++static inline size_t pvector_count(const struct pvector *); ++static inline bool pvector_is_empty(const struct pvector *); ++ ++/* Iteration. ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * Iteration is safe even in a pvector that is changing concurrently. ++ * Multiple writers must exclude each other via e.g., a mutex. ++ * ++ * Example ++ * ======= ++ * ++ * struct my_node { ++ * int data; ++ * }; ++ * ++ * struct my_node elem1, elem2, *iter; ++ * struct pvector my_pvector; ++ * ++ * pvector_init(&my_pvector); ++ * ...add data... ++ * pvector_insert(&my_pvector, &elem1, 1); ++ * pvector_insert(&my_pvector, &elem2, 2); ++ * ... ++ * PVECTOR_FOR_EACH (iter, &my_pvector) { ++ * ...operate on '*iter'... ++ * ...elem2 to be seen before elem1... ++ * } ++ * ... ++ * pvector_destroy(&my_pvector); ++ * ++ * There is no PVECTOR_FOR_EACH_SAFE variant as iteration is performed on RCU ++ * protected instance of the priority vector. Any concurrent modifications ++ * that would be disruptive for readers (such as deletions), will be performed ++ * on a new instance. To see any of the modifications, a new iteration loop ++ * has to be started. ++ * ++ * The PVECTOR_FOR_EACH_PRIORITY limits the iteration to entries with higher ++ * than or equal to the given priority and allows for object lookahead. ++ * ++ * The iteration loop must be completed without entering the OVS RCU quiescent ++ * period. That is, an old iteration loop must not be continued after any ++ * blocking IO (VLOG is non-blocking, so that is OK). ++ */ ++struct pvector_cursor { ++ size_t size; /* Number of entries in the vector. */ ++ size_t entry_idx; /* Current index. */ ++ const struct pvector_entry *vector; ++}; ++ ++static inline struct pvector_cursor pvector_cursor_init(const struct pvector *, ++ size_t n_ahead, ++ size_t obj_size); ++static inline void *pvector_cursor_next(struct pvector_cursor *, ++ int lowest_priority, ++ size_t n_ahead, size_t obj_size); ++static inline void pvector_cursor_lookahead(const struct pvector_cursor *, ++ int n, size_t size); ++ ++#define PVECTOR_FOR_EACH(PTR, PVECTOR) \ ++ for (struct pvector_cursor cursor__ = pvector_cursor_init(PVECTOR, 0, 0); \ ++ ((PTR) = pvector_cursor_next(&cursor__, INT_MIN, 0, 0)) != NULL; ) ++ ++/* Loop while priority is higher than or equal to 'PRIORITY' and prefetch ++ * objects of size 'SZ' 'N' objects ahead from the current object. */ ++#define PVECTOR_FOR_EACH_PRIORITY(PTR, PRIORITY, N, SZ, PVECTOR) \ ++ for (struct pvector_cursor cursor__ = pvector_cursor_init(PVECTOR, N, SZ); \ ++ ((PTR) = pvector_cursor_next(&cursor__, PRIORITY, N, SZ)) != NULL; ) ++ ++#define PVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, PVECTOR) \ ++ for (*(CURSOR) = pvector_cursor_init(PVECTOR, 0, 0); \ ++ ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) ++ ++#define PVECTOR_CURSOR_FOR_EACH_CONTINUE(PTR, CURSOR) \ ++ for (; ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) ++ ++ ++/* Inline implementations. */ ++ ++static inline struct pvector_cursor ++pvector_cursor_init(const struct pvector *pvec, ++ size_t n_ahead, size_t obj_size) ++{ ++ const struct pvector_impl *impl; ++ struct pvector_cursor cursor; ++ size_t size; ++ ++ impl = ovsrcu_get(struct pvector_impl *, &pvec->impl); ++ ++ /* Use memory_order_acquire to ensure entry access can not be ++ * reordered to happen before size read. */ ++ atomic_read_explicit(&CONST_CAST(struct pvector_impl *, impl)->size, ++ &size, memory_order_acquire); ++ ovs_prefetch_range(impl->vector, size * sizeof impl->vector[0]); ++ ++ cursor.size = size; ++ cursor.vector = impl->vector; ++ cursor.entry_idx = -1; ++ ++ for (size_t i = 0; i < n_ahead; i++) { ++ /* Prefetch the first objects. */ ++ pvector_cursor_lookahead(&cursor, i, obj_size); ++ } ++ return cursor; ++} ++ ++static inline void *pvector_cursor_next(struct pvector_cursor *cursor, ++ int lowest_priority, ++ size_t n_ahead, size_t obj_size) ++{ ++ if (++cursor->entry_idx < cursor->size && ++ cursor->vector[cursor->entry_idx].priority >= lowest_priority) { ++ if (n_ahead) { ++ pvector_cursor_lookahead(cursor, n_ahead, obj_size); ++ } ++ return cursor->vector[cursor->entry_idx].ptr; ++ } ++ return NULL; ++} ++ ++static inline void pvector_cursor_lookahead(const struct pvector_cursor *cursor, ++ int n, size_t size) ++{ ++ if (cursor->entry_idx + n < cursor->size) { ++ ovs_prefetch_range(cursor->vector[cursor->entry_idx + n].ptr, size); ++ } ++} ++ ++static inline size_t pvector_count(const struct pvector *pvec) ++{ ++ return ovsrcu_get(struct pvector_impl *, &pvec->impl)->size; ++} ++ ++static inline bool pvector_is_empty(const struct pvector *pvec) ++{ ++ return pvector_count(pvec) == 0; ++} ++ ++void pvector_publish__(struct pvector *); ++ ++/* Make the modified pvector available for iteration. */ ++static inline void pvector_publish(struct pvector *pvec) ++{ ++ if (pvec->temp) { ++ pvector_publish__(pvec); ++ } ++} ++ ++#endif /* pvector.h */ +Index: openvswitch-2.17.2/lib/rculist.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/rculist.h ++++ /dev/null +@@ -1,421 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-#ifndef RCULIST_H +-#define RCULIST_H 1 +- +-/* A single writer multiple RCU-reader doubly linked list. +- * +- * RCU readers may iterate over the list at the same time as a writer is +- * modifying the list. Multiple writers can be supported by use of mutual +- * exclusion, but rculist does not provide that, as the user of rculist +- * typically does that already. +- * +- * To be RCU-friendly, the struct rculist instances must be freed via +- * ovsrcu_postpone(). +- * +- * The API is almost the same as for struct ovs_list, with the following +- * exceptions: +- * +- * - The 'prev' pointer may not be accessed by the user. +- * - The 'next' pointer should be accessed via rculist_next() by readers, and +- * rculist_next_protected() by the writer. +- * - No rculist_moved(): due to the memory management limitation stated above, +- * rculist instances may not be reallocated, as realloc may instantly free +- * the old memory. +- * - rculist_front() returns a const pointer to accommodate for an RCU reader. +- * - rculist_splice_hidden(): Spliced elements may not have been visible to +- * RCU readers before the operation. +- * - rculist_poison(): Only poisons the 'prev' pointer. +- * +- * The following functions are variations of the struct ovs_list functions with +- * similar names, but are now restricted to the writer use: +- * +- * - rculist_back_protected() +- * - rculist_is_short_protected() +- * - rculist_is_singleton_protected() +- */ +- +-#include +-#include -#include "ovs-rcu.h" -#include "util.h" +- +-/* A non-existing mutex to make it more difficult for an user to accidentally +- * keep using the 'prev' pointer. This may be helpful when porting code from +- * struct ovs_list to rculist. */ +-extern struct ovs_mutex rculist_fake_mutex; +- +-/* Doubly linked list head or element. */ +-struct rculist { +- /* Previous list element. */ +- struct rculist *prev OVS_GUARDED_BY(rculist_fake_mutex); +- +- /* Next list element. */ +- OVSRCU_TYPE(struct rculist *) next; +-}; +- +-/* Easier access to 'next' member. */ +-static inline const struct rculist *rculist_next(const struct rculist *); +-static inline struct rculist *rculist_next_protected(const struct rculist *); +- +-/* List initialization. */ +-#define RCUOVS_LIST_INITIALIZER(LIST) { LIST, OVSRCU_INITIALIZER(LIST) } +- +-static inline void rculist_init(struct rculist *list); +-static inline void rculist_poison(struct rculist *elem); +- +-/* List insertion. */ +-static inline void rculist_insert(struct rculist *list, struct rculist *elem); +-static inline void rculist_splice_hidden(struct rculist *before, +- struct rculist *first, +- struct rculist *last); +-static inline void rculist_push_front(struct rculist *list, +- struct rculist *elem); +-static inline void rculist_push_back(struct rculist *list, +- struct rculist *elem); +-static inline void rculist_replace(struct rculist *replacement, +- struct rculist *replaced); +-static inline void rculist_move(struct rculist *dst, struct rculist *src); +- +-/* List removal. */ +-static inline struct rculist *rculist_remove(struct rculist *elem); +-static inline struct rculist *rculist_pop_front(struct rculist *list); +-static inline struct rculist *rculist_pop_back(struct rculist *list); +- +-/* List elements. */ +-static inline const struct rculist *rculist_front(const struct rculist *); +-static inline struct rculist *rculist_back_protected(const struct rculist *); +- +-/* List properties. */ +-static inline size_t rculist_size(const struct rculist *); +-static inline bool rculist_is_empty(const struct rculist *); +-static inline bool rculist_is_singleton_protected(const struct rculist *); +-static inline bool rculist_is_short_protected(const struct rculist *); +- +- +-/* Inline implementations. */ +- +-static inline const struct rculist * +-rculist_next(const struct rculist *list) +-{ +- return ovsrcu_get(struct rculist *, &list->next); +-} +- +-static inline struct rculist * +-rculist_next_protected(const struct rculist *list) +- +-{ +- return ovsrcu_get_protected(struct rculist *, &list->next); +-} +- +-static inline void +-rculist_init(struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- list->prev = list; +- ovsrcu_init(&list->next, list); +-} +- +-#define RCULIST_POISON (struct rculist *)(UINTPTR_MAX / 0xf * 0xc) +- +-/* Initializes 'list' with pointers that will (probably) cause segfaults if +- * dereferenced and, better yet, show up clearly in a debugger. */ +-static inline void +-rculist_poison(struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- list->prev = RCULIST_POISON; +-} +- +-/* Initializes 'list' with pointers that will (probably) cause segfaults if +- * dereferenced and, better yet, show up clearly in a debugger. +- * +- * This variant poisons also the next pointer, so this may not be called if +- * this list element is still visible to RCU readers. */ +-static inline void +-rculist_poison__(struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- rculist_poison(list); +- ovsrcu_set_hidden(&list->next, RCULIST_POISON); +-} +- +-/* rculist insertion. */ +-static inline void +-rculist_insert(struct rculist *before, struct rculist *elem) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- elem->prev = before->prev; +- ovsrcu_set_hidden(&elem->next, before); +- ovsrcu_set(&before->prev->next, elem); +- before->prev = elem; +-} +- +-/* Removes elements 'first' though 'last' (exclusive) from their current list, +- * which may NOT be visible to any other threads (== be hidden from them), +- * then inserts them just before 'before'. */ +-static inline void +-rculist_splice_hidden(struct rculist *before, struct rculist *first, +- struct rculist *last) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- struct rculist *last_next; +- +- if (first == last) { +- return; +- } +- last = last->prev; +- +- /* Cleanly remove 'first'...'last' from its current list. */ +- last_next = rculist_next_protected(last); +- last_next->prev = first->prev; +- ovsrcu_set_hidden(&first->prev->next, last_next); +- +- /* Splice 'first'...'last' into new list. */ +- first->prev = before->prev; +- ovsrcu_set(&last->next, before); +- ovsrcu_set(&before->prev->next, first); +- before->prev = last; +-} +- +-/* Inserts 'elem' at the beginning of 'list', so that it becomes the front in +- * 'list'. */ +-static inline void +-rculist_push_front(struct rculist *list, struct rculist *elem) +-{ +- rculist_insert(rculist_next_protected(list), elem); +-} +- +-/* Inserts 'elem' at the end of 'list', so that it becomes the back in +- * 'list'. */ +-static inline void +-rculist_push_back(struct rculist *list, struct rculist *elem) +-{ +- rculist_insert(list, elem); +-} +- +-/* Puts 'element' in the position currently occupied by 'position'. +- * +- * Afterward, 'position' is not linked to from the list any more, but still +- * links to the nodes in the list, and may still be referenced by other threads +- * until all other threads quiesce. The replaced node ('position') may not be +- * re-inserted, re-initialized, or deleted until after all other threads have +- * quiesced (use ovsrcu_postpone). */ +-static inline void +-rculist_replace(struct rculist *element, struct rculist *position) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- struct rculist *position_next = rculist_next_protected(position); +- +- ovsrcu_set_hidden(&element->next, position_next); +- position_next->prev = element; +- element->prev = position->prev; +- ovsrcu_set(&element->prev->next, element); +- rculist_poison(position); +-} +- +-/* Initializes 'dst' with the contents of 'src', compensating for moving it +- * around in memory. The effect is that, if 'src' was the head of a list, now +- * 'dst' is the head of a list containing the same elements. +- * +- * Memory for 'src' must be kept around until the next RCU quiescent period. +- * rculist cannot be simply reallocated, so there is no rculist_moved(). */ +-static inline void +-rculist_move(struct rculist *dst, struct rculist *src) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- if (!rculist_is_empty(src)) { +- struct rculist *src_next = rculist_next_protected(src); +- +- dst->prev = src->prev; +- ovsrcu_set_hidden(&dst->next, src_next); +- +- src_next->prev = dst; +- ovsrcu_set(&src->prev->next, dst); +- } else { +- rculist_init(dst); +- } +- rculist_poison(src); +-} +- +-/* Removes 'elem' from its list and returns the element that followed it. +- * Has no effect when 'elem' is initialized, but not in a list. +- * Undefined behavior if 'elem' is not initialized. +- * +- * Afterward, 'elem' is not linked to from the list any more, but still links +- * to the nodes in the list, and may still be referenced by other threads until +- * all other threads quiesce. The removed node ('elem') may not be +- * re-inserted, re-initialized, or deleted until after all other threads have +- * quiesced (use ovsrcu_postpone). +- */ +-static inline struct rculist * +-rculist_remove(struct rculist *elem) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- struct rculist *elem_next = rculist_next_protected(elem); +- +- elem_next->prev = elem->prev; +- ovsrcu_set(&elem->prev->next, elem_next); +- rculist_poison(elem); +- return elem_next; +-} +- +-/* Removes the front element from 'list' and returns it. Undefined behavior if +- * 'list' is empty before removal. +- * +- * Afterward, teh returned former first node is not linked to from the list any +- * more, but still links to the nodes in the list, and may still be referenced +- * by other threads until all other threads quiesce. The returned node may not +- * be re-inserted, re-initialized, or deleted until after all other threads +- * have quiesced (use ovsrcu_postpone). */ +-static inline struct rculist * +-rculist_pop_front(struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- struct rculist *front = rculist_next_protected(list); +- rculist_remove(front); +- return front; +-} +- +-/* Removes the back element from 'list' and returns it. +- * Undefined behavior if 'list' is empty before removal. +- * +- * Afterward, teh returned former last node is not linked to from the list any +- * more, but still links to the nodes in the list, and may still be referenced +- * by other threads until all other threads quiesce. The returned node may not +- * be re-inserted, re-initialized, or deleted until after all other threads +- * have quiesced (use ovsrcu_postpone). */ +-static inline struct rculist * +-rculist_pop_back(struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- struct rculist *back = list->prev; +- rculist_remove(back); +- return back; +-} +- +-/* Returns the front element in 'list_'. +- * Undefined behavior if 'list_' is empty. */ +-static inline const struct rculist * +-rculist_front(const struct rculist *list) +-{ +- ovs_assert(!rculist_is_empty(list)); +- +- return rculist_next(list); +-} +- +-/* Returns the back element in 'list_'. +- * Returns the 'list_' itself, if 'list_' is empty. */ +-static inline struct rculist * +-rculist_back_protected(const struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- return CONST_CAST(struct rculist *, list)->prev; +-} +- +-/* Returns the number of elements in 'list'. +- * Runs in O(n) in the number of elements. */ +-static inline size_t +-rculist_size(const struct rculist *list) +-{ +- const struct rculist *e; +- size_t cnt = 0; +- +- for (e = rculist_next(list); e != list; e = rculist_next(e)) { +- cnt++; +- } +- return cnt; +-} +- +-/* Returns true if 'list' is empty, false otherwise. */ +-static inline bool +-rculist_is_empty(const struct rculist *list) +-{ +- return rculist_next(list) == list; +-} +- +-/* Returns true if 'list' has 0 or 1 elements, false otherwise. */ +-static inline bool +-rculist_is_short_protected(const struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- return rculist_next_protected(list) == list->prev; +-} +- +-/* Returns true if 'list' has exactly 1 element, false otherwise. */ +-static inline bool +-rculist_is_singleton_protected(const struct rculist *list) +- OVS_NO_THREAD_SAFETY_ANALYSIS +-{ +- const struct rculist *list_next = rculist_next_protected(list); +- +- return list_next == list->prev && list_next != list; +-} +- +-#define RCULIST_FOR_EACH(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(RCULIST), \ +- const struct rculist); \ +- CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ +- UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) +- +-#define RCULIST_FOR_EACH_CONTINUE(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(&(ITER)->MEMBER), \ +- const struct rculist); \ +- CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ +- UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) +- +-#define RCULIST_FOR_EACH_REVERSE_PROTECTED(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR(ITER, MEMBER, (RCULIST)->prev, struct rculist); \ +- CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ +- UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev)) +- +-#define RCULIST_FOR_EACH_REVERSE_PROTECTED_CONTINUE(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR(ITER, MEMBER, (ITER)->MEMBER.prev, struct rculist); \ +- CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ +- UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev)) +- +-#define RCULIST_FOR_EACH_PROTECTED(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR(ITER, MEMBER, rculist_next_protected(RCULIST), \ +- struct rculist); \ +- CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ +- UPDATE_MULTIVAR(ITER, rculist_next_protected(ITER_VAR(ITER))) \ +- +-#define RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED(ITER, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ +- rculist_next_protected(RCULIST), \ +- struct rculist); \ +- CONDITION_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ +- ITER_VAR(ITER) != (RCULIST), \ +- ITER_NEXT_VAR(ITER) = rculist_next_protected(ITER_VAR(VAR))); \ +- UPDATE_MULTIVAR_SHORT(ITER)) +- +-#define RCULIST_FOR_EACH_SAFE_LONG_PROTECTED(ITER, NEXT, MEMBER, RCULIST) \ +- for (INIT_MULTIVAR_SAFE_LONG(ITER, NEXT, MEMBER, \ +- rculist_next_protected(RCULIST) \ +- struct rculist); \ +- CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT, MEMBER \ +- ITER_VAR(ITER) != (RCULIST), \ +- ITER_VAR(NEXT) = rculist_next_protected(ITER_VAR(VAR)), \ +- ITER_VAR(NEXT) != (RCULIST)); \ +- UPDATE_MULTIVAR_LONG(ITER)) +- +-#define RCULIST_FOR_EACH_SAFE_PROTECTED(...) \ +- OVERLOAD_SAFE_MACRO(RCULIST_FOR_EACH_SAFE_LONG_PROTECTED, \ +- RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED, \ +- 4, __VA_ARGS__) +- +- +-#endif /* rculist.h */ +Index: openvswitch-2.17.2/include/internal/rculist.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/rculist.h +@@ -0,0 +1,421 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#ifndef RCULIST_H ++#define RCULIST_H 1 ++ ++/* A single writer multiple RCU-reader doubly linked list. ++ * ++ * RCU readers may iterate over the list at the same time as a writer is ++ * modifying the list. Multiple writers can be supported by use of mutual ++ * exclusion, but rculist does not provide that, as the user of rculist ++ * typically does that already. ++ * ++ * To be RCU-friendly, the struct rculist instances must be freed via ++ * ovsrcu_postpone(). ++ * ++ * The API is almost the same as for struct ovs_list, with the following ++ * exceptions: ++ * ++ * - The 'prev' pointer may not be accessed by the user. ++ * - The 'next' pointer should be accessed via rculist_next() by readers, and ++ * rculist_next_protected() by the writer. ++ * - No rculist_moved(): due to the memory management limitation stated above, ++ * rculist instances may not be reallocated, as realloc may instantly free ++ * the old memory. ++ * - rculist_front() returns a const pointer to accommodate for an RCU reader. ++ * - rculist_splice_hidden(): Spliced elements may not have been visible to ++ * RCU readers before the operation. ++ * - rculist_poison(): Only poisons the 'prev' pointer. ++ * ++ * The following functions are variations of the struct ovs_list functions with ++ * similar names, but are now restricted to the writer use: ++ * ++ * - rculist_back_protected() ++ * - rculist_is_short_protected() ++ * - rculist_is_singleton_protected() ++ */ ++ ++#include ++#include +#include "openvswitch/ovs-rcu.h" +#include "internal/util.h" - - /* A non-existing mutex to make it more difficult for an user to accidentally - * keep using the 'prev' pointer. This may be helpful when porting code from -diff --git a/lib/seq.h b/include/internal/seq.h -similarity index 99% -rename from lib/seq.h -rename to include/internal/seq.h -index c88b9d1c8..cc0898669 100644 ---- a/lib/seq.h -+++ b/include/internal/seq.h -@@ -115,7 +115,7 @@ - */ - - #include ++ ++/* A non-existing mutex to make it more difficult for an user to accidentally ++ * keep using the 'prev' pointer. This may be helpful when porting code from ++ * struct ovs_list to rculist. */ ++extern struct ovs_mutex rculist_fake_mutex; ++ ++/* Doubly linked list head or element. */ ++struct rculist { ++ /* Previous list element. */ ++ struct rculist *prev OVS_GUARDED_BY(rculist_fake_mutex); ++ ++ /* Next list element. */ ++ OVSRCU_TYPE(struct rculist *) next; ++}; ++ ++/* Easier access to 'next' member. */ ++static inline const struct rculist *rculist_next(const struct rculist *); ++static inline struct rculist *rculist_next_protected(const struct rculist *); ++ ++/* List initialization. */ ++#define RCUOVS_LIST_INITIALIZER(LIST) { LIST, OVSRCU_INITIALIZER(LIST) } ++ ++static inline void rculist_init(struct rculist *list); ++static inline void rculist_poison(struct rculist *elem); ++ ++/* List insertion. */ ++static inline void rculist_insert(struct rculist *list, struct rculist *elem); ++static inline void rculist_splice_hidden(struct rculist *before, ++ struct rculist *first, ++ struct rculist *last); ++static inline void rculist_push_front(struct rculist *list, ++ struct rculist *elem); ++static inline void rculist_push_back(struct rculist *list, ++ struct rculist *elem); ++static inline void rculist_replace(struct rculist *replacement, ++ struct rculist *replaced); ++static inline void rculist_move(struct rculist *dst, struct rculist *src); ++ ++/* List removal. */ ++static inline struct rculist *rculist_remove(struct rculist *elem); ++static inline struct rculist *rculist_pop_front(struct rculist *list); ++static inline struct rculist *rculist_pop_back(struct rculist *list); ++ ++/* List elements. */ ++static inline const struct rculist *rculist_front(const struct rculist *); ++static inline struct rculist *rculist_back_protected(const struct rculist *); ++ ++/* List properties. */ ++static inline size_t rculist_size(const struct rculist *); ++static inline bool rculist_is_empty(const struct rculist *); ++static inline bool rculist_is_singleton_protected(const struct rculist *); ++static inline bool rculist_is_short_protected(const struct rculist *); ++ ++ ++/* Inline implementations. */ ++ ++static inline const struct rculist * ++rculist_next(const struct rculist *list) ++{ ++ return ovsrcu_get(struct rculist *, &list->next); ++} ++ ++static inline struct rculist * ++rculist_next_protected(const struct rculist *list) ++ ++{ ++ return ovsrcu_get_protected(struct rculist *, &list->next); ++} ++ ++static inline void ++rculist_init(struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ list->prev = list; ++ ovsrcu_init(&list->next, list); ++} ++ ++#define RCULIST_POISON (struct rculist *)(UINTPTR_MAX / 0xf * 0xc) ++ ++/* Initializes 'list' with pointers that will (probably) cause segfaults if ++ * dereferenced and, better yet, show up clearly in a debugger. */ ++static inline void ++rculist_poison(struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ list->prev = RCULIST_POISON; ++} ++ ++/* Initializes 'list' with pointers that will (probably) cause segfaults if ++ * dereferenced and, better yet, show up clearly in a debugger. ++ * ++ * This variant poisons also the next pointer, so this may not be called if ++ * this list element is still visible to RCU readers. */ ++static inline void ++rculist_poison__(struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ rculist_poison(list); ++ ovsrcu_set_hidden(&list->next, RCULIST_POISON); ++} ++ ++/* rculist insertion. */ ++static inline void ++rculist_insert(struct rculist *before, struct rculist *elem) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ elem->prev = before->prev; ++ ovsrcu_set_hidden(&elem->next, before); ++ ovsrcu_set(&before->prev->next, elem); ++ before->prev = elem; ++} ++ ++/* Removes elements 'first' though 'last' (exclusive) from their current list, ++ * which may NOT be visible to any other threads (== be hidden from them), ++ * then inserts them just before 'before'. */ ++static inline void ++rculist_splice_hidden(struct rculist *before, struct rculist *first, ++ struct rculist *last) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ struct rculist *last_next; ++ ++ if (first == last) { ++ return; ++ } ++ last = last->prev; ++ ++ /* Cleanly remove 'first'...'last' from its current list. */ ++ last_next = rculist_next_protected(last); ++ last_next->prev = first->prev; ++ ovsrcu_set_hidden(&first->prev->next, last_next); ++ ++ /* Splice 'first'...'last' into new list. */ ++ first->prev = before->prev; ++ ovsrcu_set(&last->next, before); ++ ovsrcu_set(&before->prev->next, first); ++ before->prev = last; ++} ++ ++/* Inserts 'elem' at the beginning of 'list', so that it becomes the front in ++ * 'list'. */ ++static inline void ++rculist_push_front(struct rculist *list, struct rculist *elem) ++{ ++ rculist_insert(rculist_next_protected(list), elem); ++} ++ ++/* Inserts 'elem' at the end of 'list', so that it becomes the back in ++ * 'list'. */ ++static inline void ++rculist_push_back(struct rculist *list, struct rculist *elem) ++{ ++ rculist_insert(list, elem); ++} ++ ++/* Puts 'element' in the position currently occupied by 'position'. ++ * ++ * Afterward, 'position' is not linked to from the list any more, but still ++ * links to the nodes in the list, and may still be referenced by other threads ++ * until all other threads quiesce. The replaced node ('position') may not be ++ * re-inserted, re-initialized, or deleted until after all other threads have ++ * quiesced (use ovsrcu_postpone). */ ++static inline void ++rculist_replace(struct rculist *element, struct rculist *position) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ struct rculist *position_next = rculist_next_protected(position); ++ ++ ovsrcu_set_hidden(&element->next, position_next); ++ position_next->prev = element; ++ element->prev = position->prev; ++ ovsrcu_set(&element->prev->next, element); ++ rculist_poison(position); ++} ++ ++/* Initializes 'dst' with the contents of 'src', compensating for moving it ++ * around in memory. The effect is that, if 'src' was the head of a list, now ++ * 'dst' is the head of a list containing the same elements. ++ * ++ * Memory for 'src' must be kept around until the next RCU quiescent period. ++ * rculist cannot be simply reallocated, so there is no rculist_moved(). */ ++static inline void ++rculist_move(struct rculist *dst, struct rculist *src) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ if (!rculist_is_empty(src)) { ++ struct rculist *src_next = rculist_next_protected(src); ++ ++ dst->prev = src->prev; ++ ovsrcu_set_hidden(&dst->next, src_next); ++ ++ src_next->prev = dst; ++ ovsrcu_set(&src->prev->next, dst); ++ } else { ++ rculist_init(dst); ++ } ++ rculist_poison(src); ++} ++ ++/* Removes 'elem' from its list and returns the element that followed it. ++ * Has no effect when 'elem' is initialized, but not in a list. ++ * Undefined behavior if 'elem' is not initialized. ++ * ++ * Afterward, 'elem' is not linked to from the list any more, but still links ++ * to the nodes in the list, and may still be referenced by other threads until ++ * all other threads quiesce. The removed node ('elem') may not be ++ * re-inserted, re-initialized, or deleted until after all other threads have ++ * quiesced (use ovsrcu_postpone). ++ */ ++static inline struct rculist * ++rculist_remove(struct rculist *elem) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ struct rculist *elem_next = rculist_next_protected(elem); ++ ++ elem_next->prev = elem->prev; ++ ovsrcu_set(&elem->prev->next, elem_next); ++ rculist_poison(elem); ++ return elem_next; ++} ++ ++/* Removes the front element from 'list' and returns it. Undefined behavior if ++ * 'list' is empty before removal. ++ * ++ * Afterward, teh returned former first node is not linked to from the list any ++ * more, but still links to the nodes in the list, and may still be referenced ++ * by other threads until all other threads quiesce. The returned node may not ++ * be re-inserted, re-initialized, or deleted until after all other threads ++ * have quiesced (use ovsrcu_postpone). */ ++static inline struct rculist * ++rculist_pop_front(struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ struct rculist *front = rculist_next_protected(list); ++ rculist_remove(front); ++ return front; ++} ++ ++/* Removes the back element from 'list' and returns it. ++ * Undefined behavior if 'list' is empty before removal. ++ * ++ * Afterward, teh returned former last node is not linked to from the list any ++ * more, but still links to the nodes in the list, and may still be referenced ++ * by other threads until all other threads quiesce. The returned node may not ++ * be re-inserted, re-initialized, or deleted until after all other threads ++ * have quiesced (use ovsrcu_postpone). */ ++static inline struct rculist * ++rculist_pop_back(struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ struct rculist *back = list->prev; ++ rculist_remove(back); ++ return back; ++} ++ ++/* Returns the front element in 'list_'. ++ * Undefined behavior if 'list_' is empty. */ ++static inline const struct rculist * ++rculist_front(const struct rculist *list) ++{ ++ ovs_assert(!rculist_is_empty(list)); ++ ++ return rculist_next(list); ++} ++ ++/* Returns the back element in 'list_'. ++ * Returns the 'list_' itself, if 'list_' is empty. */ ++static inline struct rculist * ++rculist_back_protected(const struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ return CONST_CAST(struct rculist *, list)->prev; ++} ++ ++/* Returns the number of elements in 'list'. ++ * Runs in O(n) in the number of elements. */ ++static inline size_t ++rculist_size(const struct rculist *list) ++{ ++ const struct rculist *e; ++ size_t cnt = 0; ++ ++ for (e = rculist_next(list); e != list; e = rculist_next(e)) { ++ cnt++; ++ } ++ return cnt; ++} ++ ++/* Returns true if 'list' is empty, false otherwise. */ ++static inline bool ++rculist_is_empty(const struct rculist *list) ++{ ++ return rculist_next(list) == list; ++} ++ ++/* Returns true if 'list' has 0 or 1 elements, false otherwise. */ ++static inline bool ++rculist_is_short_protected(const struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ return rculist_next_protected(list) == list->prev; ++} ++ ++/* Returns true if 'list' has exactly 1 element, false otherwise. */ ++static inline bool ++rculist_is_singleton_protected(const struct rculist *list) ++ OVS_NO_THREAD_SAFETY_ANALYSIS ++{ ++ const struct rculist *list_next = rculist_next_protected(list); ++ ++ return list_next == list->prev && list_next != list; ++} ++ ++#define RCULIST_FOR_EACH(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(RCULIST), \ ++ const struct rculist); \ ++ CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ ++ UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) ++ ++#define RCULIST_FOR_EACH_CONTINUE(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(&(ITER)->MEMBER), \ ++ const struct rculist); \ ++ CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ ++ UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) ++ ++#define RCULIST_FOR_EACH_REVERSE_PROTECTED(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR(ITER, MEMBER, (RCULIST)->prev, struct rculist); \ ++ CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ ++ UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev)) ++ ++#define RCULIST_FOR_EACH_REVERSE_PROTECTED_CONTINUE(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR(ITER, MEMBER, (ITER)->MEMBER.prev, struct rculist); \ ++ CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ ++ UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev)) ++ ++#define RCULIST_FOR_EACH_PROTECTED(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR(ITER, MEMBER, rculist_next_protected(RCULIST), \ ++ struct rculist); \ ++ CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ ++ UPDATE_MULTIVAR(ITER, rculist_next_protected(ITER_VAR(ITER))) \ ++ ++#define RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED(ITER, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ ++ rculist_next_protected(RCULIST), \ ++ struct rculist); \ ++ CONDITION_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ ++ ITER_VAR(ITER) != (RCULIST), \ ++ ITER_NEXT_VAR(ITER) = rculist_next_protected(ITER_VAR(VAR))); \ ++ UPDATE_MULTIVAR_SHORT(ITER)) ++ ++#define RCULIST_FOR_EACH_SAFE_LONG_PROTECTED(ITER, NEXT, MEMBER, RCULIST) \ ++ for (INIT_MULTIVAR_SAFE_LONG(ITER, NEXT, MEMBER, \ ++ rculist_next_protected(RCULIST) \ ++ struct rculist); \ ++ CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT, MEMBER \ ++ ITER_VAR(ITER) != (RCULIST), \ ++ ITER_VAR(NEXT) = rculist_next_protected(ITER_VAR(VAR)), \ ++ ITER_VAR(NEXT) != (RCULIST)); \ ++ UPDATE_MULTIVAR_LONG(ITER)) ++ ++#define RCULIST_FOR_EACH_SAFE_PROTECTED(...) \ ++ OVERLOAD_SAFE_MACRO(RCULIST_FOR_EACH_SAFE_LONG_PROTECTED, \ ++ RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED, \ ++ 4, __VA_ARGS__) ++ ++ ++#endif /* rculist.h */ +Index: openvswitch-2.17.2/lib/seq.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/seq.h ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SEQ_H +-#define SEQ_H 1 +- +-/* Thread-safe, pollable sequence number. +- * +- * +- * Motivation +- * ========== +- * +- * It is sometimes desirable to take an action whenever an object changes. +- * Suppose we associate a sequence number with an object and increment the +- * sequence number whenver we change the object. An observer can then record +- * the sequence number it sees. Later on, if the current sequence number +- * differs from the one it saw last, then the observer knows to examine the +- * object for changes. +- * +- * Code that wants to run when a sequence number changes is challenging to +- * implement in a multithreaded environment. A naive implementation, that +- * simply checks whether the sequence number changed and, if so, calls +- * poll_immediate_wake(), will fail when another thread increments the sequence +- * number after the check (including during poll_block()). +- * +- * struct seq is a solution. It implements a sequence number along with enough +- * internal infrastructure so that a thread waiting on a particular value will +- * wake up if the sequence number changes, or even if the "struct seq" is +- * destroyed. +- * +- * +- * Usage +- * ===== +- * +- * The object that includes a sequence number should use seq_create() and +- * seq_destroy() at creation and destruction, and seq_change() whenever the +- * object's observable state changes. +- * +- * An observer may seq_read() to read the current sequence number and +- * seq_wait() to cause poll_block() to wake up when the sequence number changes +- * from a specified value. +- * +- * To avoid races, observers should use seq_read() to check for changes, +- * process any changes, and then use seq_wait() to wait for a change from the +- * previously read value. That is, a correct usage looks something like this: +- * +- * new_seq = seq_read(seq); +- * if (new_seq != last_seq) { +- * ...process changes... +- * last_seq = new_seq; +- * } +- * seq_wait(seq, new_seq); +- * poll_block(); +- * +- * +- * Alternate Usage +- * =============== +- * +- * struct seq can also be used as a sort of pollable condition variable. +- * Suppose that we want a thread to process items in a queue, and thus to be +- * able to wake up whenever the queue is nonempty. This requires a lock to +- * protect the queue and a seq to signal that the queue has become nonempty, +- * e.g.: +- * +- * struct ovs_mutex mutex; +- * struct ovs_list queue OVS_GUARDED_BY(mutex); +- * struct seq *nonempty_seq; +- * +- * To add an element to the queue: +- * +- * ovs_mutex_lock(&mutex); +- * ovs_list_push_back(&queue, ...element...); +- * if (ovs_list_is_singleton(&queue)) { <-- The 'if' here is optional. +- * seq_change(nonempty_seq); +- * } +- * ovs_mutex_unlock(&mutex); +- * +- * To wait for the queue to become nonempty: +- * +- * ovs_mutex_lock(&mutex); +- * if (ovs_list_is_empty(&queue)) { +- * seq_wait(nonempty_seq, seq_read(nonempty_seq)); +- * } else { +- * poll_immediate_wake(); +- * } +- * ovs_mutex_unlock(&mutex); +- * +- * (In the above code 'mutex' prevents the queue from changing between +- * seq_read() and seq_wait(). Otherwise, it would be necessary to seq_read(), +- * check for a nonempty queue, and then seq_wait() on the previously read +- * sequence number, as under Usage above.) +- * +- * +- * Thread-safety +- * ============= +- * +- * Fully thread safe. seq_change() synchronizes with seq_read() and +- * seq_wait() on the same variable in release-acquire fashion. That +- * is, all effects of the memory accesses performed by a thread prior +- * to seq_change() are visible to the threads returning from +- * seq_read() or seq_wait() observing that change. +- */ +- +-#include -#include "util.h" +- +-/* For implementation of an object with a sequence number attached. */ +-struct seq *seq_create(void); +-void seq_destroy(struct seq *); +-void seq_change(struct seq *); +-void seq_change_protected(struct seq *); +-void seq_lock(void); +-int seq_try_lock(void); +-void seq_unlock(void); +- +-/* For observers. */ +-uint64_t seq_read(const struct seq *); +-uint64_t seq_read_protected(const struct seq *); +- +-void seq_wait_at(const struct seq *, uint64_t value, const char *where); +-#define seq_wait(seq, value) seq_wait_at(seq, value, OVS_SOURCE_LOCATOR) +- +-/* For poll_block() internal use. */ +-void seq_woke(void); +- +-#endif /* seq.h */ +Index: openvswitch-2.17.2/include/internal/seq.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/seq.h +@@ -0,0 +1,139 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SEQ_H ++#define SEQ_H 1 ++ ++/* Thread-safe, pollable sequence number. ++ * ++ * ++ * Motivation ++ * ========== ++ * ++ * It is sometimes desirable to take an action whenever an object changes. ++ * Suppose we associate a sequence number with an object and increment the ++ * sequence number whenver we change the object. An observer can then record ++ * the sequence number it sees. Later on, if the current sequence number ++ * differs from the one it saw last, then the observer knows to examine the ++ * object for changes. ++ * ++ * Code that wants to run when a sequence number changes is challenging to ++ * implement in a multithreaded environment. A naive implementation, that ++ * simply checks whether the sequence number changed and, if so, calls ++ * poll_immediate_wake(), will fail when another thread increments the sequence ++ * number after the check (including during poll_block()). ++ * ++ * struct seq is a solution. It implements a sequence number along with enough ++ * internal infrastructure so that a thread waiting on a particular value will ++ * wake up if the sequence number changes, or even if the "struct seq" is ++ * destroyed. ++ * ++ * ++ * Usage ++ * ===== ++ * ++ * The object that includes a sequence number should use seq_create() and ++ * seq_destroy() at creation and destruction, and seq_change() whenever the ++ * object's observable state changes. ++ * ++ * An observer may seq_read() to read the current sequence number and ++ * seq_wait() to cause poll_block() to wake up when the sequence number changes ++ * from a specified value. ++ * ++ * To avoid races, observers should use seq_read() to check for changes, ++ * process any changes, and then use seq_wait() to wait for a change from the ++ * previously read value. That is, a correct usage looks something like this: ++ * ++ * new_seq = seq_read(seq); ++ * if (new_seq != last_seq) { ++ * ...process changes... ++ * last_seq = new_seq; ++ * } ++ * seq_wait(seq, new_seq); ++ * poll_block(); ++ * ++ * ++ * Alternate Usage ++ * =============== ++ * ++ * struct seq can also be used as a sort of pollable condition variable. ++ * Suppose that we want a thread to process items in a queue, and thus to be ++ * able to wake up whenever the queue is nonempty. This requires a lock to ++ * protect the queue and a seq to signal that the queue has become nonempty, ++ * e.g.: ++ * ++ * struct ovs_mutex mutex; ++ * struct ovs_list queue OVS_GUARDED_BY(mutex); ++ * struct seq *nonempty_seq; ++ * ++ * To add an element to the queue: ++ * ++ * ovs_mutex_lock(&mutex); ++ * ovs_list_push_back(&queue, ...element...); ++ * if (ovs_list_is_singleton(&queue)) { <-- The 'if' here is optional. ++ * seq_change(nonempty_seq); ++ * } ++ * ovs_mutex_unlock(&mutex); ++ * ++ * To wait for the queue to become nonempty: ++ * ++ * ovs_mutex_lock(&mutex); ++ * if (ovs_list_is_empty(&queue)) { ++ * seq_wait(nonempty_seq, seq_read(nonempty_seq)); ++ * } else { ++ * poll_immediate_wake(); ++ * } ++ * ovs_mutex_unlock(&mutex); ++ * ++ * (In the above code 'mutex' prevents the queue from changing between ++ * seq_read() and seq_wait(). Otherwise, it would be necessary to seq_read(), ++ * check for a nonempty queue, and then seq_wait() on the previously read ++ * sequence number, as under Usage above.) ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * Fully thread safe. seq_change() synchronizes with seq_read() and ++ * seq_wait() on the same variable in release-acquire fashion. That ++ * is, all effects of the memory accesses performed by a thread prior ++ * to seq_change() are visible to the threads returning from ++ * seq_read() or seq_wait() observing that change. ++ */ ++ ++#include +#include "internal/util.h" - - /* For implementation of an object with a sequence number attached. */ - struct seq *seq_create(void); -diff --git a/lib/simap.h b/include/internal/simap.h -similarity index 100% -rename from lib/simap.h -rename to include/internal/simap.h -diff --git a/lib/skiplist.h b/include/internal/skiplist.h -similarity index 100% -rename from lib/skiplist.h -rename to include/internal/skiplist.h -diff --git a/lib/smap.h b/include/internal/smap.h -similarity index 99% -rename from lib/smap.h -rename to include/internal/smap.h -index a92115966..ce974e775 100644 ---- a/lib/smap.h -+++ b/include/internal/smap.h -@@ -17,7 +17,7 @@ - - #include - #include ++ ++/* For implementation of an object with a sequence number attached. */ ++struct seq *seq_create(void); ++void seq_destroy(struct seq *); ++void seq_change(struct seq *); ++void seq_change_protected(struct seq *); ++void seq_lock(void); ++int seq_try_lock(void); ++void seq_unlock(void); ++ ++/* For observers. */ ++uint64_t seq_read(const struct seq *); ++uint64_t seq_read_protected(const struct seq *); ++ ++void seq_wait_at(const struct seq *, uint64_t value, const char *where); ++#define seq_wait(seq, value) seq_wait_at(seq, value, OVS_SOURCE_LOCATOR) ++ ++/* For poll_block() internal use. */ ++void seq_woke(void); ++ ++#endif /* seq.h */ +Index: openvswitch-2.17.2/lib/smap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/smap.h ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* Copyright (c) 2012, 2014, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. */ +- +-#ifndef SMAP_H +-#define SMAP_H 1 +- +-#include +-#include -#include "hash.h" +-#include "openvswitch/hmap.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct json; +-struct uuid; +- +-/* A map from string to string. */ +-struct smap { +- struct hmap map; /* Contains "struct smap_node"s. */ +-}; +- +-struct smap_node { +- struct hmap_node node; /* In struct smap's 'map' hmap. */ +- char *key; +- char *value; +-}; +- +-#define SMAP_INITIALIZER(SMAP) { HMAP_INITIALIZER(&(SMAP)->map) } +- +-#define SMAP_FOR_EACH(SMAP_NODE, SMAP) \ +- HMAP_FOR_EACH_INIT (SMAP_NODE, node, &(SMAP)->map, \ +- BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ +- BUILD_ASSERT_TYPE(SMAP, struct smap *)) +- +-#define SMAP_FOR_EACH_SAFE_SHORT(SMAP_NODE, SMAP) \ +- HMAP_FOR_EACH_SAFE_SHORT_INIT ( \ +- SMAP_NODE, node, &(SMAP)->map, \ +- BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ +- BUILD_ASSERT_TYPE(SMAP, struct smap *)) +- +-#define SMAP_FOR_EACH_SAFE_LONG(SMAP_NODE, NEXT, SMAP) \ +- HMAP_FOR_EACH_SAFE_LONG_INIT ( \ +- SMAP_NODE, NEXT, node, &(SMAP)->map, \ +- BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ +- BUILD_ASSERT_TYPE(NEXT, struct smap_node *), \ +- BUILD_ASSERT_TYPE(SMAP, struct smap *)) +- +-#define SMAP_FOR_EACH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(SMAP_FOR_EACH_SAFE_LONG, \ +- SMAP_FOR_EACH_SAFE_SHORT, \ +- 3, __VA_ARGS__) +- +-/* Initializer for an immutable struct smap 'SMAP' that contains one or two +- * key-value pairs, e.g. +- * +- * const struct smap smap1 = SMAP_CONST1(&smap, "key", "value"); +- * const struct smap smap2 = SMAP_CONST2(&smap, "key1", "value1", +- * "key2", "value2"); +- * +- * An smap initialized this way must not be modified or destroyed. +- * +- * The 'KEY', 'K1', 'K2' arguments are evaluated multiple times. +- */ +-#define SMAP_CONST1(SMAP, KEY, VALUE) (const struct smap) { \ +- HMAP_CONST(&(SMAP)->map, 1, SMAP_NODE(KEY, VALUE, NULL)) \ +- } +-#define SMAP_CONST2(SMAP, K1, V1, K2, V2) (const struct smap) { \ +- HMAP_CONST(&(SMAP)->map, 2, \ +- SMAP_NODE(K1, V1, SMAP_NODE(K2, V2, NULL))) \ +- } +-#define SMAP_NODE(KEY, VALUE, NEXT) \ +- &(struct smap_node) { \ +- .node = { \ +- .hash = hash_string(KEY, 0), \ +- .next = (NEXT), \ +- }, \ +- .key = CONST_CAST(char *, KEY), \ +- .value = CONST_CAST(char *, VALUE), \ +- }.node +- +- +-void smap_init(struct smap *); +-void smap_destroy(struct smap *); +- +-struct smap_node *smap_add(struct smap *, const char *, const char *); +-struct smap_node *smap_add_nocopy(struct smap *, char *, char *); +-bool smap_add_once(struct smap *, const char *, const char *); +-void smap_add_format(struct smap *, const char *key, const char *, ...) +- OVS_PRINTF_FORMAT(3, 4); +-void smap_add_ipv6(struct smap *, const char *, struct in6_addr *); +-void smap_replace(struct smap *, const char *, const char *); +-void smap_replace_nocopy(struct smap *, const char *, char *); +- +-void smap_remove(struct smap *, const char *); +-void smap_remove_node(struct smap *, struct smap_node *); +-void smap_steal(struct smap *, struct smap_node *, char **keyp, char **valuep); +-void smap_clear(struct smap *); +- +-const char *smap_get(const struct smap *, const char *key); +-const char *smap_get_def(const struct smap *, const char *key, +- const char *def); +-struct smap_node *smap_get_node(const struct smap *, const char *); +-bool smap_get_bool(const struct smap *smap, const char *key, bool def); +-int smap_get_int(const struct smap *smap, const char *key, int def); +-unsigned int smap_get_uint(const struct smap *smap, const char *key, +- unsigned int def); +-unsigned long long int smap_get_ullong(const struct smap *, const char *key, +- unsigned long long def); +-bool smap_get_uuid(const struct smap *, const char *key, struct uuid *); +- +-bool smap_is_empty(const struct smap *); +-size_t smap_count(const struct smap *); +- +-void smap_clone(struct smap *dst, const struct smap *src); +-const struct smap_node **smap_sort(const struct smap *); +- +-void smap_from_json(struct smap *, const struct json *); +-struct json *smap_to_json(const struct smap *); +- +-bool smap_equal(const struct smap *, const struct smap *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* smap.h */ +Index: openvswitch-2.17.2/include/internal/smap.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/smap.h +@@ -0,0 +1,139 @@ ++/* Copyright (c) 2012, 2014, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. */ ++ ++#ifndef SMAP_H ++#define SMAP_H 1 ++ ++#include ++#include +#include "internal/hash.h" - #include "openvswitch/hmap.h" - - #ifdef __cplusplus -diff --git a/lib/socket-util.h b/include/internal/socket-util.h -similarity index 100% -rename from lib/socket-util.h -rename to include/internal/socket-util.h -diff --git a/lib/sort.h b/include/internal/sort.h -similarity index 100% -rename from lib/sort.h -rename to include/internal/sort.h -diff --git a/lib/sset.h b/include/internal/sset.h -similarity index 99% -rename from lib/sset.h -rename to include/internal/sset.h -index f0bb8b534..be8627ed8 100644 ---- a/lib/sset.h -+++ b/include/internal/sset.h -@@ -18,7 +18,7 @@ - #define SSET_H - - #include "openvswitch/hmap.h" ++#include "openvswitch/hmap.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct json; ++struct uuid; ++ ++/* A map from string to string. */ ++struct smap { ++ struct hmap map; /* Contains "struct smap_node"s. */ ++}; ++ ++struct smap_node { ++ struct hmap_node node; /* In struct smap's 'map' hmap. */ ++ char *key; ++ char *value; ++}; ++ ++#define SMAP_INITIALIZER(SMAP) { HMAP_INITIALIZER(&(SMAP)->map) } ++ ++#define SMAP_FOR_EACH(SMAP_NODE, SMAP) \ ++ HMAP_FOR_EACH_INIT (SMAP_NODE, node, &(SMAP)->map, \ ++ BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ ++ BUILD_ASSERT_TYPE(SMAP, struct smap *)) ++ ++#define SMAP_FOR_EACH_SAFE_SHORT(SMAP_NODE, SMAP) \ ++ HMAP_FOR_EACH_SAFE_SHORT_INIT ( \ ++ SMAP_NODE, node, &(SMAP)->map, \ ++ BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ ++ BUILD_ASSERT_TYPE(SMAP, struct smap *)) ++ ++#define SMAP_FOR_EACH_SAFE_LONG(SMAP_NODE, NEXT, SMAP) \ ++ HMAP_FOR_EACH_SAFE_LONG_INIT ( \ ++ SMAP_NODE, NEXT, node, &(SMAP)->map, \ ++ BUILD_ASSERT_TYPE(SMAP_NODE, struct smap_node *), \ ++ BUILD_ASSERT_TYPE(NEXT, struct smap_node *), \ ++ BUILD_ASSERT_TYPE(SMAP, struct smap *)) ++ ++#define SMAP_FOR_EACH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(SMAP_FOR_EACH_SAFE_LONG, \ ++ SMAP_FOR_EACH_SAFE_SHORT, \ ++ 3, __VA_ARGS__) ++ ++/* Initializer for an immutable struct smap 'SMAP' that contains one or two ++ * key-value pairs, e.g. ++ * ++ * const struct smap smap1 = SMAP_CONST1(&smap, "key", "value"); ++ * const struct smap smap2 = SMAP_CONST2(&smap, "key1", "value1", ++ * "key2", "value2"); ++ * ++ * An smap initialized this way must not be modified or destroyed. ++ * ++ * The 'KEY', 'K1', 'K2' arguments are evaluated multiple times. ++ */ ++#define SMAP_CONST1(SMAP, KEY, VALUE) (const struct smap) { \ ++ HMAP_CONST(&(SMAP)->map, 1, SMAP_NODE(KEY, VALUE, NULL)) \ ++ } ++#define SMAP_CONST2(SMAP, K1, V1, K2, V2) (const struct smap) { \ ++ HMAP_CONST(&(SMAP)->map, 2, \ ++ SMAP_NODE(K1, V1, SMAP_NODE(K2, V2, NULL))) \ ++ } ++#define SMAP_NODE(KEY, VALUE, NEXT) \ ++ &(struct smap_node) { \ ++ .node = { \ ++ .hash = hash_string(KEY, 0), \ ++ .next = (NEXT), \ ++ }, \ ++ .key = CONST_CAST(char *, KEY), \ ++ .value = CONST_CAST(char *, VALUE), \ ++ }.node ++ ++ ++void smap_init(struct smap *); ++void smap_destroy(struct smap *); ++ ++struct smap_node *smap_add(struct smap *, const char *, const char *); ++struct smap_node *smap_add_nocopy(struct smap *, char *, char *); ++bool smap_add_once(struct smap *, const char *, const char *); ++void smap_add_format(struct smap *, const char *key, const char *, ...) ++ OVS_PRINTF_FORMAT(3, 4); ++void smap_add_ipv6(struct smap *, const char *, struct in6_addr *); ++void smap_replace(struct smap *, const char *, const char *); ++void smap_replace_nocopy(struct smap *, const char *, char *); ++ ++void smap_remove(struct smap *, const char *); ++void smap_remove_node(struct smap *, struct smap_node *); ++void smap_steal(struct smap *, struct smap_node *, char **keyp, char **valuep); ++void smap_clear(struct smap *); ++ ++const char *smap_get(const struct smap *, const char *key); ++const char *smap_get_def(const struct smap *, const char *key, ++ const char *def); ++struct smap_node *smap_get_node(const struct smap *, const char *); ++bool smap_get_bool(const struct smap *smap, const char *key, bool def); ++int smap_get_int(const struct smap *smap, const char *key, int def); ++unsigned int smap_get_uint(const struct smap *smap, const char *key, ++ unsigned int def); ++unsigned long long int smap_get_ullong(const struct smap *, const char *key, ++ unsigned long long def); ++bool smap_get_uuid(const struct smap *, const char *key, struct uuid *); ++ ++bool smap_is_empty(const struct smap *); ++size_t smap_count(const struct smap *); ++ ++void smap_clone(struct smap *dst, const struct smap *src); ++const struct smap_node **smap_sort(const struct smap *); ++ ++void smap_from_json(struct smap *, const struct json *); ++struct json *smap_to_json(const struct smap *); ++ ++bool smap_equal(const struct smap *, const struct smap *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* smap.h */ +Index: openvswitch-2.17.2/lib/sset.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/sset.h ++++ /dev/null +@@ -1,134 +0,0 @@ +-/* +- * Copyright (c) 2011, 2012, 2013, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SSET_H +-#define SSET_H +- +-#include "openvswitch/hmap.h" -#include "util.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct sset_node { +- struct hmap_node hmap_node; +- char name[1]; +-}; +- +-/* A set of strings. */ +-struct sset { +- struct hmap map; +-}; +- +-#define SSET_INITIALIZER(SSET) { HMAP_INITIALIZER(&(SSET)->map) } +- +-/* Basics. */ +-void sset_init(struct sset *); +-void sset_destroy(struct sset *); +-void sset_clone(struct sset *, const struct sset *); +-void sset_swap(struct sset *, struct sset *); +-void sset_moved(struct sset *); +- +-/* String parsing and formatting. */ +-void sset_from_delimited_string(struct sset *, const char *s, +- const char *delimiters); +-char *sset_join(const struct sset *, +- const char *delimiter, const char *terminator); +- +-/* Count. */ +-bool sset_is_empty(const struct sset *); +-size_t sset_count(const struct sset *); +- +-/* Insertion. */ +-struct sset_node *sset_add(struct sset *, const char *); +-struct sset_node *sset_add_and_free(struct sset *, char *); +-void sset_add_assert(struct sset *, const char *); +-void sset_add_array(struct sset *, char **, size_t n); +- +-/* Deletion. */ +-void sset_clear(struct sset *); +-void sset_delete(struct sset *, struct sset_node *); +-bool sset_find_and_delete(struct sset *, const char *); +-void sset_find_and_delete_assert(struct sset *, const char *); +-char *sset_pop(struct sset *); +- +-/* Search. */ +-struct sset_node *sset_find(const struct sset *, const char *); +-bool sset_contains(const struct sset *, const char *); +-bool sset_equals(const struct sset *, const struct sset *); +- +-struct sset_position { +- struct hmap_position pos; +-}; +- +-struct sset_node *sset_at_position(const struct sset *, +- struct sset_position *); +- +-/* Set operations. */ +-void sset_intersect(struct sset *, const struct sset *); +- +-/* Iteration macros. */ +-#define SSET_FOR_EACH(NAME, SSET) \ +- for ((NAME) = SSET_FIRST(SSET); \ +- NAME != NULL; \ +- (NAME) = SSET_NEXT(SSET, NAME)) +- +-#define SSET_FOR_EACH_SAFE_LONG(NAME, NEXT, SSET) \ +- for ((NAME) = SSET_FIRST(SSET); \ +- (NAME != NULL \ +- ? (NEXT) = SSET_NEXT(SSET, NAME), true \ +- : false); \ +- (NAME) = (NEXT)) +- +-#define SSET_FOR_EACH_SAFE_SHORT(NAME, SSET) \ +- for (const char * NAME__next = \ +- ((NAME) = SSET_FIRST(SSET), NULL); \ +- (NAME != NULL \ +- ? (NAME__next = SSET_NEXT(SSET, NAME), true) \ +- : (NAME__next = NULL, false)); \ +- (NAME) = NAME__next) +- +-#define SSET_FOR_EACH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(SSET_FOR_EACH_SAFE_LONG, \ +- SSET_FOR_EACH_SAFE_SHORT, \ +- 3, __VA_ARGS__) +- +-const char **sset_array(const struct sset *); +-const char **sset_sort(const struct sset *); +- +-/* Implementation helper macros. */ +- +-#define SSET_NODE_FROM_HMAP_NODE(HMAP_NODE) \ +- CONTAINER_OF(HMAP_NODE, struct sset_node, hmap_node) +-#define SSET_NAME_FROM_HMAP_NODE(HMAP_NODE) \ +- HMAP_NODE == NULL \ +- ? NULL \ +- : (CONST_CAST(const char *, (SSET_NODE_FROM_HMAP_NODE(HMAP_NODE)->name))) +-#define SSET_NODE_FROM_NAME(NAME) CONTAINER_OF(NAME, struct sset_node, name) +-#define SSET_FIRST(SSET) \ +- (BUILD_ASSERT_TYPE(SSET, struct sset *), \ +- SSET_NAME_FROM_HMAP_NODE(hmap_first(&(SSET)->map))) +-#define SSET_NEXT(SSET, NAME) \ +- (BUILD_ASSERT_TYPE(SSET, struct sset *), \ +- SSET_NAME_FROM_HMAP_NODE( \ +- hmap_next(&(SSET)->map, &SSET_NODE_FROM_NAME(NAME)->hmap_node))) +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* sset.h */ +Index: openvswitch-2.17.2/include/internal/sset.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/sset.h +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (c) 2011, 2012, 2013, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SSET_H ++#define SSET_H ++ ++#include "openvswitch/hmap.h" +#include "internal/util.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/stopwatch.h b/include/internal/stopwatch.h -similarity index 100% -rename from lib/stopwatch.h -rename to include/internal/stopwatch.h -diff --git a/lib/stream-ssl.h b/include/internal/stream-ssl.h -similarity index 100% -rename from lib/stream-ssl.h -rename to include/internal/stream-ssl.h -diff --git a/lib/stream.h b/include/internal/stream.h -similarity index 98% -rename from lib/stream.h -rename to include/internal/stream.h -index e30c51275..0f3f531d1 100644 ---- a/lib/stream.h -+++ b/include/internal/stream.h -@@ -22,8 +22,8 @@ - #include - #include - #include "openvswitch/types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct sset_node { ++ struct hmap_node hmap_node; ++ char name[1]; ++}; ++ ++/* A set of strings. */ ++struct sset { ++ struct hmap map; ++}; ++ ++#define SSET_INITIALIZER(SSET) { HMAP_INITIALIZER(&(SSET)->map) } ++ ++/* Basics. */ ++void sset_init(struct sset *); ++void sset_destroy(struct sset *); ++void sset_clone(struct sset *, const struct sset *); ++void sset_swap(struct sset *, struct sset *); ++void sset_moved(struct sset *); ++ ++/* String parsing and formatting. */ ++void sset_from_delimited_string(struct sset *, const char *s, ++ const char *delimiters); ++char *sset_join(const struct sset *, ++ const char *delimiter, const char *terminator); ++ ++/* Count. */ ++bool sset_is_empty(const struct sset *); ++size_t sset_count(const struct sset *); ++ ++/* Insertion. */ ++struct sset_node *sset_add(struct sset *, const char *); ++struct sset_node *sset_add_and_free(struct sset *, char *); ++void sset_add_assert(struct sset *, const char *); ++void sset_add_array(struct sset *, char **, size_t n); ++ ++/* Deletion. */ ++void sset_clear(struct sset *); ++void sset_delete(struct sset *, struct sset_node *); ++bool sset_find_and_delete(struct sset *, const char *); ++void sset_find_and_delete_assert(struct sset *, const char *); ++char *sset_pop(struct sset *); ++ ++/* Search. */ ++struct sset_node *sset_find(const struct sset *, const char *); ++bool sset_contains(const struct sset *, const char *); ++bool sset_equals(const struct sset *, const struct sset *); ++ ++struct sset_position { ++ struct hmap_position pos; ++}; ++ ++struct sset_node *sset_at_position(const struct sset *, ++ struct sset_position *); ++ ++/* Set operations. */ ++void sset_intersect(struct sset *, const struct sset *); ++ ++/* Iteration macros. */ ++#define SSET_FOR_EACH(NAME, SSET) \ ++ for ((NAME) = SSET_FIRST(SSET); \ ++ NAME != NULL; \ ++ (NAME) = SSET_NEXT(SSET, NAME)) ++ ++#define SSET_FOR_EACH_SAFE_LONG(NAME, NEXT, SSET) \ ++ for ((NAME) = SSET_FIRST(SSET); \ ++ (NAME != NULL \ ++ ? (NEXT) = SSET_NEXT(SSET, NAME), true \ ++ : false); \ ++ (NAME) = (NEXT)) ++ ++#define SSET_FOR_EACH_SAFE_SHORT(NAME, SSET) \ ++ for (const char * NAME__next = \ ++ ((NAME) = SSET_FIRST(SSET), NULL); \ ++ (NAME != NULL \ ++ ? (NAME__next = SSET_NEXT(SSET, NAME), true) \ ++ : (NAME__next = NULL, false)); \ ++ (NAME) = NAME__next) ++ ++#define SSET_FOR_EACH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(SSET_FOR_EACH_SAFE_LONG, \ ++ SSET_FOR_EACH_SAFE_SHORT, \ ++ 3, __VA_ARGS__) ++ ++const char **sset_array(const struct sset *); ++const char **sset_sort(const struct sset *); ++ ++/* Implementation helper macros. */ ++ ++#define SSET_NODE_FROM_HMAP_NODE(HMAP_NODE) \ ++ CONTAINER_OF(HMAP_NODE, struct sset_node, hmap_node) ++#define SSET_NAME_FROM_HMAP_NODE(HMAP_NODE) \ ++ HMAP_NODE == NULL \ ++ ? NULL \ ++ : (CONST_CAST(const char *, (SSET_NODE_FROM_HMAP_NODE(HMAP_NODE)->name))) ++#define SSET_NODE_FROM_NAME(NAME) CONTAINER_OF(NAME, struct sset_node, name) ++#define SSET_FIRST(SSET) \ ++ (BUILD_ASSERT_TYPE(SSET, struct sset *), \ ++ SSET_NAME_FROM_HMAP_NODE(hmap_first(&(SSET)->map))) ++#define SSET_NEXT(SSET, NAME) \ ++ (BUILD_ASSERT_TYPE(SSET, struct sset *), \ ++ SSET_NAME_FROM_HMAP_NODE( \ ++ hmap_next(&(SSET)->map, &SSET_NODE_FROM_NAME(NAME)->hmap_node))) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* sset.h */ +Index: openvswitch-2.17.2/lib/stream.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream.h ++++ /dev/null +@@ -1,109 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2011, 2013, 2015 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef STREAM_H +-#define STREAM_H 1 +- +-#include +-#include +-#include +-#include +-#include "openvswitch/types.h" -#include "socket-util.h" -#include "util.h" +- +-struct pstream; +-struct stream; +-struct vlog_module; +- +-void stream_usage(const char *name, bool active, bool passive, bool bootstrap); +- +-/* Bidirectional byte streams. */ +-int stream_verify_name(const char *name); +-int stream_open(const char *name, struct stream **, uint8_t dscp); +-int stream_open_block(int error, long long int timeout, struct stream **); +-void stream_close(struct stream *); +-const char *stream_get_name(const struct stream *); +-int stream_connect(struct stream *); +-int stream_recv(struct stream *, void *buffer, size_t n); +-int stream_send(struct stream *, const void *buffer, size_t n); +- +-void stream_run(struct stream *); +-void stream_run_wait(struct stream *); +- +-enum stream_wait_type { +- STREAM_CONNECT, +- STREAM_RECV, +- STREAM_SEND +-}; +-void stream_wait(struct stream *, enum stream_wait_type); +-void stream_connect_wait(struct stream *); +-void stream_recv_wait(struct stream *); +-void stream_send_wait(struct stream *); +-void stream_set_peer_id(struct stream *, const char *); +-const char *stream_get_peer_id(const struct stream *); +- +-/* Passive streams: listeners for incoming stream connections. */ +-int pstream_verify_name(const char *name); +-int pstream_open(const char *name, struct pstream **, uint8_t dscp); +-const char *pstream_get_name(const struct pstream *); +-void pstream_close(struct pstream *); +-int pstream_accept(struct pstream *, struct stream **); +-int pstream_accept_block(struct pstream *, struct stream **); +-void pstream_wait(struct pstream *); +- +-ovs_be16 pstream_get_bound_port(const struct pstream *); +- +-/* Convenience functions. */ +- +-int stream_open_with_default_port(const char *name, +- uint16_t default_port, +- struct stream **, +- uint8_t dscp); +-int pstream_open_with_default_port(const char *name, +- uint16_t default_port, +- struct pstream **, +- uint8_t dscp); +-bool stream_parse_target_with_default_port(const char *target, +- int default_port, +- struct sockaddr_storage *ss); +-int stream_or_pstream_needs_probes(const char *name); +- +-/* Error reporting. */ +- +-enum stream_content_type { +- STREAM_UNKNOWN, +- STREAM_OPENFLOW, +- STREAM_SSL, +- STREAM_JSONRPC +-}; +- +-void stream_report_content(const void *, ssize_t, enum stream_content_type, +- struct vlog_module *, const char *stream_name); +- +- +-/* Stream replay helpers. */ +-void stream_replay_open_wfd(struct stream *, int open_result, +- const char *name); +-void pstream_replay_open_wfd(struct pstream *, int listen_result, +- const char *name); +-void stream_replay_close_wfd(struct stream *); +-void pstream_replay_close_wfd(struct pstream *); +-void stream_replay_write(struct stream *, const void *, int, bool is_read); +-void pstream_replay_write_accept(struct pstream *, const struct stream *, +- int accept_result); +- +-#endif /* stream.h */ +Index: openvswitch-2.17.2/include/internal/stream.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/stream.h +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2009, 2010, 2011, 2013, 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef STREAM_H ++#define STREAM_H 1 ++ ++#include ++#include ++#include ++#include ++#include "openvswitch/types.h" +#include "internal/socket-util.h" +#include "internal/util.h" - - struct pstream; - struct stream; -diff --git a/lib/svec.h b/include/internal/svec.h -similarity index 100% -rename from lib/svec.h -rename to include/internal/svec.h -diff --git a/lib/table.h b/include/internal/table.h -similarity index 100% -rename from lib/table.h -rename to include/internal/table.h -diff --git a/lib/timer.h b/include/internal/timer.h -similarity index 96% -rename from lib/timer.h -rename to include/internal/timer.h -index 6b35d1763..e6f1a5a83 100644 ---- a/lib/timer.h -+++ b/include/internal/timer.h -@@ -19,8 +19,8 @@ - - #include - ++ ++struct pstream; ++struct stream; ++struct vlog_module; ++ ++void stream_usage(const char *name, bool active, bool passive, bool bootstrap); ++ ++/* Bidirectional byte streams. */ ++int stream_verify_name(const char *name); ++int stream_open(const char *name, struct stream **, uint8_t dscp); ++int stream_open_block(int error, long long int timeout, struct stream **); ++void stream_close(struct stream *); ++const char *stream_get_name(const struct stream *); ++int stream_connect(struct stream *); ++int stream_recv(struct stream *, void *buffer, size_t n); ++int stream_send(struct stream *, const void *buffer, size_t n); ++ ++void stream_run(struct stream *); ++void stream_run_wait(struct stream *); ++ ++enum stream_wait_type { ++ STREAM_CONNECT, ++ STREAM_RECV, ++ STREAM_SEND ++}; ++void stream_wait(struct stream *, enum stream_wait_type); ++void stream_connect_wait(struct stream *); ++void stream_recv_wait(struct stream *); ++void stream_send_wait(struct stream *); ++void stream_set_peer_id(struct stream *, const char *); ++const char *stream_get_peer_id(const struct stream *); ++ ++/* Passive streams: listeners for incoming stream connections. */ ++int pstream_verify_name(const char *name); ++int pstream_open(const char *name, struct pstream **, uint8_t dscp); ++const char *pstream_get_name(const struct pstream *); ++void pstream_close(struct pstream *); ++int pstream_accept(struct pstream *, struct stream **); ++int pstream_accept_block(struct pstream *, struct stream **); ++void pstream_wait(struct pstream *); ++ ++ovs_be16 pstream_get_bound_port(const struct pstream *); ++ ++/* Convenience functions. */ ++ ++int stream_open_with_default_port(const char *name, ++ uint16_t default_port, ++ struct stream **, ++ uint8_t dscp); ++int pstream_open_with_default_port(const char *name, ++ uint16_t default_port, ++ struct pstream **, ++ uint8_t dscp); ++bool stream_parse_target_with_default_port(const char *target, ++ int default_port, ++ struct sockaddr_storage *ss); ++int stream_or_pstream_needs_probes(const char *name); ++ ++/* Error reporting. */ ++ ++enum stream_content_type { ++ STREAM_UNKNOWN, ++ STREAM_OPENFLOW, ++ STREAM_SSL, ++ STREAM_JSONRPC ++}; ++ ++void stream_report_content(const void *, ssize_t, enum stream_content_type, ++ struct vlog_module *, const char *stream_name); ++ ++ ++/* Stream replay helpers. */ ++void stream_replay_open_wfd(struct stream *, int open_result, ++ const char *name); ++void pstream_replay_open_wfd(struct pstream *, int listen_result, ++ const char *name); ++void stream_replay_close_wfd(struct stream *); ++void pstream_replay_close_wfd(struct pstream *); ++void stream_replay_write(struct stream *, const void *, int, bool is_read); ++void pstream_replay_write_accept(struct pstream *, const struct stream *, ++ int accept_result); ++ ++#endif /* stream.h */ +Index: openvswitch-2.17.2/lib/timer.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/timer.h ++++ /dev/null +@@ -1,74 +0,0 @@ +-/* +- * Copyright (c) 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef TIMER_H +-#define TIMER_H 1 +- +-#include +- -#include "timeval.h" -#include "util.h" +- +-struct timer { +- long long int t; +-}; +- +-long long int timer_msecs_until_expired(const struct timer *); +-void timer_wait_at(const struct timer *, const char *where); +-#define timer_wait(timer) timer_wait_at(timer, OVS_SOURCE_LOCATOR) +- +-/* Causes 'timer' to expire when 'duration' milliseconds have passed. +- * +- * May be used to initialize 'timer'. */ +-static inline void +-timer_set_duration(struct timer *timer, long long int duration) +-{ +- timer->t = time_msec() + duration; +-} +- +-/* Causes 'timer' never to expire. +- * +- * May be used to initialize 'timer'. */ +-static inline void +-timer_set_infinite(struct timer *timer) +-{ +- timer->t = LLONG_MAX; +-} +- +-/* Causes 'timer' to expire immediately. +- * +- * May be used to initialize 'timer'. */ +-static inline void +-timer_set_expired(struct timer *timer) +-{ +- timer->t = LLONG_MIN; +-} +- +-/* True if 'timer' has expired. */ +-static inline bool +-timer_expired(const struct timer *timer) +-{ +- return time_msec() >= timer->t; +-} +- +-/* Returns ture if 'timer' will never expire. */ +-static inline bool +-timer_is_infinite(const struct timer *timer) +-{ +- return timer->t == LLONG_MAX; +-} +- +-#endif /* timer.h */ +Index: openvswitch-2.17.2/include/internal/timer.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/timer.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef TIMER_H ++#define TIMER_H 1 ++ ++#include ++ +#include "internal/timeval.h" +#include "internal/util.h" - - struct timer { - long long int t; -diff --git a/lib/timeval.h b/include/internal/timeval.h -similarity index 98% -rename from lib/timeval.h -rename to include/internal/timeval.h -index 502f703d4..32a1c8128 100644 ---- a/lib/timeval.h -+++ b/include/internal/timeval.h -@@ -19,7 +19,7 @@ - - #include - #include "openvswitch/type-props.h" ++ ++struct timer { ++ long long int t; ++}; ++ ++long long int timer_msecs_until_expired(const struct timer *); ++void timer_wait_at(const struct timer *, const char *where); ++#define timer_wait(timer) timer_wait_at(timer, OVS_SOURCE_LOCATOR) ++ ++/* Causes 'timer' to expire when 'duration' milliseconds have passed. ++ * ++ * May be used to initialize 'timer'. */ ++static inline void ++timer_set_duration(struct timer *timer, long long int duration) ++{ ++ timer->t = time_msec() + duration; ++} ++ ++/* Causes 'timer' never to expire. ++ * ++ * May be used to initialize 'timer'. */ ++static inline void ++timer_set_infinite(struct timer *timer) ++{ ++ timer->t = LLONG_MAX; ++} ++ ++/* Causes 'timer' to expire immediately. ++ * ++ * May be used to initialize 'timer'. */ ++static inline void ++timer_set_expired(struct timer *timer) ++{ ++ timer->t = LLONG_MIN; ++} ++ ++/* True if 'timer' has expired. */ ++static inline bool ++timer_expired(const struct timer *timer) ++{ ++ return time_msec() >= timer->t; ++} ++ ++/* Returns ture if 'timer' will never expire. */ ++static inline bool ++timer_is_infinite(const struct timer *timer) ++{ ++ return timer->t == LLONG_MAX; ++} ++ ++#endif /* timer.h */ +Index: openvswitch-2.17.2/lib/timeval.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/timeval.h ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* +- * 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef TIMEVAL_H +-#define TIMEVAL_H 1 +- +-#include +-#include "openvswitch/type-props.h" -#include "util.h" -+#include "internal/util.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/tun-metadata.h b/include/internal/tun-metadata-private.h -similarity index 99% -rename from lib/tun-metadata.h -rename to include/internal/tun-metadata-private.h -index 67dedae25..032748eac 100644 ---- a/lib/tun-metadata.h -+++ b/include/internal/tun-metadata-private.h -@@ -20,7 +20,7 @@ - #include - - #include "openvswitch/dynamic-string.h" --#include "netlink.h" -+#include "internal/netlink.h" - #include "openvswitch/ofpbuf.h" - #include "openflow/openflow.h" - #include "openvswitch/tun-metadata.h" -diff --git a/lib/unaligned.h b/include/internal/unaligned.h -similarity index 99% -rename from lib/unaligned.h -rename to include/internal/unaligned.h -index f40e4e10d..839733b64 100644 ---- a/lib/unaligned.h -+++ b/include/internal/unaligned.h -@@ -18,10 +18,10 @@ - #define UNALIGNED_H 1 - - #include --#include "byte-order.h" -+#include "internal/byte-order.h" - #include "openvswitch/types.h" - #include "openvswitch/type-props.h" --#include "util.h" -+#include "internal/util.h" - - /* Public API. */ - static inline uint16_t get_unaligned_u16(const uint16_t *); -diff --git a/lib/unixctl.h b/include/internal/unixctl.h -similarity index 100% -rename from lib/unixctl.h -rename to include/internal/unixctl.h -diff --git a/include/internal/util.h b/include/internal/util.h -new file mode 100644 -index 000000000..4f40319c4 +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct ds; +-struct pollfd; +-struct timespec; +-struct timeval; +- +-/* POSIX allows floating-point time_t, but we don't support it. */ +-BUILD_ASSERT_DECL(TYPE_IS_INTEGER(time_t)); +- +-/* We do try to cater to unsigned time_t, but I want to know about it if we +- * ever encounter such a platform. */ +-BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t)); +- +-#define TIME_MAX TYPE_MAXIMUM(time_t) +-#define TIME_MIN TYPE_MINIMUM(time_t) +- +-#ifdef _WIN32 +-#define localtime_r(timep, result) localtime_s(result, timep) +-#define gmtime_r(timep, result) gmtime_s(result, timep) +-#endif /* _WIN32 */ +- +-struct tm_msec { +- struct tm tm; +- int msec; +-}; +- +-time_t time_now(void); +-time_t time_wall(void); +-long long int time_msec(void); +-long long int time_wall_msec(void); +-long long int time_usec(void); +-long long int time_wall_usec(void); +-void time_timespec(struct timespec *); +-void time_wall_timespec(struct timespec *); +-void time_alarm(unsigned int secs); +-int time_poll(struct pollfd *, int n_pollfds, HANDLE *handles, +- long long int timeout_when, int *elapsed); +- +-long long int timespec_to_msec(const struct timespec *); +-long long int timespec_to_usec(const struct timespec *); +-long long int timeval_to_msec(const struct timeval *); +-long long int timeval_to_usec(const struct timeval *); +- +-struct tm_msec *localtime_msec(long long int now, struct tm_msec *result); +-struct tm_msec *gmtime_msec(long long int now, struct tm_msec *result); +-size_t strftime_msec(char *s, size_t max, const char *format, +- const struct tm_msec *); +-void xgettimeofday(struct timeval *); +-void xclock_gettime(clock_t, struct timespec *); +-void nsec_to_timespec(long long int, struct timespec *); +- +-int get_cpu_usage(void); +- +-long long int time_boot_msec(void); +- +-void timewarp_run(void); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* timeval.h */ +Index: openvswitch-2.17.2/include/internal/timeval.h +=================================================================== --- /dev/null -+++ b/include/internal/util.h ++++ openvswitch-2.17.2/include/internal/timeval.h +@@ -0,0 +1,88 @@ ++/* ++ * 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef TIMEVAL_H ++#define TIMEVAL_H 1 ++ ++#include ++#include "openvswitch/type-props.h" ++#include "internal/util.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct ds; ++struct pollfd; ++struct timespec; ++struct timeval; ++ ++/* POSIX allows floating-point time_t, but we don't support it. */ ++BUILD_ASSERT_DECL(TYPE_IS_INTEGER(time_t)); ++ ++/* We do try to cater to unsigned time_t, but I want to know about it if we ++ * ever encounter such a platform. */ ++BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t)); ++ ++#define TIME_MAX TYPE_MAXIMUM(time_t) ++#define TIME_MIN TYPE_MINIMUM(time_t) ++ ++#ifdef _WIN32 ++#define localtime_r(timep, result) localtime_s(result, timep) ++#define gmtime_r(timep, result) gmtime_s(result, timep) ++#endif /* _WIN32 */ ++ ++struct tm_msec { ++ struct tm tm; ++ int msec; ++}; ++ ++time_t time_now(void); ++time_t time_wall(void); ++long long int time_msec(void); ++long long int time_wall_msec(void); ++long long int time_usec(void); ++long long int time_wall_usec(void); ++void time_timespec(struct timespec *); ++void time_wall_timespec(struct timespec *); ++void time_alarm(unsigned int secs); ++int time_poll(struct pollfd *, int n_pollfds, HANDLE *handles, ++ long long int timeout_when, int *elapsed); ++ ++long long int timespec_to_msec(const struct timespec *); ++long long int timespec_to_usec(const struct timespec *); ++long long int timeval_to_msec(const struct timeval *); ++long long int timeval_to_usec(const struct timeval *); ++ ++struct tm_msec *localtime_msec(long long int now, struct tm_msec *result); ++struct tm_msec *gmtime_msec(long long int now, struct tm_msec *result); ++size_t strftime_msec(char *s, size_t max, const char *format, ++ const struct tm_msec *); ++void xgettimeofday(struct timeval *); ++void xclock_gettime(clock_t, struct timespec *); ++void nsec_to_timespec(long long int, struct timespec *); ++ ++int get_cpu_usage(void); ++ ++long long int time_boot_msec(void); ++ ++void timewarp_run(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* timeval.h */ +Index: openvswitch-2.17.2/lib/tun-metadata.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/tun-metadata.h ++++ /dev/null +@@ -1,80 +0,0 @@ +-/* +- * Copyright (c) 2015 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef TUN_METADATA_H +-#define TUN_METADATA_H 1 +- +-#include +- +-#include "openvswitch/dynamic-string.h" +-#include "netlink.h" +-#include "openvswitch/ofpbuf.h" +-#include "openflow/openflow.h" +-#include "openvswitch/tun-metadata.h" +- +-struct flow_tnl; +-struct match; +-struct mf_field; +-union mf_value; +-struct ofputil_tlv_table_mod; +-struct ofputil_tlv_table_reply; +-struct tun_table; +- +-struct tun_table *tun_metadata_alloc(const struct tun_table *old_map); +-void tun_metadata_free(struct tun_table *); +-void tun_metadata_postpone_free(struct tun_table *); +- +-enum ofperr tun_metadata_table_mod(struct ofputil_tlv_table_mod *, +- const struct tun_table *old_tab, +- struct tun_table **new_tab); +-void tun_metadata_table_request(const struct tun_table *, +- struct ofputil_tlv_table_reply *); +- +-void tun_metadata_read(const struct flow_tnl *, +- const struct mf_field *, union mf_value *); +-void tun_metadata_write(struct flow_tnl *, +- const struct mf_field *, const union mf_value *); +-void tun_metadata_delete(struct flow_tnl *, const struct mf_field *); +-void tun_metadata_set_match(const struct mf_field *, +- const union mf_value *value, +- const union mf_value *mask, struct match *, +- char **err_str); +-void tun_metadata_get_fmd(const struct flow_tnl *, struct match *flow_metadata); +- +-void tun_metadata_from_geneve_nlattr(const struct nlattr *attr, bool is_mask, +- struct flow_tnl *tun); +-void tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun, +- const struct flow_tnl *flow, +- const struct ofpbuf *key, +- struct ofpbuf *); +- +-int tun_metadata_from_geneve_udpif(const struct tun_table *, +- const struct flow_tnl *flow, +- const struct flow_tnl *src, +- struct flow_tnl *dst); +-void tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src, +- const struct flow_tnl *mask_src, +- const struct geneve_opt *flow_src_opt, +- int opts_len, struct geneve_opt *dst); +- +-int tun_metadata_to_geneve_header(const struct flow_tnl *flow, +- struct geneve_opt *, bool *crit_opt); +- +-void tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm, +- const struct match *); +-void tun_metadata_match_format(struct ds *, const struct match *); +- +-#endif /* tun-metadata.h */ +Index: openvswitch-2.17.2/include/internal/tun-metadata-private.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/tun-metadata-private.h +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef TUN_METADATA_H ++#define TUN_METADATA_H 1 ++ ++#include ++ ++#include "openvswitch/dynamic-string.h" ++#include "internal/netlink.h" ++#include "openvswitch/ofpbuf.h" ++#include "openflow/openflow.h" ++#include "openvswitch/tun-metadata.h" ++ ++struct flow_tnl; ++struct match; ++struct mf_field; ++union mf_value; ++struct ofputil_tlv_table_mod; ++struct ofputil_tlv_table_reply; ++struct tun_table; ++ ++struct tun_table *tun_metadata_alloc(const struct tun_table *old_map); ++void tun_metadata_free(struct tun_table *); ++void tun_metadata_postpone_free(struct tun_table *); ++ ++enum ofperr tun_metadata_table_mod(struct ofputil_tlv_table_mod *, ++ const struct tun_table *old_tab, ++ struct tun_table **new_tab); ++void tun_metadata_table_request(const struct tun_table *, ++ struct ofputil_tlv_table_reply *); ++ ++void tun_metadata_read(const struct flow_tnl *, ++ const struct mf_field *, union mf_value *); ++void tun_metadata_write(struct flow_tnl *, ++ const struct mf_field *, const union mf_value *); ++void tun_metadata_delete(struct flow_tnl *, const struct mf_field *); ++void tun_metadata_set_match(const struct mf_field *, ++ const union mf_value *value, ++ const union mf_value *mask, struct match *, ++ char **err_str); ++void tun_metadata_get_fmd(const struct flow_tnl *, struct match *flow_metadata); ++ ++void tun_metadata_from_geneve_nlattr(const struct nlattr *attr, bool is_mask, ++ struct flow_tnl *tun); ++void tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun, ++ const struct flow_tnl *flow, ++ const struct ofpbuf *key, ++ struct ofpbuf *); ++ ++int tun_metadata_from_geneve_udpif(const struct tun_table *, ++ const struct flow_tnl *flow, ++ const struct flow_tnl *src, ++ struct flow_tnl *dst); ++void tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src, ++ const struct flow_tnl *mask_src, ++ const struct geneve_opt *flow_src_opt, ++ int opts_len, struct geneve_opt *dst); ++ ++int tun_metadata_to_geneve_header(const struct flow_tnl *flow, ++ struct geneve_opt *, bool *crit_opt); ++ ++void tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm, ++ const struct match *); ++void tun_metadata_match_format(struct ds *, const struct match *); ++ ++#endif /* tun-metadata.h */ +Index: openvswitch-2.17.2/lib/unaligned.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/unaligned.h ++++ /dev/null +@@ -1,322 +0,0 @@ +-/* +- * Copyright (c) 2010, 2011, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef UNALIGNED_H +-#define UNALIGNED_H 1 +- +-#include +-#include "byte-order.h" +-#include "openvswitch/types.h" +-#include "openvswitch/type-props.h" +-#include "util.h" +- +-/* Public API. */ +-static inline uint16_t get_unaligned_u16(const uint16_t *); +-static inline uint32_t get_unaligned_u32(const uint32_t *); +-static inline void put_unaligned_u16(uint16_t *, uint16_t); +-static inline void put_unaligned_u32(uint32_t *, uint32_t); +-static inline void put_unaligned_u64(uint64_t *, uint64_t); +- +-static inline ovs_be16 get_unaligned_be16(const ovs_be16 *); +-static inline ovs_be32 get_unaligned_be32(const ovs_be32 *); +-static inline ovs_be64 get_unaligned_be64(const ovs_be64 *); +-static inline void put_unaligned_be16(ovs_be16 *, ovs_be16); +-static inline void put_unaligned_be32(ovs_be32 *, ovs_be32); +-static inline void put_unaligned_be64(ovs_be64 *, ovs_be64); +- +-/* uint64_t get_unaligned_u64(uint64_t *p); +- * +- * Returns the value of the possibly misaligned uint64_t at 'p'. 'p' may +- * actually be any type that points to a 64-bit integer. That is, on Unix-like +- * 32-bit ABIs, it may point to an "unsigned long long int", and on Unix-like +- * 64-bit ABIs, it may point to an "unsigned long int" or an "unsigned long +- * long int". +- * +- * This is special-cased because on some Linux targets, the kernel __u64 is +- * unsigned long long int and the userspace uint64_t is unsigned long int, so +- * that any single function prototype would fail to accept one or the other. +- * +- * Below, "sizeof (*(P) % 1)" verifies that *P has an integer type, since +- * operands to % must be integers. +- */ +-#define get_unaligned_u64(P) \ +- (BUILD_ASSERT(sizeof *(P) == 8), \ +- BUILD_ASSERT_GCCONLY(!TYPE_IS_SIGNED(typeof(*(P)))), \ +- (void) sizeof (*(P) % 1), \ +- get_unaligned_u64__((const uint64_t *) (P))) +- +-#ifdef __GNUC__ +-/* GCC implementations. */ +-#define GCC_UNALIGNED_ACCESSORS(TYPE, ABBREV) \ +-struct unaligned_##ABBREV { \ +- TYPE x __attribute__((__packed__)); \ +-}; \ +-static inline struct unaligned_##ABBREV * \ +-unaligned_##ABBREV(const TYPE *p) \ +-{ \ +- return (struct unaligned_##ABBREV *) p; \ +-} \ +- \ +-static inline TYPE \ +-get_unaligned_##ABBREV(const TYPE *p) \ +-{ \ +- return unaligned_##ABBREV(p)->x; \ +-} \ +- \ +-static inline void \ +-put_unaligned_##ABBREV(TYPE *p, TYPE x) \ +-{ \ +- unaligned_##ABBREV(p)->x = x; \ +-} +- +-GCC_UNALIGNED_ACCESSORS(uint16_t, u16); +-GCC_UNALIGNED_ACCESSORS(uint32_t, u32); +-GCC_UNALIGNED_ACCESSORS(uint64_t, u64__); /* Special case: see below. */ +- +-GCC_UNALIGNED_ACCESSORS(ovs_be16, be16); +-GCC_UNALIGNED_ACCESSORS(ovs_be32, be32); +-GCC_UNALIGNED_ACCESSORS(ovs_be64, be64); +-#else +-/* Generic implementations. */ +- +-static inline uint16_t get_unaligned_u16(const uint16_t *p_) +-{ +- const uint8_t *p = (const uint8_t *) p_; +- return ntohs((p[0] << 8) | p[1]); +-} +- +-static inline void put_unaligned_u16(uint16_t *p_, uint16_t x_) +-{ +- uint8_t *p = (uint8_t *) p_; +- uint16_t x = ntohs(x_); +- +- p[0] = x >> 8; +- p[1] = x; +-} +- +-static inline uint32_t get_unaligned_u32(const uint32_t *p_) +-{ +- const uint8_t *p = (const uint8_t *) p_; +- return ntohl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +-} +- +-static inline void put_unaligned_u32(uint32_t *p_, uint32_t x_) +-{ +- uint8_t *p = (uint8_t *) p_; +- uint32_t x = ntohl(x_); +- +- p[0] = x >> 24; +- p[1] = x >> 16; +- p[2] = x >> 8; +- p[3] = x; +-} +- +-static inline uint64_t get_unaligned_u64__(const uint64_t *p_) +-{ +- const uint8_t *p = (const uint8_t *) p_; +- return ntohll(((uint64_t) p[0] << 56) +- | ((uint64_t) p[1] << 48) +- | ((uint64_t) p[2] << 40) +- | ((uint64_t) p[3] << 32) +- | (p[4] << 24) +- | (p[5] << 16) +- | (p[6] << 8) +- | p[7]); +-} +- +-static inline void put_unaligned_u64__(uint64_t *p_, uint64_t x_) +-{ +- uint8_t *p = (uint8_t *) p_; +- uint64_t x = ntohll(x_); +- +- p[0] = x >> 56; +- p[1] = x >> 48; +- p[2] = x >> 40; +- p[3] = x >> 32; +- p[4] = x >> 24; +- p[5] = x >> 16; +- p[6] = x >> 8; +- p[7] = x; +-} +- +-/* Only sparse cares about the difference between uint_t and ovs_be, and +- * that takes the GCC branch, so there's no point in working too hard on these +- * accessors. */ +-#define get_unaligned_be16 get_unaligned_u16 +-#define get_unaligned_be32 get_unaligned_u32 +-#define put_unaligned_be16 put_unaligned_u16 +-#define put_unaligned_be32 put_unaligned_u32 +-#define put_unaligned_be64 put_unaligned_u64 +- +-/* We do not #define get_unaligned_be64 as for the other be functions above, +- * because such a definition would mean that get_unaligned_be64() would have a +- * different interface in each branch of the #if: with GCC it would take a +- * "ovs_be64 *", with other compilers any pointer-to-64-bit-type (but not void +- * *). The latter means code like "get_unaligned_be64(ofpbuf_data(b))" would +- * work with GCC but not with other compilers, which is surprising and +- * undesirable. Hence this wrapper function. */ +-static inline ovs_be64 +-get_unaligned_be64(const ovs_be64 *p) +-{ +- return get_unaligned_u64(p); +-} +-#endif +- +-/* Stores 'x' at possibly misaligned address 'p'. +- * +- * put_unaligned_u64() could be overloaded in the same way as +- * get_unaligned_u64(), but so far it has not proven necessary. +- */ +-static inline void +-put_unaligned_u64(uint64_t *p, uint64_t x) +-{ +- put_unaligned_u64__(p, x); +-} +- +-/* Returns the value in 'x'. */ +-static inline uint32_t +-get_16aligned_u32(const ovs_16aligned_u32 *x) +-{ +- return ((uint32_t) x->hi << 16) | x->lo; +-} +- +-/* Stores 'value' in 'x'. */ +-static inline void +-put_16aligned_u32(ovs_16aligned_u32 *x, uint32_t value) +-{ +- x->hi = value >> 16; +- x->lo = value; +-} +- +-/* Returns the value in 'x'. */ +-static inline uint64_t +-get_32aligned_u64(const ovs_32aligned_u64 *x) +-{ +- return ((uint64_t) x->hi << 32) | x->lo; +-} +- +-/* Stores 'value' in 'x'. */ +-static inline void +-put_32aligned_u64(ovs_32aligned_u64 *x, uint64_t value) +-{ +- x->hi = value >> 32; +- x->lo = value; +-} +- +-/* Returns the value in 'x'. */ +-static inline ovs_u128 +-get_32aligned_u128(const ovs_32aligned_u128 *x) +-{ +- ovs_u128 u; +- u.u32[0] = x->u32[0]; +- u.u32[1] = x->u32[1]; +- u.u32[2] = x->u32[2]; +- u.u32[3] = x->u32[3]; +- return u; +-} +- +-/* Stores 'value' in 'x'. */ +-static inline void +-put_32aligned_u128(ovs_32aligned_u128 *x, ovs_u128 value) +-{ +- x->u32[0] = value.u32[0]; +- x->u32[1] = value.u32[1]; +- x->u32[2] = value.u32[2]; +- x->u32[3] = value.u32[3]; +-} +- +-#ifndef __CHECKER__ +-/* Returns the value of 'x'. */ +-static inline ovs_be32 +-get_16aligned_be32(const ovs_16aligned_be32 *x) +-{ +-#ifdef WORDS_BIGENDIAN +- return ((ovs_be32) x->hi << 16) | x->lo; +-#else +- return ((ovs_be32) x->lo << 16) | x->hi; +-#endif +-} +- +-/* Stores network byte order 'value' into 'x'. */ +-static inline void +-put_16aligned_be32(ovs_16aligned_be32 *x, ovs_be32 value) +-{ +-#if WORDS_BIGENDIAN +- x->hi = value >> 16; +- x->lo = value; +-#else +- x->hi = value; +- x->lo = value >> 16; +-#endif +-} +- +-/* Returns the value of 'x'. */ +-static inline ovs_be64 +-get_32aligned_be64(const ovs_32aligned_be64 *x) +-{ +-#ifdef WORDS_BIGENDIAN +- return ((ovs_be64) x->hi << 32) | x->lo; +-#else +- return ((ovs_be64) x->lo << 32) | x->hi; +-#endif +-} +- +-/* Stores network byte order 'value' into 'x'. */ +-static inline void +-put_32aligned_be64(ovs_32aligned_be64 *x, ovs_be64 value) +-{ +-#if WORDS_BIGENDIAN +- x->hi = value >> 32; +- x->lo = value; +-#else +- x->hi = value; +- x->lo = value >> 32; +-#endif +-} +- +-/* Returns the value of 'x'. */ +-static inline ovs_be128 +-get_32aligned_be128(const ovs_32aligned_be128 *x) +-{ +- ovs_be128 u; +- u.be32[0] = x->be32[0]; +- u.be32[1] = x->be32[1]; +- u.be32[2] = x->be32[2]; +- u.be32[3] = x->be32[3]; +- return u; +-} +- +-/* Stores network byte order 'value' into 'x'. */ +-static inline void +-put_32aligned_be128(ovs_32aligned_be128 *x, ovs_be128 value) +-{ +- x->be32[0] = value.be32[0]; +- x->be32[1] = value.be32[1]; +- x->be32[2] = value.be32[2]; +- x->be32[3] = value.be32[3]; +-} +-#else /* __CHECKER__ */ +-/* Making sparse happy with these functions also makes them unreadable, so +- * don't bother to show it their implementations. */ +-ovs_be32 get_16aligned_be32(const ovs_16aligned_be32 *); +-void put_16aligned_be32(ovs_16aligned_be32 *, ovs_be32); +-ovs_be64 get_32aligned_be64(const ovs_32aligned_be64 *); +-void put_32aligned_be64(ovs_32aligned_be64 *, ovs_be64); +-ovs_be128 get_32aligned_be128(const ovs_32aligned_be128 *); +-void put_32aligned_be128(ovs_32aligned_be128 *, ovs_be128); +-#endif +- +-#endif /* unaligned.h */ +Index: openvswitch-2.17.2/include/internal/unaligned.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/unaligned.h +@@ -0,0 +1,322 @@ ++/* ++ * Copyright (c) 2010, 2011, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef UNALIGNED_H ++#define UNALIGNED_H 1 ++ ++#include ++#include "internal/byte-order.h" ++#include "openvswitch/types.h" ++#include "openvswitch/type-props.h" ++#include "internal/util.h" ++ ++/* Public API. */ ++static inline uint16_t get_unaligned_u16(const uint16_t *); ++static inline uint32_t get_unaligned_u32(const uint32_t *); ++static inline void put_unaligned_u16(uint16_t *, uint16_t); ++static inline void put_unaligned_u32(uint32_t *, uint32_t); ++static inline void put_unaligned_u64(uint64_t *, uint64_t); ++ ++static inline ovs_be16 get_unaligned_be16(const ovs_be16 *); ++static inline ovs_be32 get_unaligned_be32(const ovs_be32 *); ++static inline ovs_be64 get_unaligned_be64(const ovs_be64 *); ++static inline void put_unaligned_be16(ovs_be16 *, ovs_be16); ++static inline void put_unaligned_be32(ovs_be32 *, ovs_be32); ++static inline void put_unaligned_be64(ovs_be64 *, ovs_be64); ++ ++/* uint64_t get_unaligned_u64(uint64_t *p); ++ * ++ * Returns the value of the possibly misaligned uint64_t at 'p'. 'p' may ++ * actually be any type that points to a 64-bit integer. That is, on Unix-like ++ * 32-bit ABIs, it may point to an "unsigned long long int", and on Unix-like ++ * 64-bit ABIs, it may point to an "unsigned long int" or an "unsigned long ++ * long int". ++ * ++ * This is special-cased because on some Linux targets, the kernel __u64 is ++ * unsigned long long int and the userspace uint64_t is unsigned long int, so ++ * that any single function prototype would fail to accept one or the other. ++ * ++ * Below, "sizeof (*(P) % 1)" verifies that *P has an integer type, since ++ * operands to % must be integers. ++ */ ++#define get_unaligned_u64(P) \ ++ (BUILD_ASSERT(sizeof *(P) == 8), \ ++ BUILD_ASSERT_GCCONLY(!TYPE_IS_SIGNED(typeof(*(P)))), \ ++ (void) sizeof (*(P) % 1), \ ++ get_unaligned_u64__((const uint64_t *) (P))) ++ ++#ifdef __GNUC__ ++/* GCC implementations. */ ++#define GCC_UNALIGNED_ACCESSORS(TYPE, ABBREV) \ ++struct unaligned_##ABBREV { \ ++ TYPE x __attribute__((__packed__)); \ ++}; \ ++static inline struct unaligned_##ABBREV * \ ++unaligned_##ABBREV(const TYPE *p) \ ++{ \ ++ return (struct unaligned_##ABBREV *) p; \ ++} \ ++ \ ++static inline TYPE \ ++get_unaligned_##ABBREV(const TYPE *p) \ ++{ \ ++ return unaligned_##ABBREV(p)->x; \ ++} \ ++ \ ++static inline void \ ++put_unaligned_##ABBREV(TYPE *p, TYPE x) \ ++{ \ ++ unaligned_##ABBREV(p)->x = x; \ ++} ++ ++GCC_UNALIGNED_ACCESSORS(uint16_t, u16); ++GCC_UNALIGNED_ACCESSORS(uint32_t, u32); ++GCC_UNALIGNED_ACCESSORS(uint64_t, u64__); /* Special case: see below. */ ++ ++GCC_UNALIGNED_ACCESSORS(ovs_be16, be16); ++GCC_UNALIGNED_ACCESSORS(ovs_be32, be32); ++GCC_UNALIGNED_ACCESSORS(ovs_be64, be64); ++#else ++/* Generic implementations. */ ++ ++static inline uint16_t get_unaligned_u16(const uint16_t *p_) ++{ ++ const uint8_t *p = (const uint8_t *) p_; ++ return ntohs((p[0] << 8) | p[1]); ++} ++ ++static inline void put_unaligned_u16(uint16_t *p_, uint16_t x_) ++{ ++ uint8_t *p = (uint8_t *) p_; ++ uint16_t x = ntohs(x_); ++ ++ p[0] = x >> 8; ++ p[1] = x; ++} ++ ++static inline uint32_t get_unaligned_u32(const uint32_t *p_) ++{ ++ const uint8_t *p = (const uint8_t *) p_; ++ return ntohl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); ++} ++ ++static inline void put_unaligned_u32(uint32_t *p_, uint32_t x_) ++{ ++ uint8_t *p = (uint8_t *) p_; ++ uint32_t x = ntohl(x_); ++ ++ p[0] = x >> 24; ++ p[1] = x >> 16; ++ p[2] = x >> 8; ++ p[3] = x; ++} ++ ++static inline uint64_t get_unaligned_u64__(const uint64_t *p_) ++{ ++ const uint8_t *p = (const uint8_t *) p_; ++ return ntohll(((uint64_t) p[0] << 56) ++ | ((uint64_t) p[1] << 48) ++ | ((uint64_t) p[2] << 40) ++ | ((uint64_t) p[3] << 32) ++ | (p[4] << 24) ++ | (p[5] << 16) ++ | (p[6] << 8) ++ | p[7]); ++} ++ ++static inline void put_unaligned_u64__(uint64_t *p_, uint64_t x_) ++{ ++ uint8_t *p = (uint8_t *) p_; ++ uint64_t x = ntohll(x_); ++ ++ p[0] = x >> 56; ++ p[1] = x >> 48; ++ p[2] = x >> 40; ++ p[3] = x >> 32; ++ p[4] = x >> 24; ++ p[5] = x >> 16; ++ p[6] = x >> 8; ++ p[7] = x; ++} ++ ++/* Only sparse cares about the difference between uint_t and ovs_be, and ++ * that takes the GCC branch, so there's no point in working too hard on these ++ * accessors. */ ++#define get_unaligned_be16 get_unaligned_u16 ++#define get_unaligned_be32 get_unaligned_u32 ++#define put_unaligned_be16 put_unaligned_u16 ++#define put_unaligned_be32 put_unaligned_u32 ++#define put_unaligned_be64 put_unaligned_u64 ++ ++/* We do not #define get_unaligned_be64 as for the other be functions above, ++ * because such a definition would mean that get_unaligned_be64() would have a ++ * different interface in each branch of the #if: with GCC it would take a ++ * "ovs_be64 *", with other compilers any pointer-to-64-bit-type (but not void ++ * *). The latter means code like "get_unaligned_be64(ofpbuf_data(b))" would ++ * work with GCC but not with other compilers, which is surprising and ++ * undesirable. Hence this wrapper function. */ ++static inline ovs_be64 ++get_unaligned_be64(const ovs_be64 *p) ++{ ++ return get_unaligned_u64(p); ++} ++#endif ++ ++/* Stores 'x' at possibly misaligned address 'p'. ++ * ++ * put_unaligned_u64() could be overloaded in the same way as ++ * get_unaligned_u64(), but so far it has not proven necessary. ++ */ ++static inline void ++put_unaligned_u64(uint64_t *p, uint64_t x) ++{ ++ put_unaligned_u64__(p, x); ++} ++ ++/* Returns the value in 'x'. */ ++static inline uint32_t ++get_16aligned_u32(const ovs_16aligned_u32 *x) ++{ ++ return ((uint32_t) x->hi << 16) | x->lo; ++} ++ ++/* Stores 'value' in 'x'. */ ++static inline void ++put_16aligned_u32(ovs_16aligned_u32 *x, uint32_t value) ++{ ++ x->hi = value >> 16; ++ x->lo = value; ++} ++ ++/* Returns the value in 'x'. */ ++static inline uint64_t ++get_32aligned_u64(const ovs_32aligned_u64 *x) ++{ ++ return ((uint64_t) x->hi << 32) | x->lo; ++} ++ ++/* Stores 'value' in 'x'. */ ++static inline void ++put_32aligned_u64(ovs_32aligned_u64 *x, uint64_t value) ++{ ++ x->hi = value >> 32; ++ x->lo = value; ++} ++ ++/* Returns the value in 'x'. */ ++static inline ovs_u128 ++get_32aligned_u128(const ovs_32aligned_u128 *x) ++{ ++ ovs_u128 u; ++ u.u32[0] = x->u32[0]; ++ u.u32[1] = x->u32[1]; ++ u.u32[2] = x->u32[2]; ++ u.u32[3] = x->u32[3]; ++ return u; ++} ++ ++/* Stores 'value' in 'x'. */ ++static inline void ++put_32aligned_u128(ovs_32aligned_u128 *x, ovs_u128 value) ++{ ++ x->u32[0] = value.u32[0]; ++ x->u32[1] = value.u32[1]; ++ x->u32[2] = value.u32[2]; ++ x->u32[3] = value.u32[3]; ++} ++ ++#ifndef __CHECKER__ ++/* Returns the value of 'x'. */ ++static inline ovs_be32 ++get_16aligned_be32(const ovs_16aligned_be32 *x) ++{ ++#ifdef WORDS_BIGENDIAN ++ return ((ovs_be32) x->hi << 16) | x->lo; ++#else ++ return ((ovs_be32) x->lo << 16) | x->hi; ++#endif ++} ++ ++/* Stores network byte order 'value' into 'x'. */ ++static inline void ++put_16aligned_be32(ovs_16aligned_be32 *x, ovs_be32 value) ++{ ++#if WORDS_BIGENDIAN ++ x->hi = value >> 16; ++ x->lo = value; ++#else ++ x->hi = value; ++ x->lo = value >> 16; ++#endif ++} ++ ++/* Returns the value of 'x'. */ ++static inline ovs_be64 ++get_32aligned_be64(const ovs_32aligned_be64 *x) ++{ ++#ifdef WORDS_BIGENDIAN ++ return ((ovs_be64) x->hi << 32) | x->lo; ++#else ++ return ((ovs_be64) x->lo << 32) | x->hi; ++#endif ++} ++ ++/* Stores network byte order 'value' into 'x'. */ ++static inline void ++put_32aligned_be64(ovs_32aligned_be64 *x, ovs_be64 value) ++{ ++#if WORDS_BIGENDIAN ++ x->hi = value >> 32; ++ x->lo = value; ++#else ++ x->hi = value; ++ x->lo = value >> 32; ++#endif ++} ++ ++/* Returns the value of 'x'. */ ++static inline ovs_be128 ++get_32aligned_be128(const ovs_32aligned_be128 *x) ++{ ++ ovs_be128 u; ++ u.be32[0] = x->be32[0]; ++ u.be32[1] = x->be32[1]; ++ u.be32[2] = x->be32[2]; ++ u.be32[3] = x->be32[3]; ++ return u; ++} ++ ++/* Stores network byte order 'value' into 'x'. */ ++static inline void ++put_32aligned_be128(ovs_32aligned_be128 *x, ovs_be128 value) ++{ ++ x->be32[0] = value.be32[0]; ++ x->be32[1] = value.be32[1]; ++ x->be32[2] = value.be32[2]; ++ x->be32[3] = value.be32[3]; ++} ++#else /* __CHECKER__ */ ++/* Making sparse happy with these functions also makes them unreadable, so ++ * don't bother to show it their implementations. */ ++ovs_be32 get_16aligned_be32(const ovs_16aligned_be32 *); ++void put_16aligned_be32(ovs_16aligned_be32 *, ovs_be32); ++ovs_be64 get_32aligned_be64(const ovs_32aligned_be64 *); ++void put_32aligned_be64(ovs_32aligned_be64 *, ovs_be64); ++ovs_be128 get_32aligned_be128(const ovs_32aligned_be128 *); ++void put_32aligned_be128(ovs_32aligned_be128 *, ovs_be128); ++#endif ++ ++#endif /* unaligned.h */ +Index: openvswitch-2.17.2/include/internal/util.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/util.h @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. @@ -2184,30 +20687,168 @@ index 000000000..4f40319c4 +#endif + +#endif /* util.h */ -diff --git a/lib/uuid.h b/include/internal/uuid.h -similarity index 100% -rename from lib/uuid.h -rename to include/internal/uuid.h -diff --git a/lib/versions.h b/include/internal/versions.h -similarity index 98% -rename from lib/versions.h -rename to include/internal/versions.h -index d92f0a319..24d28102a 100644 ---- a/lib/versions.h -+++ b/include/internal/versions.h -@@ -17,7 +17,7 @@ - #ifndef VERSIONS_H - #define VERSIONS_H 1 - +Index: openvswitch-2.17.2/lib/versions.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/versions.h ++++ /dev/null +@@ -1,74 +0,0 @@ +-/* +- * Copyright (c) 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef VERSIONS_H +-#define VERSIONS_H 1 +- -#include "ovs-atomic.h" +-#include "openvswitch/type-props.h" +- +-typedef uint64_t ovs_version_t; +- +-#define OVS_VERSION_MIN 0 /* Default version number to use. */ +-#define OVS_VERSION_MAX (TYPE_MAXIMUM(ovs_version_t) - 1) +-#define OVS_VERSION_NOT_REMOVED TYPE_MAXIMUM(ovs_version_t) +- +-/* +- * OVS_VERSION_NOT_REMOVED has a special meaning for 'remove_version', +- * meaning that the rule has been added but not yet removed. +- */ +-struct versions { +- ovs_version_t add_version; /* Version object was added in. */ +- ATOMIC(ovs_version_t) remove_version; /* Version object is removed in. */ +-}; +- +-#define VERSIONS_INITIALIZER(ADD, REMOVE) \ +- (struct versions){ ADD, ATOMIC_VAR_INIT(REMOVE) } +- +-static inline void +-versions_set_remove_version(struct versions *versions, ovs_version_t version) +-{ +- atomic_store_relaxed(&versions->remove_version, version); +-} +- +-static inline bool +-versions_visible_in_version(const struct versions *versions, +- ovs_version_t version) +-{ +- ovs_version_t remove_version; +- +- /* C11 does not want to access an atomic via a const object pointer. */ +- atomic_read_relaxed(&CONST_CAST(struct versions *, +- versions)->remove_version, +- &remove_version); +- +- return versions->add_version <= version && version < remove_version; +-} +- +-static inline bool +-versions_is_eventually_invisible(const struct versions *versions) +-{ +- ovs_version_t remove_version; +- +- /* C11 does not want to access an atomic via a const object pointer. */ +- atomic_read_relaxed(&CONST_CAST(struct versions *, +- versions)->remove_version, +- &remove_version); +- +- return remove_version < OVS_VERSION_NOT_REMOVED; +-} +- +-#endif /* VERSIONS_H */ +Index: openvswitch-2.17.2/include/internal/versions.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/versions.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef VERSIONS_H ++#define VERSIONS_H 1 ++ +#include "openvswitch/ovs-atomic.h" - #include "openvswitch/type-props.h" - - typedef uint64_t ovs_version_t; -diff --git a/include/openvswitch/automake.mk b/include/openvswitch/automake.mk -index 84670d80a..2845a1ece 100644 ---- a/include/openvswitch/automake.mk -+++ b/include/openvswitch/automake.mk ++#include "openvswitch/type-props.h" ++ ++typedef uint64_t ovs_version_t; ++ ++#define OVS_VERSION_MIN 0 /* Default version number to use. */ ++#define OVS_VERSION_MAX (TYPE_MAXIMUM(ovs_version_t) - 1) ++#define OVS_VERSION_NOT_REMOVED TYPE_MAXIMUM(ovs_version_t) ++ ++/* ++ * OVS_VERSION_NOT_REMOVED has a special meaning for 'remove_version', ++ * meaning that the rule has been added but not yet removed. ++ */ ++struct versions { ++ ovs_version_t add_version; /* Version object was added in. */ ++ ATOMIC(ovs_version_t) remove_version; /* Version object is removed in. */ ++}; ++ ++#define VERSIONS_INITIALIZER(ADD, REMOVE) \ ++ (struct versions){ ADD, ATOMIC_VAR_INIT(REMOVE) } ++ ++static inline void ++versions_set_remove_version(struct versions *versions, ovs_version_t version) ++{ ++ atomic_store_relaxed(&versions->remove_version, version); ++} ++ ++static inline bool ++versions_visible_in_version(const struct versions *versions, ++ ovs_version_t version) ++{ ++ ovs_version_t remove_version; ++ ++ /* C11 does not want to access an atomic via a const object pointer. */ ++ atomic_read_relaxed(&CONST_CAST(struct versions *, ++ versions)->remove_version, ++ &remove_version); ++ ++ return versions->add_version <= version && version < remove_version; ++} ++ ++static inline bool ++versions_is_eventually_invisible(const struct versions *versions) ++{ ++ ovs_version_t remove_version; ++ ++ /* C11 does not want to access an atomic via a const object pointer. */ ++ atomic_read_relaxed(&CONST_CAST(struct versions *, ++ versions)->remove_version, ++ &remove_version); ++ ++ return remove_version < OVS_VERSION_NOT_REMOVED; ++} ++ ++#endif /* VERSIONS_H */ +Index: openvswitch-2.17.2/include/openvswitch/automake.mk +=================================================================== +--- openvswitch-2.17.2.orig/include/openvswitch/automake.mk ++++ openvswitch-2.17.2/include/openvswitch/automake.mk @@ -1,5 +1,7 @@ openvswitchincludedir = $(includedir)/openvswitch openvswitchinclude_HEADERS = \ @@ -2237,401 +20878,6942 @@ index 84670d80a..2845a1ece 100644 include/openvswitch/packets.h \ include/openvswitch/poll-loop.h \ include/openvswitch/rconn.h \ -diff --git a/lib/ovs-atomic.h b/include/openvswitch/ovs-atomic.h -similarity index 97% -rename from lib/ovs-atomic.h -rename to include/openvswitch/ovs-atomic.h -index 341e0d0cc..d155c98e4 100644 ---- a/lib/ovs-atomic.h -+++ b/include/openvswitch/ovs-atomic.h -@@ -323,35 +323,39 @@ - #include - #include - #include "openvswitch/compiler.h" +Index: openvswitch-2.17.2/lib/ovs-atomic.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic.h ++++ /dev/null +@@ -1,671 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVS_ATOMIC_H +-#define OVS_ATOMIC_H 1 +- +-/* Atomic operations. +- * +- * This library implements atomic operations with an API based on the one +- * defined in C11. It includes multiple implementations for compilers and +- * libraries with varying degrees of built-in support for C11, including a +- * fallback implementation for systems that have pthreads but no other support +- * for atomics. +- * +- * This comment describes the common features of all the implementations. +- * +- * +- * Types +- * ===== +- * +- * The following atomic types are supported as typedefs for atomic versions of +- * the listed ordinary types: +- * +- * ordinary type atomic version +- * ------------------- ---------------------- +- * bool atomic_bool +- * +- * char atomic_char +- * signed char atomic_schar +- * unsigned char atomic_uchar +- * +- * short atomic_short +- * unsigned short atomic_ushort +- * +- * int atomic_int +- * unsigned int atomic_uint +- * +- * long atomic_long +- * unsigned long atomic_ulong +- * +- * long long atomic_llong +- * unsigned long long atomic_ullong +- * +- * size_t atomic_size_t +- * ptrdiff_t atomic_ptrdiff_t +- * +- * intmax_t atomic_intmax_t +- * uintmax_t atomic_uintmax_t +- * +- * intptr_t atomic_intptr_t +- * uintptr_t atomic_uintptr_t +- * +- * uint8_t atomic_uint8_t (*) +- * uint16_t atomic_uint16_t (*) +- * uint32_t atomic_uint32_t (*) +- * int8_t atomic_int8_t (*) +- * int16_t atomic_int16_t (*) +- * int32_t atomic_int32_t (*) +- * uint64_t atomic_uint64_t (*) +- * int64_t atomic_int64_t (*) +- * +- * (*) Not specified by C11. +- * +- * Atomic types may also be obtained via ATOMIC(TYPE), e.g. ATOMIC(void *). +- * Only basic integer types and pointer types can be made atomic this way, +- * e.g. atomic structs are not supported. +- * +- * The atomic version of a type doesn't necessarily have the same size or +- * representation as the ordinary version; for example, atomic_int might be a +- * typedef for a struct. The range of an atomic type does match the range of +- * the corresponding ordinary type. +- * +- * C11 says that one may use the _Atomic keyword in place of the typedef name, +- * e.g. "_Atomic int" instead of "atomic_int". This library doesn't support +- * that. +- * +- * +- * Life Cycle +- * ========== +- * +- * To initialize an atomic variable at its point of definition, use +- * ATOMIC_VAR_INIT: +- * +- * static atomic_int ai = ATOMIC_VAR_INIT(123); +- * +- * To initialize an atomic variable in code, use atomic_init(): +- * +- * static atomic_int ai; +- * ... +- * atomic_init(&ai, 123); +- * +- * +- * Barriers +- * ======== +- * +- * enum memory_order specifies the strictness of a memory barrier. It has the +- * following values: +- * +- * memory_order_relaxed: +- * +- * Only atomicity is provided, does not imply any memory ordering with +- * respect to any other variable (atomic or not). Relaxed accesses to +- * the same atomic variable will be performed in the program order. +- * The compiler and CPU are free to move memory accesses to other +- * variables past the atomic operation. +- * +- * memory_order_consume: +- * +- * Memory accesses with data dependency on the result of the consume +- * operation (atomic_read_explicit, or a load operation preceding a +- * atomic_thread_fence) will not be moved prior to the consume +- * barrier. Non-data-dependent loads and stores can be reordered to +- * happen before the consume barrier. +- * +- * RCU is the prime example of the use of the consume barrier: The +- * consume barrier guarantees that reads from a RCU protected object +- * are performed after the RCU protected pointer is read. A +- * corresponding release barrier is used to store the modified RCU +- * protected pointer after the RCU protected object has been fully +- * constructed. The synchronization between these barriers prevents +- * the RCU "consumer" from seeing uninitialized data. +- * +- * May not be used with atomic_store_explicit(), as consume semantics +- * applies only to atomic loads. +- * +- * memory_order_acquire: +- * +- * Memory accesses after an acquire barrier cannot be moved before the +- * barrier. Memory accesses before an acquire barrier *can* be moved +- * after it. +- * +- * An atomic_thread_fence with memory_order_acquire does not have a +- * load operation by itself; it prevents all following memory accesses +- * from moving prior to preceding loads. +- * +- * May not be used with atomic_store_explicit(), as acquire semantics +- * applies only to atomic loads. +- * +- * memory_order_release: +- * +- * Memory accesses before a release barrier cannot be moved after the +- * barrier. Memory accesses after a release barrier *can* be moved +- * before it. +- * +- * An atomic_thread_fence with memory_order_release does not have a +- * store operation by itself; it prevents all preceding memory accesses +- * from moving past subsequent stores. +- * +- * May not be used with atomic_read_explicit(), as release semantics +- * applies only to atomic stores. +- * +- * memory_order_acq_rel: +- * +- * Memory accesses cannot be moved across an acquire-release barrier in +- * either direction. +- * +- * May only be used with atomic read-modify-write operations, as both +- * load and store operation is required for acquire-release semantics. +- * +- * An atomic_thread_fence with memory_order_acq_rel does not have +- * either load or store operation by itself; it prevents all following +- * memory accesses from moving prior to preceding loads and all +- * preceding memory accesses from moving past subsequent stores. +- * +- * memory_order_seq_cst: +- * +- * Prevents movement of memory accesses like an acquire-release barrier, +- * but whereas acquire-release synchronizes cooperating threads (using +- * the same atomic variable), sequential-consistency synchronizes the +- * whole system, providing a total order for stores on all atomic +- * variables. +- * +- * OVS atomics require the memory_order to be passed as a compile-time constant +- * value, as some compiler implementations may perform poorly if the memory +- * order parameter is passed in as a run-time value. +- * +- * The following functions insert explicit barriers. Most of the other atomic +- * functions also include barriers. +- * +- * void atomic_thread_fence(memory_order order); +- * +- * Inserts a barrier of the specified type. +- * +- * For memory_order_relaxed, this is a no-op. +- * +- * void atomic_signal_fence(memory_order order); +- * +- * Inserts a barrier of the specified type, but only with respect to +- * signal handlers in the same thread as the barrier. This is +- * basically a compiler optimization barrier, except for +- * memory_order_relaxed, which is a no-op. +- * +- * +- * Atomic Operations +- * ================= +- * +- * In this section, A is an atomic type and C is the corresponding non-atomic +- * type. +- * +- * The "store", "exchange", and "compare_exchange" primitives match C11: +- * +- * void atomic_store(A *object, C value); +- * void atomic_store_explicit(A *object, C value, memory_order); +- * +- * Atomically stores 'value' into '*object', respecting the given +- * memory order (or memory_order_seq_cst for atomic_store()). +- * +- * bool atomic_compare_exchange_strong(A *object, C *expected, C desired); +- * bool atomic_compare_exchange_weak(A *object, C *expected, C desired); +- * bool atomic_compare_exchange_strong_explicit(A *object, C *expected, +- * C desired, +- * memory_order success, +- * memory_order failure); +- * bool atomic_compare_exchange_weak_explicit(A *object, C *expected, +- * C desired, +- * memory_order success, +- * memory_order failure); +- * +- * Atomically loads '*object' and compares it with '*expected' and if +- * equal, stores 'desired' into '*object' (an atomic read-modify-write +- * operation) and returns true, and if non-equal, stores the actual +- * value of '*object' into '*expected' (an atomic load operation) and +- * returns false. The memory order for the successful case (atomic +- * read-modify-write operation) is 'success', and for the unsuccessful +- * case (atomic load operation) 'failure'. 'failure' may not be +- * stronger than 'success'. +- * +- * The weak forms may fail (returning false) also when '*object' equals +- * '*expected'. The strong form can be implemented by the weak form in +- * a loop. Some platforms can implement the weak form more +- * efficiently, so it should be used if the application will need to +- * loop anyway. +- * +- * C atomic_exchange(A *object, C desired); +- * C atomic_exchange_explicit(A *object, C desired, memory_order); +- * +- * Atomically stores 'desired' into '*object', returning the value +- * previously held. +- * +- * The following primitives differ from the C11 ones (and have different names) +- * because there does not appear to be a way to implement the standard +- * primitives in standard C: +- * +- * void atomic_read(A *src, C *dst); +- * void atomic_read_explicit(A *src, C *dst, memory_order); +- * +- * Atomically loads a value from 'src', writing the value read into +- * '*dst', respecting the given memory order (or memory_order_seq_cst +- * for atomic_read()). +- * +- * void atomic_add(A *rmw, C arg, C *orig); +- * void atomic_sub(A *rmw, C arg, C *orig); +- * void atomic_or(A *rmw, C arg, C *orig); +- * void atomic_xor(A *rmw, C arg, C *orig); +- * void atomic_and(A *rmw, C arg, C *orig); +- * void atomic_add_explicit(A *rmw, C arg, C *orig, memory_order); +- * void atomic_sub_explicit(A *rmw, C arg, C *orig, memory_order); +- * void atomic_or_explicit(A *rmw, C arg, C *orig, memory_order); +- * void atomic_xor_explicit(A *rmw, C arg, C *orig, memory_order); +- * void atomic_and_explicit(A *rmw, C arg, C *orig, memory_order); +- * +- * Atomically applies the given operation, with 'arg' as the second +- * operand, to '*rmw', and stores the original value of '*rmw' into +- * '*orig', respecting the given memory order (or memory_order_seq_cst +- * if none is specified). +- * +- * The results are similar to those that would be obtained with +=, -=, +- * |=, ^=, or |= on non-atomic types. +- * +- * +- * atomic_flag +- * =========== +- * +- * atomic_flag is a typedef for a type with two states, set and clear, that +- * provides atomic test-and-set functionality. +- * +- * +- * Life Cycle +- * ---------- +- * +- * ATOMIC_FLAG_INIT is an initializer for atomic_flag. The initial state is +- * "clear". +- * +- * An atomic_flag may also be initialized at runtime with atomic_flag_clear(). +- * +- * +- * Operations +- * ---------- +- * +- * The following functions are available. +- * +- * bool atomic_flag_test_and_set(atomic_flag *object) +- * bool atomic_flag_test_and_set_explicit(atomic_flag *object, +- * memory_order); +- * +- * Atomically sets '*object', respecting the given memory order (or +- * memory_order_seq_cst for atomic_flag_test_and_set()). Returns the +- * previous value of the flag (false for clear, true for set). +- * +- * void atomic_flag_clear(atomic_flag *object); +- * void atomic_flag_clear_explicit(atomic_flag *object, memory_order); +- * +- * Atomically clears '*object', respecting the given memory order (or +- * memory_order_seq_cst for atomic_flag_clear()). +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "openvswitch/compiler.h" -#include "util.h" +- +-#define IN_OVS_ATOMIC_H +- #if __CHECKER__ +- /* sparse doesn't understand some GCC extensions we use. */ +- #include "ovs-atomic-pthreads.h" +- #elif __has_extension(c_atomic) +- #include "ovs-atomic-clang.h" +- #elif HAVE_ATOMIC && __cplusplus >= 201103L +- #include "ovs-atomic-c++.h" +- #elif HAVE_STDATOMIC_H && !defined(__cplusplus) +- #include "ovs-atomic-c11.h" +- #elif __GNUC__ >= 5 && !defined(__cplusplus) +- #error "GCC 5+ should have " +- #elif __GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 7) +- #include "ovs-atomic-gcc4.7+.h" +- #elif __GNUC__ && defined(__x86_64__) +- #include "ovs-atomic-x86_64.h" +- #elif __GNUC__ && defined(__i386__) +- #include "ovs-atomic-i586.h" +- #elif HAVE_GCC4_ATOMICS +- #include "ovs-atomic-gcc4+.h" +- #elif _MSC_VER +- #include "ovs-atomic-msvc.h" +- #else +- /* ovs-atomic-pthreads implementation is provided for portability. +- * It might be too slow for real use because Open vSwitch is +- * optimized for platforms where real atomic ops are available. */ +- #include "ovs-atomic-pthreads.h" +- #endif +-#undef IN_OVS_ATOMIC_H +- +-#ifndef OMIT_STANDARD_ATOMIC_TYPES +-typedef ATOMIC(bool) atomic_bool; +- +-typedef ATOMIC(char) atomic_char; +-typedef ATOMIC(signed char) atomic_schar; +-typedef ATOMIC(unsigned char) atomic_uchar; +- +-typedef ATOMIC(short) atomic_short; +-typedef ATOMIC(unsigned short) atomic_ushort; +- +-typedef ATOMIC(int) atomic_int; +-typedef ATOMIC(unsigned int) atomic_uint; +- +-typedef ATOMIC(long) atomic_long; +-typedef ATOMIC(unsigned long) atomic_ulong; +- +-typedef ATOMIC(long long) atomic_llong; +-typedef ATOMIC(unsigned long long) atomic_ullong; +- +-typedef ATOMIC(size_t) atomic_size_t; +-typedef ATOMIC(ptrdiff_t) atomic_ptrdiff_t; +- +-typedef ATOMIC(intmax_t) atomic_intmax_t; +-typedef ATOMIC(uintmax_t) atomic_uintmax_t; +- +-typedef ATOMIC(intptr_t) atomic_intptr_t; +-typedef ATOMIC(uintptr_t) atomic_uintptr_t; +-#endif /* !OMIT_STANDARD_ATOMIC_TYPES */ +- +-/* Nonstandard atomic types. */ +-typedef ATOMIC(uint8_t) atomic_uint8_t; +-typedef ATOMIC(uint16_t) atomic_uint16_t; +-typedef ATOMIC(uint32_t) atomic_uint32_t; +-typedef ATOMIC(uint64_t) atomic_uint64_t; +- +-typedef ATOMIC(int8_t) atomic_int8_t; +-typedef ATOMIC(int16_t) atomic_int16_t; +-typedef ATOMIC(int32_t) atomic_int32_t; +-typedef ATOMIC(int64_t) atomic_int64_t; +- +-/* Relaxed atomic operations. +- * +- * When an operation on an atomic variable is not expected to synchronize +- * with operations on other (atomic or non-atomic) variables, no memory +- * barriers are needed and the relaxed memory ordering can be used. These +- * macros make such uses less daunting, but not invisible. */ +-#define atomic_store_relaxed(VAR, VALUE) \ +- atomic_store_explicit(VAR, VALUE, memory_order_relaxed) +-#define atomic_read_relaxed(VAR, DST) \ +- atomic_read_explicit(VAR, DST, memory_order_relaxed) +-#define atomic_compare_exchange_strong_relaxed(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_relaxed, \ +- memory_order_relaxed) +-#define atomic_compare_exchange_weak_relaxed(DST, EXP, SRC) \ +- atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ +- memory_order_relaxed, \ +- memory_order_relaxed) +-#define atomic_add_relaxed(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_relaxed) +-#define atomic_sub_relaxed(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_relaxed) +-#define atomic_or_relaxed(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_relaxed) +-#define atomic_xor_relaxed(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_relaxed) +-#define atomic_and_relaxed(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_relaxed) +-#define atomic_flag_test_and_set_relaxed(FLAG) \ +- atomic_flag_test_and_set_explicit(FLAG, memory_order_relaxed) +-#define atomic_flag_clear_relaxed(FLAG) \ +- atomic_flag_clear_explicit(FLAG, memory_order_relaxed) +- +-/* A simplified atomic count. Does not provide any synchronization with any +- * other variables. +- * +- * Typically a counter is not used to synchronize the state of any other +- * variables (with the notable exception of reference count, below). +- * This abstraction releaves the user from the memory order considerations, +- * and may make the code easier to read. +- * +- * We only support the unsigned int counters, as those are the most common. */ +-typedef struct atomic_count { +- atomic_uint count; +-} atomic_count; +- +-#define ATOMIC_COUNT_INIT(VALUE) { VALUE } +- +-static inline void +-atomic_count_init(atomic_count *count, unsigned int value) +-{ +- atomic_init(&count->count, value); +-} +- +-static inline unsigned int +-atomic_count_inc(atomic_count *count) +-{ +- unsigned int old; +- +- atomic_add_relaxed(&count->count, 1u, &old); +- +- return old; +-} +- +-static inline unsigned int +-atomic_count_dec(atomic_count *count) +-{ +- unsigned int old; +- +- atomic_sub_relaxed(&count->count, 1u, &old); +- +- return old; +-} +- +-static inline unsigned int +-atomic_count_get(atomic_count *count) +-{ +- unsigned int value; +- +- atomic_read_relaxed(&count->count, &value); +- +- return value; +-} +- +-static inline void +-atomic_count_set(atomic_count *count, unsigned int value) +-{ +- atomic_store_relaxed(&count->count, value); +-} +- +-static inline uint64_t +-atomic_count_inc64(atomic_uint64_t *counter) +-{ +- uint64_t old; +- +- atomic_add_relaxed(counter, 1ull, &old); +- +- return old; +-} +- +-static inline uint64_t +-atomic_count_dec64(atomic_uint64_t *counter) +-{ +- uint64_t old; +- +- atomic_sub_relaxed(counter, 1ull, &old); +- +- return old; +-} +- +-static inline uint64_t +-atomic_count_get64(atomic_uint64_t *counter) +-{ +- uint64_t value; +- +- atomic_read_relaxed(counter, &value); +- +- return value; +-} +- +-static inline void +-atomic_count_set64(atomic_uint64_t *counter, uint64_t value) +-{ +- atomic_store_relaxed(counter, value); +-} +- +-/* Reference count. */ +-struct ovs_refcount { +- atomic_uint count; +-}; +- +-/* Initializes 'refcount'. The reference count is initially 1. */ +-static inline void +-ovs_refcount_init(struct ovs_refcount *refcount) +-{ +- atomic_init(&refcount->count, 1u); +-} +- +-/* Increments 'refcount'. +- * +- * Does not provide a memory barrier, as the calling thread must have +- * protected access to the object already. */ +-static inline void +-ovs_refcount_ref(struct ovs_refcount *refcount) +-{ +- unsigned int old_refcount; +- +- atomic_add_explicit(&refcount->count, 1u, &old_refcount, +- memory_order_relaxed); +- ovs_assert(old_refcount > 0); +-} +- +-/* Decrements 'refcount' and returns the previous reference count. Often used +- * in this form: +- * +- * if (ovs_refcount_unref(&object->ref_cnt) == 1) { +- * ...uninitialize object... +- * free(object); +- * } +- * +- * Provides a release barrier making the preceding loads and stores to not be +- * reordered after the unref, and in case of the last reference provides also +- * an acquire barrier to keep all the following uninitialization from being +- * reordered before the atomic decrement operation. Together these synchronize +- * any concurrent unref operations between each other. */ +-static inline unsigned int +-ovs_refcount_unref(struct ovs_refcount *refcount) +-{ +- unsigned int old_refcount; +- +- atomic_sub_explicit(&refcount->count, 1u, &old_refcount, +- memory_order_release); +- ovs_assert(old_refcount > 0); +- if (old_refcount == 1) { +- /* 'memory_order_release' above means that there are no (reordered) +- * accesses to the protected object from any thread at this point. +- * An acquire barrier is needed to keep all subsequent access to the +- * object's memory from being reordered before the atomic operation +- * above. */ +- atomic_thread_fence(memory_order_acquire); +- } +- return old_refcount; +-} +- +-/* Reads and returns 'refcount_''s current reference count. +- * +- * Does not provide a memory barrier. +- * +- * Rarely useful. */ +-static inline unsigned int +-ovs_refcount_read(const struct ovs_refcount *refcount_) +-{ +- struct ovs_refcount *refcount +- = CONST_CAST(struct ovs_refcount *, refcount_); +- unsigned int count; +- +- atomic_read_explicit(&refcount->count, &count, memory_order_relaxed); +- return count; +-} +- +-/* Increments 'refcount', but only if it is non-zero. +- * +- * This may only be called for an object which is RCU protected during +- * this call. This implies that its possible destruction is postponed +- * until all current RCU threads quiesce. +- * +- * Returns false if the refcount was zero. In this case the object may +- * be safely accessed until the current thread quiesces, but no additional +- * references to the object may be taken. +- * +- * Does not provide a memory barrier, as the calling thread must have +- * RCU protected access to the object already. +- * +- * It is critical that we never increment a zero refcount to a +- * non-zero value, as whenever a refcount reaches the zero value, the +- * protected object may be irrevocably scheduled for deletion. */ +-static inline bool +-ovs_refcount_try_ref_rcu(struct ovs_refcount *refcount) +-{ +- unsigned int count; +- +- atomic_read_explicit(&refcount->count, &count, memory_order_relaxed); +- do { +- if (count == 0) { +- return false; +- } +- } while (!atomic_compare_exchange_weak_explicit(&refcount->count, &count, +- count + 1, +- memory_order_relaxed, +- memory_order_relaxed)); +- return true; +-} +- +-/* Decrements 'refcount' and returns the previous reference count. To +- * be used only when a memory barrier is already provided for the +- * protected object independently. +- * +- * For example: +- * +- * if (ovs_refcount_unref_relaxed(&object->ref_cnt) == 1) { +- * ovsrcu_postpone(destructor_function, object); +- * } +- * +- * Here RCU quiescing already provides a full memory barrier. No additional +- * barriers are needed here. +- * +- * Or: +- * +- * if (stp && ovs_refcount_unref_relaxed(&stp->ref_cnt) == 1) { +- * ovs_mutex_lock(&mutex); +- * ovs_list_remove(&stp->node); +- * ovs_mutex_unlock(&mutex); +- * free(stp->name); +- * free(stp); +- * } +- * +- * Here a mutex is used to guard access to all of 'stp' apart from +- * 'ref_cnt'. Hence all changes to 'stp' by other threads must be +- * visible when we get the mutex, and no access after the unlock can +- * be reordered to happen prior the lock operation. No additional +- * barriers are needed here. +- */ +-static inline unsigned int +-ovs_refcount_unref_relaxed(struct ovs_refcount *refcount) +-{ +- unsigned int old_refcount; +- +- atomic_sub_explicit(&refcount->count, 1u, &old_refcount, +- memory_order_relaxed); +- ovs_assert(old_refcount > 0); +- return old_refcount; +-} +- +-#endif /* ovs-atomic.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovs-atomic.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovs-atomic.h +@@ -0,0 +1,679 @@ ++/* ++ * Copyright (c) 2013, 2014, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVS_ATOMIC_H ++#define OVS_ATOMIC_H 1 ++ ++/* Atomic operations. ++ * ++ * This library implements atomic operations with an API based on the one ++ * defined in C11. It includes multiple implementations for compilers and ++ * libraries with varying degrees of built-in support for C11, including a ++ * fallback implementation for systems that have pthreads but no other support ++ * for atomics. ++ * ++ * This comment describes the common features of all the implementations. ++ * ++ * ++ * Types ++ * ===== ++ * ++ * The following atomic types are supported as typedefs for atomic versions of ++ * the listed ordinary types: ++ * ++ * ordinary type atomic version ++ * ------------------- ---------------------- ++ * bool atomic_bool ++ * ++ * char atomic_char ++ * signed char atomic_schar ++ * unsigned char atomic_uchar ++ * ++ * short atomic_short ++ * unsigned short atomic_ushort ++ * ++ * int atomic_int ++ * unsigned int atomic_uint ++ * ++ * long atomic_long ++ * unsigned long atomic_ulong ++ * ++ * long long atomic_llong ++ * unsigned long long atomic_ullong ++ * ++ * size_t atomic_size_t ++ * ptrdiff_t atomic_ptrdiff_t ++ * ++ * intmax_t atomic_intmax_t ++ * uintmax_t atomic_uintmax_t ++ * ++ * intptr_t atomic_intptr_t ++ * uintptr_t atomic_uintptr_t ++ * ++ * uint8_t atomic_uint8_t (*) ++ * uint16_t atomic_uint16_t (*) ++ * uint32_t atomic_uint32_t (*) ++ * int8_t atomic_int8_t (*) ++ * int16_t atomic_int16_t (*) ++ * int32_t atomic_int32_t (*) ++ * uint64_t atomic_uint64_t (*) ++ * int64_t atomic_int64_t (*) ++ * ++ * (*) Not specified by C11. ++ * ++ * Atomic types may also be obtained via ATOMIC(TYPE), e.g. ATOMIC(void *). ++ * Only basic integer types and pointer types can be made atomic this way, ++ * e.g. atomic structs are not supported. ++ * ++ * The atomic version of a type doesn't necessarily have the same size or ++ * representation as the ordinary version; for example, atomic_int might be a ++ * typedef for a struct. The range of an atomic type does match the range of ++ * the corresponding ordinary type. ++ * ++ * C11 says that one may use the _Atomic keyword in place of the typedef name, ++ * e.g. "_Atomic int" instead of "atomic_int". This library doesn't support ++ * that. ++ * ++ * ++ * Life Cycle ++ * ========== ++ * ++ * To initialize an atomic variable at its point of definition, use ++ * ATOMIC_VAR_INIT: ++ * ++ * static atomic_int ai = ATOMIC_VAR_INIT(123); ++ * ++ * To initialize an atomic variable in code, use atomic_init(): ++ * ++ * static atomic_int ai; ++ * ... ++ * atomic_init(&ai, 123); ++ * ++ * ++ * Barriers ++ * ======== ++ * ++ * enum memory_order specifies the strictness of a memory barrier. It has the ++ * following values: ++ * ++ * memory_order_relaxed: ++ * ++ * Only atomicity is provided, does not imply any memory ordering with ++ * respect to any other variable (atomic or not). Relaxed accesses to ++ * the same atomic variable will be performed in the program order. ++ * The compiler and CPU are free to move memory accesses to other ++ * variables past the atomic operation. ++ * ++ * memory_order_consume: ++ * ++ * Memory accesses with data dependency on the result of the consume ++ * operation (atomic_read_explicit, or a load operation preceding a ++ * atomic_thread_fence) will not be moved prior to the consume ++ * barrier. Non-data-dependent loads and stores can be reordered to ++ * happen before the consume barrier. ++ * ++ * RCU is the prime example of the use of the consume barrier: The ++ * consume barrier guarantees that reads from a RCU protected object ++ * are performed after the RCU protected pointer is read. A ++ * corresponding release barrier is used to store the modified RCU ++ * protected pointer after the RCU protected object has been fully ++ * constructed. The synchronization between these barriers prevents ++ * the RCU "consumer" from seeing uninitialized data. ++ * ++ * May not be used with atomic_store_explicit(), as consume semantics ++ * applies only to atomic loads. ++ * ++ * memory_order_acquire: ++ * ++ * Memory accesses after an acquire barrier cannot be moved before the ++ * barrier. Memory accesses before an acquire barrier *can* be moved ++ * after it. ++ * ++ * An atomic_thread_fence with memory_order_acquire does not have a ++ * load operation by itself; it prevents all following memory accesses ++ * from moving prior to preceding loads. ++ * ++ * May not be used with atomic_store_explicit(), as acquire semantics ++ * applies only to atomic loads. ++ * ++ * memory_order_release: ++ * ++ * Memory accesses before a release barrier cannot be moved after the ++ * barrier. Memory accesses after a release barrier *can* be moved ++ * before it. ++ * ++ * An atomic_thread_fence with memory_order_release does not have a ++ * store operation by itself; it prevents all preceding memory accesses ++ * from moving past subsequent stores. ++ * ++ * May not be used with atomic_read_explicit(), as release semantics ++ * applies only to atomic stores. ++ * ++ * memory_order_acq_rel: ++ * ++ * Memory accesses cannot be moved across an acquire-release barrier in ++ * either direction. ++ * ++ * May only be used with atomic read-modify-write operations, as both ++ * load and store operation is required for acquire-release semantics. ++ * ++ * An atomic_thread_fence with memory_order_acq_rel does not have ++ * either load or store operation by itself; it prevents all following ++ * memory accesses from moving prior to preceding loads and all ++ * preceding memory accesses from moving past subsequent stores. ++ * ++ * memory_order_seq_cst: ++ * ++ * Prevents movement of memory accesses like an acquire-release barrier, ++ * but whereas acquire-release synchronizes cooperating threads (using ++ * the same atomic variable), sequential-consistency synchronizes the ++ * whole system, providing a total order for stores on all atomic ++ * variables. ++ * ++ * OVS atomics require the memory_order to be passed as a compile-time constant ++ * value, as some compiler implementations may perform poorly if the memory ++ * order parameter is passed in as a run-time value. ++ * ++ * The following functions insert explicit barriers. Most of the other atomic ++ * functions also include barriers. ++ * ++ * void atomic_thread_fence(memory_order order); ++ * ++ * Inserts a barrier of the specified type. ++ * ++ * For memory_order_relaxed, this is a no-op. ++ * ++ * void atomic_signal_fence(memory_order order); ++ * ++ * Inserts a barrier of the specified type, but only with respect to ++ * signal handlers in the same thread as the barrier. This is ++ * basically a compiler optimization barrier, except for ++ * memory_order_relaxed, which is a no-op. ++ * ++ * ++ * Atomic Operations ++ * ================= ++ * ++ * In this section, A is an atomic type and C is the corresponding non-atomic ++ * type. ++ * ++ * The "store", "exchange", and "compare_exchange" primitives match C11: ++ * ++ * void atomic_store(A *object, C value); ++ * void atomic_store_explicit(A *object, C value, memory_order); ++ * ++ * Atomically stores 'value' into '*object', respecting the given ++ * memory order (or memory_order_seq_cst for atomic_store()). ++ * ++ * bool atomic_compare_exchange_strong(A *object, C *expected, C desired); ++ * bool atomic_compare_exchange_weak(A *object, C *expected, C desired); ++ * bool atomic_compare_exchange_strong_explicit(A *object, C *expected, ++ * C desired, ++ * memory_order success, ++ * memory_order failure); ++ * bool atomic_compare_exchange_weak_explicit(A *object, C *expected, ++ * C desired, ++ * memory_order success, ++ * memory_order failure); ++ * ++ * Atomically loads '*object' and compares it with '*expected' and if ++ * equal, stores 'desired' into '*object' (an atomic read-modify-write ++ * operation) and returns true, and if non-equal, stores the actual ++ * value of '*object' into '*expected' (an atomic load operation) and ++ * returns false. The memory order for the successful case (atomic ++ * read-modify-write operation) is 'success', and for the unsuccessful ++ * case (atomic load operation) 'failure'. 'failure' may not be ++ * stronger than 'success'. ++ * ++ * The weak forms may fail (returning false) also when '*object' equals ++ * '*expected'. The strong form can be implemented by the weak form in ++ * a loop. Some platforms can implement the weak form more ++ * efficiently, so it should be used if the application will need to ++ * loop anyway. ++ * ++ * C atomic_exchange(A *object, C desired); ++ * C atomic_exchange_explicit(A *object, C desired, memory_order); ++ * ++ * Atomically stores 'desired' into '*object', returning the value ++ * previously held. ++ * ++ * The following primitives differ from the C11 ones (and have different names) ++ * because there does not appear to be a way to implement the standard ++ * primitives in standard C: ++ * ++ * void atomic_read(A *src, C *dst); ++ * void atomic_read_explicit(A *src, C *dst, memory_order); ++ * ++ * Atomically loads a value from 'src', writing the value read into ++ * '*dst', respecting the given memory order (or memory_order_seq_cst ++ * for atomic_read()). ++ * ++ * void atomic_add(A *rmw, C arg, C *orig); ++ * void atomic_sub(A *rmw, C arg, C *orig); ++ * void atomic_or(A *rmw, C arg, C *orig); ++ * void atomic_xor(A *rmw, C arg, C *orig); ++ * void atomic_and(A *rmw, C arg, C *orig); ++ * void atomic_add_explicit(A *rmw, C arg, C *orig, memory_order); ++ * void atomic_sub_explicit(A *rmw, C arg, C *orig, memory_order); ++ * void atomic_or_explicit(A *rmw, C arg, C *orig, memory_order); ++ * void atomic_xor_explicit(A *rmw, C arg, C *orig, memory_order); ++ * void atomic_and_explicit(A *rmw, C arg, C *orig, memory_order); ++ * ++ * Atomically applies the given operation, with 'arg' as the second ++ * operand, to '*rmw', and stores the original value of '*rmw' into ++ * '*orig', respecting the given memory order (or memory_order_seq_cst ++ * if none is specified). ++ * ++ * The results are similar to those that would be obtained with +=, -=, ++ * |=, ^=, or |= on non-atomic types. ++ * ++ * ++ * atomic_flag ++ * =========== ++ * ++ * atomic_flag is a typedef for a type with two states, set and clear, that ++ * provides atomic test-and-set functionality. ++ * ++ * ++ * Life Cycle ++ * ---------- ++ * ++ * ATOMIC_FLAG_INIT is an initializer for atomic_flag. The initial state is ++ * "clear". ++ * ++ * An atomic_flag may also be initialized at runtime with atomic_flag_clear(). ++ * ++ * ++ * Operations ++ * ---------- ++ * ++ * The following functions are available. ++ * ++ * bool atomic_flag_test_and_set(atomic_flag *object) ++ * bool atomic_flag_test_and_set_explicit(atomic_flag *object, ++ * memory_order); ++ * ++ * Atomically sets '*object', respecting the given memory order (or ++ * memory_order_seq_cst for atomic_flag_test_and_set()). Returns the ++ * previous value of the flag (false for clear, true for set). ++ * ++ * void atomic_flag_clear(atomic_flag *object); ++ * void atomic_flag_clear_explicit(atomic_flag *object, memory_order); ++ * ++ * Atomically clears '*object', respecting the given memory order (or ++ * memory_order_seq_cst for atomic_flag_clear()). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "openvswitch/compiler.h" +#include "internal/util.h" + +#ifdef __cplusplus +extern "C" { +#endif - - #define IN_OVS_ATOMIC_H - #if __CHECKER__ - /* sparse doesn't understand some GCC extensions we use. */ -- #include "ovs-atomic-pthreads.h" ++ ++#define IN_OVS_ATOMIC_H ++ #if __CHECKER__ ++ /* sparse doesn't understand some GCC extensions we use. */ + #include "internal/ovs-atomic-pthreads.h" - #elif __has_extension(c_atomic) -- #include "ovs-atomic-clang.h" ++ #elif __has_extension(c_atomic) + #include "internal/ovs-atomic-clang.h" - #elif HAVE_ATOMIC && __cplusplus >= 201103L -- #include "ovs-atomic-c++.h" ++ #elif HAVE_ATOMIC && __cplusplus >= 201103L + #include "internal/ovs-atomic-c++.h" - #elif HAVE_STDATOMIC_H && !defined(__cplusplus) -- #include "ovs-atomic-c11.h" ++ #elif HAVE_STDATOMIC_H && !defined(__cplusplus) + #include "internal/ovs-atomic-c11.h" - #elif __GNUC__ >= 5 && !defined(__cplusplus) - #error "GCC 5+ should have " - #elif __GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 7) -- #include "ovs-atomic-gcc4.7+.h" ++ #elif __GNUC__ >= 5 && !defined(__cplusplus) ++ #error "GCC 5+ should have " ++ #elif __GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 7) + #include "internal/ovs-atomic-gcc4.7+.h" - #elif __GNUC__ && defined(__x86_64__) -- #include "ovs-atomic-x86_64.h" ++ #elif __GNUC__ && defined(__x86_64__) + #include "internal/ovs-atomic-x86_64.h" - #elif __GNUC__ && defined(__i386__) -- #include "ovs-atomic-i586.h" ++ #elif __GNUC__ && defined(__i386__) + #include "internal/ovs-atomic-i586.h" - #elif HAVE_GCC4_ATOMICS -- #include "ovs-atomic-gcc4+.h" ++ #elif HAVE_GCC4_ATOMICS + #include "internal/ovs-atomic-gcc4+.h" - #elif _MSC_VER -- #include "ovs-atomic-msvc.h" ++ #elif _MSC_VER + #include "internal/ovs-atomic-msvc.h" - #else - /* ovs-atomic-pthreads implementation is provided for portability. - * It might be too slow for real use because Open vSwitch is - * optimized for platforms where real atomic ops are available. */ -- #include "ovs-atomic-pthreads.h" ++ #else ++ /* ovs-atomic-pthreads implementation is provided for portability. ++ * It might be too slow for real use because Open vSwitch is ++ * optimized for platforms where real atomic ops are available. */ + #include "internal/ovs-atomic-pthreads.h" - #endif - #undef IN_OVS_ATOMIC_H - -@@ -668,4 +672,8 @@ ovs_refcount_unref_relaxed(struct ovs_refcount *refcount) - return old_refcount; - } - ++ #endif ++#undef IN_OVS_ATOMIC_H ++ ++#ifndef OMIT_STANDARD_ATOMIC_TYPES ++typedef ATOMIC(bool) atomic_bool; ++ ++typedef ATOMIC(char) atomic_char; ++typedef ATOMIC(signed char) atomic_schar; ++typedef ATOMIC(unsigned char) atomic_uchar; ++ ++typedef ATOMIC(short) atomic_short; ++typedef ATOMIC(unsigned short) atomic_ushort; ++ ++typedef ATOMIC(int) atomic_int; ++typedef ATOMIC(unsigned int) atomic_uint; ++ ++typedef ATOMIC(long) atomic_long; ++typedef ATOMIC(unsigned long) atomic_ulong; ++ ++typedef ATOMIC(long long) atomic_llong; ++typedef ATOMIC(unsigned long long) atomic_ullong; ++ ++typedef ATOMIC(size_t) atomic_size_t; ++typedef ATOMIC(ptrdiff_t) atomic_ptrdiff_t; ++ ++typedef ATOMIC(intmax_t) atomic_intmax_t; ++typedef ATOMIC(uintmax_t) atomic_uintmax_t; ++ ++typedef ATOMIC(intptr_t) atomic_intptr_t; ++typedef ATOMIC(uintptr_t) atomic_uintptr_t; ++#endif /* !OMIT_STANDARD_ATOMIC_TYPES */ ++ ++/* Nonstandard atomic types. */ ++typedef ATOMIC(uint8_t) atomic_uint8_t; ++typedef ATOMIC(uint16_t) atomic_uint16_t; ++typedef ATOMIC(uint32_t) atomic_uint32_t; ++typedef ATOMIC(uint64_t) atomic_uint64_t; ++ ++typedef ATOMIC(int8_t) atomic_int8_t; ++typedef ATOMIC(int16_t) atomic_int16_t; ++typedef ATOMIC(int32_t) atomic_int32_t; ++typedef ATOMIC(int64_t) atomic_int64_t; ++ ++/* Relaxed atomic operations. ++ * ++ * When an operation on an atomic variable is not expected to synchronize ++ * with operations on other (atomic or non-atomic) variables, no memory ++ * barriers are needed and the relaxed memory ordering can be used. These ++ * macros make such uses less daunting, but not invisible. */ ++#define atomic_store_relaxed(VAR, VALUE) \ ++ atomic_store_explicit(VAR, VALUE, memory_order_relaxed) ++#define atomic_read_relaxed(VAR, DST) \ ++ atomic_read_explicit(VAR, DST, memory_order_relaxed) ++#define atomic_compare_exchange_strong_relaxed(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_relaxed, \ ++ memory_order_relaxed) ++#define atomic_compare_exchange_weak_relaxed(DST, EXP, SRC) \ ++ atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ ++ memory_order_relaxed, \ ++ memory_order_relaxed) ++#define atomic_add_relaxed(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_relaxed) ++#define atomic_sub_relaxed(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_relaxed) ++#define atomic_or_relaxed(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_relaxed) ++#define atomic_xor_relaxed(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_relaxed) ++#define atomic_and_relaxed(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_relaxed) ++#define atomic_flag_test_and_set_relaxed(FLAG) \ ++ atomic_flag_test_and_set_explicit(FLAG, memory_order_relaxed) ++#define atomic_flag_clear_relaxed(FLAG) \ ++ atomic_flag_clear_explicit(FLAG, memory_order_relaxed) ++ ++/* A simplified atomic count. Does not provide any synchronization with any ++ * other variables. ++ * ++ * Typically a counter is not used to synchronize the state of any other ++ * variables (with the notable exception of reference count, below). ++ * This abstraction releaves the user from the memory order considerations, ++ * and may make the code easier to read. ++ * ++ * We only support the unsigned int counters, as those are the most common. */ ++typedef struct atomic_count { ++ atomic_uint count; ++} atomic_count; ++ ++#define ATOMIC_COUNT_INIT(VALUE) { VALUE } ++ ++static inline void ++atomic_count_init(atomic_count *count, unsigned int value) ++{ ++ atomic_init(&count->count, value); ++} ++ ++static inline unsigned int ++atomic_count_inc(atomic_count *count) ++{ ++ unsigned int old; ++ ++ atomic_add_relaxed(&count->count, 1u, &old); ++ ++ return old; ++} ++ ++static inline unsigned int ++atomic_count_dec(atomic_count *count) ++{ ++ unsigned int old; ++ ++ atomic_sub_relaxed(&count->count, 1u, &old); ++ ++ return old; ++} ++ ++static inline unsigned int ++atomic_count_get(atomic_count *count) ++{ ++ unsigned int value; ++ ++ atomic_read_relaxed(&count->count, &value); ++ ++ return value; ++} ++ ++static inline void ++atomic_count_set(atomic_count *count, unsigned int value) ++{ ++ atomic_store_relaxed(&count->count, value); ++} ++ ++static inline uint64_t ++atomic_count_inc64(atomic_uint64_t *counter) ++{ ++ uint64_t old; ++ ++ atomic_add_relaxed(counter, 1ull, &old); ++ ++ return old; ++} ++ ++static inline uint64_t ++atomic_count_dec64(atomic_uint64_t *counter) ++{ ++ uint64_t old; ++ ++ atomic_sub_relaxed(counter, 1ull, &old); ++ ++ return old; ++} ++ ++static inline uint64_t ++atomic_count_get64(atomic_uint64_t *counter) ++{ ++ uint64_t value; ++ ++ atomic_read_relaxed(counter, &value); ++ ++ return value; ++} ++ ++static inline void ++atomic_count_set64(atomic_uint64_t *counter, uint64_t value) ++{ ++ atomic_store_relaxed(counter, value); ++} ++ ++/* Reference count. */ ++struct ovs_refcount { ++ atomic_uint count; ++}; ++ ++/* Initializes 'refcount'. The reference count is initially 1. */ ++static inline void ++ovs_refcount_init(struct ovs_refcount *refcount) ++{ ++ atomic_init(&refcount->count, 1u); ++} ++ ++/* Increments 'refcount'. ++ * ++ * Does not provide a memory barrier, as the calling thread must have ++ * protected access to the object already. */ ++static inline void ++ovs_refcount_ref(struct ovs_refcount *refcount) ++{ ++ unsigned int old_refcount; ++ ++ atomic_add_explicit(&refcount->count, 1u, &old_refcount, ++ memory_order_relaxed); ++ ovs_assert(old_refcount > 0); ++} ++ ++/* Decrements 'refcount' and returns the previous reference count. Often used ++ * in this form: ++ * ++ * if (ovs_refcount_unref(&object->ref_cnt) == 1) { ++ * ...uninitialize object... ++ * free(object); ++ * } ++ * ++ * Provides a release barrier making the preceding loads and stores to not be ++ * reordered after the unref, and in case of the last reference provides also ++ * an acquire barrier to keep all the following uninitialization from being ++ * reordered before the atomic decrement operation. Together these synchronize ++ * any concurrent unref operations between each other. */ ++static inline unsigned int ++ovs_refcount_unref(struct ovs_refcount *refcount) ++{ ++ unsigned int old_refcount; ++ ++ atomic_sub_explicit(&refcount->count, 1u, &old_refcount, ++ memory_order_release); ++ ovs_assert(old_refcount > 0); ++ if (old_refcount == 1) { ++ /* 'memory_order_release' above means that there are no (reordered) ++ * accesses to the protected object from any thread at this point. ++ * An acquire barrier is needed to keep all subsequent access to the ++ * object's memory from being reordered before the atomic operation ++ * above. */ ++ atomic_thread_fence(memory_order_acquire); ++ } ++ return old_refcount; ++} ++ ++/* Reads and returns 'refcount_''s current reference count. ++ * ++ * Does not provide a memory barrier. ++ * ++ * Rarely useful. */ ++static inline unsigned int ++ovs_refcount_read(const struct ovs_refcount *refcount_) ++{ ++ struct ovs_refcount *refcount ++ = CONST_CAST(struct ovs_refcount *, refcount_); ++ unsigned int count; ++ ++ atomic_read_explicit(&refcount->count, &count, memory_order_relaxed); ++ return count; ++} ++ ++/* Increments 'refcount', but only if it is non-zero. ++ * ++ * This may only be called for an object which is RCU protected during ++ * this call. This implies that its possible destruction is postponed ++ * until all current RCU threads quiesce. ++ * ++ * Returns false if the refcount was zero. In this case the object may ++ * be safely accessed until the current thread quiesces, but no additional ++ * references to the object may be taken. ++ * ++ * Does not provide a memory barrier, as the calling thread must have ++ * RCU protected access to the object already. ++ * ++ * It is critical that we never increment a zero refcount to a ++ * non-zero value, as whenever a refcount reaches the zero value, the ++ * protected object may be irrevocably scheduled for deletion. */ ++static inline bool ++ovs_refcount_try_ref_rcu(struct ovs_refcount *refcount) ++{ ++ unsigned int count; ++ ++ atomic_read_explicit(&refcount->count, &count, memory_order_relaxed); ++ do { ++ if (count == 0) { ++ return false; ++ } ++ } while (!atomic_compare_exchange_weak_explicit(&refcount->count, &count, ++ count + 1, ++ memory_order_relaxed, ++ memory_order_relaxed)); ++ return true; ++} ++ ++/* Decrements 'refcount' and returns the previous reference count. To ++ * be used only when a memory barrier is already provided for the ++ * protected object independently. ++ * ++ * For example: ++ * ++ * if (ovs_refcount_unref_relaxed(&object->ref_cnt) == 1) { ++ * ovsrcu_postpone(destructor_function, object); ++ * } ++ * ++ * Here RCU quiescing already provides a full memory barrier. No additional ++ * barriers are needed here. ++ * ++ * Or: ++ * ++ * if (stp && ovs_refcount_unref_relaxed(&stp->ref_cnt) == 1) { ++ * ovs_mutex_lock(&mutex); ++ * ovs_list_remove(&stp->node); ++ * ovs_mutex_unlock(&mutex); ++ * free(stp->name); ++ * free(stp); ++ * } ++ * ++ * Here a mutex is used to guard access to all of 'stp' apart from ++ * 'ref_cnt'. Hence all changes to 'stp' by other threads must be ++ * visible when we get the mutex, and no access after the unlock can ++ * be reordered to happen prior the lock operation. No additional ++ * barriers are needed here. ++ */ ++static inline unsigned int ++ovs_refcount_unref_relaxed(struct ovs_refcount *refcount) ++{ ++ unsigned int old_refcount; ++ ++ atomic_sub_explicit(&refcount->count, 1u, &old_refcount, ++ memory_order_relaxed); ++ ovs_assert(old_refcount > 0); ++ return old_refcount; ++} ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovs-atomic.h */ -diff --git a/lib/ovs-numa.h b/include/openvswitch/ovs-numa.h -similarity index 96% -rename from lib/ovs-numa.h -rename to include/openvswitch/ovs-numa.h -index 2030bdb64..06661a03e 100644 ---- a/lib/ovs-numa.h -+++ b/include/openvswitch/ovs-numa.h -@@ -28,6 +28,10 @@ - - #define MAX_NUMA_NODES 128 - ++#endif /* ovs-atomic.h */ +Index: openvswitch-2.17.2/lib/ovs-numa.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-numa.h ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Copyright (c) 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVS_NUMA_H +-#define OVS_NUMA_H 1 +- +-#include +-#include +- +-#include "openvswitch/compiler.h" +-#include "openvswitch/hmap.h" +- +-#define OVS_CORE_UNSPEC INT_MAX +-#define OVS_NUMA_UNSPEC INT_MAX +- +-#define MAX_NUMA_NODES 128 +- +-/* Dump of a list of 'struct ovs_numa_info'. */ +-struct ovs_numa_dump { +- struct hmap cores; +- struct hmap numas; +-}; +- +-/* A numa_id - core_id pair. */ +-struct ovs_numa_info_core { +- struct hmap_node hmap_node; +- int numa_id; +- unsigned core_id; +-}; +- +-/* A numa node. */ +-struct ovs_numa_info_numa { +- struct hmap_node hmap_node; +- int numa_id; +- size_t n_cores; +-}; +- +-void ovs_numa_init(void); +-void ovs_numa_set_dummy(const char *config); +-bool ovs_numa_numa_id_is_valid(int numa_id); +-bool ovs_numa_core_id_is_valid(unsigned core_id); +-int ovs_numa_get_n_numas(void); +-int ovs_numa_get_n_cores(void); +-int ovs_numa_get_numa_id(unsigned core_id); +-int ovs_numa_get_n_cores_on_numa(int numa_id); +-struct ovs_numa_dump *ovs_numa_dump_cores_on_numa(int numa_id); +-struct ovs_numa_dump *ovs_numa_dump_cores_with_cmask(const char *cmask); +-struct ovs_numa_dump *ovs_numa_dump_n_cores_per_numa(int n); +-bool ovs_numa_dump_contains_core(const struct ovs_numa_dump *, +- int numa_id, unsigned core_id); +-size_t ovs_numa_dump_count(const struct ovs_numa_dump *); +-struct ovs_numa_dump * ovs_numa_thread_getaffinity_dump(void); +-int ovs_numa_thread_setaffinity_dump(const struct ovs_numa_dump *); +-void ovs_numa_dump_destroy(struct ovs_numa_dump *); +-int ovs_numa_thread_setaffinity_core(unsigned core_id); +- +-#define FOR_EACH_CORE_ON_DUMP(ITER, DUMP) \ +- HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores) +- +-#define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP) \ +- HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas) +- +-#endif /* ovs-numa.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovs-numa.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovs-numa.h +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVS_NUMA_H ++#define OVS_NUMA_H 1 ++ ++#include ++#include ++ ++#include "openvswitch/compiler.h" ++#include "openvswitch/hmap.h" ++ ++#define OVS_CORE_UNSPEC INT_MAX ++#define OVS_NUMA_UNSPEC INT_MAX ++ ++#define MAX_NUMA_NODES 128 ++ +#ifdef __cplusplus +extern "C" { +#endif + - /* Dump of a list of 'struct ovs_numa_info'. */ - struct ovs_numa_dump { - struct hmap cores; -@@ -73,4 +77,8 @@ int ovs_numa_thread_setaffinity_core(unsigned core_id); - #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP) \ - HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas) - ++/* Dump of a list of 'struct ovs_numa_info'. */ ++struct ovs_numa_dump { ++ struct hmap cores; ++ struct hmap numas; ++}; ++ ++/* A numa_id - core_id pair. */ ++struct ovs_numa_info_core { ++ struct hmap_node hmap_node; ++ int numa_id; ++ unsigned core_id; ++}; ++ ++/* A numa node. */ ++struct ovs_numa_info_numa { ++ struct hmap_node hmap_node; ++ int numa_id; ++ size_t n_cores; ++}; ++ ++void ovs_numa_init(void); ++void ovs_numa_set_dummy(const char *config); ++bool ovs_numa_numa_id_is_valid(int numa_id); ++bool ovs_numa_core_id_is_valid(unsigned core_id); ++int ovs_numa_get_n_numas(void); ++int ovs_numa_get_n_cores(void); ++int ovs_numa_get_numa_id(unsigned core_id); ++int ovs_numa_get_n_cores_on_numa(int numa_id); ++struct ovs_numa_dump *ovs_numa_dump_cores_on_numa(int numa_id); ++struct ovs_numa_dump *ovs_numa_dump_cores_with_cmask(const char *cmask); ++struct ovs_numa_dump *ovs_numa_dump_n_cores_per_numa(int n); ++bool ovs_numa_dump_contains_core(const struct ovs_numa_dump *, ++ int numa_id, unsigned core_id); ++size_t ovs_numa_dump_count(const struct ovs_numa_dump *); ++struct ovs_numa_dump * ovs_numa_thread_getaffinity_dump(void); ++int ovs_numa_thread_setaffinity_dump(const struct ovs_numa_dump *); ++void ovs_numa_dump_destroy(struct ovs_numa_dump *); ++int ovs_numa_thread_setaffinity_core(unsigned core_id); ++ ++#define FOR_EACH_CORE_ON_DUMP(ITER, DUMP) \ ++ HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores) ++ ++#define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP) \ ++ HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas) ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovs-numa.h */ -diff --git a/lib/ovs-rcu.h b/include/openvswitch/ovs-rcu.h -similarity index 99% -rename from lib/ovs-rcu.h -rename to include/openvswitch/ovs-rcu.h -index 5e31181d8..9eee05659 100644 ---- a/lib/ovs-rcu.h -+++ b/include/openvswitch/ovs-rcu.h -@@ -158,7 +158,11 @@ - */ - - #include "openvswitch/compiler.h" ++#endif /* ovs-numa.h */ +Index: openvswitch-2.17.2/lib/ovs-rcu.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-rcu.h ++++ /dev/null +@@ -1,328 +0,0 @@ +-/* +- * Copyright (c) 2014, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVS_RCU_H +-#define OVS_RCU_H 1 +- +-/* Read-Copy-Update (RCU) +- * ====================== +- * +- * Introduction +- * ------------ +- * +- * Atomic pointer access makes it pretty easy to implement lock-free +- * algorithms. There is one big problem, though: when a writer updates a +- * pointer to point to a new data structure, some thread might be reading the +- * old version, and there's no convenient way to free the old version when all +- * threads are done with the old version. +- * +- * The function ovsrcu_postpone() solves that problem. The function pointer +- * passed in as its argument is called only after all threads are done with old +- * versions of data structures. The function callback frees an old version of +- * data no longer in use. This technique is called "read-copy-update", or RCU +- * for short. +- * +- * +- * Details +- * ------- +- * +- * A "quiescent state" is a time at which a thread holds no pointers to memory +- * that is managed by RCU; that is, when the thread is known not to reference +- * memory that might be an old version of some object freed via RCU. For +- * example, poll_block() includes a quiescent state. +- * +- * The following functions manage the recognition of quiescent states: +- * +- * void ovsrcu_quiesce(void) +- * +- * Recognizes a momentary quiescent state in the current thread. +- * +- * void ovsrcu_quiesce_start(void) +- * void ovsrcu_quiesce_end(void) +- * +- * Brackets a time period during which the current thread is quiescent. +- * +- * A newly created thread is initially active, not quiescent. When a process +- * becomes multithreaded, the main thread becomes active, not quiescent. +- * +- * When a quiescient state has occurred in every thread, we say that a "grace +- * period" has occurred. Following a grace period, all of the callbacks +- * postponed before the start of the grace period MAY be invoked. OVS takes +- * care of this automatically through the RCU mechanism: while a process still +- * has only a single thread, it invokes the postponed callbacks directly from +- * ovsrcu_quiesce() and ovsrcu_quiesce_start(); after additional threads have +- * been created, it creates an extra helper thread to invoke callbacks. +- * +- * Please note that while a postponed function call is guaranteed to happen +- * after the next time all participating threads have quiesced at least once, +- * there is no quarantee that all postponed functions are called as early as +- * possible, or that the functions postponed by different threads would be +- * called in the order the registrations took place. In particular, even if +- * two threads provably postpone a function each in a specific order, the +- * postponed functions may still be called in the opposite order, depending on +- * the timing of when the threads call ovsrcu_quiesce(), how many functions +- * they postpone, and when the ovs-rcu thread happens to grab the functions to +- * be called. +- * +- * All functions postponed by a single thread are guaranteed to execute in the +- * order they were postponed, however. +- * +- * Usage +- * ----- +- * +- * Use OVSRCU_TYPE(TYPE) to declare a pointer to RCU-protected data, e.g. the +- * following declares an RCU-protected "struct flow *" named flowp: +- * +- * OVSRCU_TYPE(struct flow *) flowp; +- * +- * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the +- * pointer variable declared above: +- * +- * struct flow *flow = ovsrcu_get(struct flow *, &flowp); +- * +- * If the pointer variable is currently protected against change (because +- * the current thread holds a mutex that protects it), ovsrcu_get_protected() +- * may be used instead. Only on the Alpha architecture is this likely to +- * generate different code, but it may be useful documentation. +- * +- * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other +- * compilers will merrily carry along accepting the wrong type.) +- * +- * Use ovsrcu_set() to write an RCU-protected pointer and ovsrcu_postpone() to +- * free the previous data. ovsrcu_set_hidden() can be used on RCU protected +- * data not visible to any readers yet, but will be made visible by a later +- * ovsrcu_set(). ovsrcu_init() can be used to initialize RCU pointers when +- * no readers are yet executing. If more than one thread can write the +- * pointer, then some form of external synchronization, e.g. a mutex, is +- * needed to prevent writers from interfering with one another. For example, +- * to write the pointer variable declared above while safely freeing the old +- * value: +- * +- * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; +- * +- * OVSRCU_TYPE(struct flow *) flowp; +- * +- * void +- * change_flow(struct flow *new_flow) +- * { +- * ovs_mutex_lock(&mutex); +- * ovsrcu_postpone(free, +- * ovsrcu_get_protected(struct flow *, &flowp)); +- * ovsrcu_set(&flowp, new_flow); +- * ovs_mutex_unlock(&mutex); +- * } +- * +- * In some rare cases an object may not be addressable with a pointer, but only +- * through an array index (e.g. because it's provided by another library). It +- * is still possible to have RCU semantics by using the ovsrcu_index type. +- * +- * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; +- * +- * ovsrcu_index port_id; +- * +- * void tx() +- * { +- * int id = ovsrcu_index_get(&port_id); +- * if (id == -1) { +- * return; +- * } +- * port_tx(id); +- * } +- * +- * void delete() +- * { +- * int id; +- * +- * ovs_mutex_lock(&mutex); +- * id = ovsrcu_index_get_protected(&port_id); +- * ovsrcu_index_set(&port_id, -1); +- * ovs_mutex_unlock(&mutex); +- * +- * ovsrcu_synchronize(); +- * port_delete(id); +- * } +- * +- * Use ovsrcu_barrier() to wait for all the outstanding RCU callbacks to +- * finish. This is useful when you have to destroy some resources however +- * these resources are referenced in the outstanding RCU callbacks. +- * +- * void rcu_cb(void *A) { +- * do_something(A); +- * } +- * +- * void destroy_A() { +- * ovsrcu_postpone(rcu_cb, A); // will use A later +- * ovsrcu_barrier(); // wait for rcu_cb done +- * do_destroy_A(); // free A +- * } +- */ +- +-#include "openvswitch/compiler.h" -#include "ovs-atomic.h" +- +-#if __GNUC__ +-#define OVSRCU_TYPE(TYPE) struct { ATOMIC(TYPE) p; } +-#define OVSRCU_INITIALIZER(VALUE) { ATOMIC_VAR_INIT(VALUE) } +-#define ovsrcu_get__(TYPE, VAR, ORDER) \ +- ({ \ +- TYPE value__; \ +- typeof(VAR) ovsrcu_var = (VAR); \ +- \ +- atomic_read_explicit(CONST_CAST(ATOMIC(TYPE) *, &ovsrcu_var->p), \ +- &value__, ORDER); \ +- \ +- value__; \ +- }) +-#define ovsrcu_get(TYPE, VAR) \ +- ovsrcu_get__(TYPE, VAR, memory_order_consume) +-#define ovsrcu_get_protected(TYPE, VAR) \ +- ovsrcu_get__(TYPE, VAR, memory_order_relaxed) +- +-/* 'VALUE' may be an atomic operation, which must be evaluated before +- * any of the body of the atomic_store_explicit. Since the type of +- * 'VAR' is not fixed, we cannot use an inline function to get +- * function semantics for this. */ +-#define ovsrcu_set__(VAR, VALUE, ORDER) \ +- ({ \ +- typeof(VAR) ovsrcu_var = (VAR); \ +- typeof(VALUE) ovsrcu_value = (VALUE); \ +- memory_order ovsrcu_order = (ORDER); \ +- \ +- atomic_store_explicit(&ovsrcu_var->p, ovsrcu_value, ovsrcu_order); \ +- (void *) 0; \ +- }) +-#else /* not GNU C */ +-struct ovsrcu_pointer { ATOMIC(void *) p; }; +-#define OVSRCU_TYPE(TYPE) struct ovsrcu_pointer +-#define OVSRCU_INITIALIZER(VALUE) { ATOMIC_VAR_INIT(VALUE) } +-static inline void * +-ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) +-{ +- void *value; +- atomic_read_explicit(&CONST_CAST(struct ovsrcu_pointer *, pointer)->p, +- &value, order); +- return value; +-} +-#define ovsrcu_get(TYPE, VAR) \ +- CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_consume)) +-#define ovsrcu_get_protected(TYPE, VAR) \ +- CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_relaxed)) +- +-static inline void ovsrcu_set__(struct ovsrcu_pointer *pointer, +- const void *value, +- memory_order order) +-{ +- atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), order); +-} +-#endif +- +-/* Writes VALUE to the RCU-protected pointer whose address is VAR. +- * +- * Users require external synchronization (e.g. a mutex). See "Usage" above +- * for an example. */ +-#define ovsrcu_set(VAR, VALUE) \ +- ovsrcu_set__(VAR, VALUE, memory_order_release) +- +-/* This can be used for initializing RCU pointers before any readers can +- * see them. A later ovsrcu_set() needs to make the bigger structure this +- * is part of visible to the readers. */ +-#define ovsrcu_set_hidden(VAR, VALUE) \ +- ovsrcu_set__(VAR, VALUE, memory_order_relaxed) +- +-/* This can be used for initializing RCU pointers before any readers are +- * executing. */ +-#define ovsrcu_init(VAR, VALUE) atomic_init(&(VAR)->p, VALUE) +- +-/* Calls FUNCTION passing ARG as its pointer-type argument following the next +- * grace period. See "Usage" above for an example. */ +-void ovsrcu_postpone__(void (*function)(void *aux), void *aux); +-#define ovsrcu_postpone(FUNCTION, ARG) \ +- (/* Verify that ARG is appropriate for FUNCTION. */ \ +- (void) sizeof((FUNCTION)(ARG), 1), \ +- /* Verify that ARG is a pointer type. */ \ +- (void) sizeof(*(ARG)), \ +- ovsrcu_postpone__((void (*)(void *))(FUNCTION), ARG)) +- +-/* An array index protected by RCU semantics. This is an easier alternative to +- * an RCU protected pointer to a malloc'd int. */ +-typedef struct { atomic_int v; } ovsrcu_index; +- +-static inline int ovsrcu_index_get__(const ovsrcu_index *i, memory_order order) +-{ +- int ret; +- atomic_read_explicit(CONST_CAST(atomic_int *, &i->v), &ret, order); +- return ret; +-} +- +-/* Returns the index contained in 'i'. The returned value can be used until +- * the next grace period. */ +-static inline int ovsrcu_index_get(const ovsrcu_index *i) +-{ +- return ovsrcu_index_get__(i, memory_order_consume); +-} +- +-/* Returns the index contained in 'i'. This is an alternative to +- * ovsrcu_index_get() that can be used when there's no possible concurrent +- * writer. */ +-static inline int ovsrcu_index_get_protected(const ovsrcu_index *i) +-{ +- return ovsrcu_index_get__(i, memory_order_relaxed); +-} +- +-static inline void ovsrcu_index_set__(ovsrcu_index *i, int value, +- memory_order order) +-{ +- atomic_store_explicit(&i->v, value, order); +-} +- +-/* Writes the index 'value' in 'i'. The previous value of 'i' may still be +- * used by readers until the next grace period. */ +-static inline void ovsrcu_index_set(ovsrcu_index *i, int value) +-{ +- ovsrcu_index_set__(i, value, memory_order_release); +-} +- +-/* Writes the index 'value' in 'i'. This is an alternative to +- * ovsrcu_index_set() that can be used when there's no possible concurrent +- * reader. */ +-static inline void ovsrcu_index_set_hidden(ovsrcu_index *i, int value) +-{ +- ovsrcu_index_set__(i, value, memory_order_relaxed); +-} +- +-/* Initializes 'i' with 'value'. This is safe to call as long as there are no +- * concurrent readers. */ +-static inline void ovsrcu_index_init(ovsrcu_index *i, int value) +-{ +- atomic_init(&i->v, value); +-} +- +-/* Quiescent states. */ +-void ovsrcu_quiesce_start(void); +-void ovsrcu_quiesce_end(void); +-void ovsrcu_quiesce(void); +-int ovsrcu_try_quiesce(void); +-bool ovsrcu_is_quiescent(void); +- +-/* Synchronization. Waits for all non-quiescent threads to quiesce at least +- * once. This can block for a relatively long time. */ +-void ovsrcu_synchronize(void); +- +-void ovsrcu_exit(void); +- +-void ovsrcu_barrier(void); +- +-#endif /* ovs-rcu.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovs-rcu.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovs-rcu.h +@@ -0,0 +1,336 @@ ++/* ++ * Copyright (c) 2014, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVS_RCU_H ++#define OVS_RCU_H 1 ++ ++/* Read-Copy-Update (RCU) ++ * ====================== ++ * ++ * Introduction ++ * ------------ ++ * ++ * Atomic pointer access makes it pretty easy to implement lock-free ++ * algorithms. There is one big problem, though: when a writer updates a ++ * pointer to point to a new data structure, some thread might be reading the ++ * old version, and there's no convenient way to free the old version when all ++ * threads are done with the old version. ++ * ++ * The function ovsrcu_postpone() solves that problem. The function pointer ++ * passed in as its argument is called only after all threads are done with old ++ * versions of data structures. The function callback frees an old version of ++ * data no longer in use. This technique is called "read-copy-update", or RCU ++ * for short. ++ * ++ * ++ * Details ++ * ------- ++ * ++ * A "quiescent state" is a time at which a thread holds no pointers to memory ++ * that is managed by RCU; that is, when the thread is known not to reference ++ * memory that might be an old version of some object freed via RCU. For ++ * example, poll_block() includes a quiescent state. ++ * ++ * The following functions manage the recognition of quiescent states: ++ * ++ * void ovsrcu_quiesce(void) ++ * ++ * Recognizes a momentary quiescent state in the current thread. ++ * ++ * void ovsrcu_quiesce_start(void) ++ * void ovsrcu_quiesce_end(void) ++ * ++ * Brackets a time period during which the current thread is quiescent. ++ * ++ * A newly created thread is initially active, not quiescent. When a process ++ * becomes multithreaded, the main thread becomes active, not quiescent. ++ * ++ * When a quiescient state has occurred in every thread, we say that a "grace ++ * period" has occurred. Following a grace period, all of the callbacks ++ * postponed before the start of the grace period MAY be invoked. OVS takes ++ * care of this automatically through the RCU mechanism: while a process still ++ * has only a single thread, it invokes the postponed callbacks directly from ++ * ovsrcu_quiesce() and ovsrcu_quiesce_start(); after additional threads have ++ * been created, it creates an extra helper thread to invoke callbacks. ++ * ++ * Please note that while a postponed function call is guaranteed to happen ++ * after the next time all participating threads have quiesced at least once, ++ * there is no quarantee that all postponed functions are called as early as ++ * possible, or that the functions postponed by different threads would be ++ * called in the order the registrations took place. In particular, even if ++ * two threads provably postpone a function each in a specific order, the ++ * postponed functions may still be called in the opposite order, depending on ++ * the timing of when the threads call ovsrcu_quiesce(), how many functions ++ * they postpone, and when the ovs-rcu thread happens to grab the functions to ++ * be called. ++ * ++ * All functions postponed by a single thread are guaranteed to execute in the ++ * order they were postponed, however. ++ * ++ * Usage ++ * ----- ++ * ++ * Use OVSRCU_TYPE(TYPE) to declare a pointer to RCU-protected data, e.g. the ++ * following declares an RCU-protected "struct flow *" named flowp: ++ * ++ * OVSRCU_TYPE(struct flow *) flowp; ++ * ++ * Use ovsrcu_get(TYPE, VAR) to read an RCU-protected pointer, e.g. to read the ++ * pointer variable declared above: ++ * ++ * struct flow *flow = ovsrcu_get(struct flow *, &flowp); ++ * ++ * If the pointer variable is currently protected against change (because ++ * the current thread holds a mutex that protects it), ovsrcu_get_protected() ++ * may be used instead. Only on the Alpha architecture is this likely to ++ * generate different code, but it may be useful documentation. ++ * ++ * (With GNU C or Clang, you get a compiler error if TYPE is wrong; other ++ * compilers will merrily carry along accepting the wrong type.) ++ * ++ * Use ovsrcu_set() to write an RCU-protected pointer and ovsrcu_postpone() to ++ * free the previous data. ovsrcu_set_hidden() can be used on RCU protected ++ * data not visible to any readers yet, but will be made visible by a later ++ * ovsrcu_set(). ovsrcu_init() can be used to initialize RCU pointers when ++ * no readers are yet executing. If more than one thread can write the ++ * pointer, then some form of external synchronization, e.g. a mutex, is ++ * needed to prevent writers from interfering with one another. For example, ++ * to write the pointer variable declared above while safely freeing the old ++ * value: ++ * ++ * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; ++ * ++ * OVSRCU_TYPE(struct flow *) flowp; ++ * ++ * void ++ * change_flow(struct flow *new_flow) ++ * { ++ * ovs_mutex_lock(&mutex); ++ * ovsrcu_postpone(free, ++ * ovsrcu_get_protected(struct flow *, &flowp)); ++ * ovsrcu_set(&flowp, new_flow); ++ * ovs_mutex_unlock(&mutex); ++ * } ++ * ++ * In some rare cases an object may not be addressable with a pointer, but only ++ * through an array index (e.g. because it's provided by another library). It ++ * is still possible to have RCU semantics by using the ovsrcu_index type. ++ * ++ * static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; ++ * ++ * ovsrcu_index port_id; ++ * ++ * void tx() ++ * { ++ * int id = ovsrcu_index_get(&port_id); ++ * if (id == -1) { ++ * return; ++ * } ++ * port_tx(id); ++ * } ++ * ++ * void delete() ++ * { ++ * int id; ++ * ++ * ovs_mutex_lock(&mutex); ++ * id = ovsrcu_index_get_protected(&port_id); ++ * ovsrcu_index_set(&port_id, -1); ++ * ovs_mutex_unlock(&mutex); ++ * ++ * ovsrcu_synchronize(); ++ * port_delete(id); ++ * } ++ * ++ * Use ovsrcu_barrier() to wait for all the outstanding RCU callbacks to ++ * finish. This is useful when you have to destroy some resources however ++ * these resources are referenced in the outstanding RCU callbacks. ++ * ++ * void rcu_cb(void *A) { ++ * do_something(A); ++ * } ++ * ++ * void destroy_A() { ++ * ovsrcu_postpone(rcu_cb, A); // will use A later ++ * ovsrcu_barrier(); // wait for rcu_cb done ++ * do_destroy_A(); // free A ++ * } ++ */ ++ ++#include "openvswitch/compiler.h" +#include "openvswitch/ovs-atomic.h" + +#ifdef __cplusplus +extern "C" { +#endif - - #if __GNUC__ - #define OVSRCU_TYPE(TYPE) struct { ATOMIC(TYPE) p; } -@@ -310,4 +314,8 @@ void ovsrcu_synchronize(void); - - void ovsrcu_exit(void); - ++ ++#if __GNUC__ ++#define OVSRCU_TYPE(TYPE) struct { ATOMIC(TYPE) p; } ++#define OVSRCU_INITIALIZER(VALUE) { ATOMIC_VAR_INIT(VALUE) } ++#define ovsrcu_get__(TYPE, VAR, ORDER) \ ++ ({ \ ++ TYPE value__; \ ++ typeof(VAR) ovsrcu_var = (VAR); \ ++ \ ++ atomic_read_explicit(CONST_CAST(ATOMIC(TYPE) *, &ovsrcu_var->p), \ ++ &value__, ORDER); \ ++ \ ++ value__; \ ++ }) ++#define ovsrcu_get(TYPE, VAR) \ ++ ovsrcu_get__(TYPE, VAR, memory_order_consume) ++#define ovsrcu_get_protected(TYPE, VAR) \ ++ ovsrcu_get__(TYPE, VAR, memory_order_relaxed) ++ ++/* 'VALUE' may be an atomic operation, which must be evaluated before ++ * any of the body of the atomic_store_explicit. Since the type of ++ * 'VAR' is not fixed, we cannot use an inline function to get ++ * function semantics for this. */ ++#define ovsrcu_set__(VAR, VALUE, ORDER) \ ++ ({ \ ++ typeof(VAR) ovsrcu_var = (VAR); \ ++ typeof(VALUE) ovsrcu_value = (VALUE); \ ++ memory_order ovsrcu_order = (ORDER); \ ++ \ ++ atomic_store_explicit(&ovsrcu_var->p, ovsrcu_value, ovsrcu_order); \ ++ (void *) 0; \ ++ }) ++#else /* not GNU C */ ++struct ovsrcu_pointer { ATOMIC(void *) p; }; ++#define OVSRCU_TYPE(TYPE) struct ovsrcu_pointer ++#define OVSRCU_INITIALIZER(VALUE) { ATOMIC_VAR_INIT(VALUE) } ++static inline void * ++ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) ++{ ++ void *value; ++ atomic_read_explicit(&CONST_CAST(struct ovsrcu_pointer *, pointer)->p, ++ &value, order); ++ return value; ++} ++#define ovsrcu_get(TYPE, VAR) \ ++ CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_consume)) ++#define ovsrcu_get_protected(TYPE, VAR) \ ++ CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_relaxed)) ++ ++static inline void ovsrcu_set__(struct ovsrcu_pointer *pointer, ++ const void *value, ++ memory_order order) ++{ ++ atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), order); ++} ++#endif ++ ++/* Writes VALUE to the RCU-protected pointer whose address is VAR. ++ * ++ * Users require external synchronization (e.g. a mutex). See "Usage" above ++ * for an example. */ ++#define ovsrcu_set(VAR, VALUE) \ ++ ovsrcu_set__(VAR, VALUE, memory_order_release) ++ ++/* This can be used for initializing RCU pointers before any readers can ++ * see them. A later ovsrcu_set() needs to make the bigger structure this ++ * is part of visible to the readers. */ ++#define ovsrcu_set_hidden(VAR, VALUE) \ ++ ovsrcu_set__(VAR, VALUE, memory_order_relaxed) ++ ++/* This can be used for initializing RCU pointers before any readers are ++ * executing. */ ++#define ovsrcu_init(VAR, VALUE) atomic_init(&(VAR)->p, VALUE) ++ ++/* Calls FUNCTION passing ARG as its pointer-type argument following the next ++ * grace period. See "Usage" above for an example. */ ++void ovsrcu_postpone__(void (*function)(void *aux), void *aux); ++#define ovsrcu_postpone(FUNCTION, ARG) \ ++ (/* Verify that ARG is appropriate for FUNCTION. */ \ ++ (void) sizeof((FUNCTION)(ARG), 1), \ ++ /* Verify that ARG is a pointer type. */ \ ++ (void) sizeof(*(ARG)), \ ++ ovsrcu_postpone__((void (*)(void *))(FUNCTION), ARG)) ++ ++/* An array index protected by RCU semantics. This is an easier alternative to ++ * an RCU protected pointer to a malloc'd int. */ ++typedef struct { atomic_int v; } ovsrcu_index; ++ ++static inline int ovsrcu_index_get__(const ovsrcu_index *i, memory_order order) ++{ ++ int ret; ++ atomic_read_explicit(CONST_CAST(atomic_int *, &i->v), &ret, order); ++ return ret; ++} ++ ++/* Returns the index contained in 'i'. The returned value can be used until ++ * the next grace period. */ ++static inline int ovsrcu_index_get(const ovsrcu_index *i) ++{ ++ return ovsrcu_index_get__(i, memory_order_consume); ++} ++ ++/* Returns the index contained in 'i'. This is an alternative to ++ * ovsrcu_index_get() that can be used when there's no possible concurrent ++ * writer. */ ++static inline int ovsrcu_index_get_protected(const ovsrcu_index *i) ++{ ++ return ovsrcu_index_get__(i, memory_order_relaxed); ++} ++ ++static inline void ovsrcu_index_set__(ovsrcu_index *i, int value, ++ memory_order order) ++{ ++ atomic_store_explicit(&i->v, value, order); ++} ++ ++/* Writes the index 'value' in 'i'. The previous value of 'i' may still be ++ * used by readers until the next grace period. */ ++static inline void ovsrcu_index_set(ovsrcu_index *i, int value) ++{ ++ ovsrcu_index_set__(i, value, memory_order_release); ++} ++ ++/* Writes the index 'value' in 'i'. This is an alternative to ++ * ovsrcu_index_set() that can be used when there's no possible concurrent ++ * reader. */ ++static inline void ovsrcu_index_set_hidden(ovsrcu_index *i, int value) ++{ ++ ovsrcu_index_set__(i, value, memory_order_relaxed); ++} ++ ++/* Initializes 'i' with 'value'. This is safe to call as long as there are no ++ * concurrent readers. */ ++static inline void ovsrcu_index_init(ovsrcu_index *i, int value) ++{ ++ atomic_init(&i->v, value); ++} ++ ++/* Quiescent states. */ ++void ovsrcu_quiesce_start(void); ++void ovsrcu_quiesce_end(void); ++void ovsrcu_quiesce(void); ++int ovsrcu_try_quiesce(void); ++bool ovsrcu_is_quiescent(void); ++ ++/* Synchronization. Waits for all non-quiescent threads to quiesce at least ++ * once. This can block for a relatively long time. */ ++void ovsrcu_synchronize(void); ++ ++void ovsrcu_exit(void); ++ ++void ovsrcu_barrier(void); ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovs-rcu.h */ -diff --git a/lib/ovs-thread.h b/include/openvswitch/ovs-thread.h -similarity index 99% -rename from lib/ovs-thread.h -rename to include/openvswitch/ovs-thread.h -index 3b444ccdc..b1ac36096 100644 ---- a/lib/ovs-thread.h -+++ b/include/openvswitch/ovs-thread.h -@@ -20,10 +20,14 @@ - #include - #include - #include ++#endif /* ovs-rcu.h */ +Index: openvswitch-2.17.2/lib/ovs-thread.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-thread.h ++++ /dev/null +@@ -1,527 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVS_THREAD_H +-#define OVS_THREAD_H 1 +- +-#include +-#include +-#include -#include "ovs-atomic.h" -#include "ovs-rcu.h" +-#include "openvswitch/thread.h" +-#include "util.h" +- +-struct seq; +- +-/* Poll-block()-able barrier similar to pthread_barrier_t. */ +-struct ovs_barrier_impl; +-struct ovs_barrier { +- OVSRCU_TYPE(struct ovs_barrier_impl *) impl; +-}; +- +-/* Wrappers for pthread_mutexattr_*() that abort the process on any error. */ +-void xpthread_mutexattr_init(pthread_mutexattr_t *); +-void xpthread_mutexattr_destroy(pthread_mutexattr_t *); +-void xpthread_mutexattr_settype(pthread_mutexattr_t *, int type); +-void xpthread_mutexattr_gettype(pthread_mutexattr_t *, int *typep); +- +-/* Read-write lock. +- * +- * An ovs_rwlock does not support recursive readers, because POSIX allows +- * taking the reader lock recursively to deadlock when a thread is waiting on +- * the write-lock. (NetBSD does deadlock.) glibc rwlocks in their default +- * configuration do not deadlock, but ovs_rwlock_init() initializes rwlocks as +- * non-recursive (which will deadlock) for two reasons: +- * +- * - glibc only provides fairness to writers in this mode. +- * +- * - It's better to find bugs in the primary Open vSwitch target rather +- * than exposing them only to porters. */ +-struct OVS_LOCKABLE ovs_rwlock { +- pthread_rwlock_t lock; +- const char *where; /* NULL if and only if uninitialized. */ +-}; +- +-/* Initializer. */ +-#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +-#define OVS_RWLOCK_INITIALIZER \ +- { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, "" } +-#else +-#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, "" } +-#endif +- +-/* ovs_rwlock functions analogous to pthread_rwlock_*() functions. +- * +- * Most of these functions abort the process with an error message on any +- * error. The "trylock" functions are exception: they pass through a 0 or +- * EBUSY return value to the caller and abort on any other error. */ +-void ovs_rwlock_init(const struct ovs_rwlock *); +-void ovs_rwlock_destroy(const struct ovs_rwlock *); +-void ovs_rwlock_unlock(const struct ovs_rwlock *rwlock) OVS_RELEASES(rwlock); +- +-/* Wrappers for pthread_rwlockattr_*() that abort the process on any error. */ +-void xpthread_rwlockattr_init(pthread_rwlockattr_t *); +-void xpthread_rwlockattr_destroy(pthread_rwlockattr_t *); +-#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +-void xpthread_rwlockattr_setkind_np(pthread_rwlockattr_t *, int kind); +-#endif +- +-void ovs_rwlock_wrlock_at(const struct ovs_rwlock *rwlock, const char *where) +- OVS_ACQ_WRLOCK(rwlock); +-#define ovs_rwlock_wrlock(rwlock) \ +- ovs_rwlock_wrlock_at(rwlock, OVS_SOURCE_LOCATOR) +- +-int ovs_rwlock_trywrlock_at(const struct ovs_rwlock *rwlock, const char *where) +- OVS_TRY_WRLOCK(0, rwlock); +-#define ovs_rwlock_trywrlock(rwlock) \ +- ovs_rwlock_trywrlock_at(rwlock, OVS_SOURCE_LOCATOR) +- +-void ovs_rwlock_rdlock_at(const struct ovs_rwlock *rwlock, const char *where) +- OVS_ACQ_RDLOCK(rwlock); +-#define ovs_rwlock_rdlock(rwlock) \ +- ovs_rwlock_rdlock_at(rwlock, OVS_SOURCE_LOCATOR) +- +-int ovs_rwlock_tryrdlock_at(const struct ovs_rwlock *rwlock, const char *where) +- OVS_TRY_RDLOCK(0, rwlock); +-#define ovs_rwlock_tryrdlock(rwlock) \ +- ovs_rwlock_tryrdlock_at(rwlock, OVS_SOURCE_LOCATOR) +- +-/* ovs_barrier functions analogous to pthread_barrier_*() functions. */ +-void ovs_barrier_init(struct ovs_barrier *, uint32_t count); +-void ovs_barrier_destroy(struct ovs_barrier *); +-void ovs_barrier_block(struct ovs_barrier *); +- +-/* Wrappers for xpthread_cond_*() that abort the process on any error. +- * +- * Use ovs_mutex_cond_wait() to wait for a condition. */ +-void xpthread_cond_init(pthread_cond_t *, pthread_condattr_t *); +-void xpthread_cond_destroy(pthread_cond_t *); +-void xpthread_cond_signal(pthread_cond_t *); +-void xpthread_cond_broadcast(pthread_cond_t *); +- +-void xpthread_key_create(pthread_key_t *, void (*destructor)(void *)); +-void xpthread_key_delete(pthread_key_t); +-void xpthread_setspecific(pthread_key_t, const void *); +- +-#ifndef _WIN32 +-void xpthread_sigmask(int, const sigset_t *, sigset_t *); +-#endif +- +-pthread_t ovs_thread_create(const char *name, void *(*)(void *), void *); +-void xpthread_join(pthread_t, void **); +- +-/* Per-thread data. +- * +- * +- * Standard Forms +- * ============== +- * +- * Multiple forms of standard per-thread data exist, each with its own pluses +- * and minuses. In general, if one of these forms is appropriate, then it's a +- * good idea to use it: +- * +- * - POSIX per-thread data via pthread_key_t is portable to any pthreads +- * implementation, and allows a destructor function to be defined. It +- * only (directly) supports per-thread pointers, which are always +- * initialized to NULL. It requires once-only allocation of a +- * pthread_key_t value. It is relatively slow. Typically few +- * "pthread_key_t"s are available (POSIX requires only at least 128, +- * glibc supplies only 1024). +- * +- * - The thread_local feature newly defined in C11 works with +- * any data type and initializer, and it is fast. thread_local does not +- * require once-only initialization like pthread_key_t. C11 does not +- * define what happens if one attempts to access a thread_local object +- * from a thread other than the one to which that object belongs. There +- * is no provision to call a user-specified destructor when a thread +- * ends. Typical implementations allow for an arbitrary amount of +- * thread_local storage, but statically allocated only. +- * +- * - The __thread keyword is a GCC extension similar to thread_local but +- * with a longer history. __thread is not portable to every GCC version +- * or environment. __thread does not restrict the use of a thread-local +- * object outside its own thread. +- * +- * Here's a handy summary: +- * +- * pthread_key_t thread_local __thread +- * ------------- ------------ ------------- +- * portability high low medium +- * speed low high high +- * supports destructors? yes no no +- * needs key allocation? yes no no +- * arbitrary initializer? no yes yes +- * cross-thread access? yes no yes +- * amount available? few arbitrary arbitrary +- * dynamically allocated? yes no no +- * +- * +- * Extensions +- * ========== +- * +- * OVS provides some extensions and wrappers: +- * +- * - In a situation where the performance of thread_local or __thread is +- * desirable, but portability is required, DEFINE_STATIC_PER_THREAD_DATA +- * and DECLARE_EXTERN_PER_THREAD_DATA/DEFINE_EXTERN_PER_THREAD_DATA may +- * be appropriate (see below). +- * +- * - DEFINE_PER_THREAD_MALLOCED_DATA can be convenient for simple +- * per-thread malloc()'d buffers. +- * +- * - struct ovs_tsd provides an alternative to pthread_key_t that isn't +- * limited to a small number of keys. +- */ +- +-/* For static data, use this macro in a source file: +- * +- * DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, INITIALIZER). +- * +- * For global data, "declare" the data in the header and "define" it in +- * the source file, with: +- * +- * DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME). +- * DEFINE_EXTERN_PER_THREAD_DATA(NAME, INITIALIZER). +- * +- * One should prefer to use POSIX per-thread data, via pthread_key_t, when its +- * performance is acceptable, because of its portability (see the table above). +- * This macro is an alternatives that takes advantage of thread_local (and +- * __thread), for its performance, when it is available, and falls back to +- * POSIX per-thread data otherwise. +- * +- * Defines per-thread variable NAME with the given TYPE, initialized to +- * INITIALIZER (which must be valid as an initializer for a variable with +- * static lifetime). +- * +- * The public interface to the variable is: +- * +- * TYPE *NAME_get(void) +- * TYPE *NAME_get_unsafe(void) +- * +- * Returns the address of this thread's instance of NAME. +- * +- * Use NAME_get() in a context where this might be the first use of the +- * per-thread variable in the program. Use NAME_get_unsafe(), which +- * avoids a conditional test and is thus slightly faster, in a context +- * where one knows that NAME_get() has already been called previously. +- * +- * There is no "NAME_set()" (or "NAME_set_unsafe()") function. To set the +- * value of the per-thread variable, dereference the pointer returned by +- * TYPE_get() or TYPE_get_unsafe(), e.g. *TYPE_get() = 0. +- */ +-#if HAVE_THREAD_LOCAL || HAVE___THREAD +- +-#if HAVE_THREAD_LOCAL +-#include +-#elif HAVE___THREAD +-#define thread_local __thread +-#else +-#error +-#endif +- +-#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ +- typedef TYPE NAME##_type; \ +- \ +- static NAME##_type * \ +- NAME##_get_unsafe(void) \ +- { \ +- static thread_local NAME##_type var = __VA_ARGS__; \ +- return &var; \ +- } \ +- \ +- static NAME##_type * \ +- NAME##_get(void) \ +- { \ +- return NAME##_get_unsafe(); \ +- } +-#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ +- typedef TYPE NAME##_type; \ +- extern thread_local NAME##_type NAME##_var; \ +- \ +- static inline NAME##_type * \ +- NAME##_get_unsafe(void) \ +- { \ +- return (NAME##_type *)&NAME##_var; \ +- } \ +- \ +- static inline NAME##_type * \ +- NAME##_get(void) \ +- { \ +- return NAME##_get_unsafe(); \ +- } +-#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ +- thread_local NAME##_type NAME##_var = __VA_ARGS__; +-#else /* no C implementation support for thread-local storage */ +-#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ +- typedef TYPE NAME##_type; \ +- static pthread_key_t NAME##_key; \ +- \ +- static NAME##_type * \ +- NAME##_get_unsafe(void) \ +- { \ +- return pthread_getspecific(NAME##_key); \ +- } \ +- \ +- static void \ +- NAME##_once_init(void) \ +- { \ +- if (pthread_key_create(&NAME##_key, free)) { \ +- abort(); \ +- } \ +- } \ +- \ +- static NAME##_type * \ +- NAME##_get(void) \ +- { \ +- static pthread_once_t once = PTHREAD_ONCE_INIT; \ +- NAME##_type *value; \ +- \ +- pthread_once(&once, NAME##_once_init); \ +- value = NAME##_get_unsafe(); \ +- if (!value) { \ +- static const NAME##_type initial_value = __VA_ARGS__; \ +- \ +- value = xmalloc__(sizeof *value); \ +- *value = initial_value; \ +- xpthread_setspecific(NAME##_key, value); \ +- } \ +- return value; \ +- } +-#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ +- typedef TYPE NAME##_type; \ +- static pthread_key_t NAME##_key; \ +- \ +- static inline NAME##_type * \ +- NAME##_get_unsafe(void) \ +- { \ +- return (NAME##_type *)pthread_getspecific(NAME##_key); \ +- } \ +- \ +- NAME##_type *NAME##_get(void); +-#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ +- static void \ +- NAME##_once_init(void) \ +- { \ +- if (pthread_key_create(&NAME##_key, free)) { \ +- abort(); \ +- } \ +- } \ +- \ +- NAME##_type * \ +- NAME##_get(void) \ +- { \ +- static pthread_once_t once = PTHREAD_ONCE_INIT; \ +- NAME##_type *value; \ +- \ +- pthread_once(&once, NAME##_once_init); \ +- value = NAME##_get_unsafe(); \ +- if (!value) { \ +- static const NAME##_type initial_value = __VA_ARGS__; \ +- \ +- value = xmalloc__(sizeof *value); \ +- *value = initial_value; \ +- xpthread_setspecific(NAME##_key, value); \ +- } \ +- return value; \ +- } +-#endif +- +-/* DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME). +- * +- * This is a simple wrapper around POSIX per-thread data primitives. It +- * defines per-thread variable NAME with the given TYPE, which must be a +- * pointer type. In each thread, the per-thread variable is initialized to +- * NULL. When a thread terminates, the variable is freed with free(). +- * +- * The public interface to the variable is: +- * +- * TYPE NAME_get(void) +- * TYPE NAME_get_unsafe(void) +- * +- * Returns the value of per-thread variable NAME in this thread. +- * +- * Use NAME_get() in a context where this might be the first use of the +- * per-thread variable in the program. Use NAME_get_unsafe(), which +- * avoids a conditional test and is thus slightly faster, in a context +- * where one knows that NAME_get() has already been called previously. +- * +- * TYPE NAME_set(TYPE new_value) +- * TYPE NAME_set_unsafe(TYPE new_value) +- * +- * Sets the value of per-thread variable NAME to 'new_value' in this +- * thread, and returns its previous value. +- * +- * Use NAME_set() in a context where this might be the first use of the +- * per-thread variable in the program. Use NAME_set_unsafe(), which +- * avoids a conditional test and is thus slightly faster, in a context +- * where one knows that NAME_set() has already been called previously. +- */ +-#define DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME) \ +- static pthread_key_t NAME##_key; \ +- \ +- static void \ +- NAME##_once_init(void) \ +- { \ +- if (pthread_key_create(&NAME##_key, free)) { \ +- abort(); \ +- } \ +- } \ +- \ +- static void \ +- NAME##_init(void) \ +- { \ +- static pthread_once_t once = PTHREAD_ONCE_INIT; \ +- pthread_once(&once, NAME##_once_init); \ +- } \ +- \ +- static TYPE \ +- NAME##_get_unsafe(void) \ +- { \ +- return pthread_getspecific(NAME##_key); \ +- } \ +- \ +- static OVS_UNUSED TYPE \ +- NAME##_get(void) \ +- { \ +- NAME##_init(); \ +- return NAME##_get_unsafe(); \ +- } \ +- \ +- static TYPE \ +- NAME##_set_unsafe(TYPE value) \ +- { \ +- TYPE old_value = NAME##_get_unsafe(); \ +- xpthread_setspecific(NAME##_key, value); \ +- return old_value; \ +- } \ +- \ +- static OVS_UNUSED TYPE \ +- NAME##_set(TYPE value) \ +- { \ +- NAME##_init(); \ +- return NAME##_set_unsafe(value); \ +- } +- +-/* Dynamically allocated thread-specific data with lots of slots. +- * +- * pthread_key_t can provide as few as 128 pieces of thread-specific data (even +- * glibc is limited to 1,024). Thus, one must be careful to allocate only a +- * few keys globally. One cannot, for example, allocate a key for every +- * instance of a data structure if there might be an arbitrary number of those +- * data structures. +- * +- * This API is similar to the pthread one (simply search and replace pthread_ +- * by ovsthread_) but it a much larger limit that can be raised if necessary +- * (by recompiling). Thus, one may more freely use this form of +- * thread-specific data. +- * +- * ovsthread_key_t also differs from pthread_key_t in the following ways: +- * +- * - Destructors must not access thread-specific data (via ovsthread_key). +- * +- * - The pthread_key_t API allows concurrently exiting threads to start +- * executing the destructor after pthread_key_delete() returns. The +- * ovsthread_key_t API guarantees that, when ovsthread_key_delete() +- * returns, all destructors have returned and no new ones will start +- * execution. +- */ +-typedef struct ovsthread_key *ovsthread_key_t; +- +-void ovsthread_key_create(ovsthread_key_t *, void (*destructor)(void *)); +-void ovsthread_key_delete(ovsthread_key_t); +- +-void ovsthread_setspecific(ovsthread_key_t, const void *); +-void *ovsthread_getspecific(ovsthread_key_t); +- +-/* Thread ID. +- * +- * pthread_t isn't so nice for some purposes. Its size and representation are +- * implementation dependent, which means that there is no way to hash it. +- * This thread ID avoids the problem. +- */ +- +-#define OVSTHREAD_ID_UNSET UINT_MAX +-DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, ovsthread_id); +- +-/* Initializes the unique per thread identifier */ +-unsigned int ovsthread_id_init(void); +- +-/* Returns a per-thread identifier unique within the lifetime of the +- * process. */ +-static inline unsigned int +-ovsthread_id_self(void) +-{ +- unsigned int id = *ovsthread_id_get(); +- +- if (OVS_UNLIKELY(id == OVSTHREAD_ID_UNSET)) { +- id = ovsthread_id_init(); +- } +- +- return id; +-} +- +-/* Simulated global counter. +- * +- * Incrementing such a counter is meant to be cheaper than incrementing a +- * global counter protected by a lock. It is probably more expensive than +- * incrementing a truly thread-local variable, but such a variable has no +- * straightforward way to get the sum. +- * +- * +- * Thread-safety +- * ============= +- * +- * Fully thread-safe. */ +- +-struct ovsthread_stats { +- struct ovs_mutex mutex; +- void *volatile buckets[16]; +-}; +- +-void ovsthread_stats_init(struct ovsthread_stats *); +-void ovsthread_stats_destroy(struct ovsthread_stats *); +- +-void *ovsthread_stats_bucket_get(struct ovsthread_stats *, +- void *(*new_bucket)(void)); +- +-#define OVSTHREAD_STATS_FOR_EACH_BUCKET(BUCKET, IDX, STATS) \ +- for ((IDX) = ovs_thread_stats_next_bucket(STATS, 0); \ +- ((IDX) < ARRAY_SIZE((STATS)->buckets) \ +- ? ((BUCKET) = (STATS)->buckets[IDX], true) \ +- : false); \ +- (IDX) = ovs_thread_stats_next_bucket(STATS, (IDX) + 1)) +-size_t ovs_thread_stats_next_bucket(const struct ovsthread_stats *, size_t); +- +-bool single_threaded(void); +- +-void assert_single_threaded_at(const char *where); +-#define assert_single_threaded() assert_single_threaded_at(OVS_SOURCE_LOCATOR) +- +-#ifndef _WIN32 +-pid_t xfork_at(const char *where); +-#define xfork() xfork_at(OVS_SOURCE_LOCATOR) +-#endif +- +-void forbid_forking(const char *reason); +-bool may_fork(void); +- +-/* Useful functions related to threading. */ +- +-int count_cpu_cores(void); +-bool thread_is_pmd(void); +- +-#endif /* ovs-thread.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovs-thread.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovs-thread.h +@@ -0,0 +1,535 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVS_THREAD_H ++#define OVS_THREAD_H 1 ++ ++#include ++#include ++#include +#include "openvswitch/ovs-atomic.h" +#include "openvswitch/ovs-rcu.h" - #include "openvswitch/thread.h" --#include "util.h" ++#include "openvswitch/thread.h" +#include "internal/util.h" + +#ifdef __cplusplus +extern "C" { +#endif - - struct seq; - -@@ -524,4 +528,8 @@ bool may_fork(void); - int count_cpu_cores(void); - bool thread_is_pmd(void); - ++ ++struct seq; ++ ++/* Poll-block()-able barrier similar to pthread_barrier_t. */ ++struct ovs_barrier_impl; ++struct ovs_barrier { ++ OVSRCU_TYPE(struct ovs_barrier_impl *) impl; ++}; ++ ++/* Wrappers for pthread_mutexattr_*() that abort the process on any error. */ ++void xpthread_mutexattr_init(pthread_mutexattr_t *); ++void xpthread_mutexattr_destroy(pthread_mutexattr_t *); ++void xpthread_mutexattr_settype(pthread_mutexattr_t *, int type); ++void xpthread_mutexattr_gettype(pthread_mutexattr_t *, int *typep); ++ ++/* Read-write lock. ++ * ++ * An ovs_rwlock does not support recursive readers, because POSIX allows ++ * taking the reader lock recursively to deadlock when a thread is waiting on ++ * the write-lock. (NetBSD does deadlock.) glibc rwlocks in their default ++ * configuration do not deadlock, but ovs_rwlock_init() initializes rwlocks as ++ * non-recursive (which will deadlock) for two reasons: ++ * ++ * - glibc only provides fairness to writers in this mode. ++ * ++ * - It's better to find bugs in the primary Open vSwitch target rather ++ * than exposing them only to porters. */ ++struct OVS_LOCKABLE ovs_rwlock { ++ pthread_rwlock_t lock; ++ const char *where; /* NULL if and only if uninitialized. */ ++}; ++ ++/* Initializer. */ ++#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP ++#define OVS_RWLOCK_INITIALIZER \ ++ { PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, "" } ++#else ++#define OVS_RWLOCK_INITIALIZER { PTHREAD_RWLOCK_INITIALIZER, "" } ++#endif ++ ++/* ovs_rwlock functions analogous to pthread_rwlock_*() functions. ++ * ++ * Most of these functions abort the process with an error message on any ++ * error. The "trylock" functions are exception: they pass through a 0 or ++ * EBUSY return value to the caller and abort on any other error. */ ++void ovs_rwlock_init(const struct ovs_rwlock *); ++void ovs_rwlock_destroy(const struct ovs_rwlock *); ++void ovs_rwlock_unlock(const struct ovs_rwlock *rwlock) OVS_RELEASES(rwlock); ++ ++/* Wrappers for pthread_rwlockattr_*() that abort the process on any error. */ ++void xpthread_rwlockattr_init(pthread_rwlockattr_t *); ++void xpthread_rwlockattr_destroy(pthread_rwlockattr_t *); ++#ifdef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP ++void xpthread_rwlockattr_setkind_np(pthread_rwlockattr_t *, int kind); ++#endif ++ ++void ovs_rwlock_wrlock_at(const struct ovs_rwlock *rwlock, const char *where) ++ OVS_ACQ_WRLOCK(rwlock); ++#define ovs_rwlock_wrlock(rwlock) \ ++ ovs_rwlock_wrlock_at(rwlock, OVS_SOURCE_LOCATOR) ++ ++int ovs_rwlock_trywrlock_at(const struct ovs_rwlock *rwlock, const char *where) ++ OVS_TRY_WRLOCK(0, rwlock); ++#define ovs_rwlock_trywrlock(rwlock) \ ++ ovs_rwlock_trywrlock_at(rwlock, OVS_SOURCE_LOCATOR) ++ ++void ovs_rwlock_rdlock_at(const struct ovs_rwlock *rwlock, const char *where) ++ OVS_ACQ_RDLOCK(rwlock); ++#define ovs_rwlock_rdlock(rwlock) \ ++ ovs_rwlock_rdlock_at(rwlock, OVS_SOURCE_LOCATOR) ++ ++int ovs_rwlock_tryrdlock_at(const struct ovs_rwlock *rwlock, const char *where) ++ OVS_TRY_RDLOCK(0, rwlock); ++#define ovs_rwlock_tryrdlock(rwlock) \ ++ ovs_rwlock_tryrdlock_at(rwlock, OVS_SOURCE_LOCATOR) ++ ++/* ovs_barrier functions analogous to pthread_barrier_*() functions. */ ++void ovs_barrier_init(struct ovs_barrier *, uint32_t count); ++void ovs_barrier_destroy(struct ovs_barrier *); ++void ovs_barrier_block(struct ovs_barrier *); ++ ++/* Wrappers for xpthread_cond_*() that abort the process on any error. ++ * ++ * Use ovs_mutex_cond_wait() to wait for a condition. */ ++void xpthread_cond_init(pthread_cond_t *, pthread_condattr_t *); ++void xpthread_cond_destroy(pthread_cond_t *); ++void xpthread_cond_signal(pthread_cond_t *); ++void xpthread_cond_broadcast(pthread_cond_t *); ++ ++void xpthread_key_create(pthread_key_t *, void (*destructor)(void *)); ++void xpthread_key_delete(pthread_key_t); ++void xpthread_setspecific(pthread_key_t, const void *); ++ ++#ifndef _WIN32 ++void xpthread_sigmask(int, const sigset_t *, sigset_t *); ++#endif ++ ++pthread_t ovs_thread_create(const char *name, void *(*)(void *), void *); ++void xpthread_join(pthread_t, void **); ++ ++/* Per-thread data. ++ * ++ * ++ * Standard Forms ++ * ============== ++ * ++ * Multiple forms of standard per-thread data exist, each with its own pluses ++ * and minuses. In general, if one of these forms is appropriate, then it's a ++ * good idea to use it: ++ * ++ * - POSIX per-thread data via pthread_key_t is portable to any pthreads ++ * implementation, and allows a destructor function to be defined. It ++ * only (directly) supports per-thread pointers, which are always ++ * initialized to NULL. It requires once-only allocation of a ++ * pthread_key_t value. It is relatively slow. Typically few ++ * "pthread_key_t"s are available (POSIX requires only at least 128, ++ * glibc supplies only 1024). ++ * ++ * - The thread_local feature newly defined in C11 works with ++ * any data type and initializer, and it is fast. thread_local does not ++ * require once-only initialization like pthread_key_t. C11 does not ++ * define what happens if one attempts to access a thread_local object ++ * from a thread other than the one to which that object belongs. There ++ * is no provision to call a user-specified destructor when a thread ++ * ends. Typical implementations allow for an arbitrary amount of ++ * thread_local storage, but statically allocated only. ++ * ++ * - The __thread keyword is a GCC extension similar to thread_local but ++ * with a longer history. __thread is not portable to every GCC version ++ * or environment. __thread does not restrict the use of a thread-local ++ * object outside its own thread. ++ * ++ * Here's a handy summary: ++ * ++ * pthread_key_t thread_local __thread ++ * ------------- ------------ ------------- ++ * portability high low medium ++ * speed low high high ++ * supports destructors? yes no no ++ * needs key allocation? yes no no ++ * arbitrary initializer? no yes yes ++ * cross-thread access? yes no yes ++ * amount available? few arbitrary arbitrary ++ * dynamically allocated? yes no no ++ * ++ * ++ * Extensions ++ * ========== ++ * ++ * OVS provides some extensions and wrappers: ++ * ++ * - In a situation where the performance of thread_local or __thread is ++ * desirable, but portability is required, DEFINE_STATIC_PER_THREAD_DATA ++ * and DECLARE_EXTERN_PER_THREAD_DATA/DEFINE_EXTERN_PER_THREAD_DATA may ++ * be appropriate (see below). ++ * ++ * - DEFINE_PER_THREAD_MALLOCED_DATA can be convenient for simple ++ * per-thread malloc()'d buffers. ++ * ++ * - struct ovs_tsd provides an alternative to pthread_key_t that isn't ++ * limited to a small number of keys. ++ */ ++ ++/* For static data, use this macro in a source file: ++ * ++ * DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, INITIALIZER). ++ * ++ * For global data, "declare" the data in the header and "define" it in ++ * the source file, with: ++ * ++ * DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME). ++ * DEFINE_EXTERN_PER_THREAD_DATA(NAME, INITIALIZER). ++ * ++ * One should prefer to use POSIX per-thread data, via pthread_key_t, when its ++ * performance is acceptable, because of its portability (see the table above). ++ * This macro is an alternatives that takes advantage of thread_local (and ++ * __thread), for its performance, when it is available, and falls back to ++ * POSIX per-thread data otherwise. ++ * ++ * Defines per-thread variable NAME with the given TYPE, initialized to ++ * INITIALIZER (which must be valid as an initializer for a variable with ++ * static lifetime). ++ * ++ * The public interface to the variable is: ++ * ++ * TYPE *NAME_get(void) ++ * TYPE *NAME_get_unsafe(void) ++ * ++ * Returns the address of this thread's instance of NAME. ++ * ++ * Use NAME_get() in a context where this might be the first use of the ++ * per-thread variable in the program. Use NAME_get_unsafe(), which ++ * avoids a conditional test and is thus slightly faster, in a context ++ * where one knows that NAME_get() has already been called previously. ++ * ++ * There is no "NAME_set()" (or "NAME_set_unsafe()") function. To set the ++ * value of the per-thread variable, dereference the pointer returned by ++ * TYPE_get() or TYPE_get_unsafe(), e.g. *TYPE_get() = 0. ++ */ ++#if HAVE_THREAD_LOCAL || HAVE___THREAD ++ ++#if HAVE_THREAD_LOCAL ++#include ++#elif HAVE___THREAD ++#define thread_local __thread ++#else ++#error ++#endif ++ ++#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ ++ typedef TYPE NAME##_type; \ ++ \ ++ static NAME##_type * \ ++ NAME##_get_unsafe(void) \ ++ { \ ++ static thread_local NAME##_type var = __VA_ARGS__; \ ++ return &var; \ ++ } \ ++ \ ++ static NAME##_type * \ ++ NAME##_get(void) \ ++ { \ ++ return NAME##_get_unsafe(); \ ++ } ++#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ ++ typedef TYPE NAME##_type; \ ++ extern thread_local NAME##_type NAME##_var; \ ++ \ ++ static inline NAME##_type * \ ++ NAME##_get_unsafe(void) \ ++ { \ ++ return (NAME##_type *)&NAME##_var; \ ++ } \ ++ \ ++ static inline NAME##_type * \ ++ NAME##_get(void) \ ++ { \ ++ return NAME##_get_unsafe(); \ ++ } ++#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ ++ thread_local NAME##_type NAME##_var = __VA_ARGS__; ++#else /* no C implementation support for thread-local storage */ ++#define DEFINE_STATIC_PER_THREAD_DATA(TYPE, NAME, ...) \ ++ typedef TYPE NAME##_type; \ ++ static pthread_key_t NAME##_key; \ ++ \ ++ static NAME##_type * \ ++ NAME##_get_unsafe(void) \ ++ { \ ++ return pthread_getspecific(NAME##_key); \ ++ } \ ++ \ ++ static void \ ++ NAME##_once_init(void) \ ++ { \ ++ if (pthread_key_create(&NAME##_key, free)) { \ ++ abort(); \ ++ } \ ++ } \ ++ \ ++ static NAME##_type * \ ++ NAME##_get(void) \ ++ { \ ++ static pthread_once_t once = PTHREAD_ONCE_INIT; \ ++ NAME##_type *value; \ ++ \ ++ pthread_once(&once, NAME##_once_init); \ ++ value = NAME##_get_unsafe(); \ ++ if (!value) { \ ++ static const NAME##_type initial_value = __VA_ARGS__; \ ++ \ ++ value = xmalloc__(sizeof *value); \ ++ *value = initial_value; \ ++ xpthread_setspecific(NAME##_key, value); \ ++ } \ ++ return value; \ ++ } ++#define DECLARE_EXTERN_PER_THREAD_DATA(TYPE, NAME) \ ++ typedef TYPE NAME##_type; \ ++ static pthread_key_t NAME##_key; \ ++ \ ++ static inline NAME##_type * \ ++ NAME##_get_unsafe(void) \ ++ { \ ++ return (NAME##_type *)pthread_getspecific(NAME##_key); \ ++ } \ ++ \ ++ NAME##_type *NAME##_get(void); ++#define DEFINE_EXTERN_PER_THREAD_DATA(NAME, ...) \ ++ static void \ ++ NAME##_once_init(void) \ ++ { \ ++ if (pthread_key_create(&NAME##_key, free)) { \ ++ abort(); \ ++ } \ ++ } \ ++ \ ++ NAME##_type * \ ++ NAME##_get(void) \ ++ { \ ++ static pthread_once_t once = PTHREAD_ONCE_INIT; \ ++ NAME##_type *value; \ ++ \ ++ pthread_once(&once, NAME##_once_init); \ ++ value = NAME##_get_unsafe(); \ ++ if (!value) { \ ++ static const NAME##_type initial_value = __VA_ARGS__; \ ++ \ ++ value = xmalloc__(sizeof *value); \ ++ *value = initial_value; \ ++ xpthread_setspecific(NAME##_key, value); \ ++ } \ ++ return value; \ ++ } ++#endif ++ ++/* DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME). ++ * ++ * This is a simple wrapper around POSIX per-thread data primitives. It ++ * defines per-thread variable NAME with the given TYPE, which must be a ++ * pointer type. In each thread, the per-thread variable is initialized to ++ * NULL. When a thread terminates, the variable is freed with free(). ++ * ++ * The public interface to the variable is: ++ * ++ * TYPE NAME_get(void) ++ * TYPE NAME_get_unsafe(void) ++ * ++ * Returns the value of per-thread variable NAME in this thread. ++ * ++ * Use NAME_get() in a context where this might be the first use of the ++ * per-thread variable in the program. Use NAME_get_unsafe(), which ++ * avoids a conditional test and is thus slightly faster, in a context ++ * where one knows that NAME_get() has already been called previously. ++ * ++ * TYPE NAME_set(TYPE new_value) ++ * TYPE NAME_set_unsafe(TYPE new_value) ++ * ++ * Sets the value of per-thread variable NAME to 'new_value' in this ++ * thread, and returns its previous value. ++ * ++ * Use NAME_set() in a context where this might be the first use of the ++ * per-thread variable in the program. Use NAME_set_unsafe(), which ++ * avoids a conditional test and is thus slightly faster, in a context ++ * where one knows that NAME_set() has already been called previously. ++ */ ++#define DEFINE_PER_THREAD_MALLOCED_DATA(TYPE, NAME) \ ++ static pthread_key_t NAME##_key; \ ++ \ ++ static void \ ++ NAME##_once_init(void) \ ++ { \ ++ if (pthread_key_create(&NAME##_key, free)) { \ ++ abort(); \ ++ } \ ++ } \ ++ \ ++ static void \ ++ NAME##_init(void) \ ++ { \ ++ static pthread_once_t once = PTHREAD_ONCE_INIT; \ ++ pthread_once(&once, NAME##_once_init); \ ++ } \ ++ \ ++ static TYPE \ ++ NAME##_get_unsafe(void) \ ++ { \ ++ return pthread_getspecific(NAME##_key); \ ++ } \ ++ \ ++ static OVS_UNUSED TYPE \ ++ NAME##_get(void) \ ++ { \ ++ NAME##_init(); \ ++ return NAME##_get_unsafe(); \ ++ } \ ++ \ ++ static TYPE \ ++ NAME##_set_unsafe(TYPE value) \ ++ { \ ++ TYPE old_value = NAME##_get_unsafe(); \ ++ xpthread_setspecific(NAME##_key, value); \ ++ return old_value; \ ++ } \ ++ \ ++ static OVS_UNUSED TYPE \ ++ NAME##_set(TYPE value) \ ++ { \ ++ NAME##_init(); \ ++ return NAME##_set_unsafe(value); \ ++ } ++ ++/* Dynamically allocated thread-specific data with lots of slots. ++ * ++ * pthread_key_t can provide as few as 128 pieces of thread-specific data (even ++ * glibc is limited to 1,024). Thus, one must be careful to allocate only a ++ * few keys globally. One cannot, for example, allocate a key for every ++ * instance of a data structure if there might be an arbitrary number of those ++ * data structures. ++ * ++ * This API is similar to the pthread one (simply search and replace pthread_ ++ * by ovsthread_) but it a much larger limit that can be raised if necessary ++ * (by recompiling). Thus, one may more freely use this form of ++ * thread-specific data. ++ * ++ * ovsthread_key_t also differs from pthread_key_t in the following ways: ++ * ++ * - Destructors must not access thread-specific data (via ovsthread_key). ++ * ++ * - The pthread_key_t API allows concurrently exiting threads to start ++ * executing the destructor after pthread_key_delete() returns. The ++ * ovsthread_key_t API guarantees that, when ovsthread_key_delete() ++ * returns, all destructors have returned and no new ones will start ++ * execution. ++ */ ++typedef struct ovsthread_key *ovsthread_key_t; ++ ++void ovsthread_key_create(ovsthread_key_t *, void (*destructor)(void *)); ++void ovsthread_key_delete(ovsthread_key_t); ++ ++void ovsthread_setspecific(ovsthread_key_t, const void *); ++void *ovsthread_getspecific(ovsthread_key_t); ++ ++/* Thread ID. ++ * ++ * pthread_t isn't so nice for some purposes. Its size and representation are ++ * implementation dependent, which means that there is no way to hash it. ++ * This thread ID avoids the problem. ++ */ ++ ++#define OVSTHREAD_ID_UNSET UINT_MAX ++DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, ovsthread_id); ++ ++/* Initializes the unique per thread identifier */ ++unsigned int ovsthread_id_init(void); ++ ++/* Returns a per-thread identifier unique within the lifetime of the ++ * process. */ ++static inline unsigned int ++ovsthread_id_self(void) ++{ ++ unsigned int id = *ovsthread_id_get(); ++ ++ if (OVS_UNLIKELY(id == OVSTHREAD_ID_UNSET)) { ++ id = ovsthread_id_init(); ++ } ++ ++ return id; ++} ++ ++/* Simulated global counter. ++ * ++ * Incrementing such a counter is meant to be cheaper than incrementing a ++ * global counter protected by a lock. It is probably more expensive than ++ * incrementing a truly thread-local variable, but such a variable has no ++ * straightforward way to get the sum. ++ * ++ * ++ * Thread-safety ++ * ============= ++ * ++ * Fully thread-safe. */ ++ ++struct ovsthread_stats { ++ struct ovs_mutex mutex; ++ void *volatile buckets[16]; ++}; ++ ++void ovsthread_stats_init(struct ovsthread_stats *); ++void ovsthread_stats_destroy(struct ovsthread_stats *); ++ ++void *ovsthread_stats_bucket_get(struct ovsthread_stats *, ++ void *(*new_bucket)(void)); ++ ++#define OVSTHREAD_STATS_FOR_EACH_BUCKET(BUCKET, IDX, STATS) \ ++ for ((IDX) = ovs_thread_stats_next_bucket(STATS, 0); \ ++ ((IDX) < ARRAY_SIZE((STATS)->buckets) \ ++ ? ((BUCKET) = (STATS)->buckets[IDX], true) \ ++ : false); \ ++ (IDX) = ovs_thread_stats_next_bucket(STATS, (IDX) + 1)) ++size_t ovs_thread_stats_next_bucket(const struct ovsthread_stats *, size_t); ++ ++bool single_threaded(void); ++ ++void assert_single_threaded_at(const char *where); ++#define assert_single_threaded() assert_single_threaded_at(OVS_SOURCE_LOCATOR) ++ ++#ifndef _WIN32 ++pid_t xfork_at(const char *where); ++#define xfork() xfork_at(OVS_SOURCE_LOCATOR) ++#endif ++ ++void forbid_forking(const char *reason); ++bool may_fork(void); ++ ++/* Useful functions related to threading. */ ++ ++int count_cpu_cores(void); ++bool thread_is_pmd(void); ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovs-thread.h */ -diff --git a/lib/ovsdb-condition.h b/include/openvswitch/ovsdb-condition.h -similarity index 95% -rename from lib/ovsdb-condition.h -rename to include/openvswitch/ovsdb-condition.h -index 65496e1b2..cd72d7b38 100644 ---- a/lib/ovsdb-condition.h -+++ b/include/openvswitch/ovsdb-condition.h -@@ -31,6 +31,10 @@ - OVSDB_FUNCTION(OVSDB_F_EXCLUDES, "excludes") \ - OVSDB_FUNCTION(OVSDB_F_NE, "!=") - ++#endif /* ovs-thread.h */ +Index: openvswitch-2.17.2/lib/ovsdb-condition.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-condition.h ++++ /dev/null +@@ -1,45 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_LIB_CONDITION_H +-#define OVSDB_LIB_CONDITION_H 1 +- +-/* These list is ordered first with boolean functions and then in +- * ascending order of the fraction of tables row that they are +- * (heuristically) expected to leave in query results. */ +-#define OVSDB_FUNCTIONS \ +- OVSDB_FUNCTION(OVSDB_F_FALSE, "false") \ +- OVSDB_FUNCTION(OVSDB_F_TRUE, "true") \ +- OVSDB_FUNCTION(OVSDB_F_EQ, "==") \ +- OVSDB_FUNCTION(OVSDB_F_INCLUDES, "includes") \ +- OVSDB_FUNCTION(OVSDB_F_LE, "<=") \ +- OVSDB_FUNCTION(OVSDB_F_LT, "<") \ +- OVSDB_FUNCTION(OVSDB_F_GE, ">=") \ +- OVSDB_FUNCTION(OVSDB_F_GT, ">") \ +- OVSDB_FUNCTION(OVSDB_F_EXCLUDES, "excludes") \ +- OVSDB_FUNCTION(OVSDB_F_NE, "!=") +- +-enum ovsdb_function { +-#define OVSDB_FUNCTION(ENUM, NAME) ENUM, +- OVSDB_FUNCTIONS +-#undef OVSDB_FUNCTION +- OVSDB_F_LAST = OVSDB_F_NE +-}; +- +-struct ovsdb_error * ovsdb_function_from_string(const char *name, +- enum ovsdb_function *function); +-const char * ovsdb_function_to_string(enum ovsdb_function function); +- +-#endif /* ovsdb-condition.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-condition.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-condition.h +@@ -0,0 +1,53 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_LIB_CONDITION_H ++#define OVSDB_LIB_CONDITION_H 1 ++ ++/* These list is ordered first with boolean functions and then in ++ * ascending order of the fraction of tables row that they are ++ * (heuristically) expected to leave in query results. */ ++#define OVSDB_FUNCTIONS \ ++ OVSDB_FUNCTION(OVSDB_F_FALSE, "false") \ ++ OVSDB_FUNCTION(OVSDB_F_TRUE, "true") \ ++ OVSDB_FUNCTION(OVSDB_F_EQ, "==") \ ++ OVSDB_FUNCTION(OVSDB_F_INCLUDES, "includes") \ ++ OVSDB_FUNCTION(OVSDB_F_LE, "<=") \ ++ OVSDB_FUNCTION(OVSDB_F_LT, "<") \ ++ OVSDB_FUNCTION(OVSDB_F_GE, ">=") \ ++ OVSDB_FUNCTION(OVSDB_F_GT, ">") \ ++ OVSDB_FUNCTION(OVSDB_F_EXCLUDES, "excludes") \ ++ OVSDB_FUNCTION(OVSDB_F_NE, "!=") ++ +#ifdef __cplusplus +extern "C" { +#endif + - enum ovsdb_function { - #define OVSDB_FUNCTION(ENUM, NAME) ENUM, - OVSDB_FUNCTIONS -@@ -42,4 +46,8 @@ struct ovsdb_error * ovsdb_function_from_string(const char *name, - enum ovsdb_function *function); - const char * ovsdb_function_to_string(enum ovsdb_function function); - ++enum ovsdb_function { ++#define OVSDB_FUNCTION(ENUM, NAME) ENUM, ++ OVSDB_FUNCTIONS ++#undef OVSDB_FUNCTION ++ OVSDB_F_LAST = OVSDB_F_NE ++}; ++ ++struct ovsdb_error * ovsdb_function_from_string(const char *name, ++ enum ovsdb_function *function); ++const char * ovsdb_function_to_string(enum ovsdb_function function); ++ +#ifdef __cplusplus +} // extern "C" { +#endif + - #endif /* ovsdb-condition.h */ -diff --git a/lib/ovsdb-cs.h b/include/openvswitch/ovsdb-cs.h -similarity index 98% -rename from lib/ovsdb-cs.h -rename to include/openvswitch/ovsdb-cs.h -index 03bbd7ee1..2c06559a8 100644 ---- a/lib/ovsdb-cs.h -+++ b/include/openvswitch/ovsdb-cs.h -@@ -31,9 +31,13 @@ - #include "openvswitch/shash.h" - #include "openvswitch/uuid.h" - -+#ifdef __cplusplus -+extern "C" { -+#endif -+ - struct json; - struct ovsdb_cs; ++#endif /* ovsdb-condition.h */ +Index: openvswitch-2.17.2/lib/ovsdb-cs.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-cs.h ++++ /dev/null +@@ -1,205 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. +- * Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_CS_H +-#define OVSDB_CS_H 1 +- +-/* Open vSwitch Database client synchronization layer. +- * +- * This is a base layer for maintaining an in-memory replica of a database. It +- * issues RPC requests to an OVSDB database server and passes the semantically +- * meaningful parts of the stream up to a higher layer. The OVSDB IDL uses +- * this as a base layer, as well as OVN's DDlog-based northd implementation. +- */ +- +-#include +-#include "openvswitch/hmap.h" +-#include "openvswitch/list.h" +-#include "openvswitch/shash.h" +-#include "openvswitch/uuid.h" +- +-struct json; +-struct ovsdb_cs; - +-struct ovsdb_cs_ops { +- /* Returns to use for the specified . The +- * implementation might find ovsdb_cs_parse_table_updates() to be a useful +- * helper. +- * +- * The caller might actually use "monitor_cond" or "monitor_cond_since", +- * rather than plain "monitor". If so, this function's implementation +- * doesn't need to worry about that, because the caller will add the +- * conditions itself. */ +- struct json *(*compose_monitor_requests)(const struct json *schema, +- void *aux); +-}; +- +-/* An event is a happening that is worth reporting to the CS client. +- * +- * Currently there are three kinds of events: +- * +- * - "Reconnect": The connection to the database was lost and it is now +- * being reconnected. This means that any transactions submitted by the +- * client will never receive a reply (although it's possible that some of +- * them were actually committed). This event has no associated data. +- * +- * - "Locked": The server granted the lock we requested. +- * +- * - "Update": The server sent an update to one or more monitored tables. +- * The client can use the associated data to update its idea of the +- * snapshot. +- * +- * - "Transaction reply": The server sent a reply to a transaction sent by +- * the client using ovsdb_cs_send_transaction(). +- */ +-struct ovsdb_cs_event { +- struct ovs_list list_node; +- +- enum ovsdb_cs_event_type { +- OVSDB_CS_EVENT_TYPE_RECONNECT, /* Connection lost. */ +- OVSDB_CS_EVENT_TYPE_LOCKED, /* Got the lock we wanted. */ +- OVSDB_CS_EVENT_TYPE_UPDATE, /* Received update notification. */ +- OVSDB_CS_EVENT_TYPE_TXN_REPLY, /* Received reply to transaction. */ +- } type; +- +- union { +- /* Represents a or that contains +- * either the initial data in a monitor reply or a delta received in an +- * update notification. The client can use this to update its database +- * replica. +- * +- * If 'clear' is true, then the client should first clear its idea of +- * what's in the replica before applying the update; otherwise, it's an +- * incremental update. +- * +- * If 'monitor_reply' is true, then this comes from a monitor reply. +- * This doesn't have real semantic meaning, but it allows the caller +- * to imitate the exact behavior of previous versions of code that +- * behaved differently on updates from monitor replies vs. updates. +- * +- * 'table-updates' is a if 'version' if 1, otherwise a +- * . The client can use ovsdb_cs_parse_table_updates() +- * to parse the update. +- */ +- struct ovsdb_cs_update_event { +- bool clear; +- bool monitor_reply; +- struct json *table_updates; +- int version; +- } update; +- +- /* The "result" member from a transaction reply. The transaction is +- * one sent by the client using ovsdb_cs_send_transaction(). The +- * client can match 'txn_reply->id' against the ID in a transaction it +- * sent. */ +- struct jsonrpc_msg *txn_reply; +- }; +-}; +-void ovsdb_cs_event_destroy(struct ovsdb_cs_event *); +- +-/* Lifecycle. */ +-struct ovsdb_cs *ovsdb_cs_create(const char *database, int max_version, +- const struct ovsdb_cs_ops *ops, +- void *ops_aux); +-void ovsdb_cs_destroy(struct ovsdb_cs *); +- +-void ovsdb_cs_run(struct ovsdb_cs *, struct ovs_list *events); +-void ovsdb_cs_wait(struct ovsdb_cs *); +- +-/* Network connection. */ +-void ovsdb_cs_set_remote(struct ovsdb_cs *, const char *remote, bool retry); +- +-void ovsdb_cs_enable_reconnect(struct ovsdb_cs *); +-void ovsdb_cs_force_reconnect(struct ovsdb_cs *); +-void ovsdb_cs_flag_inconsistency(struct ovsdb_cs *); +- +-bool ovsdb_cs_is_alive(const struct ovsdb_cs *); +-bool ovsdb_cs_is_connected(const struct ovsdb_cs *); +-int ovsdb_cs_get_last_error(const struct ovsdb_cs *); +- +-void ovsdb_cs_set_probe_interval(const struct ovsdb_cs *, int probe_interval); +- +-/* Conditional monitoring (specifying that only rows matching particular +- * criteria should be monitored). +- * +- * Some database servers don't support conditional monitoring; in that case, +- * the client will get all the rows. */ +-unsigned int ovsdb_cs_set_condition(struct ovsdb_cs *, const char *table, +- const struct json *condition); +-unsigned int ovsdb_cs_get_condition_seqno(const struct ovsdb_cs *); +- +-/* Clustered servers. */ +-void ovsdb_cs_set_leader_only(struct ovsdb_cs *, bool leader_only); +-void ovsdb_cs_set_shuffle_remotes(struct ovsdb_cs *, bool shuffle); +-void ovsdb_cs_reset_min_index(struct ovsdb_cs *); +- +-/* Database locks. */ +-void ovsdb_cs_set_lock(struct ovsdb_cs *, const char *lock_name); +-const char *ovsdb_cs_get_lock(const struct ovsdb_cs *); +-bool ovsdb_cs_has_lock(const struct ovsdb_cs *); +-bool ovsdb_cs_is_lock_contended(const struct ovsdb_cs *); +- +-/* Transactions. */ +-bool ovsdb_cs_may_send_transaction(const struct ovsdb_cs *); +-struct json *ovsdb_cs_send_transaction(struct ovsdb_cs *, struct json *ops) +- OVS_WARN_UNUSED_RESULT; +-bool ovsdb_cs_forget_transaction(struct ovsdb_cs *, const struct json *); +- +-/* Helper for partially parsing the or that +- * appear in struct ovsdb_cs_update_event. The helper leaves the data in JSON +- * format, so it doesn't need to know column types. */ +- +-/* The kind of change to a row. */ +-enum ovsdb_cs_row_update_type { +- OVSDB_CS_ROW_DELETE, /* Row deletion. */ +- OVSDB_CS_ROW_INSERT, /* Row insertion. */ +- OVSDB_CS_ROW_UPDATE, /* Replacement of data within a row. */ +- OVSDB_CS_ROW_XOR /* diff application. */ +-}; +- +-/* Partially parsed or . */ +-struct ovsdb_cs_row_update { +- struct uuid row_uuid; /* Row's _uuid. */ +- enum ovsdb_cs_row_update_type type; /* Type of change. */ +- const struct shash *columns; /* Map from column name to json data. */ +-}; +- +-/* Partially parsed or . */ +-struct ovsdb_cs_table_update { +- const char *table_name; +- struct ovsdb_cs_row_update *row_updates; +- size_t n; +-}; +- +-struct ovsdb_cs_db_update { +- struct ovsdb_cs_table_update *table_updates; +- size_t n; +-}; +- +-struct ovsdb_error *ovsdb_cs_parse_db_update( +- const struct json *table_updates, int version, +- struct ovsdb_cs_db_update **db_updatep) +- OVS_WARN_UNUSED_RESULT; +-void ovsdb_cs_db_update_destroy(struct ovsdb_cs_db_update *); +-const struct ovsdb_cs_table_update *ovsdb_cs_db_update_find_table( +- const struct ovsdb_cs_db_update *, const char *table_name); +- +-/* Simple parsing of OVSDB schemas for use by ovsdb_cs clients. */ +- +-struct shash *ovsdb_cs_parse_schema(const struct json *schema_json); +-void ovsdb_cs_free_schema(struct shash *schema); +- +-#endif /* ovsdb-cs.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-cs.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-cs.h +@@ -0,0 +1,213 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. ++ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ + - struct ovsdb_cs_ops { - /* Returns to use for the specified . The - * implementation might find ovsdb_cs_parse_table_updates() to be a useful -@@ -202,4 +206,8 @@ const struct ovsdb_cs_table_update *ovsdb_cs_db_update_find_table( - struct shash *ovsdb_cs_parse_schema(const struct json *schema_json); - void ovsdb_cs_free_schema(struct shash *schema); - -+#ifdef __cplusplus -+} // extern "C" -+#endif ++#ifndef OVSDB_CS_H ++#define OVSDB_CS_H 1 ++ ++/* Open vSwitch Database client synchronization layer. ++ * ++ * This is a base layer for maintaining an in-memory replica of a database. It ++ * issues RPC requests to an OVSDB database server and passes the semantically ++ * meaningful parts of the stream up to a higher layer. The OVSDB IDL uses ++ * this as a base layer, as well as OVN's DDlog-based northd implementation. ++ */ ++ ++#include ++#include "openvswitch/hmap.h" ++#include "openvswitch/list.h" ++#include "openvswitch/shash.h" ++#include "openvswitch/uuid.h" + - #endif /* ovsdb-cs.h */ -diff --git a/lib/ovsdb-data.h b/include/openvswitch/ovsdb-data.h -similarity index 99% -rename from lib/ovsdb-data.h -rename to include/openvswitch/ovsdb-data.h -index a27ce91ed..525a33db0 100644 ---- a/lib/ovsdb-data.h -+++ b/include/openvswitch/ovsdb-data.h -@@ -18,10 +18,10 @@ - - #include - #include "openvswitch/compiler.h" --#include "ovsdb-types.h" -+#include "openvswitch/ovsdb-types.h" - #include "openvswitch/json.h" - #include "openvswitch/shash.h" --#include "util.h" -+#include "internal/util.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/ovsdb-error.h b/include/openvswitch/ovsdb-error.h -similarity index 97% -rename from lib/ovsdb-error.h -rename to include/openvswitch/ovsdb-error.h -index 1621f0eac..ccae8470e 100644 ---- a/lib/ovsdb-error.h -+++ b/include/openvswitch/ovsdb-error.h -@@ -18,6 +18,10 @@ - - #include "openvswitch/compiler.h" - +#ifdef __cplusplus +extern "C" { +#endif + - struct json; - - struct ovsdb_error *ovsdb_error(const char *tag, const char *details, ...) -@@ -72,4 +76,8 @@ const char *ovsdb_error_get_tag(const struct ovsdb_error *); - - void ovsdb_error_assert(struct ovsdb_error *); - ++struct json; ++struct ovsdb_cs; ++ ++struct ovsdb_cs_ops { ++ /* Returns to use for the specified . The ++ * implementation might find ovsdb_cs_parse_table_updates() to be a useful ++ * helper. ++ * ++ * The caller might actually use "monitor_cond" or "monitor_cond_since", ++ * rather than plain "monitor". If so, this function's implementation ++ * doesn't need to worry about that, because the caller will add the ++ * conditions itself. */ ++ struct json *(*compose_monitor_requests)(const struct json *schema, ++ void *aux); ++}; ++ ++/* An event is a happening that is worth reporting to the CS client. ++ * ++ * Currently there are three kinds of events: ++ * ++ * - "Reconnect": The connection to the database was lost and it is now ++ * being reconnected. This means that any transactions submitted by the ++ * client will never receive a reply (although it's possible that some of ++ * them were actually committed). This event has no associated data. ++ * ++ * - "Locked": The server granted the lock we requested. ++ * ++ * - "Update": The server sent an update to one or more monitored tables. ++ * The client can use the associated data to update its idea of the ++ * snapshot. ++ * ++ * - "Transaction reply": The server sent a reply to a transaction sent by ++ * the client using ovsdb_cs_send_transaction(). ++ */ ++struct ovsdb_cs_event { ++ struct ovs_list list_node; ++ ++ enum ovsdb_cs_event_type { ++ OVSDB_CS_EVENT_TYPE_RECONNECT, /* Connection lost. */ ++ OVSDB_CS_EVENT_TYPE_LOCKED, /* Got the lock we wanted. */ ++ OVSDB_CS_EVENT_TYPE_UPDATE, /* Received update notification. */ ++ OVSDB_CS_EVENT_TYPE_TXN_REPLY, /* Received reply to transaction. */ ++ } type; ++ ++ union { ++ /* Represents a or that contains ++ * either the initial data in a monitor reply or a delta received in an ++ * update notification. The client can use this to update its database ++ * replica. ++ * ++ * If 'clear' is true, then the client should first clear its idea of ++ * what's in the replica before applying the update; otherwise, it's an ++ * incremental update. ++ * ++ * If 'monitor_reply' is true, then this comes from a monitor reply. ++ * This doesn't have real semantic meaning, but it allows the caller ++ * to imitate the exact behavior of previous versions of code that ++ * behaved differently on updates from monitor replies vs. updates. ++ * ++ * 'table-updates' is a if 'version' if 1, otherwise a ++ * . The client can use ovsdb_cs_parse_table_updates() ++ * to parse the update. ++ */ ++ struct ovsdb_cs_update_event { ++ bool clear; ++ bool monitor_reply; ++ struct json *table_updates; ++ int version; ++ } update; ++ ++ /* The "result" member from a transaction reply. The transaction is ++ * one sent by the client using ovsdb_cs_send_transaction(). The ++ * client can match 'txn_reply->id' against the ID in a transaction it ++ * sent. */ ++ struct jsonrpc_msg *txn_reply; ++ }; ++}; ++void ovsdb_cs_event_destroy(struct ovsdb_cs_event *); ++ ++/* Lifecycle. */ ++struct ovsdb_cs *ovsdb_cs_create(const char *database, int max_version, ++ const struct ovsdb_cs_ops *ops, ++ void *ops_aux); ++void ovsdb_cs_destroy(struct ovsdb_cs *); ++ ++void ovsdb_cs_run(struct ovsdb_cs *, struct ovs_list *events); ++void ovsdb_cs_wait(struct ovsdb_cs *); ++ ++/* Network connection. */ ++void ovsdb_cs_set_remote(struct ovsdb_cs *, const char *remote, bool retry); ++ ++void ovsdb_cs_enable_reconnect(struct ovsdb_cs *); ++void ovsdb_cs_force_reconnect(struct ovsdb_cs *); ++void ovsdb_cs_flag_inconsistency(struct ovsdb_cs *); ++ ++bool ovsdb_cs_is_alive(const struct ovsdb_cs *); ++bool ovsdb_cs_is_connected(const struct ovsdb_cs *); ++int ovsdb_cs_get_last_error(const struct ovsdb_cs *); ++ ++void ovsdb_cs_set_probe_interval(const struct ovsdb_cs *, int probe_interval); ++ ++/* Conditional monitoring (specifying that only rows matching particular ++ * criteria should be monitored). ++ * ++ * Some database servers don't support conditional monitoring; in that case, ++ * the client will get all the rows. */ ++unsigned int ovsdb_cs_set_condition(struct ovsdb_cs *, const char *table, ++ const struct json *condition); ++unsigned int ovsdb_cs_get_condition_seqno(const struct ovsdb_cs *); ++ ++/* Clustered servers. */ ++void ovsdb_cs_set_leader_only(struct ovsdb_cs *, bool leader_only); ++void ovsdb_cs_set_shuffle_remotes(struct ovsdb_cs *, bool shuffle); ++void ovsdb_cs_reset_min_index(struct ovsdb_cs *); ++ ++/* Database locks. */ ++void ovsdb_cs_set_lock(struct ovsdb_cs *, const char *lock_name); ++const char *ovsdb_cs_get_lock(const struct ovsdb_cs *); ++bool ovsdb_cs_has_lock(const struct ovsdb_cs *); ++bool ovsdb_cs_is_lock_contended(const struct ovsdb_cs *); ++ ++/* Transactions. */ ++bool ovsdb_cs_may_send_transaction(const struct ovsdb_cs *); ++struct json *ovsdb_cs_send_transaction(struct ovsdb_cs *, struct json *ops) ++ OVS_WARN_UNUSED_RESULT; ++bool ovsdb_cs_forget_transaction(struct ovsdb_cs *, const struct json *); ++ ++/* Helper for partially parsing the or that ++ * appear in struct ovsdb_cs_update_event. The helper leaves the data in JSON ++ * format, so it doesn't need to know column types. */ ++ ++/* The kind of change to a row. */ ++enum ovsdb_cs_row_update_type { ++ OVSDB_CS_ROW_DELETE, /* Row deletion. */ ++ OVSDB_CS_ROW_INSERT, /* Row insertion. */ ++ OVSDB_CS_ROW_UPDATE, /* Replacement of data within a row. */ ++ OVSDB_CS_ROW_XOR /* diff application. */ ++}; ++ ++/* Partially parsed or . */ ++struct ovsdb_cs_row_update { ++ struct uuid row_uuid; /* Row's _uuid. */ ++ enum ovsdb_cs_row_update_type type; /* Type of change. */ ++ const struct shash *columns; /* Map from column name to json data. */ ++}; ++ ++/* Partially parsed or . */ ++struct ovsdb_cs_table_update { ++ const char *table_name; ++ struct ovsdb_cs_row_update *row_updates; ++ size_t n; ++}; ++ ++struct ovsdb_cs_db_update { ++ struct ovsdb_cs_table_update *table_updates; ++ size_t n; ++}; ++ ++struct ovsdb_error *ovsdb_cs_parse_db_update( ++ const struct json *table_updates, int version, ++ struct ovsdb_cs_db_update **db_updatep) ++ OVS_WARN_UNUSED_RESULT; ++void ovsdb_cs_db_update_destroy(struct ovsdb_cs_db_update *); ++const struct ovsdb_cs_table_update *ovsdb_cs_db_update_find_table( ++ const struct ovsdb_cs_db_update *, const char *table_name); ++ ++/* Simple parsing of OVSDB schemas for use by ovsdb_cs clients. */ ++ ++struct shash *ovsdb_cs_parse_schema(const struct json *schema_json); ++void ovsdb_cs_free_schema(struct shash *schema); ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovsdb-error.h */ -diff --git a/lib/ovsdb-idl-provider.h b/include/openvswitch/ovsdb-idl-provider.h -similarity index 97% -rename from lib/ovsdb-idl-provider.h -rename to include/openvswitch/ovsdb-idl-provider.h -index 8797686f9..53efd911c 100644 ---- a/lib/ovsdb-idl-provider.h -+++ b/include/openvswitch/ovsdb-idl-provider.h -@@ -19,13 +19,13 @@ - - #include "openvswitch/hmap.h" - #include "openvswitch/list.h" ++#endif /* ovsdb-cs.h */ +Index: openvswitch-2.17.2/lib/ovsdb-data.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-data.h ++++ /dev/null +@@ -1,339 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2012, 2015, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_DATA_H +-#define OVSDB_DATA_H 1 +- +-#include +-#include "openvswitch/compiler.h" +-#include "ovsdb-types.h" +-#include "openvswitch/json.h" +-#include "openvswitch/shash.h" +-#include "util.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#define MAX_OVSDB_ATOM_RANGE_SIZE 4096 +- +-struct ds; +-struct ovsdb_symbol_table; +-struct smap; +- +-static inline struct json * +-ovsdb_atom_string_create_nocopy(char *str) +-{ +- return json_string_create_nocopy(str); +-} +- +-static inline struct json * +-ovsdb_atom_string_create(const char *str) +-{ +- return json_string_create(str); +-} +- +-/* One value of an atomic type (given by enum ovs_atomic_type). */ +-union ovsdb_atom { +- int64_t integer; +- double real; +- bool boolean; +- struct json *s; +- struct uuid uuid; +-}; +- +-void ovsdb_atom_init_default(union ovsdb_atom *, enum ovsdb_atomic_type); +-const union ovsdb_atom *ovsdb_atom_default(enum ovsdb_atomic_type); +-bool ovsdb_atom_is_default(const union ovsdb_atom *, enum ovsdb_atomic_type); +-void ovsdb_atom_clone(union ovsdb_atom *, const union ovsdb_atom *, +- enum ovsdb_atomic_type); +-void ovsdb_atom_swap(union ovsdb_atom *, union ovsdb_atom *); +- +-/* Returns false if ovsdb_atom_destroy() is a no-op when it is applied to an +- * initialized atom of the given 'type', true if ovsdb_atom_destroy() actually +- * does something. +- * +- * This can be used to avoid calling ovsdb_atom_destroy() for each element in +- * an array of homogeneous atoms. (It's not worthwhile for a single atom.) */ +-static inline bool +-ovsdb_atom_needs_destruction(enum ovsdb_atomic_type type) +-{ +- return type == OVSDB_TYPE_STRING; +-} +- +-/* Frees the contents of 'atom', which must have the specified 'type'. +- * +- * This does not actually call free(atom). If necessary, the caller must be +- * responsible for that. */ +-static inline void +-ovsdb_atom_destroy(union ovsdb_atom *atom, enum ovsdb_atomic_type type) +-{ +- if (type == OVSDB_TYPE_STRING) { +- json_destroy(atom->s); +- } +-} +- +-uint32_t ovsdb_atom_hash(const union ovsdb_atom *, enum ovsdb_atomic_type, +- uint32_t basis); +- +-int ovsdb_atom_compare_3way(const union ovsdb_atom *, +- const union ovsdb_atom *, +- enum ovsdb_atomic_type); +- +-/* Returns true if 'a' and 'b', which are both of type 'type', has the same +- * contents, false if their contents differ. */ +-static inline bool ovsdb_atom_equals(const union ovsdb_atom *a, +- const union ovsdb_atom *b, +- enum ovsdb_atomic_type type) +-{ +- return !ovsdb_atom_compare_3way(a, b, type); +-} +- +-struct ovsdb_error *ovsdb_atom_from_json(union ovsdb_atom *, +- const struct ovsdb_base_type *, +- const struct json *, +- struct ovsdb_symbol_table *) +- OVS_WARN_UNUSED_RESULT; +-struct json *ovsdb_atom_to_json(const union ovsdb_atom *, +- enum ovsdb_atomic_type); +- +-char *ovsdb_atom_from_string(union ovsdb_atom *, union ovsdb_atom **, +- const struct ovsdb_base_type *, const char *, +- struct ovsdb_symbol_table *) +- OVS_WARN_UNUSED_RESULT; +-void ovsdb_atom_to_string(const union ovsdb_atom *, enum ovsdb_atomic_type, +- struct ds *); +-void ovsdb_atom_to_bare(const union ovsdb_atom *, enum ovsdb_atomic_type, +- struct ds *); +- +-struct ovsdb_error *ovsdb_atom_check_constraints( +- const union ovsdb_atom *, const struct ovsdb_base_type *) +- OVS_WARN_UNUSED_RESULT; +- +-/* An instance of an OVSDB type (given by struct ovsdb_type). +- * +- * - The 'keys' must be unique and in sorted order. Most functions that modify +- * an ovsdb_datum maintain these invariants. Functions that don't maintain +- * the invariants have names that end in "_unsafe". Use ovsdb_datum_sort() +- * to check and restore these invariants. +- * +- * - 'n' is constrained by the ovsdb_type's 'n_min' and 'n_max'. +- * +- * If 'n' is nonzero, then 'keys' points to an array of 'n' atoms of the type +- * specified by the ovsdb_type's 'key_type'. (Otherwise, 'keys' should be +- * null.) +- * +- * If 'n' is nonzero and the ovsdb_type's 'value_type' is not +- * OVSDB_TYPE_VOID, then 'values' points to an array of 'n' atoms of the type +- * specified by the 'value_type'. (Otherwise, 'values' should be null.) +- * +- * Thus, for 'n' > 0, 'keys' will always be nonnull and 'values' will be +- * nonnull only for "map" types. +- */ +-struct ovsdb_datum { +- unsigned int n; /* Number of 'keys' and 'values'. */ +- union ovsdb_atom *keys; /* Each of the ovsdb_type's 'key_type'. */ +- union ovsdb_atom *values; /* Each of the ovsdb_type's 'value_type'. */ +-}; +-#define OVSDB_DATUM_INITIALIZER { 0, NULL, NULL } +- +-/* Basics. */ +-void ovsdb_datum_init_empty(struct ovsdb_datum *); +-void ovsdb_datum_init_default(struct ovsdb_datum *, const struct ovsdb_type *); +-bool ovsdb_datum_is_default(const struct ovsdb_datum *, +- const struct ovsdb_type *); +-const struct ovsdb_datum *ovsdb_datum_default(const struct ovsdb_type *); +-void ovsdb_datum_clone(struct ovsdb_datum *, const struct ovsdb_datum *, +- const struct ovsdb_type *); +-void ovsdb_datum_destroy(struct ovsdb_datum *, const struct ovsdb_type *); +-void ovsdb_datum_swap(struct ovsdb_datum *, struct ovsdb_datum *); +- +-/* Checking and maintaining invariants. */ +-struct ovsdb_error *ovsdb_datum_sort(struct ovsdb_datum *, +- enum ovsdb_atomic_type key_type) +- OVS_WARN_UNUSED_RESULT; +- +-void ovsdb_datum_sort_assert(struct ovsdb_datum *, +- enum ovsdb_atomic_type key_type); +- +-size_t ovsdb_datum_sort_unique(struct ovsdb_datum *, +- enum ovsdb_atomic_type key_type, +- enum ovsdb_atomic_type value_type); +- +-struct ovsdb_error *ovsdb_datum_check_constraints( +- const struct ovsdb_datum *, const struct ovsdb_type *) +- OVS_WARN_UNUSED_RESULT; +- +-/* Type conversion. */ +-struct ovsdb_error *ovsdb_datum_from_json(struct ovsdb_datum *, +- const struct ovsdb_type *, +- const struct json *, +- struct ovsdb_symbol_table *) +- OVS_WARN_UNUSED_RESULT; +-struct ovsdb_error *ovsdb_transient_datum_from_json( +- struct ovsdb_datum *, +- const struct ovsdb_type *, +- const struct json *) +- OVS_WARN_UNUSED_RESULT; +-struct ovsdb_error * +-ovsdb_unconstrained_datum_from_json(struct ovsdb_datum *, +- const struct ovsdb_type *, +- const struct json *) +- OVS_WARN_UNUSED_RESULT; +-struct json *ovsdb_datum_to_json(const struct ovsdb_datum *, +- const struct ovsdb_type *); +- +-char *ovsdb_datum_from_string(struct ovsdb_datum *, +- const struct ovsdb_type *, const char *, +- struct ovsdb_symbol_table *) +- OVS_WARN_UNUSED_RESULT; +-void ovsdb_datum_to_string(const struct ovsdb_datum *, +- const struct ovsdb_type *, struct ds *); +-void ovsdb_datum_to_bare(const struct ovsdb_datum *, +- const struct ovsdb_type *, struct ds *); +- +-void ovsdb_datum_from_smap(struct ovsdb_datum *, const struct smap *); +- +-struct ovsdb_error *ovsdb_datum_convert(struct ovsdb_datum *dst, +- const struct ovsdb_type *dst_type, +- const struct ovsdb_datum *src, +- const struct ovsdb_type *src_type) +- OVS_WARN_UNUSED_RESULT; +- +-/* Comparison. */ +-uint32_t ovsdb_datum_hash(const struct ovsdb_datum *, +- const struct ovsdb_type *, uint32_t basis); +-int ovsdb_datum_compare_3way(const struct ovsdb_datum *, +- const struct ovsdb_datum *, +- const struct ovsdb_type *); +-bool ovsdb_datum_equals(const struct ovsdb_datum *, +- const struct ovsdb_datum *, +- const struct ovsdb_type *); +- +-/* Search. */ +-bool ovsdb_datum_find_key(const struct ovsdb_datum *, +- const union ovsdb_atom *key, +- enum ovsdb_atomic_type key_type, +- unsigned int *pos); +-unsigned int ovsdb_datum_find_key_value(const struct ovsdb_datum *, +- const union ovsdb_atom *key, +- enum ovsdb_atomic_type key_type, +- const union ovsdb_atom *value, +- enum ovsdb_atomic_type value_type); +- +-/* Set operations. */ +-bool ovsdb_datum_includes_all(const struct ovsdb_datum *, +- const struct ovsdb_datum *, +- const struct ovsdb_type *); +-bool ovsdb_datum_excludes_all(const struct ovsdb_datum *, +- const struct ovsdb_datum *, +- const struct ovsdb_type *); +-void ovsdb_datum_union(struct ovsdb_datum *, +- const struct ovsdb_datum *, +- const struct ovsdb_type *); +-void ovsdb_datum_subtract(struct ovsdb_datum *a, +- const struct ovsdb_type *a_type, +- const struct ovsdb_datum *b, +- const struct ovsdb_type *b_type); +- +-/* Generate and apply diffs */ +-void ovsdb_datum_added_removed(struct ovsdb_datum *added, +- struct ovsdb_datum *removed, +- const struct ovsdb_datum *old, +- const struct ovsdb_datum *new, +- const struct ovsdb_type *type); +- +-void ovsdb_datum_diff(struct ovsdb_datum *diff, +- const struct ovsdb_datum *old_datum, +- const struct ovsdb_datum *new_datum, +- const struct ovsdb_type *type); +- +-struct ovsdb_error *ovsdb_datum_apply_diff(struct ovsdb_datum *new_datum, +- const struct ovsdb_datum *old_datum, +- const struct ovsdb_datum *diff, +- const struct ovsdb_type *type) +-OVS_WARN_UNUSED_RESULT; +- +-struct ovsdb_error * ovsdb_datum_apply_diff_in_place( +- struct ovsdb_datum *a, +- const struct ovsdb_datum *diff, +- const struct ovsdb_type *type) +-OVS_WARN_UNUSED_RESULT; +- +-/* Raw operations that may not maintain the invariants. */ +-void ovsdb_datum_remove_unsafe(struct ovsdb_datum *, size_t idx, +- const struct ovsdb_type *); +-void ovsdb_datum_add_unsafe(struct ovsdb_datum *, +- const union ovsdb_atom *key, +- const union ovsdb_atom *value, +- const struct ovsdb_type *, +- const union ovsdb_atom *range_end_atom); +-void ovsdb_datum_add_from_index_unsafe(struct ovsdb_datum *dst, +- const struct ovsdb_datum *src, +- size_t idx, +- const struct ovsdb_type *type); +- +-/* Transactions with named-uuid row names. */ +-struct json *ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *, +- const struct ovsdb_type *); +-char *ovsdb_data_row_name(const struct uuid *); +- +-/* Type checking. */ +-static inline bool +-ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum, +- const struct ovsdb_type *type) +-{ +- return datum->n >= type->n_min && datum->n <= type->n_max; +-} +- +-/* A table mapping from names to data items. Currently the data items are +- * always UUIDs; perhaps this will be expanded in the future. */ +- +-struct ovsdb_symbol_table { +- struct shash sh; /* Maps from name to struct ovsdb_symbol *. */ +-}; +- +-struct ovsdb_symbol { +- struct uuid uuid; /* The UUID that the symbol represents. */ +- bool created; /* Already used to create row? */ +- bool strong_ref; /* Parsed a strong reference to this row? */ +- bool weak_ref; /* Parsed a weak reference to this row? */ +-}; +- +-struct ovsdb_symbol_table *ovsdb_symbol_table_create(void); +-void ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *); +-struct ovsdb_symbol *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *, +- const char *name); +-struct ovsdb_symbol *ovsdb_symbol_table_put(struct ovsdb_symbol_table *, +- const char *name, +- const struct uuid *, bool used); +-struct ovsdb_symbol *ovsdb_symbol_table_insert(struct ovsdb_symbol_table *, +- const char *name); +- +-/* Tokenization +- * +- * Used by ovsdb_atom_from_string() and ovsdb_datum_from_string(). */ +- +-char *ovsdb_token_parse(const char **, char **outp) OVS_WARN_UNUSED_RESULT; +-bool ovsdb_token_is_delim(unsigned char); +- +-struct ovsdb_error *ovsdb_atom_range_check_size(int64_t range_start, +- int64_t range_end); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-data.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-data.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-data.h +@@ -0,0 +1,339 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012, 2015, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_DATA_H ++#define OVSDB_DATA_H 1 ++ ++#include ++#include "openvswitch/compiler.h" ++#include "openvswitch/ovsdb-types.h" ++#include "openvswitch/json.h" ++#include "openvswitch/shash.h" ++#include "internal/util.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define MAX_OVSDB_ATOM_RANGE_SIZE 4096 ++ ++struct ds; ++struct ovsdb_symbol_table; ++struct smap; ++ ++static inline struct json * ++ovsdb_atom_string_create_nocopy(char *str) ++{ ++ return json_string_create_nocopy(str); ++} ++ ++static inline struct json * ++ovsdb_atom_string_create(const char *str) ++{ ++ return json_string_create(str); ++} ++ ++/* One value of an atomic type (given by enum ovs_atomic_type). */ ++union ovsdb_atom { ++ int64_t integer; ++ double real; ++ bool boolean; ++ struct json *s; ++ struct uuid uuid; ++}; ++ ++void ovsdb_atom_init_default(union ovsdb_atom *, enum ovsdb_atomic_type); ++const union ovsdb_atom *ovsdb_atom_default(enum ovsdb_atomic_type); ++bool ovsdb_atom_is_default(const union ovsdb_atom *, enum ovsdb_atomic_type); ++void ovsdb_atom_clone(union ovsdb_atom *, const union ovsdb_atom *, ++ enum ovsdb_atomic_type); ++void ovsdb_atom_swap(union ovsdb_atom *, union ovsdb_atom *); ++ ++/* Returns false if ovsdb_atom_destroy() is a no-op when it is applied to an ++ * initialized atom of the given 'type', true if ovsdb_atom_destroy() actually ++ * does something. ++ * ++ * This can be used to avoid calling ovsdb_atom_destroy() for each element in ++ * an array of homogeneous atoms. (It's not worthwhile for a single atom.) */ ++static inline bool ++ovsdb_atom_needs_destruction(enum ovsdb_atomic_type type) ++{ ++ return type == OVSDB_TYPE_STRING; ++} ++ ++/* Frees the contents of 'atom', which must have the specified 'type'. ++ * ++ * This does not actually call free(atom). If necessary, the caller must be ++ * responsible for that. */ ++static inline void ++ovsdb_atom_destroy(union ovsdb_atom *atom, enum ovsdb_atomic_type type) ++{ ++ if (type == OVSDB_TYPE_STRING) { ++ json_destroy(atom->s); ++ } ++} ++ ++uint32_t ovsdb_atom_hash(const union ovsdb_atom *, enum ovsdb_atomic_type, ++ uint32_t basis); ++ ++int ovsdb_atom_compare_3way(const union ovsdb_atom *, ++ const union ovsdb_atom *, ++ enum ovsdb_atomic_type); ++ ++/* Returns true if 'a' and 'b', which are both of type 'type', has the same ++ * contents, false if their contents differ. */ ++static inline bool ovsdb_atom_equals(const union ovsdb_atom *a, ++ const union ovsdb_atom *b, ++ enum ovsdb_atomic_type type) ++{ ++ return !ovsdb_atom_compare_3way(a, b, type); ++} ++ ++struct ovsdb_error *ovsdb_atom_from_json(union ovsdb_atom *, ++ const struct ovsdb_base_type *, ++ const struct json *, ++ struct ovsdb_symbol_table *) ++ OVS_WARN_UNUSED_RESULT; ++struct json *ovsdb_atom_to_json(const union ovsdb_atom *, ++ enum ovsdb_atomic_type); ++ ++char *ovsdb_atom_from_string(union ovsdb_atom *, union ovsdb_atom **, ++ const struct ovsdb_base_type *, const char *, ++ struct ovsdb_symbol_table *) ++ OVS_WARN_UNUSED_RESULT; ++void ovsdb_atom_to_string(const union ovsdb_atom *, enum ovsdb_atomic_type, ++ struct ds *); ++void ovsdb_atom_to_bare(const union ovsdb_atom *, enum ovsdb_atomic_type, ++ struct ds *); ++ ++struct ovsdb_error *ovsdb_atom_check_constraints( ++ const union ovsdb_atom *, const struct ovsdb_base_type *) ++ OVS_WARN_UNUSED_RESULT; ++ ++/* An instance of an OVSDB type (given by struct ovsdb_type). ++ * ++ * - The 'keys' must be unique and in sorted order. Most functions that modify ++ * an ovsdb_datum maintain these invariants. Functions that don't maintain ++ * the invariants have names that end in "_unsafe". Use ovsdb_datum_sort() ++ * to check and restore these invariants. ++ * ++ * - 'n' is constrained by the ovsdb_type's 'n_min' and 'n_max'. ++ * ++ * If 'n' is nonzero, then 'keys' points to an array of 'n' atoms of the type ++ * specified by the ovsdb_type's 'key_type'. (Otherwise, 'keys' should be ++ * null.) ++ * ++ * If 'n' is nonzero and the ovsdb_type's 'value_type' is not ++ * OVSDB_TYPE_VOID, then 'values' points to an array of 'n' atoms of the type ++ * specified by the 'value_type'. (Otherwise, 'values' should be null.) ++ * ++ * Thus, for 'n' > 0, 'keys' will always be nonnull and 'values' will be ++ * nonnull only for "map" types. ++ */ ++struct ovsdb_datum { ++ unsigned int n; /* Number of 'keys' and 'values'. */ ++ union ovsdb_atom *keys; /* Each of the ovsdb_type's 'key_type'. */ ++ union ovsdb_atom *values; /* Each of the ovsdb_type's 'value_type'. */ ++}; ++#define OVSDB_DATUM_INITIALIZER { 0, NULL, NULL } ++ ++/* Basics. */ ++void ovsdb_datum_init_empty(struct ovsdb_datum *); ++void ovsdb_datum_init_default(struct ovsdb_datum *, const struct ovsdb_type *); ++bool ovsdb_datum_is_default(const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++const struct ovsdb_datum *ovsdb_datum_default(const struct ovsdb_type *); ++void ovsdb_datum_clone(struct ovsdb_datum *, const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++void ovsdb_datum_destroy(struct ovsdb_datum *, const struct ovsdb_type *); ++void ovsdb_datum_swap(struct ovsdb_datum *, struct ovsdb_datum *); ++ ++/* Checking and maintaining invariants. */ ++struct ovsdb_error *ovsdb_datum_sort(struct ovsdb_datum *, ++ enum ovsdb_atomic_type key_type) ++ OVS_WARN_UNUSED_RESULT; ++ ++void ovsdb_datum_sort_assert(struct ovsdb_datum *, ++ enum ovsdb_atomic_type key_type); ++ ++size_t ovsdb_datum_sort_unique(struct ovsdb_datum *, ++ enum ovsdb_atomic_type key_type, ++ enum ovsdb_atomic_type value_type); ++ ++struct ovsdb_error *ovsdb_datum_check_constraints( ++ const struct ovsdb_datum *, const struct ovsdb_type *) ++ OVS_WARN_UNUSED_RESULT; ++ ++/* Type conversion. */ ++struct ovsdb_error *ovsdb_datum_from_json(struct ovsdb_datum *, ++ const struct ovsdb_type *, ++ const struct json *, ++ struct ovsdb_symbol_table *) ++ OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error *ovsdb_transient_datum_from_json( ++ struct ovsdb_datum *, ++ const struct ovsdb_type *, ++ const struct json *) ++ OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error * ++ovsdb_unconstrained_datum_from_json(struct ovsdb_datum *, ++ const struct ovsdb_type *, ++ const struct json *) ++ OVS_WARN_UNUSED_RESULT; ++struct json *ovsdb_datum_to_json(const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++ ++char *ovsdb_datum_from_string(struct ovsdb_datum *, ++ const struct ovsdb_type *, const char *, ++ struct ovsdb_symbol_table *) ++ OVS_WARN_UNUSED_RESULT; ++void ovsdb_datum_to_string(const struct ovsdb_datum *, ++ const struct ovsdb_type *, struct ds *); ++void ovsdb_datum_to_bare(const struct ovsdb_datum *, ++ const struct ovsdb_type *, struct ds *); ++ ++void ovsdb_datum_from_smap(struct ovsdb_datum *, const struct smap *); ++ ++struct ovsdb_error *ovsdb_datum_convert(struct ovsdb_datum *dst, ++ const struct ovsdb_type *dst_type, ++ const struct ovsdb_datum *src, ++ const struct ovsdb_type *src_type) ++ OVS_WARN_UNUSED_RESULT; ++ ++/* Comparison. */ ++uint32_t ovsdb_datum_hash(const struct ovsdb_datum *, ++ const struct ovsdb_type *, uint32_t basis); ++int ovsdb_datum_compare_3way(const struct ovsdb_datum *, ++ const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++bool ovsdb_datum_equals(const struct ovsdb_datum *, ++ const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++ ++/* Search. */ ++bool ovsdb_datum_find_key(const struct ovsdb_datum *, ++ const union ovsdb_atom *key, ++ enum ovsdb_atomic_type key_type, ++ unsigned int *pos); ++unsigned int ovsdb_datum_find_key_value(const struct ovsdb_datum *, ++ const union ovsdb_atom *key, ++ enum ovsdb_atomic_type key_type, ++ const union ovsdb_atom *value, ++ enum ovsdb_atomic_type value_type); ++ ++/* Set operations. */ ++bool ovsdb_datum_includes_all(const struct ovsdb_datum *, ++ const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++bool ovsdb_datum_excludes_all(const struct ovsdb_datum *, ++ const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++void ovsdb_datum_union(struct ovsdb_datum *, ++ const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++void ovsdb_datum_subtract(struct ovsdb_datum *a, ++ const struct ovsdb_type *a_type, ++ const struct ovsdb_datum *b, ++ const struct ovsdb_type *b_type); ++ ++/* Generate and apply diffs */ ++void ovsdb_datum_added_removed(struct ovsdb_datum *added, ++ struct ovsdb_datum *removed, ++ const struct ovsdb_datum *old, ++ const struct ovsdb_datum *new, ++ const struct ovsdb_type *type); ++ ++void ovsdb_datum_diff(struct ovsdb_datum *diff, ++ const struct ovsdb_datum *old_datum, ++ const struct ovsdb_datum *new_datum, ++ const struct ovsdb_type *type); ++ ++struct ovsdb_error *ovsdb_datum_apply_diff(struct ovsdb_datum *new_datum, ++ const struct ovsdb_datum *old_datum, ++ const struct ovsdb_datum *diff, ++ const struct ovsdb_type *type) ++OVS_WARN_UNUSED_RESULT; ++ ++struct ovsdb_error * ovsdb_datum_apply_diff_in_place( ++ struct ovsdb_datum *a, ++ const struct ovsdb_datum *diff, ++ const struct ovsdb_type *type) ++OVS_WARN_UNUSED_RESULT; ++ ++/* Raw operations that may not maintain the invariants. */ ++void ovsdb_datum_remove_unsafe(struct ovsdb_datum *, size_t idx, ++ const struct ovsdb_type *); ++void ovsdb_datum_add_unsafe(struct ovsdb_datum *, ++ const union ovsdb_atom *key, ++ const union ovsdb_atom *value, ++ const struct ovsdb_type *, ++ const union ovsdb_atom *range_end_atom); ++void ovsdb_datum_add_from_index_unsafe(struct ovsdb_datum *dst, ++ const struct ovsdb_datum *src, ++ size_t idx, ++ const struct ovsdb_type *type); ++ ++/* Transactions with named-uuid row names. */ ++struct json *ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *, ++ const struct ovsdb_type *); ++char *ovsdb_data_row_name(const struct uuid *); ++ ++/* Type checking. */ ++static inline bool ++ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum, ++ const struct ovsdb_type *type) ++{ ++ return datum->n >= type->n_min && datum->n <= type->n_max; ++} ++ ++/* A table mapping from names to data items. Currently the data items are ++ * always UUIDs; perhaps this will be expanded in the future. */ ++ ++struct ovsdb_symbol_table { ++ struct shash sh; /* Maps from name to struct ovsdb_symbol *. */ ++}; ++ ++struct ovsdb_symbol { ++ struct uuid uuid; /* The UUID that the symbol represents. */ ++ bool created; /* Already used to create row? */ ++ bool strong_ref; /* Parsed a strong reference to this row? */ ++ bool weak_ref; /* Parsed a weak reference to this row? */ ++}; ++ ++struct ovsdb_symbol_table *ovsdb_symbol_table_create(void); ++void ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *); ++struct ovsdb_symbol *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *, ++ const char *name); ++struct ovsdb_symbol *ovsdb_symbol_table_put(struct ovsdb_symbol_table *, ++ const char *name, ++ const struct uuid *, bool used); ++struct ovsdb_symbol *ovsdb_symbol_table_insert(struct ovsdb_symbol_table *, ++ const char *name); ++ ++/* Tokenization ++ * ++ * Used by ovsdb_atom_from_string() and ovsdb_datum_from_string(). */ ++ ++char *ovsdb_token_parse(const char **, char **outp) OVS_WARN_UNUSED_RESULT; ++bool ovsdb_token_is_delim(unsigned char); ++ ++struct ovsdb_error *ovsdb_atom_range_check_size(int64_t range_start, ++ int64_t range_end); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-data.h */ +Index: openvswitch-2.17.2/lib/ovsdb-error.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-error.h ++++ /dev/null +@@ -1,75 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_ERROR_H +-#define OVSDB_ERROR_H 1 +- +-#include "openvswitch/compiler.h" +- +-struct json; +- +-struct ovsdb_error *ovsdb_error(const char *tag, const char *details, ...) +- OVS_PRINTF_FORMAT(2, 3) +- OVS_WARN_UNUSED_RESULT; +-struct ovsdb_error *ovsdb_io_error(int error, const char *details, ...) +- OVS_PRINTF_FORMAT(2, 3) +- OVS_WARN_UNUSED_RESULT; +-struct ovsdb_error *ovsdb_syntax_error(const struct json *, const char *tag, +- const char *details, ...) +- OVS_PRINTF_FORMAT(3, 4) +- OVS_WARN_UNUSED_RESULT; +- +-struct ovsdb_error *ovsdb_wrap_error(struct ovsdb_error *error, +- const char *details, ...) +- OVS_PRINTF_FORMAT(2, 3); +- +-struct ovsdb_error *ovsdb_internal_error(struct ovsdb_error *error, +- const char *file, int line, +- const char *details, ...) +- OVS_PRINTF_FORMAT(4, 5) +- OVS_WARN_UNUSED_RESULT; +- +-struct ovsdb_error *ovsdb_perm_error(const char *details, ...) +- OVS_PRINTF_FORMAT(1, 2) +- OVS_WARN_UNUSED_RESULT; +- +-/* Returns a pointer to an ovsdb_error that represents an internal error for +- * the current file name and line number with MSG as the associated message. +- * The caller is responsible for freeing the internal error. */ +-#define OVSDB_BUG(MSG) \ +- ovsdb_internal_error(NULL, __FILE__, __LINE__, "%s", MSG) +- +-/* Returns a pointer to an ovsdb_error that represents an internal error for +- * the current file name and line number, with MSG as the associated message. +- * If ERROR is nonnull then the internal error is wrapped around ERROR. Takes +- * ownership of ERROR. The caller is responsible for freeing the returned +- * error. */ +-#define OVSDB_WRAP_BUG(MSG, ERROR) \ +- ovsdb_internal_error(ERROR, __FILE__, __LINE__, "%s", MSG) +- +-void ovsdb_error_destroy(struct ovsdb_error *); +-struct ovsdb_error *ovsdb_error_clone(const struct ovsdb_error *) +- OVS_WARN_UNUSED_RESULT; +- +-char *ovsdb_error_to_string(const struct ovsdb_error *); +-char *ovsdb_error_to_string_free(struct ovsdb_error *); +-struct json *ovsdb_error_to_json(const struct ovsdb_error *); +-struct json *ovsdb_error_to_json_free(struct ovsdb_error *); +- +-const char *ovsdb_error_get_tag(const struct ovsdb_error *); +- +-void ovsdb_error_assert(struct ovsdb_error *); +- +-#endif /* ovsdb-error.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-error.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-error.h +@@ -0,0 +1,83 @@ ++/* Copyright (c) 2009, 2010, 2011, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_ERROR_H ++#define OVSDB_ERROR_H 1 ++ ++#include "openvswitch/compiler.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct json; ++ ++struct ovsdb_error *ovsdb_error(const char *tag, const char *details, ...) ++ OVS_PRINTF_FORMAT(2, 3) ++ OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error *ovsdb_io_error(int error, const char *details, ...) ++ OVS_PRINTF_FORMAT(2, 3) ++ OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error *ovsdb_syntax_error(const struct json *, const char *tag, ++ const char *details, ...) ++ OVS_PRINTF_FORMAT(3, 4) ++ OVS_WARN_UNUSED_RESULT; ++ ++struct ovsdb_error *ovsdb_wrap_error(struct ovsdb_error *error, ++ const char *details, ...) ++ OVS_PRINTF_FORMAT(2, 3); ++ ++struct ovsdb_error *ovsdb_internal_error(struct ovsdb_error *error, ++ const char *file, int line, ++ const char *details, ...) ++ OVS_PRINTF_FORMAT(4, 5) ++ OVS_WARN_UNUSED_RESULT; ++ ++struct ovsdb_error *ovsdb_perm_error(const char *details, ...) ++ OVS_PRINTF_FORMAT(1, 2) ++ OVS_WARN_UNUSED_RESULT; ++ ++/* Returns a pointer to an ovsdb_error that represents an internal error for ++ * the current file name and line number with MSG as the associated message. ++ * The caller is responsible for freeing the internal error. */ ++#define OVSDB_BUG(MSG) \ ++ ovsdb_internal_error(NULL, __FILE__, __LINE__, "%s", MSG) ++ ++/* Returns a pointer to an ovsdb_error that represents an internal error for ++ * the current file name and line number, with MSG as the associated message. ++ * If ERROR is nonnull then the internal error is wrapped around ERROR. Takes ++ * ownership of ERROR. The caller is responsible for freeing the returned ++ * error. */ ++#define OVSDB_WRAP_BUG(MSG, ERROR) \ ++ ovsdb_internal_error(ERROR, __FILE__, __LINE__, "%s", MSG) ++ ++void ovsdb_error_destroy(struct ovsdb_error *); ++struct ovsdb_error *ovsdb_error_clone(const struct ovsdb_error *) ++ OVS_WARN_UNUSED_RESULT; ++ ++char *ovsdb_error_to_string(const struct ovsdb_error *); ++char *ovsdb_error_to_string_free(struct ovsdb_error *); ++struct json *ovsdb_error_to_json(const struct ovsdb_error *); ++struct json *ovsdb_error_to_json_free(struct ovsdb_error *); ++ ++const char *ovsdb_error_get_tag(const struct ovsdb_error *); ++ ++void ovsdb_error_assert(struct ovsdb_error *); ++ ++#ifdef __cplusplus ++} // extern "C" ++#endif ++ ++#endif /* ovsdb-error.h */ +Index: openvswitch-2.17.2/lib/ovsdb-idl-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-idl-provider.h ++++ /dev/null +@@ -1,181 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2012, 2016 Nicira, Inc. +- * Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_IDL_PROVIDER_H +-#define OVSDB_IDL_PROVIDER_H 1 +- +-#include "openvswitch/hmap.h" +-#include "openvswitch/list.h" -#include "ovsdb-idl.h" -#include "ovsdb-map-op.h" -#include "ovsdb-set-op.h" -#include "ovsdb-types.h" +-#include "openvswitch/shash.h" +-#include "sset.h" +-#include "uuid.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* A local copy of a row in an OVSDB table, replicated from an OVSDB server. +- * This structure is used as a header for a larger structure that translates +- * the "struct ovsdb_datum"s into easier-to-use forms, via the ->parse() and +- * ->unparse functions in struct ovsdb_idl_column. (Those functions are +- * generated automatically via ovsdb-idlc.) +- * +- * When no transaction is in progress: +- * +- * - 'old_datum' points to the data committed to the database and currently +- * in the row. +- * +- * - 'new_datum == old_datum'. +- * +- * When a transaction is in progress, the situation is a little different. For +- * a row inserted in the transaction, 'old_datum' is NULL and 'new_datum' +- * points to the row's initial contents. Otherwise: +- * +- * - 'old_datum' points to the data committed to the database and currently +- * in the row. (This is the same as when no transaction is in progress.) +- * +- * - If the transaction does not modify the row, 'new_datum == old_datum'. +- * +- * - If the transaction modifies the row, 'new_datum' points to the +- * modified data. +- * +- * - If the transaction deletes the row, 'new_datum' is NULL. +- * +- * Thus: +- * +- * - 'old_datum' always points to committed data, except that it is NULL if +- * the row is inserted within the current transaction. +- * +- * - 'new_datum' always points to the newest, possibly uncommitted version +- * of the row's data, except that it is NULL if the row is deleted within +- * the current transaction. +- */ +-struct ovsdb_idl_row { +- struct hmap_node hmap_node; /* In struct ovsdb_idl_table's 'rows'. */ +- struct uuid uuid; /* Row "_uuid" field. */ +- struct ovs_list src_arcs; /* Forward arcs (ovsdb_idl_arc.src_node). */ +- struct ovs_list dst_arcs; /* Backward arcs (ovsdb_idl_arc.dst_node). */ +- struct ovsdb_idl_table *table; /* Containing table. */ +- struct ovsdb_datum *old_datum; /* Committed data (null if orphaned). */ +- bool parsed; /* Whether the row is parsed. */ +- struct ovs_list reparse_node; /* Rows that needs to be re-parsed due to +- * insertion of a referenced row. */ +- +- /* Transactional data. */ +- struct ovsdb_datum *new_datum; /* Modified data (null to delete row). */ +- unsigned long int *prereqs; /* Bitmap of "old_datum" columns to verify. */ +- unsigned long int *written; /* Bitmap of "new_datum" columns to write. */ +- struct hmap_node txn_node; /* Node in ovsdb_idl_txn's list. */ +- unsigned long int *map_op_written; /* Bitmap of columns pending map ops. */ +- struct map_op_list **map_op_lists; /* Per-column map operations. */ +- unsigned long int *set_op_written; /* Bitmap of columns pending set ops. */ +- struct set_op_list **set_op_lists; /* Per-column set operations. */ +- +- /* Tracking data */ +- unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX]; +- struct ovs_list track_node; /* Rows modified/added/deleted by IDL */ +- unsigned long int *updated; /* Bitmap of columns updated by IDL */ +- struct ovsdb_datum *tracked_old_datum; /* Old deleted data. */ +-}; +- +-struct ovsdb_idl_column { +- char *name; +- struct ovsdb_type type; +- bool is_mutable; +- bool is_synthetic; +- void (*parse)(struct ovsdb_idl_row *, const struct ovsdb_datum *); +- void (*unparse)(struct ovsdb_idl_row *); +-}; +- +-struct ovsdb_idl_table_class { +- char *name; +- bool is_root; +- bool is_singleton; +- const struct ovsdb_idl_column *columns; +- size_t n_columns; +- size_t allocation_size; +- void (*row_init)(struct ovsdb_idl_row *); +-}; +- +-struct ovsdb_idl_table { +- const struct ovsdb_idl_table_class *class_; +- unsigned char *modes; /* OVSDB_IDL_* bitmasks, indexed by column. */ +- bool need_table; /* Monitor table even if no columns are selected +- * for replication. */ +- struct shash columns; /* Contains "const struct ovsdb_idl_column *"s. */ +- struct sset schema_columns; /* Column names from schema. */ +- struct hmap rows; /* Contains "struct ovsdb_idl_row"s. */ +- struct ovsdb_idl *idl; /* Containing IDL instance. */ +- unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX]; +- bool in_server_schema; /* Indicates if this table is in the server schema +- * or not. */ +- struct ovs_list indexes; /* Contains "struct ovsdb_idl_index"s */ +- struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */ +-}; +- +-struct ovsdb_idl_class { +- const char *database; /* for this database. */ +- const struct ovsdb_idl_table_class *tables; +- size_t n_tables; +-}; +- +-struct ovsdb_idl_row *ovsdb_idl_get_row_arc( +- struct ovsdb_idl_row *src, +- const struct ovsdb_idl_table_class *dst_table, +- const struct uuid *dst_uuid); +- +-void ovsdb_idl_txn_verify(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *); +- +-struct ovsdb_idl_txn *ovsdb_idl_txn_get(const struct ovsdb_idl_row *); +- +-/* Index internals. */ +- +-struct ovsdb_idl_index { +- struct ovs_list node; /* In ->table->indexes. */ +- struct ovsdb_idl_table *table; /* The indexed table. */ +- struct ovsdb_idl_index_column *columns; /* The indexed columns. */ +- size_t n_columns; +- +- /* Skiplist with pointers to rows. */ +- struct skiplist *skiplist; +- +- /* True if a row in the index is being inserted or deleted. If true, the +- search key is augmented with the UUID and address to discriminate +- between entries with identical keys. */ +- bool ins_del; +-}; +- +-int ovsdb_idl_index_compare(struct ovsdb_idl_index *, +- const struct ovsdb_idl_row *a, +- const struct ovsdb_idl_row *b); +- +-void ovsdb_idl_index_write(struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *, +- const struct ovsdb_idl_table_class *); +-struct ovsdb_idl_row *ovsdb_idl_index_init_row(struct ovsdb_idl_index *); +-void ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-idl-provider.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-idl-provider.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-idl-provider.h +@@ -0,0 +1,181 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012, 2016 Nicira, Inc. ++ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_IDL_PROVIDER_H ++#define OVSDB_IDL_PROVIDER_H 1 ++ ++#include "openvswitch/hmap.h" ++#include "openvswitch/list.h" +#include "openvswitch/ovsdb-idl.h" +#include "openvswitch/ovsdb-map-op.h" +#include "openvswitch/ovsdb-set-op.h" +#include "openvswitch/ovsdb-types.h" - #include "openvswitch/shash.h" --#include "sset.h" --#include "uuid.h" ++#include "openvswitch/shash.h" +#include "internal/sset.h" +#include "internal/uuid.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/ovsdb-idl.h b/include/openvswitch/ovsdb-idl.h -similarity index 99% -rename from lib/ovsdb-idl.h -rename to include/openvswitch/ovsdb-idl.h -index 48cff8a83..7e2101704 100644 ---- a/lib/ovsdb-idl.h -+++ b/include/openvswitch/ovsdb-idl.h -@@ -38,11 +38,11 @@ - #include - #include - #include "openvswitch/compiler.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* A local copy of a row in an OVSDB table, replicated from an OVSDB server. ++ * This structure is used as a header for a larger structure that translates ++ * the "struct ovsdb_datum"s into easier-to-use forms, via the ->parse() and ++ * ->unparse functions in struct ovsdb_idl_column. (Those functions are ++ * generated automatically via ovsdb-idlc.) ++ * ++ * When no transaction is in progress: ++ * ++ * - 'old_datum' points to the data committed to the database and currently ++ * in the row. ++ * ++ * - 'new_datum == old_datum'. ++ * ++ * When a transaction is in progress, the situation is a little different. For ++ * a row inserted in the transaction, 'old_datum' is NULL and 'new_datum' ++ * points to the row's initial contents. Otherwise: ++ * ++ * - 'old_datum' points to the data committed to the database and currently ++ * in the row. (This is the same as when no transaction is in progress.) ++ * ++ * - If the transaction does not modify the row, 'new_datum == old_datum'. ++ * ++ * - If the transaction modifies the row, 'new_datum' points to the ++ * modified data. ++ * ++ * - If the transaction deletes the row, 'new_datum' is NULL. ++ * ++ * Thus: ++ * ++ * - 'old_datum' always points to committed data, except that it is NULL if ++ * the row is inserted within the current transaction. ++ * ++ * - 'new_datum' always points to the newest, possibly uncommitted version ++ * of the row's data, except that it is NULL if the row is deleted within ++ * the current transaction. ++ */ ++struct ovsdb_idl_row { ++ struct hmap_node hmap_node; /* In struct ovsdb_idl_table's 'rows'. */ ++ struct uuid uuid; /* Row "_uuid" field. */ ++ struct ovs_list src_arcs; /* Forward arcs (ovsdb_idl_arc.src_node). */ ++ struct ovs_list dst_arcs; /* Backward arcs (ovsdb_idl_arc.dst_node). */ ++ struct ovsdb_idl_table *table; /* Containing table. */ ++ struct ovsdb_datum *old_datum; /* Committed data (null if orphaned). */ ++ bool parsed; /* Whether the row is parsed. */ ++ struct ovs_list reparse_node; /* Rows that needs to be re-parsed due to ++ * insertion of a referenced row. */ ++ ++ /* Transactional data. */ ++ struct ovsdb_datum *new_datum; /* Modified data (null to delete row). */ ++ unsigned long int *prereqs; /* Bitmap of "old_datum" columns to verify. */ ++ unsigned long int *written; /* Bitmap of "new_datum" columns to write. */ ++ struct hmap_node txn_node; /* Node in ovsdb_idl_txn's list. */ ++ unsigned long int *map_op_written; /* Bitmap of columns pending map ops. */ ++ struct map_op_list **map_op_lists; /* Per-column map operations. */ ++ unsigned long int *set_op_written; /* Bitmap of columns pending set ops. */ ++ struct set_op_list **set_op_lists; /* Per-column set operations. */ ++ ++ /* Tracking data */ ++ unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX]; ++ struct ovs_list track_node; /* Rows modified/added/deleted by IDL */ ++ unsigned long int *updated; /* Bitmap of columns updated by IDL */ ++ struct ovsdb_datum *tracked_old_datum; /* Old deleted data. */ ++}; ++ ++struct ovsdb_idl_column { ++ char *name; ++ struct ovsdb_type type; ++ bool is_mutable; ++ bool is_synthetic; ++ void (*parse)(struct ovsdb_idl_row *, const struct ovsdb_datum *); ++ void (*unparse)(struct ovsdb_idl_row *); ++}; ++ ++struct ovsdb_idl_table_class { ++ char *name; ++ bool is_root; ++ bool is_singleton; ++ const struct ovsdb_idl_column *columns; ++ size_t n_columns; ++ size_t allocation_size; ++ void (*row_init)(struct ovsdb_idl_row *); ++}; ++ ++struct ovsdb_idl_table { ++ const struct ovsdb_idl_table_class *class_; ++ unsigned char *modes; /* OVSDB_IDL_* bitmasks, indexed by column. */ ++ bool need_table; /* Monitor table even if no columns are selected ++ * for replication. */ ++ struct shash columns; /* Contains "const struct ovsdb_idl_column *"s. */ ++ struct sset schema_columns; /* Column names from schema. */ ++ struct hmap rows; /* Contains "struct ovsdb_idl_row"s. */ ++ struct ovsdb_idl *idl; /* Containing IDL instance. */ ++ unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX]; ++ bool in_server_schema; /* Indicates if this table is in the server schema ++ * or not. */ ++ struct ovs_list indexes; /* Contains "struct ovsdb_idl_index"s */ ++ struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */ ++}; ++ ++struct ovsdb_idl_class { ++ const char *database; /* for this database. */ ++ const struct ovsdb_idl_table_class *tables; ++ size_t n_tables; ++}; ++ ++struct ovsdb_idl_row *ovsdb_idl_get_row_arc( ++ struct ovsdb_idl_row *src, ++ const struct ovsdb_idl_table_class *dst_table, ++ const struct uuid *dst_uuid); ++ ++void ovsdb_idl_txn_verify(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *); ++ ++struct ovsdb_idl_txn *ovsdb_idl_txn_get(const struct ovsdb_idl_row *); ++ ++/* Index internals. */ ++ ++struct ovsdb_idl_index { ++ struct ovs_list node; /* In ->table->indexes. */ ++ struct ovsdb_idl_table *table; /* The indexed table. */ ++ struct ovsdb_idl_index_column *columns; /* The indexed columns. */ ++ size_t n_columns; ++ ++ /* Skiplist with pointers to rows. */ ++ struct skiplist *skiplist; ++ ++ /* True if a row in the index is being inserted or deleted. If true, the ++ search key is augmented with the UUID and address to discriminate ++ between entries with identical keys. */ ++ bool ins_del; ++}; ++ ++int ovsdb_idl_index_compare(struct ovsdb_idl_index *, ++ const struct ovsdb_idl_row *a, ++ const struct ovsdb_idl_row *b); ++ ++void ovsdb_idl_index_write(struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *, ++ const struct ovsdb_idl_table_class *); ++struct ovsdb_idl_row *ovsdb_idl_index_init_row(struct ovsdb_idl_index *); ++void ovsdb_idl_index_destroy_row(const struct ovsdb_idl_row *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-idl-provider.h */ +Index: openvswitch-2.17.2/lib/ovsdb-idl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-idl.h ++++ /dev/null +@@ -1,488 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2019 Nicira, Inc. +- * Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_IDL_H +-#define OVSDB_IDL_H 1 +- +-/* Open vSwitch Database Interface Definition Language (OVSDB IDL). +- * +- * The OVSDB IDL maintains an in-memory replica of a database. It issues RPC +- * requests to an OVSDB database server and parses the responses, converting +- * raw JSON into data structures that are easier for clients to digest. Most +- * notably, references to rows via UUID become C pointers. +- * +- * The IDL always presents a consistent snapshot of the database to its client, +- * that is, it won't present the effects of some part of a transaction applied +- * at the database server without presenting all of its effects. +- * +- * The IDL also assists with issuing database transactions. The client creates +- * a transaction, manipulates the IDL data structures, and commits or aborts +- * the transaction. The IDL then composes and issues the necessary JSON-RPC +- * requests and reports to the client whether the transaction completed +- * successfully. +- */ +- +-#include +-#include +-#include "openvswitch/compiler.h" -#include "ovsdb-types.h" -#include "ovsdb-data.h" -+#include "openvswitch/ovsdb-types.h" -+#include "openvswitch/ovsdb-data.h" - #include "openvswitch/list.h" +-#include "openvswitch/list.h" -#include "ovsdb-condition.h" -#include "skiplist.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct json; +-struct ovsdb_datum; +-struct ovsdb_idl_class; +-struct ovsdb_idl_row; +-struct ovsdb_idl_column; +-struct ovsdb_idl_table; +-struct ovsdb_idl_table_class; +-struct simap; +-struct uuid; +- +-struct ovsdb_idl *ovsdb_idl_create(const char *remote, +- const struct ovsdb_idl_class *, +- bool monitor_everything_by_default, +- bool retry); +-struct ovsdb_idl *ovsdb_idl_create_unconnected( +- const struct ovsdb_idl_class *, bool monitor_everything_by_default); +-void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *remote, bool retry); +-void ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *, bool shuffle); +-void ovsdb_idl_reset_min_index(struct ovsdb_idl *); +-void ovsdb_idl_destroy(struct ovsdb_idl *); +- +-void ovsdb_idl_set_leader_only(struct ovsdb_idl *, bool leader_only); +- +-void ovsdb_idl_run(struct ovsdb_idl *); +-void ovsdb_idl_wait(struct ovsdb_idl *); +- +-void ovsdb_idl_get_memory_usage(struct ovsdb_idl *, struct simap *usage); +- +-void ovsdb_idl_set_lock(struct ovsdb_idl *, const char *lock_name); +-bool ovsdb_idl_has_lock(const struct ovsdb_idl *); +-bool ovsdb_idl_is_lock_contended(const struct ovsdb_idl *); +- +-unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *); +-bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *); +-void ovsdb_idl_enable_reconnect(struct ovsdb_idl *); +-void ovsdb_idl_force_reconnect(struct ovsdb_idl *); +-void ovsdb_idl_verify_write_only(struct ovsdb_idl *); +- +-bool ovsdb_idl_is_alive(const struct ovsdb_idl *); +-bool ovsdb_idl_is_connected(const struct ovsdb_idl *idl); +-int ovsdb_idl_get_last_error(const struct ovsdb_idl *); +- +-void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval); +- +-void ovsdb_idl_check_consistency(const struct ovsdb_idl *); +- +-const struct ovsdb_idl_class *ovsdb_idl_get_class(const struct ovsdb_idl *); +-const struct ovsdb_idl_table_class *ovsdb_idl_table_class_from_column( +- const struct ovsdb_idl_class *, const struct ovsdb_idl_column *); +-bool ovsdb_idl_server_has_table(const struct ovsdb_idl *, +- const struct ovsdb_idl_table_class *); +-bool ovsdb_idl_server_has_column(const struct ovsdb_idl *, +- const struct ovsdb_idl_column *); +- +-/* Choosing columns and tables to replicate. +- * +- * The client may choose any subset of the columns and tables to replicate, +- * specifying it one of two ways: +- * +- * - As a deny list (adding the columns or tables to replicate). To do so, +- * the client passes false as 'monitor_everything_by_default' to +- * ovsdb_idl_create() and then calls ovsdb_idl_add_column() and +- * ovsdb_idl_add_table() for the desired columns and, if necessary, tables. +- * +- * - As an allow list (replicating all columns and tables except those +- * explicitly removed). To do so, the client passes true as +- * 'monitor_everything_by_default' to ovsdb_idl_create() and then calls +- * ovsdb_idl_omit() to remove columns. +- * +- * There are multiple modes a column may be replicated: +- * +- * - Read-only. This is the default. Whenever the column changes in any +- * replicated row, the value returned by ovsdb_idl_get_seqno() will change, +- * letting the client know to look at the replicated data again. +- * +- * - Write-only. This is for columns that the client sets and updates but +- * does not want to be alerted about its own updates (which, at the OVSDB +- * level, cannot be distinguished from updates made by any other client). +- * The column will be replicated in the same way as for read-only columns, +- * but the value returned by ovsdb_idl_get_seqno() will not change when the +- * column changes, saving wasted CPU time. +- * +- * (A "write-only" client probably does read the column so that it can know +- * whether it needs to update it, but it doesn't expect to react to changes +- * by other clients.) +- * +- * To mark a replicated column as write-only, a client calls +- * ovsdb_idl_omit_alert(). (The column must already be replicated one of +- * the ways described in the previous list.) +- * +- * This is an optimization only and does not affect behavioral correctness +- * of an otherwise well-written client. +- * +- * - Read/write. In theory, an OVSDB client might both read and write a +- * column, although OVSDB schemas are usually designed so that any given +- * client only does one or the other. This is actually the same as +- * read/write columns; that is, the client need take no special action. +- */ +- +-/* Modes with which the IDL can replicate a column. See above comment for +- * overview. +- * +- * If no bits are set, the IDL does not replicate the column at all. The +- * client will always see it with the default value for its type. +- * +- * If OVSDB_IDL_MONITOR is set, then the IDL replicates the column and sets it +- * to to the value in the database. If OVSDB_IDL_ALERT is also set, then the +- * IDL will change the value returned by ovsdb_idl_get_seqno() when the +- * column's value changes in any row. +- * +- * The possible mode combinations are: +- * +- * - 0, for a column that a client doesn't care about. This is the default +- * for every column in every table, if the client passes false for +- * 'monitor_everything_by_default' to ovsdb_idl_create(). +- * +- * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT), for a column that a client wants +- * to track and possibly update. This is the default for every column in +- * every table, if the client passes true for +- * 'monitor_everything_by_default' to ovsdb_idl_create(). +- * +- * - OVSDB_IDL_MONITOR, for columns that a client treats as "write-only", +- * that is, it updates them but doesn't want to get alerted about its own +- * updates. It also won't be alerted about other clients' updates, so this +- * is suitable only for use by a client that "owns" a particular column. +- * Use ovsdb_idl_omit_alert() to set a column that is already replicated to +- * this mode. +- * +- * - OVDSB_IDL_ALERT without OVSDB_IDL_MONITOR is not valid. +- * +- * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column +- * that a client wants to track using the change tracking +- * ovsdb_idl_track_get_*() functions. +- */ +-#define OVSDB_IDL_MONITOR (1 << 0) /* Replicate this column? */ +-#define OVSDB_IDL_ALERT (1 << 1) /* Alert client when column changes? */ +-#define OVSDB_IDL_TRACK (1 << 2) +- +-void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *); +-void ovsdb_idl_add_table(struct ovsdb_idl *, +- const struct ovsdb_idl_table_class *); +- +-void ovsdb_idl_omit(struct ovsdb_idl *, const struct ovsdb_idl_column *); +-void ovsdb_idl_omit_alert(struct ovsdb_idl *, const struct ovsdb_idl_column *); +- +-/* Change tracking. +- * +- * In OVSDB, change tracking is applied at each client in the IDL layer. This +- * means that when a client makes a request to track changes on a particular +- * table, they are essentially requesting information about the incremental +- * changes to that table from the point in time that the request is made. Once +- * the client clears tracked changes, that information will no longer be +- * available. +- * +- * The implication of the above is that if a client requires replaying +- * untracked history, it faces the choice of either trying to remember changes +- * itself (which translates into a memory leak) or of being structured with a +- * path for processing the full untracked table as well as a path that +- * processes incremental changes. */ +-enum ovsdb_idl_change { +- OVSDB_IDL_CHANGE_INSERT, +- OVSDB_IDL_CHANGE_MODIFY, +- OVSDB_IDL_CHANGE_DELETE, +- OVSDB_IDL_CHANGE_MAX +-}; +- +-/* Row, table sequence numbers */ +-unsigned int ovsdb_idl_table_get_seqno( +- const struct ovsdb_idl *idl, +- const struct ovsdb_idl_table_class *table_class); +-unsigned int ovsdb_idl_row_get_seqno( +- const struct ovsdb_idl_row *row, +- enum ovsdb_idl_change change); +- +-void ovsdb_idl_track_add_column(struct ovsdb_idl *idl, +- const struct ovsdb_idl_column *column); +-void ovsdb_idl_track_add_all(struct ovsdb_idl *idl); +-bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table); +-const struct ovsdb_idl_row *ovsdb_idl_track_get_first( +- const struct ovsdb_idl *, const struct ovsdb_idl_table_class *); +-const struct ovsdb_idl_row *ovsdb_idl_track_get_next(const struct ovsdb_idl_row *); +-bool ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row, +- const struct ovsdb_idl_column *column); +-void ovsdb_idl_track_clear(struct ovsdb_idl *); +- +- +-/* Reading the database replica. */ +- +-const struct ovsdb_idl_row *ovsdb_idl_get_row_for_uuid( +- const struct ovsdb_idl *, const struct ovsdb_idl_table_class *, +- const struct uuid *); +-const struct ovsdb_idl_row *ovsdb_idl_first_row( +- const struct ovsdb_idl *, const struct ovsdb_idl_table_class *); +-const struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *); +- +-const struct ovsdb_datum *ovsdb_idl_read(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *); +-const struct ovsdb_datum *ovsdb_idl_get(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- enum ovsdb_atomic_type key_type, +- enum ovsdb_atomic_type value_type); +-bool ovsdb_idl_is_mutable(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *); +- +-bool ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *); +- +-/* Transactions. +- * +- * A transaction may modify the contents of a database by modifying the values +- * of columns, deleting rows, inserting rows, or adding checks that columns in +- * the database have not changed ("verify" operations), through +- * ovsdb_idl_txn_*() functions. (The OVSDB IDL code generator produces helper +- * functions that internally call the ovsdb_idl_txn_*() functions. These are +- * likely to be more convenient.) +- * +- * Reading and writing columns and inserting and deleting rows are all +- * straightforward. The reasons to verify columns are less obvious. +- * Verification is the key to maintaining transactional integrity. Because +- * OVSDB handles multiple clients, it can happen that between the time that +- * OVSDB client A reads a column and writes a new value, OVSDB client B has +- * written that column. Client A's write should not ordinarily overwrite +- * client B's, especially if the column in question is a "map" column that +- * contains several more or less independent data items. If client A adds a +- * "verify" operation before it writes the column, then the transaction fails +- * in case client B modifies it first. Client A will then see the new value of +- * the column and compose a new transaction based on the new contents written +- * by client B. +- * +- * When a transaction is complete, which must be before the next call to +- * ovsdb_idl_run() on 'idl', call ovsdb_idl_txn_commit() or +- * ovsdb_idl_txn_abort(). +- * +- * The life-cycle of a transaction looks like this: +- * +- * 1. Create the transaction and record the initial sequence number: +- * +- * seqno = ovsdb_idl_get_seqno(idl); +- * txn = ovsdb_idl_txn_create(idl); +- * +- * 2. Modify the database with ovsdb_idl_txn_*() functions directly or +- * indirectly. +- * +- * 3. Commit the transaction by calling ovsdb_idl_txn_commit(). The first call +- * to this function probably returns TXN_INCOMPLETE. The client must keep +- * calling again along as this remains true, calling ovsdb_idl_run() in +- * between to let the IDL do protocol processing. (If the client doesn't +- * have anything else to do in the meantime, it can use +- * ovsdb_idl_txn_commit_block() to avoid having to loop itself.) +- * +- * 4. If the final status is TXN_TRY_AGAIN, wait for ovsdb_idl_get_seqno() to +- * change from the saved 'seqno' (it's possible that it's already changed, +- * in which case the client should not wait at all), then start over from +- * step 1. Only a call to ovsdb_idl_run() will change the return value of +- * ovsdb_idl_get_seqno(). (ovsdb_idl_txn_commit_block() calls +- * ovsdb_idl_run().) +- */ +- +-enum ovsdb_idl_txn_status { +- TXN_UNCOMMITTED, /* Not yet committed or aborted. */ +- TXN_UNCHANGED, /* Transaction didn't include any changes. */ +- TXN_INCOMPLETE, /* Commit in progress, please wait. */ +- TXN_ABORTED, /* ovsdb_idl_txn_abort() called. */ +- TXN_SUCCESS, /* Commit successful. */ +- TXN_TRY_AGAIN, /* Commit failed because a "verify" operation +- * reported an inconsistency, due to a network +- * problem, or other transient failure. Wait +- * for a change, then try again. */ +- TXN_NOT_LOCKED, /* Server hasn't given us the lock yet. */ +- TXN_ERROR /* Commit failed due to a hard error. */ +-}; +- +-const char *ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status); +- +-struct ovsdb_idl_txn *ovsdb_idl_txn_create(struct ovsdb_idl *); +-void ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *, const char *, ...) +- OVS_PRINTF_FORMAT (2, 3); +-void ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *); +-void ovsdb_idl_txn_increment(struct ovsdb_idl_txn *, +- const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- bool force); +-void ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *); +-void ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *); +-enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *); +-enum ovsdb_idl_txn_status ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *); +-void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *); +- +-const char *ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *); +- +-int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *); +-const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *, +- const struct uuid *); +- +-void ovsdb_idl_txn_write(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *); +-void ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- const struct ovsdb_datum *); +-void ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *); +-void ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *); +-void ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *); +-void ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *, +- const struct ovsdb_idl_column *, +- struct ovsdb_datum *); +-void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *); +-const struct ovsdb_idl_row *ovsdb_idl_txn_insert( +- struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *, +- const struct uuid *); +- +-struct ovsdb_idl *ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *); +-void ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *); +- +- +-/* ovsdb_idl_loop provides an easy way to manage the transactions related +- * to 'idl' and to cope with different status during transaction. */ +-struct ovsdb_idl_loop { +- struct ovsdb_idl *idl; +- unsigned int skip_seqno; +- +- struct ovsdb_idl_txn *committing_txn; +- unsigned int precommit_seqno; +- +- struct ovsdb_idl_txn *open_txn; +- +- /* These members allow a client a simple, stateless way to keep track of +- * transactions that commit: when a transaction commits successfully, +- * ovsdb_idl_loop_commit_and_wait() copies 'next_cfg' to 'cur_cfg'. Thus, +- * the client can set 'next_cfg' to a value that indicates a successful +- * commit and check 'cur_cfg' on each iteration. */ +- int64_t cur_cfg; +- int64_t next_cfg; +-}; +- +-#define OVSDB_IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) } +- +-void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *); +-struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *); +-int ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *); +- +-/* Conditional Replication +- * ======================= +- * +- * By default, when the IDL replicates a particular table in the database, it +- * replicates every row in the table. These functions allow the client to +- * specify that only selected rows should be replicated, by constructing a +- * per-table condition that specifies the rows to replicate. +- * +- * A condition is a disjunction of clauses. The condition is true, and thus a +- * row is replicated, if any of the clauses evaluates to true for a given row. +- * (Thus, a condition with no clauses is always false.) +- */ +- +-struct ovsdb_idl_condition { +- struct hmap clauses; /* Contains "struct ovsdb_idl_clause"s. */ +- bool is_true; /* Is the condition unconditionally true? */ +-}; +-#define OVSDB_IDL_CONDITION_INIT(CONDITION) \ +- { HMAP_INITIALIZER(&(CONDITION)->clauses), false } +- +-void ovsdb_idl_condition_init(struct ovsdb_idl_condition *); +-void ovsdb_idl_condition_clear(struct ovsdb_idl_condition *); +-void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *); +-void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *, +- enum ovsdb_function function, +- const struct ovsdb_idl_column *column, +- const struct ovsdb_datum *arg); +-void ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition *); +-bool ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition *); +- +-unsigned int ovsdb_idl_set_condition(struct ovsdb_idl *, +- const struct ovsdb_idl_table_class *, +- const struct ovsdb_idl_condition *); +- +-unsigned int ovsdb_idl_get_condition_seqno(const struct ovsdb_idl *); +- +-/* Indexes over one or more columns in the IDL, to retrieve rows matching +- * particular search criteria and to iterate over a subset of rows in a defined +- * order. */ +- +-enum ovsdb_index_order { +- OVSDB_INDEX_ASC, /* 0, 1, 2, ... */ +- OVSDB_INDEX_DESC /* 2, 1, 0, ... */ +-}; +- +-typedef int column_comparator_func(const void *a, const void *b); +- +-struct ovsdb_idl_index_column { +- const struct ovsdb_idl_column *column; +- column_comparator_func *comparer; +- enum ovsdb_index_order order; +-}; +- +-/* Creating an index. */ +-struct ovsdb_idl_index *ovsdb_idl_index_create( +- struct ovsdb_idl *, const struct ovsdb_idl_index_column *, size_t n); +-struct ovsdb_idl_index *ovsdb_idl_index_create1( +- struct ovsdb_idl *, const struct ovsdb_idl_column *); +-struct ovsdb_idl_index *ovsdb_idl_index_create2( +- struct ovsdb_idl *, const struct ovsdb_idl_column *, +- const struct ovsdb_idl_column *); +- +-/* Searching an index. */ +-struct ovsdb_idl_row *ovsdb_idl_index_find(struct ovsdb_idl_index *, +- const struct ovsdb_idl_row *); +- +-/* Iteration over an index. +- * +- * Usually these would be invoked through table-specific wrappers generated +- * by the IDL. */ +- +-struct ovsdb_idl_cursor { +- struct ovsdb_idl_index *index; /* Index being iterated. */ +- struct skiplist_node *position; /* Current position in 'index'. */ +-}; +- +-struct ovsdb_idl_cursor ovsdb_idl_cursor_first(struct ovsdb_idl_index *); +-struct ovsdb_idl_cursor ovsdb_idl_cursor_first_eq( +- struct ovsdb_idl_index *, const struct ovsdb_idl_row *); +-struct ovsdb_idl_cursor ovsdb_idl_cursor_first_ge( +- struct ovsdb_idl_index *, const struct ovsdb_idl_row *); +- +-void ovsdb_idl_cursor_next(struct ovsdb_idl_cursor *); +-void ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor *); +- +-struct ovsdb_idl_row *ovsdb_idl_cursor_data(struct ovsdb_idl_cursor *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-idl.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-idl.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-idl.h +@@ -0,0 +1,488 @@ ++/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2019 Nicira, Inc. ++ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_IDL_H ++#define OVSDB_IDL_H 1 ++ ++/* Open vSwitch Database Interface Definition Language (OVSDB IDL). ++ * ++ * The OVSDB IDL maintains an in-memory replica of a database. It issues RPC ++ * requests to an OVSDB database server and parses the responses, converting ++ * raw JSON into data structures that are easier for clients to digest. Most ++ * notably, references to rows via UUID become C pointers. ++ * ++ * The IDL always presents a consistent snapshot of the database to its client, ++ * that is, it won't present the effects of some part of a transaction applied ++ * at the database server without presenting all of its effects. ++ * ++ * The IDL also assists with issuing database transactions. The client creates ++ * a transaction, manipulates the IDL data structures, and commits or aborts ++ * the transaction. The IDL then composes and issues the necessary JSON-RPC ++ * requests and reports to the client whether the transaction completed ++ * successfully. ++ */ ++ ++#include ++#include ++#include "openvswitch/compiler.h" ++#include "openvswitch/ovsdb-types.h" ++#include "openvswitch/ovsdb-data.h" ++#include "openvswitch/list.h" +#include "openvswitch/ovsdb-condition.h" +#include "internal/skiplist.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/ovsdb-map-op.h b/include/openvswitch/ovsdb-map-op.h -similarity index 97% -rename from lib/ovsdb-map-op.h -rename to include/openvswitch/ovsdb-map-op.h -index 282f0534e..9de4013f7 100644 ---- a/lib/ovsdb-map-op.h -+++ b/include/openvswitch/ovsdb-map-op.h -@@ -17,7 +17,7 @@ - #ifndef OVSDB_MAP_OP_H - #define OVSDB_MAP_OP_H 1 - ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct json; ++struct ovsdb_datum; ++struct ovsdb_idl_class; ++struct ovsdb_idl_row; ++struct ovsdb_idl_column; ++struct ovsdb_idl_table; ++struct ovsdb_idl_table_class; ++struct simap; ++struct uuid; ++ ++struct ovsdb_idl *ovsdb_idl_create(const char *remote, ++ const struct ovsdb_idl_class *, ++ bool monitor_everything_by_default, ++ bool retry); ++struct ovsdb_idl *ovsdb_idl_create_unconnected( ++ const struct ovsdb_idl_class *, bool monitor_everything_by_default); ++void ovsdb_idl_set_remote(struct ovsdb_idl *, const char *remote, bool retry); ++void ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *, bool shuffle); ++void ovsdb_idl_reset_min_index(struct ovsdb_idl *); ++void ovsdb_idl_destroy(struct ovsdb_idl *); ++ ++void ovsdb_idl_set_leader_only(struct ovsdb_idl *, bool leader_only); ++ ++void ovsdb_idl_run(struct ovsdb_idl *); ++void ovsdb_idl_wait(struct ovsdb_idl *); ++ ++void ovsdb_idl_get_memory_usage(struct ovsdb_idl *, struct simap *usage); ++ ++void ovsdb_idl_set_lock(struct ovsdb_idl *, const char *lock_name); ++bool ovsdb_idl_has_lock(const struct ovsdb_idl *); ++bool ovsdb_idl_is_lock_contended(const struct ovsdb_idl *); ++ ++unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *); ++bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *); ++void ovsdb_idl_enable_reconnect(struct ovsdb_idl *); ++void ovsdb_idl_force_reconnect(struct ovsdb_idl *); ++void ovsdb_idl_verify_write_only(struct ovsdb_idl *); ++ ++bool ovsdb_idl_is_alive(const struct ovsdb_idl *); ++bool ovsdb_idl_is_connected(const struct ovsdb_idl *idl); ++int ovsdb_idl_get_last_error(const struct ovsdb_idl *); ++ ++void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval); ++ ++void ovsdb_idl_check_consistency(const struct ovsdb_idl *); ++ ++const struct ovsdb_idl_class *ovsdb_idl_get_class(const struct ovsdb_idl *); ++const struct ovsdb_idl_table_class *ovsdb_idl_table_class_from_column( ++ const struct ovsdb_idl_class *, const struct ovsdb_idl_column *); ++bool ovsdb_idl_server_has_table(const struct ovsdb_idl *, ++ const struct ovsdb_idl_table_class *); ++bool ovsdb_idl_server_has_column(const struct ovsdb_idl *, ++ const struct ovsdb_idl_column *); ++ ++/* Choosing columns and tables to replicate. ++ * ++ * The client may choose any subset of the columns and tables to replicate, ++ * specifying it one of two ways: ++ * ++ * - As a deny list (adding the columns or tables to replicate). To do so, ++ * the client passes false as 'monitor_everything_by_default' to ++ * ovsdb_idl_create() and then calls ovsdb_idl_add_column() and ++ * ovsdb_idl_add_table() for the desired columns and, if necessary, tables. ++ * ++ * - As an allow list (replicating all columns and tables except those ++ * explicitly removed). To do so, the client passes true as ++ * 'monitor_everything_by_default' to ovsdb_idl_create() and then calls ++ * ovsdb_idl_omit() to remove columns. ++ * ++ * There are multiple modes a column may be replicated: ++ * ++ * - Read-only. This is the default. Whenever the column changes in any ++ * replicated row, the value returned by ovsdb_idl_get_seqno() will change, ++ * letting the client know to look at the replicated data again. ++ * ++ * - Write-only. This is for columns that the client sets and updates but ++ * does not want to be alerted about its own updates (which, at the OVSDB ++ * level, cannot be distinguished from updates made by any other client). ++ * The column will be replicated in the same way as for read-only columns, ++ * but the value returned by ovsdb_idl_get_seqno() will not change when the ++ * column changes, saving wasted CPU time. ++ * ++ * (A "write-only" client probably does read the column so that it can know ++ * whether it needs to update it, but it doesn't expect to react to changes ++ * by other clients.) ++ * ++ * To mark a replicated column as write-only, a client calls ++ * ovsdb_idl_omit_alert(). (The column must already be replicated one of ++ * the ways described in the previous list.) ++ * ++ * This is an optimization only and does not affect behavioral correctness ++ * of an otherwise well-written client. ++ * ++ * - Read/write. In theory, an OVSDB client might both read and write a ++ * column, although OVSDB schemas are usually designed so that any given ++ * client only does one or the other. This is actually the same as ++ * read/write columns; that is, the client need take no special action. ++ */ ++ ++/* Modes with which the IDL can replicate a column. See above comment for ++ * overview. ++ * ++ * If no bits are set, the IDL does not replicate the column at all. The ++ * client will always see it with the default value for its type. ++ * ++ * If OVSDB_IDL_MONITOR is set, then the IDL replicates the column and sets it ++ * to to the value in the database. If OVSDB_IDL_ALERT is also set, then the ++ * IDL will change the value returned by ovsdb_idl_get_seqno() when the ++ * column's value changes in any row. ++ * ++ * The possible mode combinations are: ++ * ++ * - 0, for a column that a client doesn't care about. This is the default ++ * for every column in every table, if the client passes false for ++ * 'monitor_everything_by_default' to ovsdb_idl_create(). ++ * ++ * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT), for a column that a client wants ++ * to track and possibly update. This is the default for every column in ++ * every table, if the client passes true for ++ * 'monitor_everything_by_default' to ovsdb_idl_create(). ++ * ++ * - OVSDB_IDL_MONITOR, for columns that a client treats as "write-only", ++ * that is, it updates them but doesn't want to get alerted about its own ++ * updates. It also won't be alerted about other clients' updates, so this ++ * is suitable only for use by a client that "owns" a particular column. ++ * Use ovsdb_idl_omit_alert() to set a column that is already replicated to ++ * this mode. ++ * ++ * - OVDSB_IDL_ALERT without OVSDB_IDL_MONITOR is not valid. ++ * ++ * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column ++ * that a client wants to track using the change tracking ++ * ovsdb_idl_track_get_*() functions. ++ */ ++#define OVSDB_IDL_MONITOR (1 << 0) /* Replicate this column? */ ++#define OVSDB_IDL_ALERT (1 << 1) /* Alert client when column changes? */ ++#define OVSDB_IDL_TRACK (1 << 2) ++ ++void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *); ++void ovsdb_idl_add_table(struct ovsdb_idl *, ++ const struct ovsdb_idl_table_class *); ++ ++void ovsdb_idl_omit(struct ovsdb_idl *, const struct ovsdb_idl_column *); ++void ovsdb_idl_omit_alert(struct ovsdb_idl *, const struct ovsdb_idl_column *); ++ ++/* Change tracking. ++ * ++ * In OVSDB, change tracking is applied at each client in the IDL layer. This ++ * means that when a client makes a request to track changes on a particular ++ * table, they are essentially requesting information about the incremental ++ * changes to that table from the point in time that the request is made. Once ++ * the client clears tracked changes, that information will no longer be ++ * available. ++ * ++ * The implication of the above is that if a client requires replaying ++ * untracked history, it faces the choice of either trying to remember changes ++ * itself (which translates into a memory leak) or of being structured with a ++ * path for processing the full untracked table as well as a path that ++ * processes incremental changes. */ ++enum ovsdb_idl_change { ++ OVSDB_IDL_CHANGE_INSERT, ++ OVSDB_IDL_CHANGE_MODIFY, ++ OVSDB_IDL_CHANGE_DELETE, ++ OVSDB_IDL_CHANGE_MAX ++}; ++ ++/* Row, table sequence numbers */ ++unsigned int ovsdb_idl_table_get_seqno( ++ const struct ovsdb_idl *idl, ++ const struct ovsdb_idl_table_class *table_class); ++unsigned int ovsdb_idl_row_get_seqno( ++ const struct ovsdb_idl_row *row, ++ enum ovsdb_idl_change change); ++ ++void ovsdb_idl_track_add_column(struct ovsdb_idl *idl, ++ const struct ovsdb_idl_column *column); ++void ovsdb_idl_track_add_all(struct ovsdb_idl *idl); ++bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table); ++const struct ovsdb_idl_row *ovsdb_idl_track_get_first( ++ const struct ovsdb_idl *, const struct ovsdb_idl_table_class *); ++const struct ovsdb_idl_row *ovsdb_idl_track_get_next(const struct ovsdb_idl_row *); ++bool ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row, ++ const struct ovsdb_idl_column *column); ++void ovsdb_idl_track_clear(struct ovsdb_idl *); ++ ++ ++/* Reading the database replica. */ ++ ++const struct ovsdb_idl_row *ovsdb_idl_get_row_for_uuid( ++ const struct ovsdb_idl *, const struct ovsdb_idl_table_class *, ++ const struct uuid *); ++const struct ovsdb_idl_row *ovsdb_idl_first_row( ++ const struct ovsdb_idl *, const struct ovsdb_idl_table_class *); ++const struct ovsdb_idl_row *ovsdb_idl_next_row(const struct ovsdb_idl_row *); ++ ++const struct ovsdb_datum *ovsdb_idl_read(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *); ++const struct ovsdb_datum *ovsdb_idl_get(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ enum ovsdb_atomic_type key_type, ++ enum ovsdb_atomic_type value_type); ++bool ovsdb_idl_is_mutable(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *); ++ ++bool ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *); ++ ++/* Transactions. ++ * ++ * A transaction may modify the contents of a database by modifying the values ++ * of columns, deleting rows, inserting rows, or adding checks that columns in ++ * the database have not changed ("verify" operations), through ++ * ovsdb_idl_txn_*() functions. (The OVSDB IDL code generator produces helper ++ * functions that internally call the ovsdb_idl_txn_*() functions. These are ++ * likely to be more convenient.) ++ * ++ * Reading and writing columns and inserting and deleting rows are all ++ * straightforward. The reasons to verify columns are less obvious. ++ * Verification is the key to maintaining transactional integrity. Because ++ * OVSDB handles multiple clients, it can happen that between the time that ++ * OVSDB client A reads a column and writes a new value, OVSDB client B has ++ * written that column. Client A's write should not ordinarily overwrite ++ * client B's, especially if the column in question is a "map" column that ++ * contains several more or less independent data items. If client A adds a ++ * "verify" operation before it writes the column, then the transaction fails ++ * in case client B modifies it first. Client A will then see the new value of ++ * the column and compose a new transaction based on the new contents written ++ * by client B. ++ * ++ * When a transaction is complete, which must be before the next call to ++ * ovsdb_idl_run() on 'idl', call ovsdb_idl_txn_commit() or ++ * ovsdb_idl_txn_abort(). ++ * ++ * The life-cycle of a transaction looks like this: ++ * ++ * 1. Create the transaction and record the initial sequence number: ++ * ++ * seqno = ovsdb_idl_get_seqno(idl); ++ * txn = ovsdb_idl_txn_create(idl); ++ * ++ * 2. Modify the database with ovsdb_idl_txn_*() functions directly or ++ * indirectly. ++ * ++ * 3. Commit the transaction by calling ovsdb_idl_txn_commit(). The first call ++ * to this function probably returns TXN_INCOMPLETE. The client must keep ++ * calling again along as this remains true, calling ovsdb_idl_run() in ++ * between to let the IDL do protocol processing. (If the client doesn't ++ * have anything else to do in the meantime, it can use ++ * ovsdb_idl_txn_commit_block() to avoid having to loop itself.) ++ * ++ * 4. If the final status is TXN_TRY_AGAIN, wait for ovsdb_idl_get_seqno() to ++ * change from the saved 'seqno' (it's possible that it's already changed, ++ * in which case the client should not wait at all), then start over from ++ * step 1. Only a call to ovsdb_idl_run() will change the return value of ++ * ovsdb_idl_get_seqno(). (ovsdb_idl_txn_commit_block() calls ++ * ovsdb_idl_run().) ++ */ ++ ++enum ovsdb_idl_txn_status { ++ TXN_UNCOMMITTED, /* Not yet committed or aborted. */ ++ TXN_UNCHANGED, /* Transaction didn't include any changes. */ ++ TXN_INCOMPLETE, /* Commit in progress, please wait. */ ++ TXN_ABORTED, /* ovsdb_idl_txn_abort() called. */ ++ TXN_SUCCESS, /* Commit successful. */ ++ TXN_TRY_AGAIN, /* Commit failed because a "verify" operation ++ * reported an inconsistency, due to a network ++ * problem, or other transient failure. Wait ++ * for a change, then try again. */ ++ TXN_NOT_LOCKED, /* Server hasn't given us the lock yet. */ ++ TXN_ERROR /* Commit failed due to a hard error. */ ++}; ++ ++const char *ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status); ++ ++struct ovsdb_idl_txn *ovsdb_idl_txn_create(struct ovsdb_idl *); ++void ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *, const char *, ...) ++ OVS_PRINTF_FORMAT (2, 3); ++void ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *); ++void ovsdb_idl_txn_increment(struct ovsdb_idl_txn *, ++ const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ bool force); ++void ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *); ++void ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *); ++enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *); ++enum ovsdb_idl_txn_status ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *); ++void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *); ++ ++const char *ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *); ++ ++int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *); ++const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *, ++ const struct uuid *); ++ ++void ovsdb_idl_txn_write(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *); ++void ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ const struct ovsdb_datum *); ++void ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *); ++void ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *); ++void ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *); ++void ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *, ++ const struct ovsdb_idl_column *, ++ struct ovsdb_datum *); ++void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *); ++const struct ovsdb_idl_row *ovsdb_idl_txn_insert( ++ struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *, ++ const struct uuid *); ++ ++struct ovsdb_idl *ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *); ++void ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *); ++ ++ ++/* ovsdb_idl_loop provides an easy way to manage the transactions related ++ * to 'idl' and to cope with different status during transaction. */ ++struct ovsdb_idl_loop { ++ struct ovsdb_idl *idl; ++ unsigned int skip_seqno; ++ ++ struct ovsdb_idl_txn *committing_txn; ++ unsigned int precommit_seqno; ++ ++ struct ovsdb_idl_txn *open_txn; ++ ++ /* These members allow a client a simple, stateless way to keep track of ++ * transactions that commit: when a transaction commits successfully, ++ * ovsdb_idl_loop_commit_and_wait() copies 'next_cfg' to 'cur_cfg'. Thus, ++ * the client can set 'next_cfg' to a value that indicates a successful ++ * commit and check 'cur_cfg' on each iteration. */ ++ int64_t cur_cfg; ++ int64_t next_cfg; ++}; ++ ++#define OVSDB_IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) } ++ ++void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *); ++struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *); ++int ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *); ++ ++/* Conditional Replication ++ * ======================= ++ * ++ * By default, when the IDL replicates a particular table in the database, it ++ * replicates every row in the table. These functions allow the client to ++ * specify that only selected rows should be replicated, by constructing a ++ * per-table condition that specifies the rows to replicate. ++ * ++ * A condition is a disjunction of clauses. The condition is true, and thus a ++ * row is replicated, if any of the clauses evaluates to true for a given row. ++ * (Thus, a condition with no clauses is always false.) ++ */ ++ ++struct ovsdb_idl_condition { ++ struct hmap clauses; /* Contains "struct ovsdb_idl_clause"s. */ ++ bool is_true; /* Is the condition unconditionally true? */ ++}; ++#define OVSDB_IDL_CONDITION_INIT(CONDITION) \ ++ { HMAP_INITIALIZER(&(CONDITION)->clauses), false } ++ ++void ovsdb_idl_condition_init(struct ovsdb_idl_condition *); ++void ovsdb_idl_condition_clear(struct ovsdb_idl_condition *); ++void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *); ++void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *, ++ enum ovsdb_function function, ++ const struct ovsdb_idl_column *column, ++ const struct ovsdb_datum *arg); ++void ovsdb_idl_condition_add_clause_true(struct ovsdb_idl_condition *); ++bool ovsdb_idl_condition_is_true(const struct ovsdb_idl_condition *); ++ ++unsigned int ovsdb_idl_set_condition(struct ovsdb_idl *, ++ const struct ovsdb_idl_table_class *, ++ const struct ovsdb_idl_condition *); ++ ++unsigned int ovsdb_idl_get_condition_seqno(const struct ovsdb_idl *); ++ ++/* Indexes over one or more columns in the IDL, to retrieve rows matching ++ * particular search criteria and to iterate over a subset of rows in a defined ++ * order. */ ++ ++enum ovsdb_index_order { ++ OVSDB_INDEX_ASC, /* 0, 1, 2, ... */ ++ OVSDB_INDEX_DESC /* 2, 1, 0, ... */ ++}; ++ ++typedef int column_comparator_func(const void *a, const void *b); ++ ++struct ovsdb_idl_index_column { ++ const struct ovsdb_idl_column *column; ++ column_comparator_func *comparer; ++ enum ovsdb_index_order order; ++}; ++ ++/* Creating an index. */ ++struct ovsdb_idl_index *ovsdb_idl_index_create( ++ struct ovsdb_idl *, const struct ovsdb_idl_index_column *, size_t n); ++struct ovsdb_idl_index *ovsdb_idl_index_create1( ++ struct ovsdb_idl *, const struct ovsdb_idl_column *); ++struct ovsdb_idl_index *ovsdb_idl_index_create2( ++ struct ovsdb_idl *, const struct ovsdb_idl_column *, ++ const struct ovsdb_idl_column *); ++ ++/* Searching an index. */ ++struct ovsdb_idl_row *ovsdb_idl_index_find(struct ovsdb_idl_index *, ++ const struct ovsdb_idl_row *); ++ ++/* Iteration over an index. ++ * ++ * Usually these would be invoked through table-specific wrappers generated ++ * by the IDL. */ ++ ++struct ovsdb_idl_cursor { ++ struct ovsdb_idl_index *index; /* Index being iterated. */ ++ struct skiplist_node *position; /* Current position in 'index'. */ ++}; ++ ++struct ovsdb_idl_cursor ovsdb_idl_cursor_first(struct ovsdb_idl_index *); ++struct ovsdb_idl_cursor ovsdb_idl_cursor_first_eq( ++ struct ovsdb_idl_index *, const struct ovsdb_idl_row *); ++struct ovsdb_idl_cursor ovsdb_idl_cursor_first_ge( ++ struct ovsdb_idl_index *, const struct ovsdb_idl_row *); ++ ++void ovsdb_idl_cursor_next(struct ovsdb_idl_cursor *); ++void ovsdb_idl_cursor_next_eq(struct ovsdb_idl_cursor *); ++ ++struct ovsdb_idl_row *ovsdb_idl_cursor_data(struct ovsdb_idl_cursor *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-idl.h */ +Index: openvswitch-2.17.2/lib/ovsdb-map-op.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-map-op.h ++++ /dev/null +@@ -1,53 +0,0 @@ +-/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * All Rights Reserved. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); you may +- * not use this file except in compliance with the License. You may obtain +- * a copy of the License at +- * +- *     http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-#ifndef OVSDB_MAP_OP_H +-#define OVSDB_MAP_OP_H 1 +- -#include "ovsdb-data.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-enum map_op_type { +- MAP_OP_UPDATE, +- MAP_OP_INSERT, +- MAP_OP_DELETE +-}; +- +-struct map_op; /* Map Operation: a Partial Map Update */ +-struct map_op_list; /* List of Map Operations */ +- +-/* Map Operation functions */ +-struct map_op *map_op_create(struct ovsdb_datum *, enum map_op_type); +-void map_op_destroy(struct map_op *, const struct ovsdb_type *); +-struct ovsdb_datum *map_op_datum(const struct map_op*); +-enum map_op_type map_op_type(const struct map_op*); +- +-/* Map Operation List functions */ +-struct map_op_list *map_op_list_create(void); +-void map_op_list_destroy(struct map_op_list *, const struct ovsdb_type *); +-void map_op_list_add(struct map_op_list *, struct map_op *, +- const struct ovsdb_type *); +-struct map_op *map_op_list_first(struct map_op_list *); +-struct map_op *map_op_list_next(struct map_op_list *, struct map_op *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-map-op.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-map-op.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-map-op.h +@@ -0,0 +1,53 @@ ++/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * All Rights Reserved. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may ++ * not use this file except in compliance with the License. You may obtain ++ * a copy of the License at ++ * ++ *     http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++ ++#ifndef OVSDB_MAP_OP_H ++#define OVSDB_MAP_OP_H 1 ++ +#include "openvswitch/ovsdb-data.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/ovsdb-parser.h b/include/openvswitch/ovsdb-parser.h -similarity index 96% -rename from lib/ovsdb-parser.h -rename to include/openvswitch/ovsdb-parser.h -index 8af64de36..86a2d1c80 100644 ---- a/lib/ovsdb-parser.h -+++ b/include/openvswitch/ovsdb-parser.h -@@ -19,8 +19,12 @@ - #include - #include "openvswitch/compiler.h" - #include "openvswitch/json.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++enum map_op_type { ++ MAP_OP_UPDATE, ++ MAP_OP_INSERT, ++ MAP_OP_DELETE ++}; ++ ++struct map_op; /* Map Operation: a Partial Map Update */ ++struct map_op_list; /* List of Map Operations */ ++ ++/* Map Operation functions */ ++struct map_op *map_op_create(struct ovsdb_datum *, enum map_op_type); ++void map_op_destroy(struct map_op *, const struct ovsdb_type *); ++struct ovsdb_datum *map_op_datum(const struct map_op*); ++enum map_op_type map_op_type(const struct map_op*); ++ ++/* Map Operation List functions */ ++struct map_op_list *map_op_list_create(void); ++void map_op_list_destroy(struct map_op_list *, const struct ovsdb_type *); ++void map_op_list_add(struct map_op_list *, struct map_op *, ++ const struct ovsdb_type *); ++struct map_op *map_op_list_first(struct map_op_list *); ++struct map_op *map_op_list_next(struct map_op_list *, struct map_op *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-map-op.h */ +Index: openvswitch-2.17.2/lib/ovsdb-parser.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-parser.h ++++ /dev/null +@@ -1,81 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_PARSER_H +-#define OVSDB_PARSER_H 1 +- +-#include +-#include "openvswitch/compiler.h" +-#include "openvswitch/json.h" -#include "sset.h" -#include "util.h" +- +-struct ovsdb_parser { +- char *name; /* Used only in error messages. */ +- struct sset used; /* Already-parsed names from 'object'. */ +- const struct json *json; /* JSON object being parsed. */ +- struct ovsdb_error *error; /* Error signaled, if any. */ +-}; +- +-/* Check that the JSON types make the bitwise tricks below work OK. */ +-BUILD_ASSERT_DECL(JSON_NULL >= 0 && JSON_NULL < 10); +-BUILD_ASSERT_DECL(JSON_FALSE >= 0 && JSON_FALSE < 10); +-BUILD_ASSERT_DECL(JSON_TRUE >= 0 && JSON_TRUE < 10); +-BUILD_ASSERT_DECL(JSON_OBJECT >= 0 && JSON_OBJECT < 10); +-BUILD_ASSERT_DECL(JSON_ARRAY >= 0 && JSON_ARRAY < 10); +-BUILD_ASSERT_DECL(JSON_INTEGER >= 0 && JSON_INTEGER < 10); +-BUILD_ASSERT_DECL(JSON_REAL >= 0 && JSON_REAL < 10); +-BUILD_ASSERT_DECL(JSON_STRING >= 0 && JSON_STRING < 10); +-BUILD_ASSERT_DECL(JSON_N_TYPES == 8); +- +-enum ovsdb_parser_types { +- OP_NULL = 1 << JSON_NULL, /* null */ +- OP_FALSE = 1 << JSON_FALSE, /* false */ +- OP_TRUE = 1 << JSON_TRUE, /* true */ +- OP_OBJECT = 1 << JSON_OBJECT, /* {"a": b, "c": d, ...} */ +- OP_ARRAY = 1 << JSON_ARRAY, /* [1, 2, 3, ...] */ +- OP_INTEGER = 1 << JSON_INTEGER, /* 123. */ +- OP_NONINTEGER = 1 << JSON_REAL, /* 123.456. */ +- OP_STRING = 1 << JSON_STRING, /* "..." */ +- OP_ANY = (OP_NULL | OP_FALSE | OP_TRUE | OP_OBJECT | OP_ARRAY +- | OP_INTEGER | OP_NONINTEGER | OP_STRING), +- +- OP_BOOLEAN = OP_FALSE | OP_TRUE, +- OP_NUMBER = OP_INTEGER | OP_NONINTEGER, +- +- OP_ID = 1 << JSON_N_TYPES, /* "[_a-zA-Z][_a-zA-Z0-9]*" */ +- OP_OPTIONAL = 1 << (JSON_N_TYPES + 1) /* no value at all */ +-}; +- +-void ovsdb_parser_init(struct ovsdb_parser *, const struct json *, +- const char *name, ...) +- OVS_PRINTF_FORMAT(3, 4); +-const struct json *ovsdb_parser_member(struct ovsdb_parser *, const char *name, +- enum ovsdb_parser_types); +- +-void ovsdb_parser_raise_error(struct ovsdb_parser *parser, +- const char *format, ...) +- OVS_PRINTF_FORMAT(2, 3); +-void ovsdb_parser_put_error(struct ovsdb_parser *, struct ovsdb_error *); +-bool ovsdb_parser_has_error(const struct ovsdb_parser *); +-struct ovsdb_error *ovsdb_parser_get_error(const struct ovsdb_parser *); +-struct ovsdb_error *ovsdb_parser_finish(struct ovsdb_parser *) +- OVS_WARN_UNUSED_RESULT; +-struct ovsdb_error *ovsdb_parser_destroy(struct ovsdb_parser *) +- OVS_WARN_UNUSED_RESULT; +- +-bool ovsdb_parser_is_id(const char *string); +- +-#endif /* ovsdb-parser.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-parser.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-parser.h +@@ -0,0 +1,89 @@ ++/* Copyright (c) 2009, 2010, 2011, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_PARSER_H ++#define OVSDB_PARSER_H 1 ++ ++#include ++#include "openvswitch/compiler.h" ++#include "openvswitch/json.h" +#include "internal/sset.h" +#include "internal/util.h" + +#ifdef __cplusplus +extern "C" { +#endif - - struct ovsdb_parser { - char *name; /* Used only in error messages. */ -@@ -78,4 +82,8 @@ struct ovsdb_error *ovsdb_parser_destroy(struct ovsdb_parser *) - - bool ovsdb_parser_is_id(const char *string); - ++ ++struct ovsdb_parser { ++ char *name; /* Used only in error messages. */ ++ struct sset used; /* Already-parsed names from 'object'. */ ++ const struct json *json; /* JSON object being parsed. */ ++ struct ovsdb_error *error; /* Error signaled, if any. */ ++}; ++ ++/* Check that the JSON types make the bitwise tricks below work OK. */ ++BUILD_ASSERT_DECL(JSON_NULL >= 0 && JSON_NULL < 10); ++BUILD_ASSERT_DECL(JSON_FALSE >= 0 && JSON_FALSE < 10); ++BUILD_ASSERT_DECL(JSON_TRUE >= 0 && JSON_TRUE < 10); ++BUILD_ASSERT_DECL(JSON_OBJECT >= 0 && JSON_OBJECT < 10); ++BUILD_ASSERT_DECL(JSON_ARRAY >= 0 && JSON_ARRAY < 10); ++BUILD_ASSERT_DECL(JSON_INTEGER >= 0 && JSON_INTEGER < 10); ++BUILD_ASSERT_DECL(JSON_REAL >= 0 && JSON_REAL < 10); ++BUILD_ASSERT_DECL(JSON_STRING >= 0 && JSON_STRING < 10); ++BUILD_ASSERT_DECL(JSON_N_TYPES == 8); ++ ++enum ovsdb_parser_types { ++ OP_NULL = 1 << JSON_NULL, /* null */ ++ OP_FALSE = 1 << JSON_FALSE, /* false */ ++ OP_TRUE = 1 << JSON_TRUE, /* true */ ++ OP_OBJECT = 1 << JSON_OBJECT, /* {"a": b, "c": d, ...} */ ++ OP_ARRAY = 1 << JSON_ARRAY, /* [1, 2, 3, ...] */ ++ OP_INTEGER = 1 << JSON_INTEGER, /* 123. */ ++ OP_NONINTEGER = 1 << JSON_REAL, /* 123.456. */ ++ OP_STRING = 1 << JSON_STRING, /* "..." */ ++ OP_ANY = (OP_NULL | OP_FALSE | OP_TRUE | OP_OBJECT | OP_ARRAY ++ | OP_INTEGER | OP_NONINTEGER | OP_STRING), ++ ++ OP_BOOLEAN = OP_FALSE | OP_TRUE, ++ OP_NUMBER = OP_INTEGER | OP_NONINTEGER, ++ ++ OP_ID = 1 << JSON_N_TYPES, /* "[_a-zA-Z][_a-zA-Z0-9]*" */ ++ OP_OPTIONAL = 1 << (JSON_N_TYPES + 1) /* no value at all */ ++}; ++ ++void ovsdb_parser_init(struct ovsdb_parser *, const struct json *, ++ const char *name, ...) ++ OVS_PRINTF_FORMAT(3, 4); ++const struct json *ovsdb_parser_member(struct ovsdb_parser *, const char *name, ++ enum ovsdb_parser_types); ++ ++void ovsdb_parser_raise_error(struct ovsdb_parser *parser, ++ const char *format, ...) ++ OVS_PRINTF_FORMAT(2, 3); ++void ovsdb_parser_put_error(struct ovsdb_parser *, struct ovsdb_error *); ++bool ovsdb_parser_has_error(const struct ovsdb_parser *); ++struct ovsdb_error *ovsdb_parser_get_error(const struct ovsdb_parser *); ++struct ovsdb_error *ovsdb_parser_finish(struct ovsdb_parser *) ++ OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error *ovsdb_parser_destroy(struct ovsdb_parser *) ++ OVS_WARN_UNUSED_RESULT; ++ ++bool ovsdb_parser_is_id(const char *string); ++ +#ifdef __cplusplus +} // extern "C" +#endif + - #endif /* ovsdb-parser.h */ -diff --git a/lib/ovsdb-set-op.h b/include/openvswitch/ovsdb-set-op.h -similarity index 97% -rename from lib/ovsdb-set-op.h -rename to include/openvswitch/ovsdb-set-op.h -index 419080b8a..d3adbb3f1 100644 ---- a/lib/ovsdb-set-op.h -+++ b/include/openvswitch/ovsdb-set-op.h -@@ -18,7 +18,7 @@ - #ifndef OVSDB_SET_OP_H - #define OVSDB_SET_OP_H 1 - ++#endif /* ovsdb-parser.h */ +Index: openvswitch-2.17.2/lib/ovsdb-set-op.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-set-op.h ++++ /dev/null +@@ -1,53 +0,0 @@ +-/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * Copyright (C) 2016, IBM +- * All Rights Reserved. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); you may +- * not use this file except in compliance with the License. You may obtain +- * a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-#ifndef OVSDB_SET_OP_H +-#define OVSDB_SET_OP_H 1 +- -#include "ovsdb-data.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-enum set_op_type { +- SET_OP_INSERT, +- SET_OP_DELETE +-}; +- +-struct set_op; /* Set Operation: a Partial Set Update */ +-struct set_op_list; /* List of Set Operations */ +- +-/* Set Operation functions */ +-struct set_op *set_op_create(struct ovsdb_datum *, enum set_op_type); +-void set_op_destroy(struct set_op *, const struct ovsdb_type *); +-struct ovsdb_datum *set_op_datum(const struct set_op*); +-enum set_op_type set_op_type(const struct set_op*); +- +-/* Set Operation List functions */ +-struct set_op_list *set_op_list_create(void); +-void set_op_list_destroy(struct set_op_list *, const struct ovsdb_type *); +-void set_op_list_add(struct set_op_list *, struct set_op *, +- const struct ovsdb_type *); +-struct set_op *set_op_list_first(struct set_op_list *); +-struct set_op *set_op_list_next(struct set_op_list *, struct set_op *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-set-op.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-set-op.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-set-op.h +@@ -0,0 +1,53 @@ ++/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * Copyright (C) 2016, IBM ++ * All Rights Reserved. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may ++ * not use this file except in compliance with the License. You may obtain ++ * a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++ ++#ifndef OVSDB_SET_OP_H ++#define OVSDB_SET_OP_H 1 ++ +#include "openvswitch/ovsdb-data.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/lib/ovsdb-types.h b/include/openvswitch/ovsdb-types.h -similarity index 99% -rename from lib/ovsdb-types.h -rename to include/openvswitch/ovsdb-types.h -index 1776fdbec..810499a4a 100644 ---- a/lib/ovsdb-types.h -+++ b/include/openvswitch/ovsdb-types.h -@@ -20,7 +20,7 @@ - #include - #include - #include "openvswitch/compiler.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++enum set_op_type { ++ SET_OP_INSERT, ++ SET_OP_DELETE ++}; ++ ++struct set_op; /* Set Operation: a Partial Set Update */ ++struct set_op_list; /* List of Set Operations */ ++ ++/* Set Operation functions */ ++struct set_op *set_op_create(struct ovsdb_datum *, enum set_op_type); ++void set_op_destroy(struct set_op *, const struct ovsdb_type *); ++struct ovsdb_datum *set_op_datum(const struct set_op*); ++enum set_op_type set_op_type(const struct set_op*); ++ ++/* Set Operation List functions */ ++struct set_op_list *set_op_list_create(void); ++void set_op_list_destroy(struct set_op_list *, const struct ovsdb_type *); ++void set_op_list_add(struct set_op_list *, struct set_op *, ++ const struct ovsdb_type *); ++struct set_op *set_op_list_first(struct set_op_list *); ++struct set_op *set_op_list_next(struct set_op_list *, struct set_op *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-set-op.h */ +Index: openvswitch-2.17.2/lib/ovsdb-types.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-types.h ++++ /dev/null +@@ -1,242 +0,0 @@ +-/* Copyright (c) 2009, 2010, 2011 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef OVSDB_TYPES_H +-#define OVSDB_TYPES_H 1 +- +-#include +-#include +-#include +-#include "openvswitch/compiler.h" -#include "uuid.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct json; +- +-/* An atomic type: one that OVSDB regards as a single unit of data. */ +-enum ovsdb_atomic_type { +- OVSDB_TYPE_VOID, /* No value. */ +- OVSDB_TYPE_INTEGER, /* Signed 64-bit integer. */ +- OVSDB_TYPE_REAL, /* IEEE 754 double-precision floating point. */ +- OVSDB_TYPE_BOOLEAN, /* True or false. */ +- OVSDB_TYPE_STRING, /* UTF-8 string. */ +- OVSDB_TYPE_UUID, /* RFC 4122 UUID referencing a table row. */ +- OVSDB_N_TYPES +-}; +- +-static inline bool ovsdb_atomic_type_is_valid(enum ovsdb_atomic_type); +-bool ovsdb_atomic_type_from_string(const char *, enum ovsdb_atomic_type *); +-struct ovsdb_error *ovsdb_atomic_type_from_json(enum ovsdb_atomic_type *, +- const struct json *); +-const char *ovsdb_atomic_type_to_string(enum ovsdb_atomic_type); +-struct json *ovsdb_atomic_type_to_json(enum ovsdb_atomic_type); +- +-/* An atomic type plus optional constraints. */ +- +-enum ovsdb_ref_type { +- OVSDB_REF_STRONG, /* Target must exist. */ +- OVSDB_REF_WEAK /* Delete reference if target disappears. */ +-}; +- +-struct ovsdb_integer_constraints { +- int64_t min; /* minInteger or INT64_MIN. */ +- int64_t max; /* maxInteger or INT64_MAX. */ +-}; +- +-struct ovsdb_real_constraints { +- double min; /* minReal or -DBL_MAX. */ +- double max; /* minReal or DBL_MAX. */ +-}; +- +-struct ovsdb_string_constraints { +- unsigned int minLen; /* minLength or 0. */ +- unsigned int maxLen; /* maxLength or UINT_MAX. */ +-}; +- +-struct ovsdb_uuid_constraints { +- char *refTableName; /* Name of referenced table, or NULL. */ +- struct ovsdb_table *refTable; /* Referenced table, if available. */ +- enum ovsdb_ref_type refType; /* Reference type. */ +-}; +- +-struct ovsdb_base_type { +- enum ovsdb_atomic_type type; +- +- /* If nonnull, a datum with keys of type 'type' that expresses all the +- * valid values for this base_type. */ +- struct ovsdb_datum *enum_; +- +- union { +- struct ovsdb_integer_constraints integer; +- struct ovsdb_real_constraints real; +- /* No constraints for Boolean types. */ +- struct ovsdb_string_constraints string; +- struct ovsdb_uuid_constraints uuid; +- }; +-}; +- +-#define OVSDB_BASE_VOID_INIT { .type = OVSDB_TYPE_VOID } +-#define OVSDB_BASE_INTEGER_INIT { .type = OVSDB_TYPE_INTEGER, \ +- .integer = { INT64_MIN, INT64_MAX } } +-#define OVSDB_BASE_REAL_INIT { .type = OVSDB_TYPE_REAL, \ +- .real = { -DBL_MAX, DBL_MAX } } +-#define OVSDB_BASE_BOOLEAN_INIT { .type = OVSDB_TYPE_BOOLEAN } +-#define OVSDB_BASE_STRING_INIT { .type = OVSDB_TYPE_STRING, \ +- .string = { 0, UINT_MAX } } +-#define OVSDB_BASE_UUID_INIT { .type = OVSDB_TYPE_UUID, \ +- .uuid = { NULL, NULL, 0 } } +- +-void ovsdb_base_type_init(struct ovsdb_base_type *, enum ovsdb_atomic_type); +-void ovsdb_base_type_clone(struct ovsdb_base_type *, +- const struct ovsdb_base_type *); +-void ovsdb_base_type_destroy(struct ovsdb_base_type *); +- +-bool ovsdb_base_type_is_valid(const struct ovsdb_base_type *); +-bool ovsdb_base_type_has_constraints(const struct ovsdb_base_type *); +-void ovsdb_base_type_clear_constraints(struct ovsdb_base_type *); +-const struct ovsdb_type *ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type); +- +-struct ovsdb_error *ovsdb_base_type_from_json(struct ovsdb_base_type *, +- const struct json *) +- OVS_WARN_UNUSED_RESULT; +-struct json *ovsdb_base_type_to_json(const struct ovsdb_base_type *); +- +-static inline bool ovsdb_base_type_is_ref(const struct ovsdb_base_type *); +-static inline bool ovsdb_base_type_is_strong_ref( +- const struct ovsdb_base_type *); +-static inline bool ovsdb_base_type_is_weak_ref(const struct ovsdb_base_type *); +- +-/* An OVSDB type. +- * +- * Several rules constrain the valid types. See ovsdb_type_is_valid() (in +- * ovsdb-types.c) for details. +- * +- * If 'value_type' is OVSDB_TYPE_VOID, 'n_min' is 1, and 'n_max' is 1, then the +- * type is a single atomic 'key_type'. +- * +- * If 'value_type' is OVSDB_TYPE_VOID and 'n_min' or 'n_max' (or both) has a +- * value other than 1, then the type is a set of 'key_type'. If 'n_min' is 0 +- * and 'n_max' is 1, then the type can also be considered an optional +- * 'key_type'. +- * +- * If 'value_type' is not OVSDB_TYPE_VOID, then the type is a map from +- * 'key_type' to 'value_type'. If 'n_min' is 0 and 'n_max' is 1, then the type +- * can also be considered an optional pair of 'key_type' and 'value_type'. +- */ +-struct ovsdb_type { +- struct ovsdb_base_type key; +- struct ovsdb_base_type value; +- unsigned int n_min; +- unsigned int n_max; /* UINT_MAX stands in for "unlimited". */ +-}; +- +-#define OVSDB_TYPE_SCALAR_INITIALIZER(KEY) { KEY, OVSDB_BASE_VOID_INIT, 1, 1 } +- +-extern const struct ovsdb_type ovsdb_type_integer; +-extern const struct ovsdb_type ovsdb_type_real; +-extern const struct ovsdb_type ovsdb_type_boolean; +-extern const struct ovsdb_type ovsdb_type_string; +-extern const struct ovsdb_type ovsdb_type_uuid; +- +-void ovsdb_type_clone(struct ovsdb_type *, const struct ovsdb_type *); +-void ovsdb_type_destroy(struct ovsdb_type *); +- +-bool ovsdb_type_is_valid(const struct ovsdb_type *); +- +-static inline bool ovsdb_type_is_scalar(const struct ovsdb_type *); +-static inline bool ovsdb_type_is_optional(const struct ovsdb_type *); +-static inline bool ovsdb_type_is_optional_scalar( +- const struct ovsdb_type *); +-static inline bool ovsdb_type_is_composite(const struct ovsdb_type *); +-static inline bool ovsdb_type_is_set(const struct ovsdb_type *); +-static inline bool ovsdb_type_is_map(const struct ovsdb_type *); +- +-char *ovsdb_type_to_english(const struct ovsdb_type *); +- +-struct ovsdb_error *ovsdb_type_from_json(struct ovsdb_type *, +- const struct json *) +- OVS_WARN_UNUSED_RESULT; +-struct json *ovsdb_type_to_json(const struct ovsdb_type *); +- +-/* Inline function implementations. */ +- +-static inline bool +-ovsdb_atomic_type_is_valid(enum ovsdb_atomic_type atomic_type) +-{ +- return (int) atomic_type >= 0 && atomic_type < OVSDB_N_TYPES; +-} +- +-static inline bool +-ovsdb_base_type_is_ref(const struct ovsdb_base_type *base) +-{ +- return base->type == OVSDB_TYPE_UUID && base->uuid.refTableName; +-} +- +-static inline bool +-ovsdb_base_type_is_strong_ref(const struct ovsdb_base_type *base) +-{ +- return (ovsdb_base_type_is_ref(base) +- && base->uuid.refType == OVSDB_REF_STRONG); +-} +- +-static inline bool +-ovsdb_base_type_is_weak_ref(const struct ovsdb_base_type *base) +-{ +- return (ovsdb_base_type_is_ref(base) +- && base->uuid.refType == OVSDB_REF_WEAK); +-} +- +-static inline bool ovsdb_type_is_scalar(const struct ovsdb_type *type) +-{ +- return (type->value.type == OVSDB_TYPE_VOID +- && type->n_min == 1 && type->n_max == 1); +-} +- +-static inline bool ovsdb_type_is_optional(const struct ovsdb_type *type) +-{ +- return type->n_min == 0; +-} +- +-static inline bool ovsdb_type_is_optional_scalar( +- const struct ovsdb_type *type) +-{ +- return (type->value.type == OVSDB_TYPE_VOID +- && type->n_min == 0 && type->n_max == 1); +-} +- +-static inline bool ovsdb_type_is_composite(const struct ovsdb_type *type) +-{ +- return type->n_max > 1; +-} +- +-static inline bool ovsdb_type_is_set(const struct ovsdb_type *type) +-{ +- return (type->value.type == OVSDB_TYPE_VOID +- && (type->n_min != 1 || type->n_max != 1)); +-} +- +-static inline bool ovsdb_type_is_map(const struct ovsdb_type *type) +-{ +- return type->value.type != OVSDB_TYPE_VOID; +-} +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* ovsdb-types.h */ +Index: openvswitch-2.17.2/include/openvswitch/ovsdb-types.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/openvswitch/ovsdb-types.h +@@ -0,0 +1,242 @@ ++/* Copyright (c) 2009, 2010, 2011 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef OVSDB_TYPES_H ++#define OVSDB_TYPES_H 1 ++ ++#include ++#include ++#include ++#include "openvswitch/compiler.h" +#include "internal/uuid.h" - - #ifdef __cplusplus - extern "C" { -diff --git a/include/sparse/automake.mk b/include/sparse/automake.mk -index e96637119..4b53bce0e 100644 ---- a/include/sparse/automake.mk -+++ b/include/sparse/automake.mk ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct json; ++ ++/* An atomic type: one that OVSDB regards as a single unit of data. */ ++enum ovsdb_atomic_type { ++ OVSDB_TYPE_VOID, /* No value. */ ++ OVSDB_TYPE_INTEGER, /* Signed 64-bit integer. */ ++ OVSDB_TYPE_REAL, /* IEEE 754 double-precision floating point. */ ++ OVSDB_TYPE_BOOLEAN, /* True or false. */ ++ OVSDB_TYPE_STRING, /* UTF-8 string. */ ++ OVSDB_TYPE_UUID, /* RFC 4122 UUID referencing a table row. */ ++ OVSDB_N_TYPES ++}; ++ ++static inline bool ovsdb_atomic_type_is_valid(enum ovsdb_atomic_type); ++bool ovsdb_atomic_type_from_string(const char *, enum ovsdb_atomic_type *); ++struct ovsdb_error *ovsdb_atomic_type_from_json(enum ovsdb_atomic_type *, ++ const struct json *); ++const char *ovsdb_atomic_type_to_string(enum ovsdb_atomic_type); ++struct json *ovsdb_atomic_type_to_json(enum ovsdb_atomic_type); ++ ++/* An atomic type plus optional constraints. */ ++ ++enum ovsdb_ref_type { ++ OVSDB_REF_STRONG, /* Target must exist. */ ++ OVSDB_REF_WEAK /* Delete reference if target disappears. */ ++}; ++ ++struct ovsdb_integer_constraints { ++ int64_t min; /* minInteger or INT64_MIN. */ ++ int64_t max; /* maxInteger or INT64_MAX. */ ++}; ++ ++struct ovsdb_real_constraints { ++ double min; /* minReal or -DBL_MAX. */ ++ double max; /* minReal or DBL_MAX. */ ++}; ++ ++struct ovsdb_string_constraints { ++ unsigned int minLen; /* minLength or 0. */ ++ unsigned int maxLen; /* maxLength or UINT_MAX. */ ++}; ++ ++struct ovsdb_uuid_constraints { ++ char *refTableName; /* Name of referenced table, or NULL. */ ++ struct ovsdb_table *refTable; /* Referenced table, if available. */ ++ enum ovsdb_ref_type refType; /* Reference type. */ ++}; ++ ++struct ovsdb_base_type { ++ enum ovsdb_atomic_type type; ++ ++ /* If nonnull, a datum with keys of type 'type' that expresses all the ++ * valid values for this base_type. */ ++ struct ovsdb_datum *enum_; ++ ++ union { ++ struct ovsdb_integer_constraints integer; ++ struct ovsdb_real_constraints real; ++ /* No constraints for Boolean types. */ ++ struct ovsdb_string_constraints string; ++ struct ovsdb_uuid_constraints uuid; ++ }; ++}; ++ ++#define OVSDB_BASE_VOID_INIT { .type = OVSDB_TYPE_VOID } ++#define OVSDB_BASE_INTEGER_INIT { .type = OVSDB_TYPE_INTEGER, \ ++ .integer = { INT64_MIN, INT64_MAX } } ++#define OVSDB_BASE_REAL_INIT { .type = OVSDB_TYPE_REAL, \ ++ .real = { -DBL_MAX, DBL_MAX } } ++#define OVSDB_BASE_BOOLEAN_INIT { .type = OVSDB_TYPE_BOOLEAN } ++#define OVSDB_BASE_STRING_INIT { .type = OVSDB_TYPE_STRING, \ ++ .string = { 0, UINT_MAX } } ++#define OVSDB_BASE_UUID_INIT { .type = OVSDB_TYPE_UUID, \ ++ .uuid = { NULL, NULL, 0 } } ++ ++void ovsdb_base_type_init(struct ovsdb_base_type *, enum ovsdb_atomic_type); ++void ovsdb_base_type_clone(struct ovsdb_base_type *, ++ const struct ovsdb_base_type *); ++void ovsdb_base_type_destroy(struct ovsdb_base_type *); ++ ++bool ovsdb_base_type_is_valid(const struct ovsdb_base_type *); ++bool ovsdb_base_type_has_constraints(const struct ovsdb_base_type *); ++void ovsdb_base_type_clear_constraints(struct ovsdb_base_type *); ++const struct ovsdb_type *ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type); ++ ++struct ovsdb_error *ovsdb_base_type_from_json(struct ovsdb_base_type *, ++ const struct json *) ++ OVS_WARN_UNUSED_RESULT; ++struct json *ovsdb_base_type_to_json(const struct ovsdb_base_type *); ++ ++static inline bool ovsdb_base_type_is_ref(const struct ovsdb_base_type *); ++static inline bool ovsdb_base_type_is_strong_ref( ++ const struct ovsdb_base_type *); ++static inline bool ovsdb_base_type_is_weak_ref(const struct ovsdb_base_type *); ++ ++/* An OVSDB type. ++ * ++ * Several rules constrain the valid types. See ovsdb_type_is_valid() (in ++ * ovsdb-types.c) for details. ++ * ++ * If 'value_type' is OVSDB_TYPE_VOID, 'n_min' is 1, and 'n_max' is 1, then the ++ * type is a single atomic 'key_type'. ++ * ++ * If 'value_type' is OVSDB_TYPE_VOID and 'n_min' or 'n_max' (or both) has a ++ * value other than 1, then the type is a set of 'key_type'. If 'n_min' is 0 ++ * and 'n_max' is 1, then the type can also be considered an optional ++ * 'key_type'. ++ * ++ * If 'value_type' is not OVSDB_TYPE_VOID, then the type is a map from ++ * 'key_type' to 'value_type'. If 'n_min' is 0 and 'n_max' is 1, then the type ++ * can also be considered an optional pair of 'key_type' and 'value_type'. ++ */ ++struct ovsdb_type { ++ struct ovsdb_base_type key; ++ struct ovsdb_base_type value; ++ unsigned int n_min; ++ unsigned int n_max; /* UINT_MAX stands in for "unlimited". */ ++}; ++ ++#define OVSDB_TYPE_SCALAR_INITIALIZER(KEY) { KEY, OVSDB_BASE_VOID_INIT, 1, 1 } ++ ++extern const struct ovsdb_type ovsdb_type_integer; ++extern const struct ovsdb_type ovsdb_type_real; ++extern const struct ovsdb_type ovsdb_type_boolean; ++extern const struct ovsdb_type ovsdb_type_string; ++extern const struct ovsdb_type ovsdb_type_uuid; ++ ++void ovsdb_type_clone(struct ovsdb_type *, const struct ovsdb_type *); ++void ovsdb_type_destroy(struct ovsdb_type *); ++ ++bool ovsdb_type_is_valid(const struct ovsdb_type *); ++ ++static inline bool ovsdb_type_is_scalar(const struct ovsdb_type *); ++static inline bool ovsdb_type_is_optional(const struct ovsdb_type *); ++static inline bool ovsdb_type_is_optional_scalar( ++ const struct ovsdb_type *); ++static inline bool ovsdb_type_is_composite(const struct ovsdb_type *); ++static inline bool ovsdb_type_is_set(const struct ovsdb_type *); ++static inline bool ovsdb_type_is_map(const struct ovsdb_type *); ++ ++char *ovsdb_type_to_english(const struct ovsdb_type *); ++ ++struct ovsdb_error *ovsdb_type_from_json(struct ovsdb_type *, ++ const struct json *) ++ OVS_WARN_UNUSED_RESULT; ++struct json *ovsdb_type_to_json(const struct ovsdb_type *); ++ ++/* Inline function implementations. */ ++ ++static inline bool ++ovsdb_atomic_type_is_valid(enum ovsdb_atomic_type atomic_type) ++{ ++ return (int) atomic_type >= 0 && atomic_type < OVSDB_N_TYPES; ++} ++ ++static inline bool ++ovsdb_base_type_is_ref(const struct ovsdb_base_type *base) ++{ ++ return base->type == OVSDB_TYPE_UUID && base->uuid.refTableName; ++} ++ ++static inline bool ++ovsdb_base_type_is_strong_ref(const struct ovsdb_base_type *base) ++{ ++ return (ovsdb_base_type_is_ref(base) ++ && base->uuid.refType == OVSDB_REF_STRONG); ++} ++ ++static inline bool ++ovsdb_base_type_is_weak_ref(const struct ovsdb_base_type *base) ++{ ++ return (ovsdb_base_type_is_ref(base) ++ && base->uuid.refType == OVSDB_REF_WEAK); ++} ++ ++static inline bool ovsdb_type_is_scalar(const struct ovsdb_type *type) ++{ ++ return (type->value.type == OVSDB_TYPE_VOID ++ && type->n_min == 1 && type->n_max == 1); ++} ++ ++static inline bool ovsdb_type_is_optional(const struct ovsdb_type *type) ++{ ++ return type->n_min == 0; ++} ++ ++static inline bool ovsdb_type_is_optional_scalar( ++ const struct ovsdb_type *type) ++{ ++ return (type->value.type == OVSDB_TYPE_VOID ++ && type->n_min == 0 && type->n_max == 1); ++} ++ ++static inline bool ovsdb_type_is_composite(const struct ovsdb_type *type) ++{ ++ return type->n_max > 1; ++} ++ ++static inline bool ovsdb_type_is_set(const struct ovsdb_type *type) ++{ ++ return (type->value.type == OVSDB_TYPE_VOID ++ && (type->n_min != 1 || type->n_max != 1)); ++} ++ ++static inline bool ovsdb_type_is_map(const struct ovsdb_type *type) ++{ ++ return type->value.type != OVSDB_TYPE_VOID; ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ovsdb-types.h */ +Index: openvswitch-2.17.2/include/sparse/automake.mk +=================================================================== +--- openvswitch-2.17.2.orig/include/sparse/automake.mk ++++ openvswitch-2.17.2/include/sparse/automake.mk @@ -1,4 +1,4 @@ -noinst_HEADERS += \ +sparse_headers = \ @@ -2650,10 +27832,10 @@ index e96637119..4b53bce0e 100644 +else + noinst_HEADERS += $(sparse_headers) +endif -diff --git a/include/windows/netinet/icmp6.h b/include/windows/netinet/icmp6.h -index 81f8f5d23..14051be81 100644 ---- a/include/windows/netinet/icmp6.h -+++ b/include/windows/netinet/icmp6.h +Index: openvswitch-2.17.2/include/windows/netinet/icmp6.h +=================================================================== +--- openvswitch-2.17.2.orig/include/windows/netinet/icmp6.h ++++ openvswitch-2.17.2/include/windows/netinet/icmp6.h @@ -61,7 +61,7 @@ #ifndef _NETINET_ICMP6_H_ #define _NETINET_ICMP6_H_ @@ -2663,10 +27845,10 @@ index 81f8f5d23..14051be81 100644 #define ICMPV6_PLD_MAXLEN 1232 /* IPV6_MMTU - sizeof(struct ip6_hdr) - sizeof(struct icmp6_hdr) */ -diff --git a/include/windows/netinet/ip6.h b/include/windows/netinet/ip6.h -index c14c4eec4..ab9f9f296 100644 ---- a/include/windows/netinet/ip6.h -+++ b/include/windows/netinet/ip6.h +Index: openvswitch-2.17.2/include/windows/netinet/ip6.h +=================================================================== +--- openvswitch-2.17.2.orig/include/windows/netinet/ip6.h ++++ openvswitch-2.17.2/include/windows/netinet/ip6.h @@ -62,7 +62,7 @@ #define _NETINET_IP6_H_ #include @@ -2676,10 +27858,10 @@ index c14c4eec4..ab9f9f296 100644 /* * Definition for internet protocol version 6. -diff --git a/lib/aes128.c b/lib/aes128.c -index 98447d14b..9a3b21d23 100644 ---- a/lib/aes128.c -+++ b/lib/aes128.c +Index: openvswitch-2.17.2/lib/aes128.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/aes128.c ++++ openvswitch-2.17.2/lib/aes128.c @@ -26,7 +26,7 @@ #include "aes128.h" @@ -2689,10 +27871,10 @@ index 98447d14b..9a3b21d23 100644 static const uint32_t Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, -diff --git a/lib/async-append-aio.c b/lib/async-append-aio.c -index 23430a455..4d4f07f66 100644 ---- a/lib/async-append-aio.c -+++ b/lib/async-append-aio.c +Index: openvswitch-2.17.2/lib/async-append-aio.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/async-append-aio.c ++++ openvswitch-2.17.2/lib/async-append-aio.c @@ -26,8 +26,8 @@ #include @@ -2704,10 +27886,10 @@ index 23430a455..4d4f07f66 100644 /* Maximum number of bytes of buffered data. */ enum { BUFFER_SIZE = 65536 }; -diff --git a/lib/async-append-null.c b/lib/async-append-null.c -index 217997bec..ed7a7d276 100644 ---- a/lib/async-append-null.c -+++ b/lib/async-append-null.c +Index: openvswitch-2.17.2/lib/async-append-null.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/async-append-null.c ++++ openvswitch-2.17.2/lib/async-append-null.c @@ -23,7 +23,7 @@ #include #include @@ -2717,10 +27899,10 @@ index 217997bec..ed7a7d276 100644 struct async_append * async_append_create(int fd OVS_UNUSED) -diff --git a/lib/automake.mk b/lib/automake.mk -index a23cdc4ad..e13cc31e5 100644 ---- a/lib/automake.mk -+++ b/lib/automake.mk +Index: openvswitch-2.17.2/lib/automake.mk +=================================================================== +--- openvswitch-2.17.2.orig/lib/automake.mk ++++ openvswitch-2.17.2/lib/automake.mk @@ -237,31 +237,15 @@ lib_libopenvswitch_la_SOURCES = \ lib/ofp-version-opt.h \ lib/ofp-version-opt.c \ @@ -2753,10 +27935,10 @@ index a23cdc4ad..e13cc31e5 100644 lib/ovsdb-cs.c \ lib/ovsdb-cs.h \ lib/ovsdb-data.c \ -diff --git a/lib/backtrace.c b/lib/backtrace.c -index 2853d5ff1..a9c5897ef 100644 ---- a/lib/backtrace.c -+++ b/lib/backtrace.c +Index: openvswitch-2.17.2/lib/backtrace.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/backtrace.c ++++ openvswitch-2.17.2/lib/backtrace.c @@ -23,7 +23,7 @@ #include "backtrace.h" @@ -2766,10 +27948,10 @@ index 2853d5ff1..a9c5897ef 100644 VLOG_DEFINE_THIS_MODULE(backtrace); -diff --git a/lib/bfd.c b/lib/bfd.c -index 9698576d0..880dc43f6 100644 ---- a/lib/bfd.c -+++ b/lib/bfd.c +Index: openvswitch-2.17.2/lib/bfd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/bfd.c ++++ openvswitch-2.17.2/lib/bfd.c @@ -22,30 +22,30 @@ #include #include @@ -2816,10 +27998,10 @@ index 9698576d0..880dc43f6 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(bfd); -diff --git a/lib/bfd.h b/lib/bfd.h -index 9d32327fb..b5577223c 100644 ---- a/lib/bfd.h -+++ b/lib/bfd.h +Index: openvswitch-2.17.2/lib/bfd.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/bfd.h ++++ openvswitch-2.17.2/lib/bfd.h @@ -21,7 +21,7 @@ #include #include @@ -2829,10 +28011,10 @@ index 9d32327fb..b5577223c 100644 struct bfd; struct dpif_flow_stats; -diff --git a/lib/bundle.c b/lib/bundle.c -index d728380ec..4f653e6c0 100644 ---- a/lib/bundle.c -+++ b/lib/bundle.c +Index: openvswitch-2.17.2/lib/bundle.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/bundle.c ++++ openvswitch-2.17.2/lib/bundle.c @@ -15,16 +15,16 @@ #include @@ -2862,10 +28044,10 @@ index d728380ec..4f653e6c0 100644 VLOG_DEFINE_THIS_MODULE(bundle); -diff --git a/lib/byteq.c b/lib/byteq.c -index 3f865cf9e..e9c70268c 100644 ---- a/lib/byteq.c -+++ b/lib/byteq.c +Index: openvswitch-2.17.2/lib/byteq.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/byteq.c ++++ openvswitch-2.17.2/lib/byteq.c @@ -18,7 +18,7 @@ #include #include @@ -2875,10 +28057,10 @@ index 3f865cf9e..e9c70268c 100644 /* Initializes 'q' as an empty byteq that uses the 'size' bytes of 'buffer' to * store data. 'size' must be a power of 2. -diff --git a/lib/ccmap.c b/lib/ccmap.c -index a460833b1..317a0b85f 100644 ---- a/lib/ccmap.c -+++ b/lib/ccmap.c +Index: openvswitch-2.17.2/lib/ccmap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ccmap.c ++++ openvswitch-2.17.2/lib/ccmap.c @@ -16,12 +16,12 @@ #include @@ -2898,10 +28080,10 @@ index a460833b1..317a0b85f 100644 COVERAGE_DEFINE(ccmap_expand); COVERAGE_DEFINE(ccmap_shrink); -diff --git a/lib/ccmap.h b/lib/ccmap.h -index 9c394486e..66fcd6ceb 100644 ---- a/lib/ccmap.h -+++ b/lib/ccmap.h +Index: openvswitch-2.17.2/lib/ccmap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ccmap.h ++++ openvswitch-2.17.2/lib/ccmap.h @@ -19,8 +19,8 @@ #include @@ -2913,10 +28095,10 @@ index 9c394486e..66fcd6ceb 100644 /* Concurrent hash map for numerical counts of given hash values. * ============================================================== -diff --git a/lib/cfm.c b/lib/cfm.c -index cc43e70e3..da9fe0210 100644 ---- a/lib/cfm.c -+++ b/lib/cfm.c +Index: openvswitch-2.17.2/lib/cfm.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/cfm.c ++++ openvswitch-2.17.2/lib/cfm.c @@ -21,24 +21,24 @@ #include #include @@ -2955,10 +28137,10 @@ index cc43e70e3..da9fe0210 100644 VLOG_DEFINE_THIS_MODULE(cfm); -diff --git a/lib/cfm.h b/lib/cfm.h -index 5710c9952..a2ace3421 100644 ---- a/lib/cfm.h -+++ b/lib/cfm.h +Index: openvswitch-2.17.2/lib/cfm.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/cfm.h ++++ openvswitch-2.17.2/lib/cfm.h @@ -20,7 +20,7 @@ #include "openvswitch/hmap.h" @@ -2968,10 +28150,10 @@ index 5710c9952..a2ace3421 100644 struct flow; struct dp_packet; -diff --git a/lib/classifier-private.h b/lib/classifier-private.h -index 1d5ee007a..114a380cf 100644 ---- a/lib/classifier-private.h -+++ b/lib/classifier-private.h +Index: openvswitch-2.17.2/lib/classifier-private.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/classifier-private.h ++++ openvswitch-2.17.2/lib/classifier-private.h @@ -18,10 +18,10 @@ #define CLASSIFIER_PRIVATE_H 1 @@ -2987,10 +28169,10 @@ index 1d5ee007a..114a380cf 100644 /* Classifier internal definitions, subject to change at any time. */ -diff --git a/lib/classifier.c b/lib/classifier.c -index c4790ee6b..1f8c8bd67 100644 ---- a/lib/classifier.c -+++ b/lib/classifier.c +Index: openvswitch-2.17.2/lib/classifier.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/classifier.c ++++ openvswitch-2.17.2/lib/classifier.c @@ -15,16 +15,16 @@ */ @@ -3012,10 +28194,10 @@ index c4790ee6b..1f8c8bd67 100644 struct trie_ctx; -diff --git a/lib/cmap.c b/lib/cmap.c -index c9eef3f4a..bfa0bba34 100644 ---- a/lib/cmap.c -+++ b/lib/cmap.c +Index: openvswitch-2.17.2/lib/cmap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/cmap.c ++++ openvswitch-2.17.2/lib/cmap.c @@ -15,13 +15,13 @@ */ @@ -3037,10 +28219,10 @@ index c9eef3f4a..bfa0bba34 100644 COVERAGE_DEFINE(cmap_expand); COVERAGE_DEFINE(cmap_shrink); -diff --git a/lib/colors.c b/lib/colors.c -index 13456445e..a98c3dd71 100644 ---- a/lib/colors.c -+++ b/lib/colors.c +Index: openvswitch-2.17.2/lib/colors.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/colors.c ++++ openvswitch-2.17.2/lib/colors.c @@ -18,12 +18,12 @@ #include @@ -3056,10 +28238,10 @@ index 13456445e..a98c3dd71 100644 struct color_key { const char *name; -diff --git a/lib/command-line.c b/lib/command-line.c -index 967f4f5d5..20777a6e7 100644 ---- a/lib/command-line.c -+++ b/lib/command-line.c +Index: openvswitch-2.17.2/lib/command-line.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/command-line.c ++++ openvswitch-2.17.2/lib/command-line.c @@ -15,14 +15,14 @@ */ @@ -3079,10 +28261,10 @@ index 967f4f5d5..20777a6e7 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(command_line); -diff --git a/lib/connectivity.c b/lib/connectivity.c -index c80b5f113..7984864ff 100644 ---- a/lib/connectivity.c -+++ b/lib/connectivity.c +Index: openvswitch-2.17.2/lib/connectivity.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/connectivity.c ++++ openvswitch-2.17.2/lib/connectivity.c @@ -16,8 +16,8 @@ #include @@ -3094,10 +28276,10 @@ index c80b5f113..7984864ff 100644 static struct seq *connectivity_seq; -diff --git a/lib/conntrack-icmp.c b/lib/conntrack-icmp.c -index b40297039..993a6e3a0 100644 ---- a/lib/conntrack-icmp.c -+++ b/lib/conntrack-icmp.c +Index: openvswitch-2.17.2/lib/conntrack-icmp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack-icmp.c ++++ openvswitch-2.17.2/lib/conntrack-icmp.c @@ -23,7 +23,7 @@ #include "conntrack-private.h" @@ -3107,10 +28289,10 @@ index b40297039..993a6e3a0 100644 enum OVS_PACKED_ENUM icmp_state { ICMPS_FIRST, -diff --git a/lib/conntrack-other.c b/lib/conntrack-other.c -index d3b460185..a4061ba13 100644 ---- a/lib/conntrack-other.c -+++ b/lib/conntrack-other.c +Index: openvswitch-2.17.2/lib/conntrack-other.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack-other.c ++++ openvswitch-2.17.2/lib/conntrack-other.c @@ -18,7 +18,7 @@ #include "conntrack-private.h" @@ -3120,10 +28302,10 @@ index d3b460185..a4061ba13 100644 enum OVS_PACKED_ENUM other_state { OTHERS_FIRST, -diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h -index dfdf4e676..c987b9655 100644 ---- a/lib/conntrack-private.h -+++ b/lib/conntrack-private.h +Index: openvswitch-2.17.2/lib/conntrack-private.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack-private.h ++++ openvswitch-2.17.2/lib/conntrack-private.h @@ -21,16 +21,16 @@ #include #include @@ -3145,10 +28327,10 @@ index dfdf4e676..c987b9655 100644 struct ct_endpoint { union ct_addr addr; -diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c -index 8a7c98cc4..464e8e3f4 100644 ---- a/lib/conntrack-tcp.c -+++ b/lib/conntrack-tcp.c +Index: openvswitch-2.17.2/lib/conntrack-tcp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack-tcp.c ++++ openvswitch-2.17.2/lib/conntrack-tcp.c @@ -40,10 +40,10 @@ #include "conntrack-private.h" @@ -3163,10 +28345,10 @@ index 8a7c98cc4..464e8e3f4 100644 COVERAGE_DEFINE(conntrack_tcp_seq_chk_bypass); COVERAGE_DEFINE(conntrack_tcp_seq_chk_failed); -diff --git a/lib/conntrack.c b/lib/conntrack.c -index 33a1a9295..6bb5202b9 100644 ---- a/lib/conntrack.c -+++ b/lib/conntrack.c +Index: openvswitch-2.17.2/lib/conntrack.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack.c ++++ openvswitch-2.17.2/lib/conntrack.c @@ -22,24 +22,24 @@ #include #include @@ -3202,10 +28384,10 @@ index 33a1a9295..6bb5202b9 100644 VLOG_DEFINE_THIS_MODULE(conntrack); -diff --git a/lib/conntrack.h b/lib/conntrack.h -index 9553b188a..766c85416 100644 ---- a/lib/conntrack.h -+++ b/lib/conntrack.h +Index: openvswitch-2.17.2/lib/conntrack.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/conntrack.h ++++ openvswitch-2.17.2/lib/conntrack.h @@ -19,18 +19,18 @@ #include @@ -3231,10 +28413,10 @@ index 9553b188a..766c85416 100644 /* Userspace connection tracker * ============================ -diff --git a/lib/coverage.c b/lib/coverage.c -index a95b6aa25..a5e74236b 100644 ---- a/lib/coverage.c -+++ b/lib/coverage.c +Index: openvswitch-2.17.2/lib/coverage.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/coverage.c ++++ openvswitch-2.17.2/lib/coverage.c @@ -15,15 +15,15 @@ */ @@ -3257,10 +28439,10 @@ index a95b6aa25..a5e74236b 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(coverage); -diff --git a/lib/crc32c.c b/lib/crc32c.c -index e8dd6eee7..37f0d0a35 100644 ---- a/lib/crc32c.c -+++ b/lib/crc32c.c +Index: openvswitch-2.17.2/lib/crc32c.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/crc32c.c ++++ openvswitch-2.17.2/lib/crc32c.c @@ -43,8 +43,8 @@ */ @@ -3272,10 +28454,10 @@ index e8dd6eee7..37f0d0a35 100644 /*****************************************************************/ /* */ -diff --git a/lib/csum.c b/lib/csum.c -index eaa05ad98..98e584b51 100644 ---- a/lib/csum.c -+++ b/lib/csum.c +Index: openvswitch-2.17.2/lib/csum.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/csum.c ++++ openvswitch-2.17.2/lib/csum.c @@ -15,8 +15,8 @@ */ @@ -3287,10 +28469,10 @@ index eaa05ad98..98e584b51 100644 #include #include -diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h -index b59cba962..a31088732 100644 ---- a/lib/ct-dpif.h -+++ b/lib/ct-dpif.h +Index: openvswitch-2.17.2/lib/ct-dpif.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ct-dpif.h ++++ openvswitch-2.17.2/lib/ct-dpif.h @@ -18,7 +18,7 @@ #define CT_DPIF_H @@ -3300,10 +28482,10 @@ index b59cba962..a31088732 100644 union ct_dpif_inet_addr { ovs_be32 ip; -diff --git a/lib/daemon-unix.c b/lib/daemon-unix.c -index 34d45b82a..29b80d907 100644 ---- a/lib/daemon-unix.c -+++ b/lib/daemon-unix.c +Index: openvswitch-2.17.2/lib/daemon-unix.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/daemon-unix.c ++++ openvswitch-2.17.2/lib/daemon-unix.c @@ -16,7 +16,7 @@ #include @@ -3337,10 +28519,10 @@ index 34d45b82a..29b80d907 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(daemon_unix); -diff --git a/lib/daemon-windows.c b/lib/daemon-windows.c -index 7e5f264f5..92639eae0 100644 ---- a/lib/daemon-windows.c -+++ b/lib/daemon-windows.c +Index: openvswitch-2.17.2/lib/daemon-windows.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/daemon-windows.c ++++ openvswitch-2.17.2/lib/daemon-windows.c @@ -15,15 +15,15 @@ */ @@ -3361,10 +28543,10 @@ index 7e5f264f5..92639eae0 100644 #include "openvswitch/poll-loop.h" #include "openvswitch/vlog.h" -diff --git a/lib/daemon.c b/lib/daemon.c -index 3249c5ab4..7d44afe0a 100644 ---- a/lib/daemon.c -+++ b/lib/daemon.c +Index: openvswitch-2.17.2/lib/daemon.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/daemon.c ++++ openvswitch-2.17.2/lib/daemon.c @@ -14,13 +14,13 @@ * limitations under the License. */ @@ -3382,10 +28564,10 @@ index 3249c5ab4..7d44afe0a 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(daemon); -diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c -index 0c459156f..1a00af77a 100644 ---- a/lib/db-ctl-base.c -+++ b/lib/db-ctl-base.c +Index: openvswitch-2.17.2/lib/db-ctl-base.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/db-ctl-base.c ++++ openvswitch-2.17.2/lib/db-ctl-base.c @@ -20,24 +20,25 @@ #include #include @@ -3423,10 +28605,10 @@ index 0c459156f..1a00af77a 100644 VLOG_DEFINE_THIS_MODULE(db_ctl_base); -diff --git a/lib/dhparams.c b/lib/dhparams.c -index 85123863f..f3077a776 100644 ---- a/lib/dhparams.c -+++ b/lib/dhparams.c +Index: openvswitch-2.17.2/lib/dhparams.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dhparams.c ++++ openvswitch-2.17.2/lib/dhparams.c @@ -3,7 +3,7 @@ * If you do need to regenerate this file, run "make generate-dhparams-c". */ @@ -3436,10 +28618,10 @@ index 85123863f..f3077a776 100644 #include "openvswitch/util.h" static int -diff --git a/lib/dirs.c.in b/lib/dirs.c.in -index 85c49ee0b..e1f6e1da3 100644 ---- a/lib/dirs.c.in -+++ b/lib/dirs.c.in +Index: openvswitch-2.17.2/lib/dirs.c.in +=================================================================== +--- openvswitch-2.17.2.orig/lib/dirs.c.in ++++ openvswitch-2.17.2/lib/dirs.c.in @@ -16,10 +16,10 @@ */ @@ -3454,10 +28636,10 @@ index 85c49ee0b..e1f6e1da3 100644 struct directory { const char *value; /* Actual value; NULL if not yet determined. */ -diff --git a/lib/dns-resolve.c b/lib/dns-resolve.c -index d34451434..74c418b66 100644 ---- a/lib/dns-resolve.c -+++ b/lib/dns-resolve.c +Index: openvswitch-2.17.2/lib/dns-resolve.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dns-resolve.c ++++ openvswitch-2.17.2/lib/dns-resolve.c @@ -24,10 +24,10 @@ #include #include @@ -3471,10 +28653,10 @@ index d34451434..74c418b66 100644 VLOG_DEFINE_THIS_MODULE(dns_resolve); -diff --git a/lib/dp-packet.c b/lib/dp-packet.c -index 35c72542a..73f3fcd64 100644 ---- a/lib/dp-packet.c -+++ b/lib/dp-packet.c +Index: openvswitch-2.17.2/lib/dp-packet.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dp-packet.c ++++ openvswitch-2.17.2/lib/dp-packet.c @@ -18,11 +18,11 @@ #include #include @@ -3491,10 +28673,10 @@ index 35c72542a..73f3fcd64 100644 static void dp_packet_init__(struct dp_packet *b, size_t allocated, enum dp_packet_source source) -diff --git a/lib/dpctl.c b/lib/dpctl.c -index 81cbe3730..1ca2bece9 100644 ---- a/lib/dpctl.c -+++ b/lib/dpctl.c +Index: openvswitch-2.17.2/lib/dpctl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpctl.c ++++ openvswitch-2.17.2/lib/dpctl.c @@ -27,27 +27,28 @@ #include #include @@ -3535,10 +28717,10 @@ index 81cbe3730..1ca2bece9 100644 #include "openvswitch/ofp-flow.h" #include "openvswitch/ofp-port.h" -diff --git a/lib/dpdk-stub.c b/lib/dpdk-stub.c -index 3eee1f485..01a64c931 100644 ---- a/lib/dpdk-stub.c -+++ b/lib/dpdk-stub.c +Index: openvswitch-2.17.2/lib/dpdk-stub.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpdk-stub.c ++++ openvswitch-2.17.2/lib/dpdk-stub.c @@ -18,8 +18,8 @@ #include #include "dpdk.h" @@ -3550,10 +28732,10 @@ index 3eee1f485..01a64c931 100644 #include "openvswitch/vlog.h" #include "vswitch-idl.h" -diff --git a/lib/dpdk.c b/lib/dpdk.c -index 6886fbd9d..21068e713 100644 ---- a/lib/dpdk.c -+++ b/lib/dpdk.c +Index: openvswitch-2.17.2/lib/dpdk.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpdk.c ++++ openvswitch-2.17.2/lib/dpdk.c @@ -29,18 +29,18 @@ #include #include @@ -3582,10 +28764,10 @@ index 6886fbd9d..21068e713 100644 #include "vswitch-idl.h" VLOG_DEFINE_THIS_MODULE(dpdk); -diff --git a/lib/dpif-netdev-avx512.c b/lib/dpif-netdev-avx512.c -index b7131ba3f..68eced4ee 100644 ---- a/lib/dpif-netdev-avx512.c -+++ b/lib/dpif-netdev-avx512.c +Index: openvswitch-2.17.2/lib/dpif-netdev-avx512.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-avx512.c ++++ openvswitch-2.17.2/lib/dpif-netdev-avx512.c @@ -28,8 +28,8 @@ #include #include @@ -3597,10 +28779,10 @@ index b7131ba3f..68eced4ee 100644 #include "netdev-offload.h" /* Each AVX512 register (zmm register in assembly notation) can contain up to -diff --git a/lib/dpif-netdev-extract-avx512.c b/lib/dpif-netdev-extract-avx512.c -index b8bb4f38d..047cd914f 100644 ---- a/lib/dpif-netdev-extract-avx512.c -+++ b/lib/dpif-netdev-extract-avx512.c +Index: openvswitch-2.17.2/lib/dpif-netdev-extract-avx512.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-extract-avx512.c ++++ openvswitch-2.17.2/lib/dpif-netdev-extract-avx512.c @@ -43,7 +43,7 @@ #include @@ -3610,10 +28792,10 @@ index b8bb4f38d..047cd914f 100644 #include "dpif-netdev-private-dpcls.h" #include "dpif-netdev-private-extract.h" -diff --git a/lib/dpif-netdev-extract-study.c b/lib/dpif-netdev-extract-study.c -index 5a9370669..5807c5d42 100644 ---- a/lib/dpif-netdev-extract-study.c -+++ b/lib/dpif-netdev-extract-study.c +Index: openvswitch-2.17.2/lib/dpif-netdev-extract-study.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-extract-study.c ++++ openvswitch-2.17.2/lib/dpif-netdev-extract-study.c @@ -21,7 +21,7 @@ #include "dpif-netdev-private-thread.h" @@ -3623,10 +28805,10 @@ index 5a9370669..5807c5d42 100644 VLOG_DEFINE_THIS_MODULE(dpif_mfex_extract_study); -diff --git a/lib/dpif-netdev-lookup-avx512-gather.c b/lib/dpif-netdev-lookup-avx512-gather.c -index 6e50f6ecd..cb8de8980 100644 ---- a/lib/dpif-netdev-lookup-avx512-gather.c -+++ b/lib/dpif-netdev-lookup-avx512-gather.c +Index: openvswitch-2.17.2/lib/dpif-netdev-lookup-avx512-gather.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-lookup-avx512-gather.c ++++ openvswitch-2.17.2/lib/dpif-netdev-lookup-avx512-gather.c @@ -22,10 +22,10 @@ #include "dpif-netdev.h" #include "dpif-netdev-lookup.h" @@ -3641,10 +28823,10 @@ index 6e50f6ecd..cb8de8980 100644 #include "openvswitch/vlog.h" #include "immintrin.h" -diff --git a/lib/dpif-netdev-lookup-generic.c b/lib/dpif-netdev-lookup-generic.c -index 37a069401..898395610 100644 ---- a/lib/dpif-netdev-lookup-generic.c -+++ b/lib/dpif-netdev-lookup-generic.c +Index: openvswitch-2.17.2/lib/dpif-netdev-lookup-generic.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-lookup-generic.c ++++ openvswitch-2.17.2/lib/dpif-netdev-lookup-generic.c @@ -19,17 +19,17 @@ #include "dpif-netdev.h" #include "dpif-netdev-lookup.h" @@ -3670,10 +28852,10 @@ index 37a069401..898395610 100644 VLOG_DEFINE_THIS_MODULE(dpif_lookup_generic); -diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c -index a2a7d8f0b..c82ce5427 100644 ---- a/lib/dpif-netdev-perf.c -+++ b/lib/dpif-netdev-perf.c +Index: openvswitch-2.17.2/lib/dpif-netdev-perf.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-perf.c ++++ openvswitch-2.17.2/lib/dpif-netdev-perf.c @@ -21,9 +21,9 @@ #include "dpif-netdev-perf.h" #include "openvswitch/dynamic-string.h" @@ -3687,10 +28869,10 @@ index a2a7d8f0b..c82ce5427 100644 VLOG_DEFINE_THIS_MODULE(pmd_perf); -diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h -index 9673dddd8..b6d63fb29 100644 ---- a/lib/dpif-netdev-perf.h -+++ b/lib/dpif-netdev-perf.h +Index: openvswitch-2.17.2/lib/dpif-netdev-perf.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-perf.h ++++ openvswitch-2.17.2/lib/dpif-netdev-perf.h @@ -30,10 +30,10 @@ #endif @@ -3706,10 +28888,10 @@ index 9673dddd8..b6d63fb29 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/dpif-netdev-private-dpcls.h b/lib/dpif-netdev-private-dpcls.h -index 0d5da73c7..09416b087 100644 ---- a/lib/dpif-netdev-private-dpcls.h -+++ b/lib/dpif-netdev-private-dpcls.h +Index: openvswitch-2.17.2/lib/dpif-netdev-private-dpcls.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-private-dpcls.h ++++ openvswitch-2.17.2/lib/dpif-netdev-private-dpcls.h @@ -23,7 +23,7 @@ #include #include @@ -3719,10 +28901,10 @@ index 0d5da73c7..09416b087 100644 #include "openvswitch/thread.h" #ifdef __cplusplus -diff --git a/lib/dpif-netdev-private-dpif.c b/lib/dpif-netdev-private-dpif.c -index 84d4ec156..bc8e10774 100644 ---- a/lib/dpif-netdev-private-dpif.c -+++ b/lib/dpif-netdev-private-dpif.c +Index: openvswitch-2.17.2/lib/dpif-netdev-private-dpif.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-private-dpif.c ++++ openvswitch-2.17.2/lib/dpif-netdev-private-dpif.c @@ -24,7 +24,7 @@ #include "openvswitch/dynamic-string.h" @@ -3732,10 +28914,10 @@ index 84d4ec156..bc8e10774 100644 VLOG_DEFINE_THIS_MODULE(dpif_netdev_impl); -diff --git a/lib/dpif-netdev-private-extract.c b/lib/dpif-netdev-private-extract.c -index a29bdcfa7..b90c4f39d 100644 ---- a/lib/dpif-netdev-private-extract.c -+++ b/lib/dpif-netdev-private-extract.c +Index: openvswitch-2.17.2/lib/dpif-netdev-private-extract.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-private-extract.c ++++ openvswitch-2.17.2/lib/dpif-netdev-private-extract.c @@ -19,14 +19,14 @@ #include #include @@ -3755,10 +28937,10 @@ index a29bdcfa7..b90c4f39d 100644 VLOG_DEFINE_THIS_MODULE(dpif_netdev_extract); -diff --git a/lib/dpif-netdev-private-flow.h b/lib/dpif-netdev-private-flow.h -index 66016eb09..688efe7ce 100644 ---- a/lib/dpif-netdev-private-flow.h -+++ b/lib/dpif-netdev-private-flow.h +Index: openvswitch-2.17.2/lib/dpif-netdev-private-flow.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-private-flow.h ++++ openvswitch-2.17.2/lib/dpif-netdev-private-flow.h @@ -24,7 +24,7 @@ #include #include @@ -3768,10 +28950,10 @@ index 66016eb09..688efe7ce 100644 #include "openvswitch/thread.h" #ifdef __cplusplus -diff --git a/lib/dpif-netdev-private-thread.h b/lib/dpif-netdev-private-thread.h -index 4472b199d..4da8f805d 100644 ---- a/lib/dpif-netdev-private-thread.h -+++ b/lib/dpif-netdev-private-thread.h +Index: openvswitch-2.17.2/lib/dpif-netdev-private-thread.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev-private-thread.h ++++ openvswitch-2.17.2/lib/dpif-netdev-private-thread.h @@ -27,7 +27,7 @@ #include @@ -3781,10 +28963,10 @@ index 4472b199d..4da8f805d 100644 #include "dpif-netdev-private-dfc.h" #include "dpif-netdev-private-dpif.h" -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 9f35713ef..8840877a8 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c +Index: openvswitch-2.17.2/lib/dpif-netdev.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev.c ++++ openvswitch-2.17.2/lib/dpif-netdev.c @@ -34,15 +34,15 @@ #include #include @@ -3864,10 +29046,10 @@ index 9f35713ef..8840877a8 100644 VLOG_DEFINE_THIS_MODULE(dpif_netdev); -diff --git a/lib/dpif-netdev.h b/lib/dpif-netdev.h -index 6db6ed2e2..1ccb6fa8f 100644 ---- a/lib/dpif-netdev.h -+++ b/lib/dpif-netdev.h +Index: openvswitch-2.17.2/lib/dpif-netdev.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netdev.h ++++ openvswitch-2.17.2/lib/dpif-netdev.h @@ -22,8 +22,8 @@ #include #include "dpif.h" @@ -3879,10 +29061,10 @@ index 6db6ed2e2..1ccb6fa8f 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/dpif-netlink-rtnl.h b/lib/dpif-netlink-rtnl.h -index 5c790e0bc..fded17012 100644 ---- a/lib/dpif-netlink-rtnl.h -+++ b/lib/dpif-netlink-rtnl.h +Index: openvswitch-2.17.2/lib/dpif-netlink-rtnl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netlink-rtnl.h ++++ openvswitch-2.17.2/lib/dpif-netlink-rtnl.h @@ -19,7 +19,7 @@ #include @@ -3892,10 +29074,10 @@ index 5c790e0bc..fded17012 100644 /* Declare these to keep sparse happy. */ int dpif_netlink_rtnl_port_create(struct netdev *netdev); -diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c -index 71e35ccdd..444693efd 100644 ---- a/lib/dpif-netlink.c -+++ b/lib/dpif-netlink.c +Index: openvswitch-2.17.2/lib/dpif-netlink.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netlink.c ++++ openvswitch-2.17.2/lib/dpif-netlink.c @@ -32,20 +32,20 @@ #include #include @@ -3940,10 +29122,10 @@ index 71e35ccdd..444693efd 100644 VLOG_DEFINE_THIS_MODULE(dpif_netlink); #ifdef _WIN32 -diff --git a/lib/dpif-netlink.h b/lib/dpif-netlink.h -index 24294bc42..9c7c503c7 100644 ---- a/lib/dpif-netlink.h -+++ b/lib/dpif-netlink.h +Index: openvswitch-2.17.2/lib/dpif-netlink.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-netlink.h ++++ openvswitch-2.17.2/lib/dpif-netlink.h @@ -21,7 +21,7 @@ #include #include @@ -3953,10 +29135,10 @@ index 24294bc42..9c7c503c7 100644 struct ofpbuf; -diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h -index 12477a24f..f6cd3cad4 100644 ---- a/lib/dpif-provider.h -+++ b/lib/dpif-provider.h +Index: openvswitch-2.17.2/lib/dpif-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif-provider.h ++++ openvswitch-2.17.2/lib/dpif-provider.h @@ -24,7 +24,7 @@ #include "openflow/openflow.h" @@ -3966,10 +29148,10 @@ index 12477a24f..f6cd3cad4 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/dpif.c b/lib/dpif.c -index 40f5fe446..9225aeea4 100644 ---- a/lib/dpif.c -+++ b/lib/dpif.c +Index: openvswitch-2.17.2/lib/dpif.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif.c ++++ openvswitch-2.17.2/lib/dpif.c @@ -23,25 +23,25 @@ #include #include @@ -4007,10 +29189,10 @@ index 40f5fe446..9225aeea4 100644 #include "valgrind.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/ofp-errors.h" -diff --git a/lib/dpif.h b/lib/dpif.h -index 6cb4dae6d..ad7676c45 100644 ---- a/lib/dpif.h -+++ b/lib/dpif.h +Index: openvswitch-2.17.2/lib/dpif.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dpif.h ++++ openvswitch-2.17.2/lib/dpif.h @@ -377,13 +377,13 @@ #include @@ -4030,10 +29212,10 @@ index 6cb4dae6d..ad7676c45 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/dummy.c b/lib/dummy.c -index 899a2c0c5..1be71a70a 100644 ---- a/lib/dummy.c -+++ b/lib/dummy.c +Index: openvswitch-2.17.2/lib/dummy.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dummy.c ++++ openvswitch-2.17.2/lib/dummy.c @@ -17,7 +17,7 @@ #include #include "dummy.h" @@ -4043,10 +29225,10 @@ index 899a2c0c5..1be71a70a 100644 /* Enables support for "dummy" network devices and dpifs, which are useful for * testing. A client program might call this function if it is designed -diff --git a/lib/dynamic-string.c b/lib/dynamic-string.c -index fd0127ed1..bc0c02651 100644 ---- a/lib/dynamic-string.c -+++ b/lib/dynamic-string.c +Index: openvswitch-2.17.2/lib/dynamic-string.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/dynamic-string.c ++++ openvswitch-2.17.2/lib/dynamic-string.c @@ -20,8 +20,8 @@ #include #include @@ -4058,10 +29240,10 @@ index fd0127ed1..bc0c02651 100644 /* Initializes 'ds' as an empty string buffer. */ void -diff --git a/lib/entropy.c b/lib/entropy.c -index 05cc64835..42d59a097 100644 ---- a/lib/entropy.c -+++ b/lib/entropy.c +Index: openvswitch-2.17.2/lib/entropy.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/entropy.c ++++ openvswitch-2.17.2/lib/entropy.c @@ -23,8 +23,8 @@ #ifdef _WIN32 #include @@ -4073,10 +29255,10 @@ index 05cc64835..42d59a097 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(entropy); -diff --git a/lib/fat-rwlock.c b/lib/fat-rwlock.c -index d913b2088..6a2305c67 100644 ---- a/lib/fat-rwlock.c -+++ b/lib/fat-rwlock.c +Index: openvswitch-2.17.2/lib/fat-rwlock.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/fat-rwlock.c ++++ openvswitch-2.17.2/lib/fat-rwlock.c @@ -22,8 +22,8 @@ #include "openvswitch/hmap.h" @@ -4088,10 +29270,10 @@ index d913b2088..6a2305c67 100644 struct fat_rwlock_slot { /* Membership in rwlock's list of "struct fat_rwlock_slot"s. -diff --git a/lib/fat-rwlock.h b/lib/fat-rwlock.h -index 49480819b..33b2e472b 100644 ---- a/lib/fat-rwlock.h -+++ b/lib/fat-rwlock.h +Index: openvswitch-2.17.2/lib/fat-rwlock.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/fat-rwlock.h ++++ openvswitch-2.17.2/lib/fat-rwlock.h @@ -19,7 +19,7 @@ #include "openvswitch/compiler.h" @@ -4101,10 +29283,10 @@ index 49480819b..33b2e472b 100644 /* "Fat rwlock". * -diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c -index bbb31ef27..c54402e61 100644 ---- a/lib/fatal-signal.c -+++ b/lib/fatal-signal.c +Index: openvswitch-2.17.2/lib/fatal-signal.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/fatal-signal.c ++++ openvswitch-2.17.2/lib/fatal-signal.c @@ -15,7 +15,7 @@ */ #include @@ -4132,10 +29314,10 @@ index bbb31ef27..c54402e61 100644 #include "openvswitch/vlog.h" #include "openvswitch/type-props.h" -diff --git a/lib/flow.c b/lib/flow.c -index dd523c889..bbef74b79 100644 ---- a/lib/flow.c -+++ b/lib/flow.c +Index: openvswitch-2.17.2/lib/flow.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/flow.c ++++ openvswitch-2.17.2/lib/flow.c @@ -15,7 +15,7 @@ */ #include @@ -4186,7 +29368,7 @@ index dd523c889..bbef74b79 100644 * defined as macros. */ #if (FLOW_WC_SEQ != 42) -@@ -345,7 +345,7 @@ parse_mpls(const void **datap, size_t *sizep) +@@ -345,7 +345,7 @@ parse_mpls(const void **datap, size_t *s } /* passed vlan_hdrs arg must be at least size FLOW_MAX_VLAN_HEADERS. */ @@ -4195,7 +29377,7 @@ index dd523c889..bbef74b79 100644 parse_vlan(const void **datap, size_t *sizep, union flow_vlan_hdr *vlan_hdrs) { const ovs_be16 *eth_type; -@@ -369,7 +369,7 @@ parse_vlan(const void **datap, size_t *sizep, union flow_vlan_hdr *vlan_hdrs) +@@ -369,7 +369,7 @@ parse_vlan(const void **datap, size_t *s return n; } @@ -4204,10 +29386,10 @@ index dd523c889..bbef74b79 100644 parse_ethertype(const void **datap, size_t *sizep) { const struct llc_snap_header *llc; -diff --git a/lib/getopt_long.c b/lib/getopt_long.c -index 0663762fb..6c1721353 100644 ---- a/lib/getopt_long.c -+++ b/lib/getopt_long.c +Index: openvswitch-2.17.2/lib/getopt_long.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/getopt_long.c ++++ openvswitch-2.17.2/lib/getopt_long.c @@ -32,7 +32,7 @@ #include #include @@ -4217,10 +29399,10 @@ index 0663762fb..6c1721353 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(getopt_long); -diff --git a/lib/getrusage-windows.c b/lib/getrusage-windows.c -index 915725e37..605820ba3 100644 ---- a/lib/getrusage-windows.c -+++ b/lib/getrusage-windows.c +Index: openvswitch-2.17.2/lib/getrusage-windows.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/getrusage-windows.c ++++ openvswitch-2.17.2/lib/getrusage-windows.c @@ -19,7 +19,7 @@ #include #include @@ -4230,10 +29412,10 @@ index 915725e37..605820ba3 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(getrusage_windows); -diff --git a/lib/guarded-list.h b/lib/guarded-list.h -index 7f1d257e1..7a1b218bc 100644 ---- a/lib/guarded-list.h -+++ b/lib/guarded-list.h +Index: openvswitch-2.17.2/lib/guarded-list.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/guarded-list.h ++++ openvswitch-2.17.2/lib/guarded-list.h @@ -20,7 +20,7 @@ #include #include "openvswitch/compiler.h" @@ -4243,10 +29425,10 @@ index 7f1d257e1..7a1b218bc 100644 struct guarded_list { struct ovs_mutex mutex; -diff --git a/lib/hash.c b/lib/hash.c -index c722f3c3c..ad9e9b3d0 100644 ---- a/lib/hash.c -+++ b/lib/hash.c +Index: openvswitch-2.17.2/lib/hash.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/hash.c ++++ openvswitch-2.17.2/lib/hash.c @@ -14,9 +14,9 @@ * limitations under the License. */ @@ -4259,10 +29441,10 @@ index c722f3c3c..ad9e9b3d0 100644 /* Returns the hash of 'a', 'b', and 'c'. */ uint32_t -diff --git a/lib/heap.c b/lib/heap.c -index 682915ac3..caa3eccd0 100644 ---- a/lib/heap.c -+++ b/lib/heap.c +Index: openvswitch-2.17.2/lib/heap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/heap.c ++++ openvswitch-2.17.2/lib/heap.c @@ -17,7 +17,7 @@ #include #include "heap.h" @@ -4272,10 +29454,10 @@ index 682915ac3..caa3eccd0 100644 static void put_node(struct heap *, struct heap_node *, size_t i); static void swap_nodes(struct heap *, size_t i, size_t j); -diff --git a/lib/hindex.c b/lib/hindex.c -index 260649bf8..53a6302c0 100644 ---- a/lib/hindex.c -+++ b/lib/hindex.c +Index: openvswitch-2.17.2/lib/hindex.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/hindex.c ++++ openvswitch-2.17.2/lib/hindex.c @@ -15,8 +15,8 @@ */ @@ -4287,10 +29469,10 @@ index 260649bf8..53a6302c0 100644 static bool hindex_node_is_body(const struct hindex_node *); static bool hindex_node_is_head(const struct hindex_node *); -diff --git a/lib/hmap.c b/lib/hmap.c -index 9ee05b6d4..f71ca7160 100644 ---- a/lib/hmap.c -+++ b/lib/hmap.c +Index: openvswitch-2.17.2/lib/hmap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/hmap.c ++++ openvswitch-2.17.2/lib/hmap.c @@ -18,9 +18,9 @@ #include "openvswitch/hmap.h" #include @@ -4304,10 +29486,10 @@ index 9ee05b6d4..f71ca7160 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(hmap); -diff --git a/lib/hmapx.c b/lib/hmapx.c -index eadfe640a..cceb9f23d 100644 ---- a/lib/hmapx.c -+++ b/lib/hmapx.c +Index: openvswitch-2.17.2/lib/hmapx.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/hmapx.c ++++ openvswitch-2.17.2/lib/hmapx.c @@ -16,9 +16,9 @@ #include @@ -4320,10 +29502,10 @@ index eadfe640a..cceb9f23d 100644 static struct hmapx_node * hmapx_find__(const struct hmapx *map, const void *data, size_t hash) -diff --git a/lib/id-fpool.c b/lib/id-fpool.c -index 15cef5d00..0fd33d379 100644 ---- a/lib/id-fpool.c -+++ b/lib/id-fpool.c +Index: openvswitch-2.17.2/lib/id-fpool.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/id-fpool.c ++++ openvswitch-2.17.2/lib/id-fpool.c @@ -19,7 +19,7 @@ #include "openvswitch/list.h" #include "openvswitch/thread.h" @@ -4333,10 +29515,10 @@ index 15cef5d00..0fd33d379 100644 #include "id-fpool.h" #ifdef HAVE_PTHREAD_SPIN_LOCK -diff --git a/lib/id-pool.c b/lib/id-pool.c -index 69910ad08..c8aac587d 100644 ---- a/lib/id-pool.c -+++ b/lib/id-pool.c +Index: openvswitch-2.17.2/lib/id-pool.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/id-pool.c ++++ openvswitch-2.17.2/lib/id-pool.c @@ -16,9 +16,9 @@ */ @@ -4349,10 +29531,10 @@ index 69910ad08..c8aac587d 100644 struct id_node { struct hmap_node node; -diff --git a/lib/if-notifier-bsd.c b/lib/if-notifier-bsd.c -index b57b4b1b2..acaca8a50 100644 ---- a/lib/if-notifier-bsd.c -+++ b/lib/if-notifier-bsd.c +Index: openvswitch-2.17.2/lib/if-notifier-bsd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/if-notifier-bsd.c ++++ openvswitch-2.17.2/lib/if-notifier-bsd.c @@ -17,7 +17,7 @@ #include #include "if-notifier.h" @@ -4362,10 +29544,10 @@ index b57b4b1b2..acaca8a50 100644 struct if_notifier { struct rtbsd_notifier notifier; -diff --git a/lib/if-notifier.c b/lib/if-notifier.c -index f2d7157b9..0a23030f1 100644 ---- a/lib/if-notifier.c -+++ b/lib/if-notifier.c +Index: openvswitch-2.17.2/lib/if-notifier.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/if-notifier.c ++++ openvswitch-2.17.2/lib/if-notifier.c @@ -17,7 +17,7 @@ #include #include "if-notifier.h" @@ -4375,10 +29557,10 @@ index f2d7157b9..0a23030f1 100644 struct if_notifier { struct nln_notifier *notifier; -diff --git a/lib/ipf.c b/lib/ipf.c -index 507db2aea..ee90bc8b6 100644 ---- a/lib/ipf.c -+++ b/lib/ipf.c +Index: openvswitch-2.17.2/lib/ipf.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ipf.c ++++ openvswitch-2.17.2/lib/ipf.c @@ -23,16 +23,16 @@ #include #include @@ -4402,10 +29584,10 @@ index 507db2aea..ee90bc8b6 100644 VLOG_DEFINE_THIS_MODULE(ipf); COVERAGE_DEFINE(ipf_stuck_frag_list_purged); -diff --git a/lib/ipf.h b/lib/ipf.h -index 6ac91b270..09f7aae0b 100644 ---- a/lib/ipf.h -+++ b/lib/ipf.h +Index: openvswitch-2.17.2/lib/ipf.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ipf.h ++++ openvswitch-2.17.2/lib/ipf.h @@ -17,7 +17,7 @@ #ifndef IPF_H #define IPF_H 1 @@ -4415,10 +29597,10 @@ index 6ac91b270..09f7aae0b 100644 #include "openvswitch/types.h" struct ipf; -diff --git a/lib/jhash.c b/lib/jhash.c -index c59b51b61..5498d8803 100644 ---- a/lib/jhash.c -+++ b/lib/jhash.c +Index: openvswitch-2.17.2/lib/jhash.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/jhash.c ++++ openvswitch-2.17.2/lib/jhash.c @@ -17,7 +17,7 @@ #include #include "jhash.h" @@ -4428,10 +29610,10 @@ index c59b51b61..5498d8803 100644 /* This is the public domain lookup3 hash by Bob Jenkins from * http://burtleburtle.net/bob/c/lookup3.c, modified for style. */ -diff --git a/lib/jhash.h b/lib/jhash.h -index f83b08fad..5b39b51ce 100644 ---- a/lib/jhash.h -+++ b/lib/jhash.h +Index: openvswitch-2.17.2/lib/jhash.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/jhash.h ++++ openvswitch-2.17.2/lib/jhash.h @@ -21,7 +21,7 @@ #include #include @@ -4441,10 +29623,10 @@ index f83b08fad..5b39b51ce 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/json.c b/lib/json.c -index 720c73d94..a01cf1654 100644 ---- a/lib/json.c -+++ b/lib/json.c +Index: openvswitch-2.17.2/lib/json.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/json.c ++++ openvswitch-2.17.2/lib/json.c @@ -25,11 +25,11 @@ #include @@ -4460,10 +29642,10 @@ index 720c73d94..a01cf1654 100644 /* The type of a JSON token. */ enum json_token_type { -diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c -index c8ce5362e..8eb95d0ee 100644 ---- a/lib/jsonrpc.c -+++ b/lib/jsonrpc.c +Index: openvswitch-2.17.2/lib/jsonrpc.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/jsonrpc.c ++++ openvswitch-2.17.2/lib/jsonrpc.c @@ -16,23 +16,23 @@ #include @@ -4494,10 +29676,10 @@ index c8ce5362e..8eb95d0ee 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(jsonrpc); -diff --git a/lib/lacp.c b/lib/lacp.c -index 89d711225..f809ca5c2 100644 ---- a/lib/lacp.c -+++ b/lib/lacp.c +Index: openvswitch-2.17.2/lib/lacp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lacp.c ++++ openvswitch-2.17.2/lib/lacp.c @@ -20,19 +20,19 @@ #include "connectivity.h" @@ -4527,10 +29709,10 @@ index 89d711225..f809ca5c2 100644 VLOG_DEFINE_THIS_MODULE(lacp); -diff --git a/lib/lacp.h b/lib/lacp.h -index 1ca06f762..39ce9c50d 100644 ---- a/lib/lacp.h -+++ b/lib/lacp.h +Index: openvswitch-2.17.2/lib/lacp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/lacp.h ++++ openvswitch-2.17.2/lib/lacp.h @@ -19,7 +19,7 @@ #include @@ -4540,10 +29722,10 @@ index 1ca06f762..39ce9c50d 100644 /* LACP Protocol Implementation. */ -diff --git a/lib/latch-unix.c b/lib/latch-unix.c -index f4d10c39a..c7f10747c 100644 ---- a/lib/latch-unix.c -+++ b/lib/latch-unix.c +Index: openvswitch-2.17.2/lib/latch-unix.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/latch-unix.c ++++ openvswitch-2.17.2/lib/latch-unix.c @@ -16,12 +16,12 @@ #include @@ -4559,10 +29741,10 @@ index f4d10c39a..c7f10747c 100644 /* Initializes 'latch' as initially unset. */ void -diff --git a/lib/latch-windows.c b/lib/latch-windows.c -index 67c0592a0..47eeced39 100644 ---- a/lib/latch-windows.c -+++ b/lib/latch-windows.c +Index: openvswitch-2.17.2/lib/latch-windows.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/latch-windows.c ++++ openvswitch-2.17.2/lib/latch-windows.c @@ -16,12 +16,12 @@ #include @@ -4578,10 +29760,10 @@ index 67c0592a0..47eeced39 100644 /* Initializes 'latch' as initially unset. */ void -diff --git a/lib/learn.c b/lib/learn.c -index a40209ec0..b5231f286 100644 ---- a/lib/learn.c -+++ b/lib/learn.c +Index: openvswitch-2.17.2/lib/learn.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/learn.c ++++ openvswitch-2.17.2/lib/learn.c @@ -18,9 +18,9 @@ #include "learn.h" @@ -4604,10 +29786,10 @@ index a40209ec0..b5231f286 100644 /* Checks that 'learn' is a valid action on 'flow'. Returns 0 if it is valid, -diff --git a/lib/learning-switch.c b/lib/learning-switch.c -index 8102475ca..cc1c3e53a 100644 ---- a/lib/learning-switch.c -+++ b/lib/learning-switch.c +Index: openvswitch-2.17.2/lib/learning-switch.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/learning-switch.c ++++ openvswitch-2.17.2/lib/learning-switch.c @@ -24,10 +24,10 @@ #include #include @@ -4634,10 +29816,10 @@ index 8102475ca..cc1c3e53a 100644 VLOG_DEFINE_THIS_MODULE(learning_switch); -diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c -index 1b5b4db57..752f82a81 100644 ---- a/lib/lldp/lldp.c -+++ b/lib/lldp/lldp.c +Index: openvswitch-2.17.2/lib/lldp/lldp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldp.c ++++ openvswitch-2.17.2/lib/lldp/lldp.c @@ -26,8 +26,8 @@ #include #include @@ -4649,10 +29831,10 @@ index 1b5b4db57..752f82a81 100644 VLOG_DEFINE_THIS_MODULE(lldp); -diff --git a/lib/lldp/lldpd-structs.c b/lib/lldp/lldpd-structs.c -index 499b44174..a723b1b9c 100644 ---- a/lib/lldp/lldpd-structs.c -+++ b/lib/lldp/lldpd-structs.c +Index: openvswitch-2.17.2/lib/lldp/lldpd-structs.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldpd-structs.c ++++ openvswitch-2.17.2/lib/lldp/lldpd-structs.c @@ -21,7 +21,7 @@ #include #include @@ -4662,10 +29844,10 @@ index 499b44174..a723b1b9c 100644 VLOG_DEFINE_THIS_MODULE(lldpd_structs); -diff --git a/lib/lldp/lldpd-structs.h b/lib/lldp/lldpd-structs.h -index fe5d5f9f8..60c239bdb 100644 ---- a/lib/lldp/lldpd-structs.h -+++ b/lib/lldp/lldpd-structs.h +Index: openvswitch-2.17.2/lib/lldp/lldpd-structs.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldpd-structs.h ++++ openvswitch-2.17.2/lib/lldp/lldpd-structs.h @@ -25,7 +25,7 @@ #include #include "aa-structs.h" @@ -4675,10 +29857,10 @@ index fe5d5f9f8..60c239bdb 100644 enum { LLDPD_AF_UNSPEC = 0, -diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c -index a600da550..cde497e2a 100644 ---- a/lib/lldp/lldpd.c -+++ b/lib/lldp/lldpd.c +Index: openvswitch-2.17.2/lib/lldp/lldpd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldpd.c ++++ openvswitch-2.17.2/lib/lldp/lldpd.c @@ -42,8 +42,8 @@ #include "openvswitch/compiler.h" #include "openvswitch/dynamic-string.h" @@ -4690,10 +29872,10 @@ index a600da550..cde497e2a 100644 VLOG_DEFINE_THIS_MODULE(lldpd); -diff --git a/lib/lldp/lldpd.h b/lib/lldp/lldpd.h -index 3f5be84a2..52c694e1d 100644 ---- a/lib/lldp/lldpd.h -+++ b/lib/lldp/lldpd.h +Index: openvswitch-2.17.2/lib/lldp/lldpd.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/lldp/lldpd.h ++++ openvswitch-2.17.2/lib/lldp/lldpd.h @@ -24,11 +24,11 @@ #include #include @@ -4708,10 +29890,10 @@ index 3f5be84a2..52c694e1d 100644 #include "openvswitch/vlog.h" #define ETHERTYPE_LLDP 0x88cc -diff --git a/lib/lockfile.c b/lib/lockfile.c -index 42782d29e..69df76ee5 100644 ---- a/lib/lockfile.c -+++ b/lib/lockfile.c +Index: openvswitch-2.17.2/lib/lockfile.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/lockfile.c ++++ openvswitch-2.17.2/lib/lockfile.c @@ -24,12 +24,12 @@ #include #include @@ -4730,10 +29912,10 @@ index 42782d29e..69df76ee5 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(lockfile); -diff --git a/lib/mac-learning.c b/lib/mac-learning.c -index 3fcd7d9b7..45900d783 100644 ---- a/lib/mac-learning.c -+++ b/lib/mac-learning.c +Index: openvswitch-2.17.2/lib/mac-learning.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/mac-learning.c ++++ openvswitch-2.17.2/lib/mac-learning.c @@ -20,14 +20,14 @@ #include #include @@ -4755,10 +29937,10 @@ index 3fcd7d9b7..45900d783 100644 #include "vlan-bitmap.h" COVERAGE_DEFINE(mac_learning_learned); -diff --git a/lib/mac-learning.h b/lib/mac-learning.h -index 270fbd70d..e25c68615 100644 ---- a/lib/mac-learning.h -+++ b/lib/mac-learning.h +Index: openvswitch-2.17.2/lib/mac-learning.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/mac-learning.h ++++ openvswitch-2.17.2/lib/mac-learning.h @@ -21,10 +21,10 @@ #include "heap.h" #include "openvswitch/hmap.h" @@ -4774,10 +29956,10 @@ index 270fbd70d..e25c68615 100644 /* MAC learning table * ================== -diff --git a/lib/match.c b/lib/match.c -index 2ad03e044..88d402a86 100644 ---- a/lib/match.c -+++ b/lib/match.c +Index: openvswitch-2.17.2/lib/match.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/match.c ++++ openvswitch-2.17.2/lib/match.c @@ -17,14 +17,14 @@ #include #include "openvswitch/match.h" @@ -4798,10 +29980,10 @@ index 2ad03e044..88d402a86 100644 #include "openvswitch/nsh.h" /* Converts the flow in 'flow' into a match in 'match', with the given -diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c -index 6730301b6..2620a232b 100644 ---- a/lib/mcast-snooping.c -+++ b/lib/mcast-snooping.c +Index: openvswitch-2.17.2/lib/mcast-snooping.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/mcast-snooping.c ++++ openvswitch-2.17.2/lib/mcast-snooping.c @@ -17,21 +17,21 @@ */ @@ -4832,10 +30014,10 @@ index 6730301b6..2620a232b 100644 #include "vlan-bitmap.h" #include "openvswitch/vlog.h" -diff --git a/lib/memory.c b/lib/memory.c -index da97476c6..3ef08cf03 100644 ---- a/lib/memory.c -+++ b/lib/memory.c +Index: openvswitch-2.17.2/lib/memory.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/memory.c ++++ openvswitch-2.17.2/lib/memory.c @@ -15,15 +15,15 @@ */ @@ -4856,10 +30038,10 @@ index da97476c6..3ef08cf03 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(memory); -diff --git a/lib/meta-flow.c b/lib/meta-flow.c -index e03cd8d0c..27e720423 100644 ---- a/lib/meta-flow.c -+++ b/lib/meta-flow.c +Index: openvswitch-2.17.2/lib/meta-flow.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/meta-flow.c ++++ openvswitch-2.17.2/lib/meta-flow.c @@ -23,19 +23,19 @@ #include #include @@ -4891,10 +30073,10 @@ index e03cd8d0c..27e720423 100644 #include "openvswitch/ofp-errors.h" #include "openvswitch/ofp-match.h" #include "openvswitch/ofp-port.h" -diff --git a/lib/mpsc-queue.c b/lib/mpsc-queue.c -index 4e99c94f7..acac08538 100644 ---- a/lib/mpsc-queue.c -+++ b/lib/mpsc-queue.c +Index: openvswitch-2.17.2/lib/mpsc-queue.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/mpsc-queue.c ++++ openvswitch-2.17.2/lib/mpsc-queue.c @@ -16,7 +16,7 @@ #include @@ -4904,10 +30086,10 @@ index 4e99c94f7..acac08538 100644 #include "mpsc-queue.h" -diff --git a/lib/mpsc-queue.h b/lib/mpsc-queue.h -index 8c7109621..ec4a13886 100644 ---- a/lib/mpsc-queue.h -+++ b/lib/mpsc-queue.h +Index: openvswitch-2.17.2/lib/mpsc-queue.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/mpsc-queue.h ++++ openvswitch-2.17.2/lib/mpsc-queue.h @@ -24,7 +24,7 @@ #include #include @@ -4917,10 +30099,10 @@ index 8c7109621..ec4a13886 100644 /* Multi-producer, single-consumer queue * ===================================== -diff --git a/lib/multipath.c b/lib/multipath.c -index 6896f94a1..01de39df6 100644 ---- a/lib/multipath.c -+++ b/lib/multipath.c +Index: openvswitch-2.17.2/lib/multipath.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/multipath.c ++++ openvswitch-2.17.2/lib/multipath.c @@ -21,14 +21,14 @@ #include #include @@ -4940,10 +30122,10 @@ index 6896f94a1..01de39df6 100644 /* Checks that 'mp' is valid on flow. Returns 0 if it is valid, otherwise an * OFPERR_*. */ -diff --git a/lib/namemap.c b/lib/namemap.c -index 785cda4c2..ac6e2f39e 100644 ---- a/lib/namemap.c -+++ b/lib/namemap.c +Index: openvswitch-2.17.2/lib/namemap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/namemap.c ++++ openvswitch-2.17.2/lib/namemap.c @@ -17,7 +17,7 @@ #include #include "openvswitch/namemap.h" @@ -4953,10 +30135,10 @@ index 785cda4c2..ac6e2f39e 100644 #include "openvswitch/dynamic-string.h" #include "openvswitch/json.h" -diff --git a/lib/netdev-afxdp-pool.c b/lib/netdev-afxdp-pool.c -index 3386d2dcf..bb135ae48 100644 ---- a/lib/netdev-afxdp-pool.c -+++ b/lib/netdev-afxdp-pool.c +Index: openvswitch-2.17.2/lib/netdev-afxdp-pool.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-afxdp-pool.c ++++ openvswitch-2.17.2/lib/netdev-afxdp-pool.c @@ -15,7 +15,7 @@ */ #include @@ -4966,10 +30148,10 @@ index 3386d2dcf..bb135ae48 100644 #include "netdev-afxdp-pool.h" #include "openvswitch/util.h" -diff --git a/lib/netdev-afxdp-pool.h b/lib/netdev-afxdp-pool.h -index f929b9489..bad48f327 100644 ---- a/lib/netdev-afxdp-pool.h -+++ b/lib/netdev-afxdp-pool.h +Index: openvswitch-2.17.2/lib/netdev-afxdp-pool.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-afxdp-pool.h ++++ openvswitch-2.17.2/lib/netdev-afxdp-pool.h @@ -24,7 +24,7 @@ #include @@ -4979,10 +30161,10 @@ index f929b9489..bad48f327 100644 /* LIFO ptr_array. */ struct umem_pool { -diff --git a/lib/netdev-afxdp.c b/lib/netdev-afxdp.c -index 482400d8d..da5074cbb 100644 ---- a/lib/netdev-afxdp.c -+++ b/lib/netdev-afxdp.c +Index: openvswitch-2.17.2/lib/netdev-afxdp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-afxdp.c ++++ openvswitch-2.17.2/lib/netdev-afxdp.c @@ -18,7 +18,7 @@ #include "netdev-linux-private.h" @@ -5019,10 +30201,10 @@ index 482400d8d..da5074cbb 100644 #ifndef SOL_XDP #define SOL_XDP 283 -diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c -index 7875636cc..b4f1ca638 100644 ---- a/lib/netdev-bsd.c -+++ b/lib/netdev-bsd.c +Index: openvswitch-2.17.2/lib/netdev-bsd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-bsd.c ++++ openvswitch-2.17.2/lib/netdev-bsd.c @@ -48,19 +48,19 @@ #endif @@ -5051,10 +30233,10 @@ index 7875636cc..b4f1ca638 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_bsd); -diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c -index b6b29c75e..a1284f10e 100644 ---- a/lib/netdev-dpdk.c -+++ b/lib/netdev-dpdk.c +Index: openvswitch-2.17.2/lib/netdev-dpdk.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-dpdk.c ++++ openvswitch-2.17.2/lib/netdev-dpdk.c @@ -15,7 +15,7 @@ */ @@ -5113,10 +30295,10 @@ index b6b29c75e..a1284f10e 100644 enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; -diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c -index 72cb95471..a51a2c975 100644 ---- a/lib/netdev-dummy.c -+++ b/lib/netdev-dummy.c +Index: openvswitch-2.17.2/lib/netdev-dummy.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-dummy.c ++++ openvswitch-2.17.2/lib/netdev-dummy.c @@ -21,9 +21,9 @@ #include #include @@ -5153,10 +30335,10 @@ index 72cb95471..a51a2c975 100644 #include "reconnect.h" VLOG_DEFINE_THIS_MODULE(netdev_dummy); -diff --git a/lib/netdev-linux-private.h b/lib/netdev-linux-private.h -index deb015bdb..58e4e9283 100644 ---- a/lib/netdev-linux-private.h -+++ b/lib/netdev-linux-private.h +Index: openvswitch-2.17.2/lib/netdev-linux-private.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-linux-private.h ++++ openvswitch-2.17.2/lib/netdev-linux-private.h @@ -27,14 +27,14 @@ #include #include @@ -5176,10 +30358,10 @@ index deb015bdb..58e4e9283 100644 struct netdev; -diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c -index 620a451de..bfb1193b8 100644 ---- a/lib/netdev-linux.c -+++ b/lib/netdev-linux.c +Index: openvswitch-2.17.2/lib/netdev-linux.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-linux.c ++++ openvswitch-2.17.2/lib/netdev-linux.c @@ -49,37 +49,37 @@ #include #include @@ -5232,10 +30414,10 @@ index 620a451de..bfb1193b8 100644 VLOG_DEFINE_THIS_MODULE(netdev_linux); -diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c -index b89dfdd52..744c12a71 100644 ---- a/lib/netdev-native-tnl.c -+++ b/lib/netdev-native-tnl.c +Index: openvswitch-2.17.2/lib/netdev-native-tnl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-native-tnl.c ++++ openvswitch-2.17.2/lib/netdev-native-tnl.c @@ -32,17 +32,17 @@ #include #include @@ -5262,10 +30444,10 @@ index b89dfdd52..744c12a71 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(native_tnl); -diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h -index ba05b8b4c..758a632dc 100644 ---- a/lib/netdev-native-tnl.h -+++ b/lib/netdev-native-tnl.h +Index: openvswitch-2.17.2/lib/netdev-native-tnl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-native-tnl.h ++++ openvswitch-2.17.2/lib/netdev-native-tnl.h @@ -20,9 +20,9 @@ #include #include @@ -5279,10 +30461,10 @@ index ba05b8b4c..758a632dc 100644 struct netdev; struct ovs_action_push_tnl; -diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c -index 94dc6a9b7..359615a93 100644 ---- a/lib/netdev-offload-dpdk.c -+++ b/lib/netdev-offload-dpdk.c +Index: openvswitch-2.17.2/lib/netdev-offload-dpdk.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-offload-dpdk.c ++++ openvswitch-2.17.2/lib/netdev-offload-dpdk.c @@ -21,7 +21,7 @@ #include #include @@ -5305,10 +30487,10 @@ index 94dc6a9b7..359615a93 100644 VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(600, 600); -diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h -index 8ff2de983..360536339 100644 ---- a/lib/netdev-offload-provider.h -+++ b/lib/netdev-offload-provider.h +Index: openvswitch-2.17.2/lib/netdev-offload-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-offload-provider.h ++++ openvswitch-2.17.2/lib/netdev-offload-provider.h @@ -18,11 +18,11 @@ #ifndef NETDEV_FLOW_API_PROVIDER_H #define NETDEV_FLOW_API_PROVIDER_H 1 @@ -5323,10 +30505,10 @@ index 8ff2de983..360536339 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index 9845e8d3f..e82dd2ce4 100644 ---- a/lib/netdev-offload-tc.c -+++ b/lib/netdev-offload-tc.c +Index: openvswitch-2.17.2/lib/netdev-offload-tc.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-offload-tc.c ++++ openvswitch-2.17.2/lib/netdev-offload-tc.c @@ -20,7 +20,7 @@ #include @@ -5353,10 +30535,10 @@ index 9845e8d3f..e82dd2ce4 100644 #include "dpif-provider.h" VLOG_DEFINE_THIS_MODULE(netdev_offload_tc); -diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c -index fb108c0d5..845cc05e9 100644 ---- a/lib/netdev-offload.c -+++ b/lib/netdev-offload.c +Index: openvswitch-2.17.2/lib/netdev-offload.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-offload.c ++++ openvswitch-2.17.2/lib/netdev-offload.c @@ -26,31 +26,31 @@ #include #include @@ -5402,10 +30584,10 @@ index fb108c0d5..845cc05e9 100644 #ifdef __linux__ #include "tc.h" #endif -diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h -index 8237a85dd..1038103ee 100644 ---- a/lib/netdev-offload.h -+++ b/lib/netdev-offload.h +Index: openvswitch-2.17.2/lib/netdev-offload.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-offload.h ++++ openvswitch-2.17.2/lib/netdev-offload.h @@ -20,10 +20,10 @@ #include "openvswitch/netdev.h" @@ -5421,10 +30603,10 @@ index 8237a85dd..1038103ee 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h -index b5420947d..a83616e30 100644 ---- a/lib/netdev-provider.h -+++ b/lib/netdev-provider.h +Index: openvswitch-2.17.2/lib/netdev-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-provider.h ++++ openvswitch-2.17.2/lib/netdev-provider.h @@ -20,15 +20,15 @@ /* Generic interface to network devices. */ @@ -5447,10 +30629,10 @@ index b5420947d..a83616e30 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/netdev-vport-private.h b/lib/netdev-vport-private.h -index 490894f1a..07a9c7200 100644 ---- a/lib/netdev-vport-private.h -+++ b/lib/netdev-vport-private.h +Index: openvswitch-2.17.2/lib/netdev-vport-private.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-vport-private.h ++++ openvswitch-2.17.2/lib/netdev-vport-private.h @@ -20,9 +20,9 @@ #include #include @@ -5463,10 +30645,10 @@ index 490894f1a..07a9c7200 100644 struct netdev_vport { struct netdev up; -diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c -index 64331f74b..efb9d903d 100644 ---- a/lib/netdev-vport.c -+++ b/lib/netdev-vport.c +Index: openvswitch-2.17.2/lib/netdev-vport.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-vport.c ++++ openvswitch-2.17.2/lib/netdev-vport.c @@ -28,24 +28,24 @@ #include #include @@ -5502,10 +30684,10 @@ index 64331f74b..efb9d903d 100644 #include "openvswitch/vlog.h" #include "openvswitch/ofp-parse.h" #ifdef __linux__ -diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c -index 4ad45ffa1..65de7bf30 100644 ---- a/lib/netdev-windows.c -+++ b/lib/netdev-windows.c +Index: openvswitch-2.17.2/lib/netdev-windows.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-windows.c ++++ openvswitch-2.17.2/lib/netdev-windows.c @@ -21,18 +21,18 @@ #include @@ -5530,10 +30712,10 @@ index 4ad45ffa1..65de7bf30 100644 VLOG_DEFINE_THIS_MODULE(netdev_windows); static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5); -diff --git a/lib/netdev.c b/lib/netdev.c -index 8305f6c42..91d526463 100644 ---- a/lib/netdev.c -+++ b/lib/netdev.c +Index: openvswitch-2.17.2/lib/netdev.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev.c ++++ openvswitch-2.17.2/lib/netdev.c @@ -15,7 +15,7 @@ */ @@ -5588,10 +30770,10 @@ index 8305f6c42..91d526463 100644 #ifdef __linux__ #include "tc.h" #endif -diff --git a/lib/netflow.h b/lib/netflow.h -index 321f64ccc..a32821a8e 100644 ---- a/lib/netflow.h -+++ b/lib/netflow.h +Index: openvswitch-2.17.2/lib/netflow.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netflow.h ++++ openvswitch-2.17.2/lib/netflow.h @@ -21,7 +21,7 @@ #include @@ -5601,10 +30783,10 @@ index 321f64ccc..a32821a8e 100644 #define NETFLOW_V5_VERSION 5 -diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c -index 8dca46e55..fbc2b30e3 100644 ---- a/lib/netlink-conntrack.c -+++ b/lib/netlink-conntrack.c +Index: openvswitch-2.17.2/lib/netlink-conntrack.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-conntrack.c ++++ openvswitch-2.17.2/lib/netlink-conntrack.c @@ -26,17 +26,17 @@ #include #include @@ -5628,10 +30810,10 @@ index 8dca46e55..fbc2b30e3 100644 VLOG_DEFINE_THIS_MODULE(netlink_conntrack); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -diff --git a/lib/netlink-conntrack.h b/lib/netlink-conntrack.h -index 4972dc6ca..80a017ef9 100644 ---- a/lib/netlink-conntrack.h -+++ b/lib/netlink-conntrack.h +Index: openvswitch-2.17.2/lib/netlink-conntrack.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-conntrack.h ++++ openvswitch-2.17.2/lib/netlink-conntrack.h @@ -19,15 +19,15 @@ #include @@ -5652,10 +30834,10 @@ index 4972dc6ca..80a017ef9 100644 enum nl_ct_event_type { NL_CT_EVENT_NEW = 1 << 0, -diff --git a/lib/netlink-notifier.c b/lib/netlink-notifier.c -index dfecb9778..3770d1d98 100644 ---- a/lib/netlink-notifier.c -+++ b/lib/netlink-notifier.c +Index: openvswitch-2.17.2/lib/netlink-notifier.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-notifier.c ++++ openvswitch-2.17.2/lib/netlink-notifier.c @@ -22,8 +22,8 @@ #include #include @@ -5667,10 +30849,10 @@ index dfecb9778..3770d1d98 100644 #include "netlink-socket.h" #include "openvswitch/ofpbuf.h" #include "openvswitch/vlog.h" -diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c -index 93c1fa561..96423debb 100644 ---- a/lib/netlink-socket.c -+++ b/lib/netlink-socket.c +Index: openvswitch-2.17.2/lib/netlink-socket.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-socket.c ++++ openvswitch-2.17.2/lib/netlink-socket.c @@ -23,20 +23,20 @@ #include #include @@ -5700,10 +30882,10 @@ index 93c1fa561..96423debb 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(netlink_socket); -diff --git a/lib/netlink-socket.h b/lib/netlink-socket.h -index 7852ad052..52c3ac4e0 100644 ---- a/lib/netlink-socket.h -+++ b/lib/netlink-socket.h +Index: openvswitch-2.17.2/lib/netlink-socket.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink-socket.h ++++ openvswitch-2.17.2/lib/netlink-socket.h @@ -194,8 +194,8 @@ #include #include @@ -5715,10 +30897,10 @@ index 7852ad052..52c3ac4e0 100644 struct nl_sock; -diff --git a/lib/netlink.c b/lib/netlink.c -index 8204025a5..84b0fe47c 100644 ---- a/lib/netlink.c -+++ b/lib/netlink.c +Index: openvswitch-2.17.2/lib/netlink.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/netlink.c ++++ openvswitch-2.17.2/lib/netlink.c @@ -15,19 +15,19 @@ */ @@ -5746,10 +30928,10 @@ index 8204025a5..84b0fe47c 100644 VLOG_DEFINE_THIS_MODULE(netlink); -diff --git a/lib/nx-match.c b/lib/nx-match.c -index 440f5f763..1f317fc81 100644 ---- a/lib/nx-match.c -+++ b/lib/nx-match.c +Index: openvswitch-2.17.2/lib/nx-match.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/nx-match.c ++++ openvswitch-2.17.2/lib/nx-match.c @@ -16,12 +16,12 @@ #include @@ -5782,10 +30964,10 @@ index 440f5f763..1f317fc81 100644 #include "vl-mff-map.h" VLOG_DEFINE_THIS_MODULE(nx_match); -diff --git a/lib/object-collection.c b/lib/object-collection.c -index efabe3f92..a64029c8b 100644 ---- a/lib/object-collection.c -+++ b/lib/object-collection.c +Index: openvswitch-2.17.2/lib/object-collection.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/object-collection.c ++++ openvswitch-2.17.2/lib/object-collection.c @@ -17,7 +17,7 @@ #include @@ -5795,10 +30977,10 @@ index efabe3f92..a64029c8b 100644 void object_collection_init(struct object_collection *coll) -diff --git a/lib/odp-execute.c b/lib/odp-execute.c -index 2f4cdd92c..ebb87d3b8 100644 ---- a/lib/odp-execute.c -+++ b/lib/odp-execute.c +Index: openvswitch-2.17.2/lib/odp-execute.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/odp-execute.c ++++ openvswitch-2.17.2/lib/odp-execute.c @@ -25,17 +25,17 @@ #include #include @@ -5825,10 +31007,10 @@ index 2f4cdd92c..ebb87d3b8 100644 #include "conntrack.h" #include "openvswitch/vlog.h" -diff --git a/lib/odp-util.c b/lib/odp-util.c -index 9a705cffa..a65706466 100644 ---- a/lib/odp-util.c -+++ b/lib/odp-util.c +Index: openvswitch-2.17.2/lib/odp-util.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/odp-util.c ++++ openvswitch-2.17.2/lib/odp-util.c @@ -27,24 +27,24 @@ #include #include @@ -5866,10 +31048,10 @@ index 9a705cffa..a65706466 100644 VLOG_DEFINE_THIS_MODULE(odp_util); -diff --git a/lib/odp-util.h b/lib/odp-util.h -index a1d0d0fba..631490b86 100644 ---- a/lib/odp-util.h -+++ b/lib/odp-util.h +Index: openvswitch-2.17.2/lib/odp-util.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/odp-util.h ++++ openvswitch-2.17.2/lib/odp-util.h @@ -21,14 +21,14 @@ #include #include @@ -5888,10 +31070,10 @@ index a1d0d0fba..631490b86 100644 struct ds; struct nlattr; -diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c -index f7fb96c5c..699b8036d 100644 ---- a/lib/ofp-actions.c -+++ b/lib/ofp-actions.c +Index: openvswitch-2.17.2/lib/ofp-actions.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-actions.c ++++ openvswitch-2.17.2/lib/ofp-actions.c @@ -19,15 +19,15 @@ #include #include @@ -5923,10 +31105,10 @@ index f7fb96c5c..699b8036d 100644 #include "vl-mff-map.h" VLOG_DEFINE_THIS_MODULE(ofp_actions); -diff --git a/lib/ofp-bundle.c b/lib/ofp-bundle.c -index 0161c2bc6..360ec1b84 100644 ---- a/lib/ofp-bundle.c -+++ b/lib/ofp-bundle.c +Index: openvswitch-2.17.2/lib/ofp-bundle.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-bundle.c ++++ openvswitch-2.17.2/lib/ofp-bundle.c @@ -22,7 +22,7 @@ #include "openvswitch/ofp-print.h" #include "openvswitch/ofpbuf.h" @@ -5936,10 +31118,10 @@ index 0161c2bc6..360ec1b84 100644 VLOG_DEFINE_THIS_MODULE(ofp_bundle); -diff --git a/lib/ofp-connection.c b/lib/ofp-connection.c -index 3a7611b00..64da0bbd3 100644 ---- a/lib/ofp-connection.c -+++ b/lib/ofp-connection.c +Index: openvswitch-2.17.2/lib/ofp-connection.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-connection.c ++++ openvswitch-2.17.2/lib/ofp-connection.c @@ -16,7 +16,7 @@ #include @@ -5958,10 +31140,10 @@ index 3a7611b00..64da0bbd3 100644 VLOG_DEFINE_THIS_MODULE(ofp_connection); -diff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c -index d0649da02..5572496ab 100644 ---- a/lib/ofp-ed-props.c -+++ b/lib/ofp-ed-props.c +Index: openvswitch-2.17.2/lib/ofp-ed-props.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-ed-props.c ++++ openvswitch-2.17.2/lib/ofp-ed-props.c @@ -21,8 +21,8 @@ #include "openvswitch/ofp-ed-props.h" #include "openvswitch/ofpbuf.h" @@ -5973,10 +31155,10 @@ index d0649da02..5572496ab 100644 enum ofperr -diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c -index 35191abf1..eb0d32394 100644 ---- a/lib/ofp-errors.c -+++ b/lib/ofp-errors.c +Index: openvswitch-2.17.2/lib/ofp-errors.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-errors.c ++++ openvswitch-2.17.2/lib/ofp-errors.c @@ -16,7 +16,7 @@ #include @@ -5995,10 +31177,10 @@ index 35191abf1..eb0d32394 100644 VLOG_DEFINE_THIS_MODULE(ofp_errors); -diff --git a/lib/ofp-flow.c b/lib/ofp-flow.c -index 3bc744f78..04f120675 100644 ---- a/lib/ofp-flow.c -+++ b/lib/ofp-flow.c +Index: openvswitch-2.17.2/lib/ofp-flow.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-flow.c ++++ openvswitch-2.17.2/lib/ofp-flow.c @@ -17,10 +17,10 @@ #include #include "openvswitch/ofp-flow.h" @@ -6023,10 +31205,10 @@ index 3bc744f78..04f120675 100644 #include "ox-stat.h" VLOG_DEFINE_THIS_MODULE(ofp_flow); -diff --git a/lib/ofp-group.c b/lib/ofp-group.c -index 737f48047..0a8a3aa64 100644 ---- a/lib/ofp-group.c -+++ b/lib/ofp-group.c +Index: openvswitch-2.17.2/lib/ofp-group.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-group.c ++++ openvswitch-2.17.2/lib/ofp-group.c @@ -17,9 +17,9 @@ #include #include "openvswitch/ofp-group.h" @@ -6049,10 +31231,10 @@ index 737f48047..0a8a3aa64 100644 VLOG_DEFINE_THIS_MODULE(ofp_group); -diff --git a/lib/ofp-ipfix.c b/lib/ofp-ipfix.c -index 0ffc4d936..6dbe76ef9 100644 ---- a/lib/ofp-ipfix.c -+++ b/lib/ofp-ipfix.c +Index: openvswitch-2.17.2/lib/ofp-ipfix.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-ipfix.c ++++ openvswitch-2.17.2/lib/ofp-ipfix.c @@ -17,12 +17,12 @@ #include #include "openvswitch/ofp-ipfix.h" @@ -6068,10 +31250,10 @@ index 0ffc4d936..6dbe76ef9 100644 static void ofputil_ipfix_stats_to_reply(const struct ofputil_ipfix_stats *ois, -diff --git a/lib/ofp-match.c b/lib/ofp-match.c -index 86a082dde..4a8953a65 100644 ---- a/lib/ofp-match.c -+++ b/lib/ofp-match.c +Index: openvswitch-2.17.2/lib/ofp-match.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-match.c ++++ openvswitch-2.17.2/lib/ofp-match.c @@ -16,9 +16,9 @@ #include @@ -6085,10 +31267,10 @@ index 86a082dde..4a8953a65 100644 #include "openvswitch/match.h" #include "openvswitch/ofp-errors.h" #include "openvswitch/ofp-msgs.h" -diff --git a/lib/ofp-meter.c b/lib/ofp-meter.c -index 9ea40a0bf..37cc9384b 100644 ---- a/lib/ofp-meter.c -+++ b/lib/ofp-meter.c +Index: openvswitch-2.17.2/lib/ofp-meter.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-meter.c ++++ openvswitch-2.17.2/lib/ofp-meter.c @@ -16,8 +16,8 @@ #include @@ -6100,10 +31282,10 @@ index 9ea40a0bf..37cc9384b 100644 #include "openvswitch/ofp-errors.h" #include "openvswitch/ofp-msgs.h" #include "openvswitch/ofp-parse.h" -diff --git a/lib/ofp-monitor.c b/lib/ofp-monitor.c -index e12fa6d2b..cdf54037e 100644 ---- a/lib/ofp-monitor.c -+++ b/lib/ofp-monitor.c +Index: openvswitch-2.17.2/lib/ofp-monitor.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-monitor.c ++++ openvswitch-2.17.2/lib/ofp-monitor.c @@ -16,9 +16,9 @@ #include @@ -6117,10 +31299,10 @@ index e12fa6d2b..cdf54037e 100644 #include "openvswitch/ofp-actions.h" #include "openvswitch/ofp-errors.h" #include "openvswitch/ofp-group.h" -diff --git a/lib/ofp-msgs.c b/lib/ofp-msgs.c -index fec54f75f..ebf360dba 100644 ---- a/lib/ofp-msgs.c -+++ b/lib/ofp-msgs.c +Index: openvswitch-2.17.2/lib/ofp-msgs.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-msgs.c ++++ openvswitch-2.17.2/lib/ofp-msgs.c @@ -15,8 +15,8 @@ */ @@ -6143,10 +31325,10 @@ index fec54f75f..ebf360dba 100644 VLOG_DEFINE_THIS_MODULE(ofp_msgs); -diff --git a/lib/ofp-packet.c b/lib/ofp-packet.c -index 4579548ee..2a7584b64 100644 ---- a/lib/ofp-packet.c -+++ b/lib/ofp-packet.c +Index: openvswitch-2.17.2/lib/ofp-packet.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-packet.c ++++ openvswitch-2.17.2/lib/ofp-packet.c @@ -17,8 +17,8 @@ #include #include "openvswitch/ofp-packet.h" @@ -6169,10 +31351,10 @@ index 4579548ee..2a7584b64 100644 VLOG_DEFINE_THIS_MODULE(ofp_packet); -diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c -index a90b926ef..1bd491a88 100644 ---- a/lib/ofp-parse.c -+++ b/lib/ofp-parse.c +Index: openvswitch-2.17.2/lib/ofp-parse.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-parse.c ++++ openvswitch-2.17.2/lib/ofp-parse.c @@ -17,16 +17,16 @@ #include #include "openvswitch/ofp-parse.h" @@ -6194,10 +31376,10 @@ index a90b926ef..1bd491a88 100644 /* Parses 'str' as an 8-bit unsigned integer into '*valuep'. * -diff --git a/lib/ofp-port.c b/lib/ofp-port.c -index 16d587488..280450e30 100644 ---- a/lib/ofp-port.c -+++ b/lib/ofp-port.c +Index: openvswitch-2.17.2/lib/ofp-port.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-port.c ++++ openvswitch-2.17.2/lib/ofp-port.c @@ -17,8 +17,8 @@ #include #include "openvswitch/ofp-port.h" @@ -6209,10 +31391,10 @@ index 16d587488..280450e30 100644 #include "openflow/intel-ext.h" #include "openvswitch/json.h" #include "openvswitch/ofp-errors.h" -diff --git a/lib/ofp-print.c b/lib/ofp-print.c -index db7318205..33a214e1c 100644 ---- a/lib/ofp-print.c -+++ b/lib/ofp-print.c +Index: openvswitch-2.17.2/lib/ofp-print.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-print.c ++++ openvswitch-2.17.2/lib/ofp-print.c @@ -27,16 +27,16 @@ #include #include @@ -6252,10 +31434,10 @@ index db7318205..33a214e1c 100644 static void ofp_print_error(struct ds *, enum ofperr); -diff --git a/lib/ofp-prop.c b/lib/ofp-prop.c -index 8b2d8a85a..da5619dd1 100644 ---- a/lib/ofp-prop.c -+++ b/lib/ofp-prop.c +Index: openvswitch-2.17.2/lib/ofp-prop.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-prop.c ++++ openvswitch-2.17.2/lib/ofp-prop.c @@ -16,13 +16,13 @@ #include @@ -6273,10 +31455,10 @@ index 8b2d8a85a..da5619dd1 100644 struct ofp_prop_be16 { ovs_be16 type; -diff --git a/lib/ofp-protocol.c b/lib/ofp-protocol.c -index 4d2dd6268..eeeb9973a 100644 ---- a/lib/ofp-protocol.c -+++ b/lib/ofp-protocol.c +Index: openvswitch-2.17.2/lib/ofp-protocol.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-protocol.c ++++ openvswitch-2.17.2/lib/ofp-protocol.c @@ -22,7 +22,7 @@ #include "openvswitch/ofp-msgs.h" #include "openvswitch/ofpbuf.h" @@ -6286,10 +31468,10 @@ index 4d2dd6268..eeeb9973a 100644 VLOG_DEFINE_THIS_MODULE(ofp_protocol); -diff --git a/lib/ofp-queue.c b/lib/ofp-queue.c -index efb8a250a..c69cc2190 100644 ---- a/lib/ofp-queue.c -+++ b/lib/ofp-queue.c +Index: openvswitch-2.17.2/lib/ofp-queue.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-queue.c ++++ openvswitch-2.17.2/lib/ofp-queue.c @@ -16,15 +16,15 @@ #include @@ -6309,10 +31491,10 @@ index efb8a250a..c69cc2190 100644 VLOG_DEFINE_THIS_MODULE(ofp_queue); -diff --git a/lib/ofp-switch.c b/lib/ofp-switch.c -index 2f7a1cad2..6933dd7d0 100644 ---- a/lib/ofp-switch.c -+++ b/lib/ofp-switch.c +Index: openvswitch-2.17.2/lib/ofp-switch.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-switch.c ++++ openvswitch-2.17.2/lib/ofp-switch.c @@ -16,14 +16,14 @@ #include @@ -6330,10 +31512,10 @@ index 2f7a1cad2..6933dd7d0 100644 /* ofputil_switch_features */ -diff --git a/lib/ofp-table.c b/lib/ofp-table.c -index a956754f2..9d3ad1121 100644 ---- a/lib/ofp-table.c -+++ b/lib/ofp-table.c +Index: openvswitch-2.17.2/lib/ofp-table.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-table.c ++++ openvswitch-2.17.2/lib/ofp-table.c @@ -16,8 +16,8 @@ #include @@ -6354,10 +31536,10 @@ index a956754f2..9d3ad1121 100644 VLOG_DEFINE_THIS_MODULE(ofp_table); -diff --git a/lib/ofp-util.c b/lib/ofp-util.c -index a324ceeea..accf2fa0f 100644 ---- a/lib/ofp-util.c -+++ b/lib/ofp-util.c +Index: openvswitch-2.17.2/lib/ofp-util.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-util.c ++++ openvswitch-2.17.2/lib/ofp-util.c @@ -23,15 +23,15 @@ #include #include @@ -6400,10 +31582,10 @@ index a324ceeea..accf2fa0f 100644 VLOG_DEFINE_THIS_MODULE(ofp_util); -diff --git a/lib/ofp-version-opt.c b/lib/ofp-version-opt.c -index f97d7b738..2dc60374a 100644 ---- a/lib/ofp-version-opt.c -+++ b/lib/ofp-version-opt.c +Index: openvswitch-2.17.2/lib/ofp-version-opt.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-version-opt.c ++++ openvswitch-2.17.2/lib/ofp-version-opt.c @@ -2,7 +2,7 @@ #include "openvswitch/dynamic-string.h" #include "openvswitch/ofp-protocol.h" @@ -6413,10 +31595,10 @@ index f97d7b738..2dc60374a 100644 static uint32_t allowed_versions = 0; -diff --git a/lib/ofp-version-opt.h b/lib/ofp-version-opt.h -index f50f400d3..ec1dd7229 100644 ---- a/lib/ofp-version-opt.h -+++ b/lib/ofp-version-opt.h +Index: openvswitch-2.17.2/lib/ofp-version-opt.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofp-version-opt.h ++++ openvswitch-2.17.2/lib/ofp-version-opt.h @@ -2,7 +2,7 @@ #define OFP_VERSION_H 1 @@ -6426,10 +31608,10 @@ index f50f400d3..ec1dd7229 100644 #define OFP_VERSION_LONG_OPTIONS \ {"version", no_argument, NULL, 'V'}, \ -diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c -index 271105bde..2de734bdd 100644 ---- a/lib/ofpbuf.c -+++ b/lib/ofpbuf.c +Index: openvswitch-2.17.2/lib/ofpbuf.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ofpbuf.c ++++ openvswitch-2.17.2/lib/ofpbuf.c @@ -19,7 +19,7 @@ #include #include @@ -6439,10 +31621,10 @@ index 271105bde..2de734bdd 100644 static void ofpbuf_init__(struct ofpbuf *b, size_t allocated, enum ofpbuf_source source) -diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c -index 162311fa4..7bcab25cf 100644 ---- a/lib/ovs-lldp.c -+++ b/lib/ovs-lldp.c +Index: openvswitch-2.17.2/lib/ovs-lldp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-lldp.c ++++ openvswitch-2.17.2/lib/ovs-lldp.c @@ -35,17 +35,17 @@ #include #include @@ -6467,10 +31649,10 @@ index 162311fa4..7bcab25cf 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovs_lldp); -diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h -index 0e536e8c2..746ad3c4b 100644 ---- a/lib/ovs-lldp.h -+++ b/lib/ovs-lldp.h +Index: openvswitch-2.17.2/lib/ovs-lldp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-lldp.h ++++ openvswitch-2.17.2/lib/ovs-lldp.h @@ -20,13 +20,13 @@ #define OVS_LLDP_H @@ -6489,10 +31671,10 @@ index 0e536e8c2..746ad3c4b 100644 /* Transmit every LLDPD_TX_INTERVAL seconds. */ #define LLDP_DEFAULT_TRANSMIT_INTERVAL_MS (LLDPD_TX_INTERVAL * 1000) -diff --git a/lib/ovs-numa.c b/lib/ovs-numa.c -index 9e3fa5421..c4792cf31 100644 ---- a/lib/ovs-numa.c -+++ b/lib/ovs-numa.c +Index: openvswitch-2.17.2/lib/ovs-numa.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-numa.c ++++ openvswitch-2.17.2/lib/ovs-numa.c @@ -15,7 +15,7 @@ */ @@ -6518,10 +31700,10 @@ index 9e3fa5421..c4792cf31 100644 VLOG_DEFINE_THIS_MODULE(ovs_numa); -diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c -index 1866bd308..c9bfeab8f 100644 ---- a/lib/ovs-rcu.c -+++ b/lib/ovs-rcu.c +Index: openvswitch-2.17.2/lib/ovs-rcu.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-rcu.c ++++ openvswitch-2.17.2/lib/ovs-rcu.c @@ -16,16 +16,16 @@ #include @@ -6546,10 +31728,10 @@ index 1866bd308..c9bfeab8f 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovs_rcu); -diff --git a/lib/ovs-replay.c b/lib/ovs-replay.c -index f386246c7..59b2ce0e1 100644 ---- a/lib/ovs-replay.c -+++ b/lib/ovs-replay.c +Index: openvswitch-2.17.2/lib/ovs-replay.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-replay.c ++++ openvswitch-2.17.2/lib/ovs-replay.c @@ -22,10 +22,10 @@ #include #include @@ -6564,10 +31746,10 @@ index f386246c7..59b2ce0e1 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovs_replay); -diff --git a/lib/ovs-router.c b/lib/ovs-router.c -index e52cbb0bf..4dc3549c7 100644 ---- a/lib/ovs-router.c -+++ b/lib/ovs-router.c +Index: openvswitch-2.17.2/lib/ovs-router.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-router.c ++++ openvswitch-2.17.2/lib/ovs-router.c @@ -30,21 +30,21 @@ #include #include @@ -6600,10 +31782,10 @@ index e52cbb0bf..4dc3549c7 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovs_router); -diff --git a/lib/ovs-router.h b/lib/ovs-router.h -index 34ea163ee..57c148fce 100644 ---- a/lib/ovs-router.h -+++ b/lib/ovs-router.h +Index: openvswitch-2.17.2/lib/ovs-router.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-router.h ++++ openvswitch-2.17.2/lib/ovs-router.h @@ -20,7 +20,7 @@ #include #include @@ -6613,10 +31795,10 @@ index 34ea163ee..57c148fce 100644 #ifdef __cplusplus extern "C" { -diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c -index 542dbbc7d..1a72d78b3 100644 ---- a/lib/ovs-thread.c -+++ b/lib/ovs-thread.c +Index: openvswitch-2.17.2/lib/ovs-thread.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-thread.c ++++ openvswitch-2.17.2/lib/ovs-thread.c @@ -15,7 +15,7 @@ */ @@ -6647,10 +31829,10 @@ index 542dbbc7d..1a72d78b3 100644 #ifdef __CHECKER__ /* Omit the definitions in this file because they are somewhat difficult to -diff --git a/lib/ovsdb-condition.c b/lib/ovsdb-condition.c -index e0c4e43da..867fbbe08 100644 ---- a/lib/ovsdb-condition.c -+++ b/lib/ovsdb-condition.c +Index: openvswitch-2.17.2/lib/ovsdb-condition.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-condition.c ++++ openvswitch-2.17.2/lib/ovsdb-condition.c @@ -16,8 +16,8 @@ #include @@ -6662,10 +31844,10 @@ index e0c4e43da..867fbbe08 100644 struct ovsdb_error * ovsdb_function_from_string(const char *name, enum ovsdb_function *function) -diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c -index dead31275..553a0f82f 100644 ---- a/lib/ovsdb-cs.c -+++ b/lib/ovsdb-cs.c +Index: openvswitch-2.17.2/lib/ovsdb-cs.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-cs.c ++++ openvswitch-2.17.2/lib/ovsdb-cs.c @@ -16,27 +16,27 @@ #include @@ -6705,10 +31887,10 @@ index dead31275..553a0f82f 100644 VLOG_DEFINE_THIS_MODULE(ovsdb_cs); -diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c -index 6b1c20ff8..cd3e0c0ae 100644 ---- a/lib/ovsdb-data.c -+++ b/lib/ovsdb-data.c +Index: openvswitch-2.17.2/lib/ovsdb-data.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-data.c ++++ openvswitch-2.17.2/lib/ovsdb-data.c @@ -15,7 +15,7 @@ #include @@ -6742,10 +31924,10 @@ index 6b1c20ff8..cd3e0c0ae 100644 static struct json * wrap_json(const char *name, struct json *wrapped) -diff --git a/lib/ovsdb-error.c b/lib/ovsdb-error.c -index a75ad36b7..15bf1e3c1 100644 ---- a/lib/ovsdb-error.c -+++ b/lib/ovsdb-error.c +Index: openvswitch-2.17.2/lib/ovsdb-error.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-error.c ++++ openvswitch-2.17.2/lib/ovsdb-error.c @@ -15,14 +15,14 @@ #include @@ -6763,10 +31945,10 @@ index a75ad36b7..15bf1e3c1 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_error); -diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c -index c19128d55..b2d3e9818 100644 ---- a/lib/ovsdb-idl.c -+++ b/lib/ovsdb-idl.c +Index: openvswitch-2.17.2/lib/ovsdb-idl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-idl.c ++++ openvswitch-2.17.2/lib/ovsdb-idl.c @@ -16,37 +16,37 @@ #include @@ -6822,10 +32004,10 @@ index c19128d55..b2d3e9818 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_idl); -diff --git a/lib/ovsdb-map-op.c b/lib/ovsdb-map-op.c -index 7b90ba84f..df568e3e2 100644 ---- a/lib/ovsdb-map-op.c -+++ b/lib/ovsdb-map-op.c +Index: openvswitch-2.17.2/lib/ovsdb-map-op.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-map-op.c ++++ openvswitch-2.17.2/lib/ovsdb-map-op.c @@ -15,10 +15,10 @@  */ @@ -6840,10 +32022,10 @@ index 7b90ba84f..df568e3e2 100644 /* Map Operation: a Partial Map Update */ struct map_op { -diff --git a/lib/ovsdb-parser.c b/lib/ovsdb-parser.c -index 38119c195..be173ac22 100644 ---- a/lib/ovsdb-parser.c -+++ b/lib/ovsdb-parser.c +Index: openvswitch-2.17.2/lib/ovsdb-parser.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-parser.c ++++ openvswitch-2.17.2/lib/ovsdb-parser.c @@ -15,12 +15,12 @@ #include @@ -6859,10 +32041,10 @@ index 38119c195..be173ac22 100644 void ovsdb_parser_init(struct ovsdb_parser *parser, const struct json *json, -diff --git a/lib/ovsdb-session.c b/lib/ovsdb-session.c -index a8cb90f22..57d627958 100644 ---- a/lib/ovsdb-session.c -+++ b/lib/ovsdb-session.c +Index: openvswitch-2.17.2/lib/ovsdb-session.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-session.c ++++ openvswitch-2.17.2/lib/ovsdb-session.c @@ -18,9 +18,9 @@ #include #include @@ -6876,10 +32058,10 @@ index a8cb90f22..57d627958 100644 static const char * next_remote(const char *s) -diff --git a/lib/ovsdb-set-op.c b/lib/ovsdb-set-op.c -index 62c462118..7b978f0f8 100644 ---- a/lib/ovsdb-set-op.c -+++ b/lib/ovsdb-set-op.c +Index: openvswitch-2.17.2/lib/ovsdb-set-op.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-set-op.c ++++ openvswitch-2.17.2/lib/ovsdb-set-op.c @@ -16,8 +16,8 @@ */ @@ -6891,10 +32073,10 @@ index 62c462118..7b978f0f8 100644 /* Set Operation: a Partial Set Update */ struct set_op { -diff --git a/lib/ovsdb-types.c b/lib/ovsdb-types.c -index 24ccdd1cc..a1a1df067 100644 ---- a/lib/ovsdb-types.c -+++ b/lib/ovsdb-types.c +Index: openvswitch-2.17.2/lib/ovsdb-types.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovsdb-types.c ++++ openvswitch-2.17.2/lib/ovsdb-types.c @@ -15,18 +15,18 @@ #include @@ -6920,10 +32102,10 @@ index 24ccdd1cc..a1a1df067 100644 const struct ovsdb_type ovsdb_type_integer = OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_INTEGER_INIT); -diff --git a/lib/ox-stat.c b/lib/ox-stat.c -index c6fbb4daa..314b6af55 100644 ---- a/lib/ox-stat.c -+++ b/lib/ox-stat.c +Index: openvswitch-2.17.2/lib/ox-stat.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/ox-stat.c ++++ openvswitch-2.17.2/lib/ox-stat.c @@ -16,12 +16,12 @@ #include @@ -6939,10 +32121,10 @@ index c6fbb4daa..314b6af55 100644 VLOG_DEFINE_THIS_MODULE(ox_stat); -diff --git a/lib/packets.c b/lib/packets.c -index d0fba8176..464f9ca68 100644 ---- a/lib/packets.c -+++ b/lib/packets.c +Index: openvswitch-2.17.2/lib/packets.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/packets.c ++++ openvswitch-2.17.2/lib/packets.c @@ -15,7 +15,7 @@ */ @@ -6976,10 +32158,10 @@ index d0fba8176..464f9ca68 100644 const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT; -diff --git a/lib/pcap-file.c b/lib/pcap-file.c -index 67c9b9bea..b1657c1e7 100644 ---- a/lib/pcap-file.c -+++ b/lib/pcap-file.c +Index: openvswitch-2.17.2/lib/pcap-file.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/pcap-file.c ++++ openvswitch-2.17.2/lib/pcap-file.c @@ -21,15 +21,15 @@ #include #include @@ -7003,10 +32185,10 @@ index 67c9b9bea..b1657c1e7 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(pcap); -diff --git a/lib/perf-counter.c b/lib/perf-counter.c -index e4eca58d0..8059c9a51 100644 ---- a/lib/perf-counter.c -+++ b/lib/perf-counter.c +Index: openvswitch-2.17.2/lib/perf-counter.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/perf-counter.c ++++ openvswitch-2.17.2/lib/perf-counter.c @@ -29,7 +29,7 @@ #include "openvswitch/dynamic-string.h" #include "perf-counter.h" @@ -7016,10 +32198,10 @@ index e4eca58d0..8059c9a51 100644 static struct shash perf_counters = SHASH_INITIALIZER(&perf_counters); static int fd__ = 0; -diff --git a/lib/poll-loop.c b/lib/poll-loop.c -index 4e751ff2c..3cec9e8a8 100644 ---- a/lib/poll-loop.c -+++ b/lib/poll-loop.c +Index: openvswitch-2.17.2/lib/poll-loop.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/poll-loop.c ++++ openvswitch-2.17.2/lib/poll-loop.c @@ -21,17 +21,17 @@ #include #include @@ -7045,10 +32227,10 @@ index 4e751ff2c..3cec9e8a8 100644 VLOG_DEFINE_THIS_MODULE(poll_loop); -diff --git a/lib/process.c b/lib/process.c -index 78de4b8df..c1b886f1a 100644 ---- a/lib/process.c -+++ b/lib/process.c +Index: openvswitch-2.17.2/lib/process.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/process.c ++++ openvswitch-2.17.2/lib/process.c @@ -15,7 +15,7 @@ */ @@ -7081,10 +32263,10 @@ index 78de4b8df..c1b886f1a 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(process); -diff --git a/lib/pvector.c b/lib/pvector.c -index cc527fdc4..e7950934f 100644 ---- a/lib/pvector.c -+++ b/lib/pvector.c +Index: openvswitch-2.17.2/lib/pvector.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/pvector.c ++++ openvswitch-2.17.2/lib/pvector.c @@ -15,7 +15,7 @@ */ @@ -7094,10 +32276,10 @@ index cc527fdc4..e7950934f 100644 /* Writers will preallocate space for some entries at the end to avoid future * reallocations. */ -diff --git a/lib/random.c b/lib/random.c -index c0bc659d1..6f58d836c 100644 ---- a/lib/random.c -+++ b/lib/random.c +Index: openvswitch-2.17.2/lib/random.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/random.c ++++ openvswitch-2.17.2/lib/random.c @@ -15,17 +15,17 @@ */ @@ -7121,10 +32303,10 @@ index c0bc659d1..6f58d836c 100644 /* This is the 32-bit PRNG recommended in G. Marsaglia, "Xorshift RNGs", * _Journal of Statistical Software_ 8:14 (July 2003). According to the paper, -diff --git a/lib/rconn.c b/lib/rconn.c -index a96b2eb8b..760f70a22 100644 ---- a/lib/rconn.c -+++ b/lib/rconn.c +Index: openvswitch-2.17.2/lib/rconn.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/rconn.c ++++ openvswitch-2.17.2/lib/rconn.c @@ -20,7 +20,7 @@ #include #include @@ -7149,10 +32331,10 @@ index a96b2eb8b..760f70a22 100644 VLOG_DEFINE_THIS_MODULE(rconn); -diff --git a/lib/reconnect.c b/lib/reconnect.c -index a929ddfd2..39d34b206 100644 ---- a/lib/reconnect.c -+++ b/lib/reconnect.c +Index: openvswitch-2.17.2/lib/reconnect.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/reconnect.c ++++ openvswitch-2.17.2/lib/reconnect.c @@ -20,7 +20,7 @@ #include @@ -7162,10 +32344,10 @@ index a929ddfd2..39d34b206 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(reconnect); -diff --git a/lib/route-table-bsd.c b/lib/route-table-bsd.c -index 34d42cfab..258d9a2d5 100644 ---- a/lib/route-table-bsd.c -+++ b/lib/route-table-bsd.c +Index: openvswitch-2.17.2/lib/route-table-bsd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/route-table-bsd.c ++++ openvswitch-2.17.2/lib/route-table-bsd.c @@ -32,9 +32,9 @@ #include @@ -7178,10 +32360,10 @@ index 34d42cfab..258d9a2d5 100644 VLOG_DEFINE_THIS_MODULE(route_table_bsd); -diff --git a/lib/route-table.c b/lib/route-table.c -index ac82cf262..22b2468ec 100644 ---- a/lib/route-table.c -+++ b/lib/route-table.c +Index: openvswitch-2.17.2/lib/route-table.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/route-table.c ++++ openvswitch-2.17.2/lib/route-table.c @@ -26,14 +26,14 @@ #include #include @@ -7201,10 +32383,10 @@ index ac82cf262..22b2468ec 100644 #include "rtnetlink.h" #include "tnl-ports.h" #include "openvswitch/vlog.h" -diff --git a/lib/rstp-common.h b/lib/rstp-common.h -index 7948842f4..3b674d02a 100644 ---- a/lib/rstp-common.h -+++ b/lib/rstp-common.h +Index: openvswitch-2.17.2/lib/rstp-common.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/rstp-common.h ++++ openvswitch-2.17.2/lib/rstp-common.h @@ -35,8 +35,8 @@ #include #include "openvswitch/hmap.h" @@ -7216,10 +32398,10 @@ index 7948842f4..3b674d02a 100644 enum admin_port_state { RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED = 0, -diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c -index 7bd1f80c4..94d15cf0c 100644 ---- a/lib/rstp-state-machines.c -+++ b/lib/rstp-state-machines.c +Index: openvswitch-2.17.2/lib/rstp-state-machines.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/rstp-state-machines.c ++++ openvswitch-2.17.2/lib/rstp-state-machines.c @@ -36,14 +36,14 @@ #include #include @@ -7241,10 +32423,10 @@ index 7bd1f80c4..94d15cf0c 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(rstp_sm); -diff --git a/lib/rstp.c b/lib/rstp.c -index 7e351bf32..a80854a3c 100644 ---- a/lib/rstp.c -+++ b/lib/rstp.c +Index: openvswitch-2.17.2/lib/rstp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/rstp.c ++++ openvswitch-2.17.2/lib/rstp.c @@ -37,15 +37,15 @@ #include #include @@ -7267,10 +32449,10 @@ index 7e351bf32..a80854a3c 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(rstp); -diff --git a/lib/rstp.h b/lib/rstp.h -index 90ea67d58..5fb4fc104 100644 ---- a/lib/rstp.h -+++ b/lib/rstp.h +Index: openvswitch-2.17.2/lib/rstp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/rstp.h ++++ openvswitch-2.17.2/lib/rstp.h @@ -34,7 +34,7 @@ #include #include @@ -7280,10 +32462,10 @@ index 90ea67d58..5fb4fc104 100644 /* Thread Safety: Callers passing in RSTP and RSTP port object * pointers must hold a reference to the passed object to ensure that -diff --git a/lib/rtbsd.c b/lib/rtbsd.c -index 564595c3a..8f8ed80f4 100644 ---- a/lib/rtbsd.c -+++ b/lib/rtbsd.c +Index: openvswitch-2.17.2/lib/rtbsd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/rtbsd.c ++++ openvswitch-2.17.2/lib/rtbsd.c @@ -25,8 +25,8 @@ #include #include @@ -7295,10 +32477,10 @@ index 564595c3a..8f8ed80f4 100644 #include "openvswitch/poll-loop.h" #include "openvswitch/vlog.h" -diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c -index f67352603..20bcb5131 100644 ---- a/lib/rtnetlink.c -+++ b/lib/rtnetlink.c +Index: openvswitch-2.17.2/lib/rtnetlink.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/rtnetlink.c ++++ openvswitch-2.17.2/lib/rtnetlink.c @@ -22,10 +22,10 @@ #include #include @@ -7312,10 +32494,10 @@ index f67352603..20bcb5131 100644 #if IFLA_INFO_MAX < 5 #define IFLA_INFO_SLAVE_KIND 4 -diff --git a/lib/seq.c b/lib/seq.c -index 6581cb06b..6c60f36cb 100644 ---- a/lib/seq.c -+++ b/lib/seq.c +Index: openvswitch-2.17.2/lib/seq.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/seq.c ++++ openvswitch-2.17.2/lib/seq.c @@ -16,16 +16,16 @@ #include @@ -7338,10 +32520,10 @@ index 6581cb06b..6c60f36cb 100644 #include "openvswitch/poll-loop.h" COVERAGE_DEFINE(seq_change); -diff --git a/lib/sflow_agent.c b/lib/sflow_agent.c -index c95f654a5..e45dc075b 100644 ---- a/lib/sflow_agent.c -+++ b/lib/sflow_agent.c +Index: openvswitch-2.17.2/lib/sflow_agent.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/sflow_agent.c ++++ openvswitch-2.17.2/lib/sflow_agent.c @@ -6,7 +6,7 @@ */ @@ -7351,10 +32533,10 @@ index c95f654a5..e45dc075b 100644 static void * sflAlloc(SFLAgent *agent, size_t bytes); static void sflFree(SFLAgent *agent, void *obj); -diff --git a/lib/sha1.c b/lib/sha1.c -index 18f245c8b..96283a008 100644 ---- a/lib/sha1.c -+++ b/lib/sha1.c +Index: openvswitch-2.17.2/lib/sha1.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/sha1.c ++++ openvswitch-2.17.2/lib/sha1.c @@ -34,7 +34,7 @@ #include #include @@ -7364,10 +32546,10 @@ index 18f245c8b..96283a008 100644 /* a bit faster & bigger, if defined */ #define UNROLL_LOOPS -diff --git a/lib/shash.c b/lib/shash.c -index a8433629a..47b05d53d 100644 ---- a/lib/shash.c -+++ b/lib/shash.c +Index: openvswitch-2.17.2/lib/shash.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/shash.c ++++ openvswitch-2.17.2/lib/shash.c @@ -16,7 +16,7 @@ #include @@ -7377,10 +32559,10 @@ index a8433629a..47b05d53d 100644 static struct shash_node *shash_find__(const struct shash *, const char *name, size_t name_len, -diff --git a/lib/signals.c b/lib/signals.c -index 70c53adc6..3a12c9b68 100644 ---- a/lib/signals.c -+++ b/lib/signals.c +Index: openvswitch-2.17.2/lib/signals.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/signals.c ++++ openvswitch-2.17.2/lib/signals.c @@ -22,9 +22,9 @@ #include #include @@ -7393,10 +32575,10 @@ index 70c53adc6..3a12c9b68 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(signals); -diff --git a/lib/simap.c b/lib/simap.c -index f404ece67..415a34247 100644 ---- a/lib/simap.c -+++ b/lib/simap.c +Index: openvswitch-2.17.2/lib/simap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/simap.c ++++ openvswitch-2.17.2/lib/simap.c @@ -15,8 +15,8 @@ */ @@ -7408,10 +32590,10 @@ index f404ece67..415a34247 100644 static size_t hash_name(const char *, size_t length); static struct simap_node *simap_find__(const struct simap *, -diff --git a/lib/skiplist.c b/lib/skiplist.c -index beb09773f..4879934c4 100644 ---- a/lib/skiplist.c -+++ b/lib/skiplist.c +Index: openvswitch-2.17.2/lib/skiplist.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/skiplist.c ++++ openvswitch-2.17.2/lib/skiplist.c @@ -25,9 +25,9 @@ #include #include @@ -7425,10 +32607,10 @@ index beb09773f..4879934c4 100644 /* * A maximum height level of 32 should be more than sufficient for -diff --git a/lib/smap.c b/lib/smap.c -index e82261497..9a4f46095 100644 ---- a/lib/smap.c -+++ b/lib/smap.c +Index: openvswitch-2.17.2/lib/smap.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/smap.c ++++ openvswitch-2.17.2/lib/smap.c @@ -13,15 +13,15 @@ * limitations under the License. */ @@ -7450,10 +32632,10 @@ index e82261497..9a4f46095 100644 static struct smap_node *smap_add__(struct smap *, char *, void *, size_t hash); -diff --git a/lib/socket-util-unix.c b/lib/socket-util-unix.c -index 59f63fcce..ae41b05c7 100644 ---- a/lib/socket-util-unix.c -+++ b/lib/socket-util-unix.c +Index: openvswitch-2.17.2/lib/socket-util-unix.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/socket-util-unix.c ++++ openvswitch-2.17.2/lib/socket-util-unix.c @@ -15,7 +15,7 @@ */ @@ -7476,10 +32658,10 @@ index 59f63fcce..ae41b05c7 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(socket_util_unix); -diff --git a/lib/socket-util.c b/lib/socket-util.c -index 4f1ffecf5..872f6c396 100644 ---- a/lib/socket-util.c -+++ b/lib/socket-util.c +Index: openvswitch-2.17.2/lib/socket-util.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/socket-util.c ++++ openvswitch-2.17.2/lib/socket-util.c @@ -15,7 +15,7 @@ */ @@ -7510,10 +32692,10 @@ index 4f1ffecf5..872f6c396 100644 #include "netlink-socket.h" #endif #include "dns-resolve.h" -diff --git a/lib/sort.c b/lib/sort.c -index ed40637e2..7a07ffa94 100644 ---- a/lib/sort.c -+++ b/lib/sort.c +Index: openvswitch-2.17.2/lib/sort.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/sort.c ++++ openvswitch-2.17.2/lib/sort.c @@ -15,9 +15,9 @@ #include @@ -7526,10 +32708,10 @@ index ed40637e2..7a07ffa94 100644 static size_t partition(size_t p, size_t r, -diff --git a/lib/sset.c b/lib/sset.c -index b2e3f43ec..60c0a3384 100644 ---- a/lib/sset.c -+++ b/lib/sset.c +Index: openvswitch-2.17.2/lib/sset.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/sset.c ++++ openvswitch-2.17.2/lib/sset.c @@ -16,10 +16,10 @@ #include @@ -7543,10 +32725,10 @@ index b2e3f43ec..60c0a3384 100644 static uint32_t hash_name__(const char *name, size_t length) -diff --git a/lib/stopwatch.c b/lib/stopwatch.c -index 1c71df1a1..3223ae6a4 100644 ---- a/lib/stopwatch.c -+++ b/lib/stopwatch.c +Index: openvswitch-2.17.2/lib/stopwatch.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stopwatch.c ++++ openvswitch-2.17.2/lib/stopwatch.c @@ -15,17 +15,17 @@ #include @@ -7571,10 +32753,10 @@ index 1c71df1a1..3223ae6a4 100644 #include "guarded-list.h" VLOG_DEFINE_THIS_MODULE(stopwatch); -diff --git a/lib/stp.c b/lib/stp.c -index a869b5f39..8c76bca26 100644 ---- a/lib/stp.c -+++ b/lib/stp.c +Index: openvswitch-2.17.2/lib/stp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stp.c ++++ openvswitch-2.17.2/lib/stp.c @@ -25,15 +25,15 @@ #include #include @@ -7598,10 +32780,10 @@ index a869b5f39..8c76bca26 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(stp); -diff --git a/lib/stp.h b/lib/stp.h -index a0a127978..b4062b077 100644 ---- a/lib/stp.h -+++ b/lib/stp.h +Index: openvswitch-2.17.2/lib/stp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stp.h ++++ openvswitch-2.17.2/lib/stp.h @@ -23,7 +23,7 @@ #include #include @@ -7611,10 +32793,10 @@ index a0a127978..b4062b077 100644 struct dp_packet; -diff --git a/lib/stream-fd.c b/lib/stream-fd.c -index 46ee7ae27..ccf180c82 100644 ---- a/lib/stream-fd.c -+++ b/lib/stream-fd.c +Index: openvswitch-2.17.2/lib/stream-fd.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-fd.c ++++ openvswitch-2.17.2/lib/stream-fd.c @@ -23,12 +23,12 @@ #include #include @@ -7632,10 +32814,10 @@ index 46ee7ae27..ccf180c82 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(stream_fd); -diff --git a/lib/stream-nossl.c b/lib/stream-nossl.c -index 6ea622b7c..153575ea9 100644 ---- a/lib/stream-nossl.c -+++ b/lib/stream-nossl.c +Index: openvswitch-2.17.2/lib/stream-nossl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-nossl.c ++++ openvswitch-2.17.2/lib/stream-nossl.c @@ -15,7 +15,7 @@ */ @@ -7645,10 +32827,10 @@ index 6ea622b7c..153575ea9 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(stream_nossl); -diff --git a/lib/stream-provider.h b/lib/stream-provider.h -index 44e3c6431..f97c143f3 100644 ---- a/lib/stream-provider.h -+++ b/lib/stream-provider.h +Index: openvswitch-2.17.2/lib/stream-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-provider.h ++++ openvswitch-2.17.2/lib/stream-provider.h @@ -19,7 +19,7 @@ #include @@ -7658,10 +32840,10 @@ index 44e3c6431..f97c143f3 100644 /* Active stream connection. */ -diff --git a/lib/stream-replay.c b/lib/stream-replay.c -index 21da5220e..c2fee2669 100644 ---- a/lib/stream-replay.c -+++ b/lib/stream-replay.c +Index: openvswitch-2.17.2/lib/stream-replay.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-replay.c ++++ openvswitch-2.17.2/lib/stream-replay.c @@ -23,11 +23,11 @@ #include #include @@ -7677,10 +32859,10 @@ index 21da5220e..c2fee2669 100644 #include "openvswitch/poll-loop.h" #include "openvswitch/vlog.h" -diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c -index f4fe3432e..9f1f0d95f 100644 ---- a/lib/stream-ssl.c -+++ b/lib/stream-ssl.c +Index: openvswitch-2.17.2/lib/stream-ssl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-ssl.c ++++ openvswitch-2.17.2/lib/stream-ssl.c @@ -15,8 +15,8 @@ */ @@ -7718,10 +32900,10 @@ index f4fe3432e..9f1f0d95f 100644 #include "openvswitch/vlog.h" #ifdef _WIN32 -diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c -index e8dc2bfaa..8e517c03c 100644 ---- a/lib/stream-tcp.c -+++ b/lib/stream-tcp.c +Index: openvswitch-2.17.2/lib/stream-tcp.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-tcp.c ++++ openvswitch-2.17.2/lib/stream-tcp.c @@ -15,7 +15,7 @@ */ @@ -7744,10 +32926,10 @@ index e8dc2bfaa..8e517c03c 100644 #include "stream-provider.h" #include "stream-fd.h" #include "openvswitch/vlog.h" -diff --git a/lib/stream-unix.c b/lib/stream-unix.c -index d265efb83..e0c8ced2b 100644 ---- a/lib/stream-unix.c -+++ b/lib/stream-unix.c +Index: openvswitch-2.17.2/lib/stream-unix.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-unix.c ++++ openvswitch-2.17.2/lib/stream-unix.c @@ -15,7 +15,7 @@ */ @@ -7775,10 +32957,10 @@ index d265efb83..e0c8ced2b 100644 #include "stream-provider.h" #include "stream-fd.h" #include "openvswitch/vlog.h" -diff --git a/lib/stream-windows.c b/lib/stream-windows.c -index 5c4c55e5d..0998d64b8 100644 ---- a/lib/stream-windows.c -+++ b/lib/stream-windows.c +Index: openvswitch-2.17.2/lib/stream-windows.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-windows.c ++++ openvswitch-2.17.2/lib/stream-windows.c @@ -21,9 +21,9 @@ #include #include @@ -7792,10 +32974,10 @@ index 5c4c55e5d..0998d64b8 100644 #include "stream-provider.h" #include "openvswitch/vlog.h" -diff --git a/lib/stream.c b/lib/stream.c -index fcaddf10a..a1ca2aa6f 100644 ---- a/lib/stream.c -+++ b/lib/stream.c +Index: openvswitch-2.17.2/lib/stream.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream.c ++++ openvswitch-2.17.2/lib/stream.c @@ -23,10 +23,10 @@ #include #include @@ -7829,10 +33011,10 @@ index fcaddf10a..a1ca2aa6f 100644 VLOG_DEFINE_THIS_MODULE(stream); -diff --git a/lib/string.c b/lib/string.c -index e7e265bdf..1eb2705e6 100644 ---- a/lib/string.c -+++ b/lib/string.c +Index: openvswitch-2.17.2/lib/string.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/string.c ++++ openvswitch-2.17.2/lib/string.c @@ -18,7 +18,7 @@ #include #include @@ -7842,10 +33024,10 @@ index e7e265bdf..1eb2705e6 100644 #ifndef HAVE_STRNLEN size_t -diff --git a/lib/strsep.c b/lib/strsep.c -index 3ec7a2626..cd63d32e6 100644 ---- a/lib/strsep.c -+++ b/lib/strsep.c +Index: openvswitch-2.17.2/lib/strsep.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/strsep.c ++++ openvswitch-2.17.2/lib/strsep.c @@ -28,7 +28,7 @@ */ @@ -7855,10 +33037,10 @@ index 3ec7a2626..cd63d32e6 100644 /* * Get next token from string *stringp, where tokens are possibly-empty -diff --git a/lib/svec.c b/lib/svec.c -index 6ea96384b..afbc1e3a3 100644 ---- a/lib/svec.c -+++ b/lib/svec.c +Index: openvswitch-2.17.2/lib/svec.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/svec.c ++++ openvswitch-2.17.2/lib/svec.c @@ -15,13 +15,13 @@ */ @@ -7876,10 +33058,10 @@ index 6ea96384b..afbc1e3a3 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(svec); -diff --git a/lib/syslog-direct.c b/lib/syslog-direct.c -index fd23a050e..9b437d0c7 100644 ---- a/lib/syslog-direct.c -+++ b/lib/syslog-direct.c +Index: openvswitch-2.17.2/lib/syslog-direct.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-direct.c ++++ openvswitch-2.17.2/lib/syslog-direct.c @@ -22,9 +22,9 @@ #include "openvswitch/compiler.h" @@ -7892,10 +33074,10 @@ index fd23a050e..9b437d0c7 100644 #define FACILITY_MASK 0x03f8 -diff --git a/lib/syslog-libc.c b/lib/syslog-libc.c -index f3f3e24c0..20f92b6f8 100644 ---- a/lib/syslog-libc.c -+++ b/lib/syslog-libc.c +Index: openvswitch-2.17.2/lib/syslog-libc.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-libc.c ++++ openvswitch-2.17.2/lib/syslog-libc.c @@ -23,9 +23,9 @@ #include "openvswitch/compiler.h" @@ -7908,10 +33090,10 @@ index f3f3e24c0..20f92b6f8 100644 static void syslog_libc_open(struct syslogger *this, int facility); -diff --git a/lib/syslog-null.c b/lib/syslog-null.c -index 294795f71..fcf3c8f4e 100644 ---- a/lib/syslog-null.c -+++ b/lib/syslog-null.c +Index: openvswitch-2.17.2/lib/syslog-null.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/syslog-null.c ++++ openvswitch-2.17.2/lib/syslog-null.c @@ -19,7 +19,7 @@ #include "openvswitch/compiler.h" @@ -7921,10 +33103,10 @@ index 294795f71..fcf3c8f4e 100644 static void syslog_null_open(struct syslogger *this, int facility); static void syslog_null_log(struct syslogger *this, int pri, const char *msg); -diff --git a/lib/table.c b/lib/table.c -index 48d18b651..877600045 100644 ---- a/lib/table.c -+++ b/lib/table.c +Index: openvswitch-2.17.2/lib/table.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/table.c ++++ openvswitch-2.17.2/lib/table.c @@ -16,14 +16,14 @@ #include @@ -7945,10 +33127,10 @@ index 48d18b651..877600045 100644 struct column { char *heading; -diff --git a/lib/tc.c b/lib/tc.c -index adb2d3182..d4038293a 100644 ---- a/lib/tc.c -+++ b/lib/tc.c +Index: openvswitch-2.17.2/lib/tc.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/tc.c ++++ openvswitch-2.17.2/lib/tc.c @@ -35,15 +35,15 @@ #include #include @@ -7970,10 +33152,10 @@ index adb2d3182..d4038293a 100644 #define MAX_PEDIT_OFFSETS 32 -diff --git a/lib/timer.c b/lib/timer.c -index 815ec3599..317008be9 100644 ---- a/lib/timer.c -+++ b/lib/timer.c +Index: openvswitch-2.17.2/lib/timer.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/timer.c ++++ openvswitch-2.17.2/lib/timer.c @@ -16,10 +16,10 @@ #include @@ -7987,10 +33169,10 @@ index 815ec3599..317008be9 100644 /* Returns the number of milliseconds until 'timer' expires. */ long long int -diff --git a/lib/timeval.c b/lib/timeval.c -index 193c7bab1..087e82f5e 100644 ---- a/lib/timeval.c -+++ b/lib/timeval.c +Index: openvswitch-2.17.2/lib/timeval.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/timeval.c ++++ openvswitch-2.17.2/lib/timeval.c @@ -15,7 +15,7 @@ */ @@ -8027,10 +33209,10 @@ index 193c7bab1..087e82f5e 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(timeval); -diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c -index bdff1debc..f3df19ba4 100644 ---- a/lib/tnl-neigh-cache.c -+++ b/lib/tnl-neigh-cache.c +Index: openvswitch-2.17.2/lib/tnl-neigh-cache.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/tnl-neigh-cache.c ++++ openvswitch-2.17.2/lib/tnl-neigh-cache.c @@ -24,24 +24,24 @@ #include #include @@ -8070,10 +33252,10 @@ index bdff1debc..f3df19ba4 100644 #include "openvswitch/vlog.h" -diff --git a/lib/tnl-neigh-cache.h b/lib/tnl-neigh-cache.h -index 877bca312..94d8e489c 100644 ---- a/lib/tnl-neigh-cache.h -+++ b/lib/tnl-neigh-cache.h +Index: openvswitch-2.17.2/lib/tnl-neigh-cache.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/tnl-neigh-cache.h ++++ openvswitch-2.17.2/lib/tnl-neigh-cache.h @@ -26,10 +26,10 @@ #include #include @@ -8089,10 +33271,10 @@ index 877bca312..94d8e489c 100644 int tnl_neigh_snoop(const struct flow *flow, struct flow_wildcards *wc, const char dev_name[IFNAMSIZ], bool allow_update); -diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c -index 58269d3b1..a017e069d 100644 ---- a/lib/tnl-ports.c -+++ b/lib/tnl-ports.c +Index: openvswitch-2.17.2/lib/tnl-ports.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/tnl-ports.c ++++ openvswitch-2.17.2/lib/tnl-ports.c @@ -22,16 +22,16 @@ #include #include @@ -8116,10 +33298,10 @@ index 58269d3b1..a017e069d 100644 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; static struct classifier cls; /* Tunnel ports. */ -diff --git a/lib/tnl-ports.h b/lib/tnl-ports.h -index 61ca0f8e2..21fb28a40 100644 ---- a/lib/tnl-ports.h -+++ b/lib/tnl-ports.h +Index: openvswitch-2.17.2/lib/tnl-ports.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/tnl-ports.h ++++ openvswitch-2.17.2/lib/tnl-ports.h @@ -20,9 +20,9 @@ #include #include @@ -8133,10 +33315,10 @@ index 61ca0f8e2..21fb28a40 100644 odp_port_t tnl_port_map_lookup(struct flow *flow, struct flow_wildcards *wc); -diff --git a/lib/token-bucket.c b/lib/token-bucket.c -index 0badeb46b..c619bfbb0 100644 ---- a/lib/token-bucket.c -+++ b/lib/token-bucket.c +Index: openvswitch-2.17.2/lib/token-bucket.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/token-bucket.c ++++ openvswitch-2.17.2/lib/token-bucket.c @@ -20,8 +20,8 @@ #include "openvswitch/poll-loop.h" @@ -8148,10 +33330,10 @@ index 0badeb46b..c619bfbb0 100644 /* Initializes 'tb' to accumulate 'rate' tokens per millisecond, with a * maximum of 'burst' tokens. -diff --git a/lib/tun-metadata.c b/lib/tun-metadata.c -index 168634a74..25795cbf2 100644 ---- a/lib/tun-metadata.c -+++ b/lib/tun-metadata.c +Index: openvswitch-2.17.2/lib/tun-metadata.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/tun-metadata.c ++++ openvswitch-2.17.2/lib/tun-metadata.c @@ -18,17 +18,17 @@ #include #include @@ -8176,10 +33358,10 @@ index 168634a74..25795cbf2 100644 struct tun_meta_entry { struct hmap_node node; /* In struct tun_table's key_hmap. */ -diff --git a/lib/unicode.c b/lib/unicode.c -index 846896da0..7040b3bd6 100644 ---- a/lib/unicode.c -+++ b/lib/unicode.c +Index: openvswitch-2.17.2/lib/unicode.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/unicode.c ++++ openvswitch-2.17.2/lib/unicode.c @@ -21,7 +21,7 @@ #include @@ -8189,10 +33371,10 @@ index 846896da0..7040b3bd6 100644 /* Returns the unicode code point corresponding to leading surrogate 'leading' * and trailing surrogate 'trailing'. The return value will not make any -diff --git a/lib/unixctl.c b/lib/unixctl.c -index 69aed6722..ad63a71bd 100644 ---- a/lib/unixctl.c -+++ b/lib/unixctl.c +Index: openvswitch-2.17.2/lib/unixctl.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/unixctl.c ++++ openvswitch-2.17.2/lib/unixctl.c @@ -15,20 +15,20 @@ */ @@ -8220,10 +33402,10 @@ index 69aed6722..ad63a71bd 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(unixctl); -diff --git a/lib/userspace-tso.c b/lib/userspace-tso.c -index f843c2a76..19e65b190 100644 ---- a/lib/userspace-tso.c -+++ b/lib/userspace-tso.c +Index: openvswitch-2.17.2/lib/userspace-tso.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/userspace-tso.c ++++ openvswitch-2.17.2/lib/userspace-tso.c @@ -16,8 +16,8 @@ #include @@ -8235,10 +33417,10 @@ index f843c2a76..19e65b190 100644 #include "openvswitch/vlog.h" #include "dpdk.h" #include "userspace-tso.h" -diff --git a/lib/util.c b/lib/util.c -index eb2341422..7ea2e0cba 100644 ---- a/lib/util.c -+++ b/lib/util.c +Index: openvswitch-2.17.2/lib/util.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/util.c ++++ openvswitch-2.17.2/lib/util.c @@ -15,7 +15,7 @@ */ @@ -8269,10 +33451,10 @@ index eb2341422..7ea2e0cba 100644 #include "openvswitch/vlog.h" #ifdef HAVE_PTHREAD_SET_NAME_NP #include -diff --git a/lib/util.h b/lib/util.h -index 964fb4f20..4f40319c4 100644 ---- a/lib/util.h -+++ b/lib/util.h +Index: openvswitch-2.17.2/lib/util.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/util.h ++++ openvswitch-2.17.2/lib/util.h @@ -27,7 +27,6 @@ #include #include @@ -8281,10 +33463,10 @@ index 964fb4f20..4f40319c4 100644 #include "openvswitch/util.h" #if defined(__aarch64__) && __GNUC__ >= 6 #include -diff --git a/lib/uuid.c b/lib/uuid.c -index 8a16606da..0c42179bf 100644 ---- a/lib/uuid.c -+++ b/lib/uuid.c +Index: openvswitch-2.17.2/lib/uuid.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/uuid.c ++++ openvswitch-2.17.2/lib/uuid.c @@ -15,7 +15,7 @@ #include @@ -8312,10 +33494,10 @@ index 8a16606da..0c42179bf 100644 VLOG_DEFINE_THIS_MODULE(uuid); -diff --git a/lib/vconn-provider.h b/lib/vconn-provider.h -index 523f26f39..f81949e0e 100644 ---- a/lib/vconn-provider.h -+++ b/lib/vconn-provider.h +Index: openvswitch-2.17.2/lib/vconn-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/vconn-provider.h ++++ openvswitch-2.17.2/lib/vconn-provider.h @@ -21,7 +21,7 @@ * OpenFlow device. */ @@ -8325,10 +33507,10 @@ index 523f26f39..f81949e0e 100644 #include "openflow/openflow-common.h" /* Active virtual connection to an OpenFlow device. */ -diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c -index 0794ecc05..b8480a2dc 100644 ---- a/lib/vconn-stream.c -+++ b/lib/vconn-stream.c +Index: openvswitch-2.17.2/lib/vconn-stream.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/vconn-stream.c ++++ openvswitch-2.17.2/lib/vconn-stream.c @@ -21,13 +21,13 @@ #include #include @@ -8347,10 +33529,10 @@ index 0794ecc05..b8480a2dc 100644 #include "vconn-provider.h" #include "openvswitch/vconn.h" #include "openvswitch/vlog.h" -diff --git a/lib/vconn.c b/lib/vconn.c -index 7415e6291..aa964ffdb 100644 ---- a/lib/vconn.c -+++ b/lib/vconn.c +Index: openvswitch-2.17.2/lib/vconn.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/vconn.c ++++ openvswitch-2.17.2/lib/vconn.c @@ -23,9 +23,9 @@ #include #include @@ -8380,10 +33562,10 @@ index 7415e6291..aa964ffdb 100644 VLOG_DEFINE_THIS_MODULE(vconn); -diff --git a/lib/vl-mff-map.h b/lib/vl-mff-map.h -index 136492cb1..a36fca66f 100644 ---- a/lib/vl-mff-map.h -+++ b/lib/vl-mff-map.h +Index: openvswitch-2.17.2/lib/vl-mff-map.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/vl-mff-map.h ++++ openvswitch-2.17.2/lib/vl-mff-map.h @@ -17,7 +17,7 @@ #ifndef VL_MFF_MAP_H #define VL_MFF_MAP_H 1 @@ -8393,10 +33575,10 @@ index 136492cb1..a36fca66f 100644 #include "openvswitch/thread.h" /* Variable length mf_fields mapping map. This is a single writer, -diff --git a/lib/vlan-bitmap.h b/lib/vlan-bitmap.h -index 3e2e82062..e3a751c59 100644 ---- a/lib/vlan-bitmap.h -+++ b/lib/vlan-bitmap.h +Index: openvswitch-2.17.2/lib/vlan-bitmap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/vlan-bitmap.h ++++ openvswitch-2.17.2/lib/vlan-bitmap.h @@ -18,7 +18,7 @@ #include @@ -8406,10 +33588,10 @@ index 3e2e82062..e3a751c59 100644 /* A "VLAN bitmap" is a 4096-bit bitmap that represents a set. A 1-bit * indicates that the respective VLAN is a member of the set, a 0-bit indicates -diff --git a/lib/vlog.c b/lib/vlog.c -index 533f93755..3a122bcc1 100644 ---- a/lib/vlog.c -+++ b/lib/vlog.c +Index: openvswitch-2.17.2/lib/vlog.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/vlog.c ++++ openvswitch-2.17.2/lib/vlog.c @@ -29,21 +29,21 @@ #include #include @@ -8440,10 +33622,10 @@ index 533f93755..3a122bcc1 100644 VLOG_DEFINE_THIS_MODULE(vlog); -diff --git a/lib/wmi.c b/lib/wmi.c -index 44c1d75e9..7ef6d006f 100644 ---- a/lib/wmi.c -+++ b/lib/wmi.c +Index: openvswitch-2.17.2/lib/wmi.c +=================================================================== +--- openvswitch-2.17.2.orig/lib/wmi.c ++++ openvswitch-2.17.2/lib/wmi.c @@ -20,7 +20,7 @@ #include #include @@ -8453,10 +33635,10 @@ index 44c1d75e9..7ef6d006f 100644 VLOG_DEFINE_THIS_MODULE(wmi); -diff --git a/ofproto/bond.c b/ofproto/bond.c -index cdfdf0b9d..810215edd 100644 ---- a/ofproto/bond.c -+++ b/ofproto/bond.c +Index: openvswitch-2.17.2/ofproto/bond.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/bond.c ++++ openvswitch-2.17.2/ofproto/bond.c @@ -24,12 +24,12 @@ #include @@ -8493,10 +33675,10 @@ index cdfdf0b9d..810215edd 100644 VLOG_DEFINE_THIS_MODULE(bond); -diff --git a/ofproto/bond.h b/ofproto/bond.h -index 1683ec878..f195e551d 100644 ---- a/ofproto/bond.h -+++ b/ofproto/bond.h +Index: openvswitch-2.17.2/ofproto/bond.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/bond.h ++++ openvswitch-2.17.2/ofproto/bond.h @@ -20,7 +20,7 @@ #include #include @@ -8506,10 +33688,10 @@ index 1683ec878..f195e551d 100644 struct flow; struct netdev; -diff --git a/ofproto/bundles.c b/ofproto/bundles.c -index 405ec8cc1..7012075e9 100644 ---- a/ofproto/bundles.c -+++ b/ofproto/bundles.c +Index: openvswitch-2.17.2/ofproto/bundles.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/bundles.c ++++ openvswitch-2.17.2/ofproto/bundles.c @@ -19,7 +19,7 @@ #include @@ -8532,10 +33714,10 @@ index 405ec8cc1..7012075e9 100644 VLOG_DEFINE_THIS_MODULE(bundles); -diff --git a/ofproto/bundles.h b/ofproto/bundles.h -index 1164fddd8..b381b9194 100644 ---- a/ofproto/bundles.h -+++ b/ofproto/bundles.h +Index: openvswitch-2.17.2/ofproto/bundles.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/bundles.h ++++ openvswitch-2.17.2/ofproto/bundles.h @@ -24,7 +24,7 @@ #include "connmgr.h" #include "ofproto-provider.h" @@ -8545,10 +33727,10 @@ index 1164fddd8..b381b9194 100644 #ifdef __cplusplus extern "C" { -diff --git a/ofproto/collectors.c b/ofproto/collectors.c -index bb6ae021f..1ae246df0 100644 ---- a/ofproto/collectors.c -+++ b/ofproto/collectors.c +Index: openvswitch-2.17.2/ofproto/collectors.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/collectors.c ++++ openvswitch-2.17.2/ofproto/collectors.c @@ -23,9 +23,9 @@ #include #include @@ -8562,10 +33744,10 @@ index bb6ae021f..1ae246df0 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(collectors); -diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c -index fa8f6cd0e..10ed18492 100644 ---- a/ofproto/connmgr.c -+++ b/ofproto/connmgr.c +Index: openvswitch-2.17.2/ofproto/connmgr.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/connmgr.c ++++ openvswitch-2.17.2/ofproto/connmgr.c @@ -20,7 +20,7 @@ #include "bundles.h" @@ -8597,10 +33779,10 @@ index fa8f6cd0e..10ed18492 100644 VLOG_DEFINE_THIS_MODULE(connmgr); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h -index e299386c7..d44a9fc87 100644 ---- a/ofproto/connmgr.h -+++ b/ofproto/connmgr.h +Index: openvswitch-2.17.2/ofproto/connmgr.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/connmgr.h ++++ openvswitch-2.17.2/ofproto/connmgr.h @@ -17,7 +17,7 @@ #ifndef CONNMGR_H #define CONNMGR_H 1 @@ -8610,10 +33792,10 @@ index e299386c7..d44a9fc87 100644 #include "openvswitch/hmap.h" #include "openvswitch/list.h" #include "openvswitch/match.h" -diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c -index 34b398eca..850ffa066 100644 ---- a/ofproto/fail-open.c -+++ b/ofproto/fail-open.c +Index: openvswitch-2.17.2/ofproto/fail-open.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/fail-open.c ++++ openvswitch-2.17.2/ofproto/fail-open.c @@ -17,11 +17,11 @@ #include #include @@ -8638,10 +33820,10 @@ index 34b398eca..850ffa066 100644 VLOG_DEFINE_THIS_MODULE(fail_open); -diff --git a/ofproto/in-band.c b/ofproto/in-band.c -index 82d8dfa14..b804d124e 100644 ---- a/ofproto/in-band.c -+++ b/ofproto/in-band.c +Index: openvswitch-2.17.2/ofproto/in-band.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/in-band.c ++++ openvswitch-2.17.2/ofproto/in-band.c @@ -24,12 +24,12 @@ #include #include @@ -8672,10 +33854,10 @@ index 82d8dfa14..b804d124e 100644 VLOG_DEFINE_THIS_MODULE(in_band); -diff --git a/ofproto/in-band.h b/ofproto/in-band.h -index 3debd0128..4bb5e191f 100644 ---- a/ofproto/in-band.h -+++ b/ofproto/in-band.h +Index: openvswitch-2.17.2/ofproto/in-band.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/in-band.h ++++ openvswitch-2.17.2/ofproto/in-band.h @@ -22,7 +22,7 @@ #include #include @@ -8685,10 +33867,10 @@ index 3debd0128..4bb5e191f 100644 struct flow; struct in_band; -diff --git a/ofproto/netflow.c b/ofproto/netflow.c -index ed58de17d..fa29aa820 100644 ---- a/ofproto/netflow.c -+++ b/ofproto/netflow.c +Index: openvswitch-2.17.2/ofproto/netflow.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/netflow.c ++++ openvswitch-2.17.2/ofproto/netflow.c @@ -22,19 +22,19 @@ #include #include @@ -8715,10 +33897,10 @@ index ed58de17d..fa29aa820 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(netflow); -diff --git a/ofproto/netflow.h b/ofproto/netflow.h -index 688a35d5c..37af68eb4 100644 ---- a/ofproto/netflow.h -+++ b/ofproto/netflow.h +Index: openvswitch-2.17.2/ofproto/netflow.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/netflow.h ++++ openvswitch-2.17.2/ofproto/netflow.h @@ -18,8 +18,8 @@ #define OFPROTO_NETFLOW_H 1 @@ -8730,10 +33912,10 @@ index 688a35d5c..37af68eb4 100644 /* Default active timeout interval, in seconds. * -diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c -index 9280e008e..939a55454 100644 ---- a/ofproto/ofproto-dpif-ipfix.c -+++ b/ofproto/ofproto-dpif-ipfix.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-ipfix.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-ipfix.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-ipfix.c @@ -17,23 +17,23 @@ #include #include "ofproto-dpif-ipfix.h" @@ -8767,10 +33949,10 @@ index 9280e008e..939a55454 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ipfix); -diff --git a/ofproto/ofproto-dpif-mirror.c b/ofproto/ofproto-dpif-mirror.c -index 343b75f0e..2fd7b1cad 100644 ---- a/ofproto/ofproto-dpif-mirror.c -+++ b/ofproto/ofproto-dpif-mirror.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-mirror.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-mirror.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-mirror.c @@ -18,8 +18,8 @@ #include @@ -8782,10 +33964,10 @@ index 343b75f0e..2fd7b1cad 100644 #include "ofproto.h" #include "vlan-bitmap.h" #include "openvswitch/vlog.h" -diff --git a/ofproto/ofproto-dpif-mirror.h b/ofproto/ofproto-dpif-mirror.h -index eed63ec4a..3006c195d 100644 ---- a/ofproto/ofproto-dpif-mirror.h -+++ b/ofproto/ofproto-dpif-mirror.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-mirror.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-mirror.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-mirror.h @@ -17,7 +17,7 @@ #include @@ -8795,10 +33977,10 @@ index eed63ec4a..3006c195d 100644 #define MAX_MIRRORS 32 typedef uint32_t mirror_mask_t; -diff --git a/ofproto/ofproto-dpif-monitor.c b/ofproto/ofproto-dpif-monitor.c -index bb0e49091..636f30b09 100644 ---- a/ofproto/ofproto-dpif-monitor.c -+++ b/ofproto/ofproto-dpif-monitor.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-monitor.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-monitor.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-monitor.c @@ -21,20 +21,20 @@ #include "bfd.h" @@ -8827,10 +34009,10 @@ index bb0e49091..636f30b09 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ofproto_dpif_monitor); -diff --git a/ofproto/ofproto-dpif-monitor.h b/ofproto/ofproto-dpif-monitor.h -index 7d6d0da87..761b40f64 100644 ---- a/ofproto/ofproto-dpif-monitor.h -+++ b/ofproto/ofproto-dpif-monitor.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-monitor.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-monitor.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-monitor.h @@ -18,7 +18,7 @@ #include @@ -8840,10 +34022,10 @@ index 7d6d0da87..761b40f64 100644 struct bfd; struct cfm; -diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h -index 4df630c62..db157e7d0 100644 ---- a/ofproto/ofproto-dpif-rid.h -+++ b/ofproto/ofproto-dpif-rid.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-rid.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-rid.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-rid.h @@ -20,13 +20,13 @@ #include #include @@ -8861,10 +34043,10 @@ index 4df630c62..db157e7d0 100644 struct ofproto_dpif; struct rule; -diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c -index 772881b0d..cb0aec052 100644 ---- a/ofproto/ofproto-dpif-sflow.c -+++ b/ofproto/ofproto-dpif-sflow.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-sflow.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.c @@ -25,22 +25,22 @@ #include "collectors.h" #include "openvswitch/compiler.h" @@ -8895,10 +34077,10 @@ index 772881b0d..cb0aec052 100644 #include "ofproto-provider.h" #include "lacp.h" -diff --git a/ofproto/ofproto-dpif-sflow.h b/ofproto/ofproto-dpif-sflow.h -index c5d9b8aad..4fe986967 100644 ---- a/ofproto/ofproto-dpif-sflow.h -+++ b/ofproto/ofproto-dpif-sflow.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-sflow.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-sflow.h @@ -19,7 +19,7 @@ #define OFPROTO_DPIF_SFLOW_H 1 @@ -8908,10 +34090,10 @@ index c5d9b8aad..4fe986967 100644 #include "lib/odp-util.h" struct dpif; -diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c -index 78a54c715..fed6cf928 100644 ---- a/ofproto/ofproto-dpif-trace.c -+++ b/ofproto/ofproto-dpif-trace.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-trace.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-trace.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-trace.c @@ -21,7 +21,7 @@ #include "conntrack.h" #include "dpif.h" @@ -8921,10 +34103,10 @@ index 78a54c715..fed6cf928 100644 static void oftrace_node_destroy(struct oftrace_node *); -diff --git a/ofproto/ofproto-dpif-trace.h b/ofproto/ofproto-dpif-trace.h -index 4b04f1756..280eabb82 100644 ---- a/ofproto/ofproto-dpif-trace.h -+++ b/ofproto/ofproto-dpif-trace.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-trace.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-trace.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-trace.h @@ -32,7 +32,7 @@ #include "ofproto/ofproto-dpif.h" #include "openvswitch/compiler.h" @@ -8934,10 +34116,10 @@ index 4b04f1756..280eabb82 100644 /* Type of a node within a trace. */ enum oftrace_node_type { -diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index 57f94df54..e1cf5fbb5 100644 ---- a/ofproto/ofproto-dpif-upcall.c -+++ b/ofproto/ofproto-dpif-upcall.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-upcall.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-upcall.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-upcall.c @@ -20,28 +20,28 @@ #include @@ -8975,10 +34157,10 @@ index 57f94df54..e1cf5fbb5 100644 #include "openvswitch/vlog.h" #include "lib/netdev-provider.h" -diff --git a/ofproto/ofproto-dpif-xlate-cache.c b/ofproto/ofproto-dpif-xlate-cache.c -index dcc91cb38..6c6c15381 100644 ---- a/ofproto/ofproto-dpif-xlate-cache.c -+++ b/ofproto/ofproto-dpif-xlate-cache.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-xlate-cache.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-xlate-cache.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-xlate-cache.c @@ -24,13 +24,13 @@ #include @@ -9010,10 +34192,10 @@ index dcc91cb38..6c6c15381 100644 VLOG_DEFINE_THIS_MODULE(ofproto_xlate_cache); -diff --git a/ofproto/ofproto-dpif-xlate-cache.h b/ofproto/ofproto-dpif-xlate-cache.h -index 114aff8ea..279d31560 100644 ---- a/ofproto/ofproto-dpif-xlate-cache.h -+++ b/ofproto/ofproto-dpif-xlate-cache.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-xlate-cache.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-xlate-cache.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-xlate-cache.h @@ -21,7 +21,7 @@ #include @@ -9023,10 +34205,10 @@ index 114aff8ea..279d31560 100644 #include "odp-util.h" #include "ofproto/ofproto-dpif-mirror.h" #include "openvswitch/ofpbuf.h" -diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 578cbfe58..cf0a5e760 100644 ---- a/ofproto/ofproto-dpif-xlate.c -+++ b/ofproto/ofproto-dpif-xlate.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-xlate.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-xlate.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-xlate.c @@ -24,25 +24,25 @@ #include @@ -9078,10 +34260,10 @@ index 578cbfe58..cf0a5e760 100644 COVERAGE_DEFINE(xlate_actions); COVERAGE_DEFINE(xlate_actions_oversize); -diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h -index 851088d79..6f294e6f2 100644 ---- a/ofproto/ofproto-dpif-xlate.h -+++ b/ofproto/ofproto-dpif-xlate.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif-xlate.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif-xlate.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif-xlate.h @@ -15,8 +15,8 @@ #ifndef OFPROTO_DPIF_XLATE_H #define OFPROTO_DPIF_XLATE_H 1 @@ -9102,10 +34284,10 @@ index 851088d79..6f294e6f2 100644 struct bfd; struct bond; -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index 8143dd965..28f77611d 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c +Index: openvswitch-2.17.2/ofproto/ofproto-dpif.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif.c ++++ openvswitch-2.17.2/ofproto/ofproto-dpif.c @@ -18,26 +18,26 @@ #include "bfd.h" @@ -9169,10 +34351,10 @@ index 8143dd965..28f77611d 100644 #include "vlan-bitmap.h" VLOG_DEFINE_THIS_MODULE(ofproto_dpif); -diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h -index d8e0cd37a..95deb27b7 100644 ---- a/ofproto/ofproto-dpif.h -+++ b/ofproto/ofproto-dpif.h +Index: openvswitch-2.17.2/ofproto/ofproto-dpif.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-dpif.h ++++ openvswitch-2.17.2/ofproto/ofproto-dpif.h @@ -48,12 +48,12 @@ #include "dpif.h" @@ -9190,10 +34372,10 @@ index d8e0cd37a..95deb27b7 100644 struct dpif_flow_stats; struct ofproto_async_msg; -diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index 14b909973..932baba6d 100644 ---- a/ofproto/ofproto-provider.h -+++ b/ofproto/ofproto-provider.h +Index: openvswitch-2.17.2/ofproto/ofproto-provider.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto-provider.h ++++ openvswitch-2.17.2/ofproto/ofproto-provider.h @@ -34,10 +34,10 @@ */ @@ -9229,10 +34411,10 @@ index 14b909973..932baba6d 100644 #include "vl-mff-map.h" struct match; -diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index 56aeac720..43b033733 100644 ---- a/ofproto/ofproto.c -+++ b/ofproto/ofproto.c +Index: openvswitch-2.17.2/ofproto/ofproto.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto.c ++++ openvswitch-2.17.2/ofproto/ofproto.c @@ -22,18 +22,18 @@ #include #include @@ -9294,10 +34476,10 @@ index 56aeac720..43b033733 100644 VLOG_DEFINE_THIS_MODULE(ofproto); -diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h -index b0262da2d..fe48aad85 100644 ---- a/ofproto/ofproto.h -+++ b/ofproto/ofproto.h +Index: openvswitch-2.17.2/ofproto/ofproto.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/ofproto.h ++++ openvswitch-2.17.2/ofproto/ofproto.h @@ -23,13 +23,13 @@ #include #include @@ -9316,10 +34498,10 @@ index b0262da2d..fe48aad85 100644 #include "stp.h" #include "lacp.h" -diff --git a/ofproto/pinsched.c b/ofproto/pinsched.c -index 59561f076..2409feafc 100644 ---- a/ofproto/pinsched.c -+++ b/ofproto/pinsched.c +Index: openvswitch-2.17.2/ofproto/pinsched.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/pinsched.c ++++ openvswitch-2.17.2/ofproto/pinsched.c @@ -21,16 +21,16 @@ #include #include @@ -9341,10 +34523,10 @@ index 59561f076..2409feafc 100644 #include "openvswitch/token-bucket.h" #include "openvswitch/vconn.h" -diff --git a/ofproto/pinsched.h b/ofproto/pinsched.h -index 96993df9a..f4c1a0b7a 100644 ---- a/ofproto/pinsched.h -+++ b/ofproto/pinsched.h +Index: openvswitch-2.17.2/ofproto/pinsched.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/pinsched.h ++++ openvswitch-2.17.2/ofproto/pinsched.h @@ -18,7 +18,7 @@ #define PINSCHED_H_H 1 @@ -9354,10 +34536,10 @@ index 96993df9a..f4c1a0b7a 100644 struct ovs_list; struct ofpbuf; -diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c -index 3455ed233..d0c55fd19 100644 ---- a/ofproto/tunnel.c -+++ b/ofproto/tunnel.c +Index: openvswitch-2.17.2/ofproto/tunnel.c +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/tunnel.c ++++ openvswitch-2.17.2/ofproto/tunnel.c @@ -15,27 +15,27 @@ #include #include @@ -9396,10 +34578,10 @@ index 3455ed233..d0c55fd19 100644 #include "ofproto-dpif.h" #include "netdev-vport.h" -diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h -index 323f3fa03..0c6af31b1 100644 ---- a/ofproto/tunnel.h -+++ b/ofproto/tunnel.h +Index: openvswitch-2.17.2/ofproto/tunnel.h +=================================================================== +--- openvswitch-2.17.2.orig/ofproto/tunnel.h ++++ openvswitch-2.17.2/ofproto/tunnel.h @@ -18,7 +18,7 @@ #include @@ -9409,10 +34591,10 @@ index 323f3fa03..0c6af31b1 100644 /* Tunnel port emulation layer. * -diff --git a/ovsdb/column.c b/ovsdb/column.c -index 9dfc8714f..494018998 100644 ---- a/ovsdb/column.c -+++ b/ovsdb/column.c +Index: openvswitch-2.17.2/ovsdb/column.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/column.c ++++ openvswitch-2.17.2/ovsdb/column.c @@ -22,10 +22,10 @@ #include "column.h" #include "openvswitch/dynamic-string.h" @@ -9427,10 +34609,10 @@ index 9dfc8714f..494018998 100644 struct ovsdb_column * ovsdb_column_create(const char *name, -diff --git a/ovsdb/column.h b/ovsdb/column.h -index 890295629..da6b827e8 100644 ---- a/ovsdb/column.h -+++ b/ovsdb/column.h +Index: openvswitch-2.17.2/ovsdb/column.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/column.h ++++ openvswitch-2.17.2/ovsdb/column.h @@ -18,7 +18,7 @@ #include @@ -9440,10 +34622,10 @@ index 890295629..da6b827e8 100644 struct ovsdb_table; struct ovsdb_table_schema; -diff --git a/ovsdb/condition.c b/ovsdb/condition.c -index 388dd54a1..d4aa3b981 100644 ---- a/ovsdb/condition.c -+++ b/ovsdb/condition.c +Index: openvswitch-2.17.2/ovsdb/condition.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/condition.c ++++ openvswitch-2.17.2/ovsdb/condition.c @@ -21,13 +21,13 @@ #include "column.h" @@ -9460,10 +34642,10 @@ index 388dd54a1..d4aa3b981 100644 static struct ovsdb_error * ovsdb_clause_from_json(const struct ovsdb_table_schema *ts, -diff --git a/ovsdb/condition.h b/ovsdb/condition.h -index 65728fb32..5212ddcb1 100644 ---- a/ovsdb/condition.h -+++ b/ovsdb/condition.h +Index: openvswitch-2.17.2/ovsdb/condition.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/condition.h ++++ openvswitch-2.17.2/ovsdb/condition.h @@ -18,9 +18,9 @@ #include @@ -9477,10 +34659,10 @@ index 65728fb32..5212ddcb1 100644 struct json; struct ovsdb_table_schema; -diff --git a/ovsdb/execution.c b/ovsdb/execution.c -index f9b8067d0..e34362c33 100644 ---- a/ovsdb/execution.c -+++ b/ovsdb/execution.c +Index: openvswitch-2.17.2/ovsdb/execution.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/execution.c ++++ openvswitch-2.17.2/ovsdb/execution.c @@ -24,15 +24,15 @@ #include "file.h" #include "openvswitch/json.h" @@ -9501,10 +34683,10 @@ index f9b8067d0..e34362c33 100644 #include "transaction.h" struct ovsdb_execution { -diff --git a/ovsdb/file.c b/ovsdb/file.c -index 9f44007d9..1689a9d4c 100644 ---- a/ovsdb/file.c -+++ b/ovsdb/file.c +Index: openvswitch-2.17.2/ovsdb/file.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/file.c ++++ openvswitch-2.17.2/ovsdb/file.c @@ -21,22 +21,22 @@ #include #include @@ -9535,10 +34717,10 @@ index 9f44007d9..1689a9d4c 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_file); -diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c -index 351c39d8a..25c7988c3 100644 ---- a/ovsdb/jsonrpc-server.c -+++ b/ovsdb/jsonrpc-server.c +Index: openvswitch-2.17.2/ovsdb/jsonrpc-server.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/jsonrpc-server.c ++++ openvswitch-2.17.2/ovsdb/jsonrpc-server.c @@ -19,28 +19,28 @@ #include @@ -9576,10 +34758,10 @@ index 351c39d8a..25c7988c3 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_jsonrpc_server); -diff --git a/ovsdb/log.c b/ovsdb/log.c -index 4a28fa3db..29bb1c9f2 100644 ---- a/ovsdb/log.c -+++ b/ovsdb/log.c +Index: openvswitch-2.17.2/ovsdb/log.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/log.c ++++ openvswitch-2.17.2/ovsdb/log.c @@ -28,17 +28,17 @@ #include "openvswitch/dynamic-string.h" #include "openvswitch/json.h" @@ -9605,10 +34787,10 @@ index 4a28fa3db..29bb1c9f2 100644 VLOG_DEFINE_THIS_MODULE(ovsdb_log); -diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c -index 0f222cc99..e5f8952e6 100644 ---- a/ovsdb/monitor.c -+++ b/ovsdb/monitor.c +Index: openvswitch-2.17.2/ovsdb/monitor.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/monitor.c ++++ openvswitch-2.17.2/ovsdb/monitor.c @@ -18,24 +18,24 @@ #include @@ -9642,10 +34824,10 @@ index 0f222cc99..e5f8952e6 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_monitor); -diff --git a/ovsdb/mutation.c b/ovsdb/mutation.c -index 03d1c3499..67a1bee0a 100644 ---- a/ovsdb/mutation.c -+++ b/ovsdb/mutation.c +Index: openvswitch-2.17.2/ovsdb/mutation.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/mutation.c ++++ openvswitch-2.17.2/ovsdb/mutation.c @@ -21,14 +21,14 @@ #include @@ -9663,10 +34845,10 @@ index 03d1c3499..67a1bee0a 100644 struct ovsdb_error * ovsdb_mutator_from_string(const char *name, enum ovsdb_mutator *mutator) -diff --git a/ovsdb/mutation.h b/ovsdb/mutation.h -index dfb2d6940..3e6424abc 100644 ---- a/ovsdb/mutation.h -+++ b/ovsdb/mutation.h +Index: openvswitch-2.17.2/ovsdb/mutation.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/mutation.h ++++ openvswitch-2.17.2/ovsdb/mutation.h @@ -18,7 +18,7 @@ #include @@ -9676,10 +34858,10 @@ index dfb2d6940..3e6424abc 100644 struct json; struct ovsdb_table_schema; -diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c -index db5eebc17..34e669395 100644 ---- a/ovsdb/ovsdb-client.c -+++ b/ovsdb/ovsdb-client.c +Index: openvswitch-2.17.2/ovsdb/ovsdb-client.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-client.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-client.c @@ -26,37 +26,37 @@ #include #include @@ -9733,10 +34915,10 @@ index db5eebc17..34e669395 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovsdb_client); -diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in -index 10a70ae26..0aee9dff2 100755 ---- a/ovsdb/ovsdb-idlc.in -+++ b/ovsdb/ovsdb-idlc.in +Index: openvswitch-2.17.2/ovsdb/ovsdb-idlc.in +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-idlc.in ++++ openvswitch-2.17.2/ovsdb/ovsdb-idlc.in @@ -193,10 +193,10 @@ def printCIDLHeader(schemaFile): #include #include @@ -9752,7 +34934,7 @@ index 10a70ae26..0aee9dff2 100755 #ifdef __cplusplus extern "C" { -@@ -469,10 +469,10 @@ def printCIDLSource(schemaFile): +@@ -484,10 +484,10 @@ def printCIDLSource(schemaFile): #include #include %(header)s #include @@ -9767,11 +34949,11 @@ index 10a70ae26..0aee9dff2 100755 %(cDecls)s -diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c -index 9fe90592e..0edcd10fd 100644 ---- a/ovsdb/ovsdb-server.c -+++ b/ovsdb/ovsdb-server.c -@@ -23,41 +23,41 @@ +Index: openvswitch-2.17.2/ovsdb/ovsdb-server.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-server.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-server.c +@@ -23,42 +23,42 @@ #include #include "column.h" @@ -9781,6 +34963,7 @@ index 9fe90592e..0edcd10fd 100644 +#include "internal/command-line.h" +#include "internal/daemon.h" +#include "internal/dirs.h" + #include "dns-resolve.h" #include "openvswitch/dynamic-string.h" -#include "fatal-signal.h" +#include "internal/fatal-signal.h" @@ -9831,10 +35014,10 @@ index 9fe90592e..0edcd10fd 100644 #include "perf-counter.h" #include "ovsdb-util.h" #include "openvswitch/vlog.h" -diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c -index 8465666e5..4fed2952d 100644 ---- a/ovsdb/ovsdb-tool.c -+++ b/ovsdb/ovsdb-tool.c +Index: openvswitch-2.17.2/ovsdb/ovsdb-tool.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-tool.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-tool.c @@ -23,29 +23,30 @@ #include @@ -9876,10 +35059,10 @@ index 8465666e5..4fed2952d 100644 #include "openvswitch/vlog.h" /* -m, --more: Verbosity level for "show-log" command output. */ -diff --git a/ovsdb/ovsdb-util.c b/ovsdb/ovsdb-util.c -index 6d7be066b..9bf35e4b9 100644 ---- a/ovsdb/ovsdb-util.c -+++ b/ovsdb/ovsdb-util.c +Index: openvswitch-2.17.2/ovsdb/ovsdb-util.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb-util.c ++++ openvswitch-2.17.2/ovsdb/ovsdb-util.c @@ -15,7 +15,7 @@ #include @@ -9889,10 +35072,10 @@ index 6d7be066b..9bf35e4b9 100644 #include "table.h" #include "ovsdb-util.h" #include "openvswitch/vlog.h" -diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c -index e6d866182..cfdf3d9dc 100644 ---- a/ovsdb/ovsdb.c -+++ b/ovsdb/ovsdb.c +Index: openvswitch-2.17.2/ovsdb/ovsdb.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/ovsdb.c ++++ openvswitch-2.17.2/ovsdb/ovsdb.c @@ -25,13 +25,13 @@ #include "file.h" #include "monitor.h" @@ -9912,10 +35095,10 @@ index e6d866182..cfdf3d9dc 100644 #include "transaction.h" #include "transaction-forward.h" #include "trigger.h" -diff --git a/ovsdb/raft-private.c b/ovsdb/raft-private.c -index 30760233e..14378cdc0 100644 ---- a/ovsdb/raft-private.c -+++ b/ovsdb/raft-private.c +Index: openvswitch-2.17.2/ovsdb/raft-private.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft-private.c ++++ openvswitch-2.17.2/ovsdb/raft-private.c @@ -18,12 +18,12 @@ #include "raft-private.h" @@ -9934,10 +35117,10 @@ index 30760233e..14378cdc0 100644 COVERAGE_DEFINE(raft_entry_serialize); -diff --git a/ovsdb/raft-private.h b/ovsdb/raft-private.h -index 48c6df511..ed6eac441 100644 ---- a/ovsdb/raft-private.h -+++ b/ovsdb/raft-private.h +Index: openvswitch-2.17.2/ovsdb/raft-private.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft-private.h ++++ openvswitch-2.17.2/ovsdb/raft-private.h @@ -23,7 +23,7 @@ #include #include "openvswitch/hmap.h" @@ -9947,10 +35130,10 @@ index 48c6df511..ed6eac441 100644 struct ds; struct ovsdb_parser; -diff --git a/ovsdb/raft-rpc.c b/ovsdb/raft-rpc.c -index 051291b0f..a757f5ad9 100644 ---- a/ovsdb/raft-rpc.c -+++ b/ovsdb/raft-rpc.c +Index: openvswitch-2.17.2/ovsdb/raft-rpc.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft-rpc.c ++++ openvswitch-2.17.2/ovsdb/raft-rpc.c @@ -20,13 +20,13 @@ #include #include @@ -9969,10 +35152,10 @@ index 051291b0f..a757f5ad9 100644 VLOG_DEFINE_THIS_MODULE(raft_rpc); -diff --git a/ovsdb/raft-rpc.h b/ovsdb/raft-rpc.h -index 221f24d00..4ae8c3ac8 100644 ---- a/ovsdb/raft-rpc.h -+++ b/ovsdb/raft-rpc.h +Index: openvswitch-2.17.2/ovsdb/raft-rpc.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft-rpc.h ++++ openvswitch-2.17.2/ovsdb/raft-rpc.h @@ -24,7 +24,7 @@ #include "openvswitch/uuid.h" #include "raft.h" @@ -9982,10 +35165,10 @@ index 221f24d00..4ae8c3ac8 100644 struct ds; -diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index 1a3447a8d..da4aa3c5f 100644 ---- a/ovsdb/raft.c -+++ b/ovsdb/raft.c +Index: openvswitch-2.17.2/ovsdb/raft.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft.c ++++ openvswitch-2.17.2/ovsdb/raft.c @@ -22,8 +22,8 @@ #include #include @@ -10027,10 +35210,10 @@ index 1a3447a8d..da4aa3c5f 100644 VLOG_DEFINE_THIS_MODULE(raft); -diff --git a/ovsdb/raft.h b/ovsdb/raft.h -index 5f2c0c773..92993a088 100644 ---- a/ovsdb/raft.h -+++ b/ovsdb/raft.h +Index: openvswitch-2.17.2/ovsdb/raft.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/raft.h ++++ openvswitch-2.17.2/ovsdb/raft.h @@ -62,7 +62,7 @@ #include #include @@ -10040,10 +35223,10 @@ index 5f2c0c773..92993a088 100644 struct json; struct ovsdb_log; -diff --git a/ovsdb/rbac.c b/ovsdb/rbac.c -index a3fe97120..a618f511a 100644 ---- a/ovsdb/rbac.c -+++ b/ovsdb/rbac.c +Index: openvswitch-2.17.2/ovsdb/rbac.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/rbac.c ++++ openvswitch-2.17.2/ovsdb/rbac.c @@ -24,16 +24,16 @@ #include "file.h" #include "mutation.h" @@ -10065,10 +35248,10 @@ index a3fe97120..a618f511a 100644 #include "transaction.h" VLOG_DEFINE_THIS_MODULE(ovsdb_rbac); -diff --git a/ovsdb/relay.c b/ovsdb/relay.c -index ef0e44d34..df21feada 100644 ---- a/ovsdb/relay.c -+++ b/ovsdb/relay.c +Index: openvswitch-2.17.2/ovsdb/relay.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/relay.c ++++ openvswitch-2.17.2/ovsdb/relay.c @@ -18,8 +18,8 @@ #include "relay.h" @@ -10099,10 +35282,10 @@ index ef0e44d34..df21feada 100644 VLOG_DEFINE_THIS_MODULE(relay); -diff --git a/ovsdb/replication.c b/ovsdb/replication.c -index d8b56d813..3dede55f5 100644 ---- a/ovsdb/replication.c -+++ b/ovsdb/replication.c +Index: openvswitch-2.17.2/ovsdb/replication.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/replication.c ++++ openvswitch-2.17.2/ovsdb/replication.c @@ -19,22 +19,22 @@ @@ -10132,10 +35315,10 @@ index d8b56d813..3dede55f5 100644 VLOG_DEFINE_THIS_MODULE(replication); -diff --git a/ovsdb/row.c b/ovsdb/row.c -index e83c60a21..94f18337e 100644 ---- a/ovsdb/row.c -+++ b/ovsdb/row.c +Index: openvswitch-2.17.2/ovsdb/row.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/row.c ++++ openvswitch-2.17.2/ovsdb/row.c @@ -21,11 +21,11 @@ #include "openvswitch/dynamic-string.h" @@ -10151,10 +35334,10 @@ index e83c60a21..94f18337e 100644 static struct ovsdb_row * allocate_row(const struct ovsdb_table *table) -diff --git a/ovsdb/row.h b/ovsdb/row.h -index fe04555d0..fcd575ebe 100644 ---- a/ovsdb/row.h -+++ b/ovsdb/row.h +Index: openvswitch-2.17.2/ovsdb/row.h +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/row.h ++++ openvswitch-2.17.2/ovsdb/row.h @@ -21,7 +21,7 @@ #include "column.h" #include "openvswitch/hmap.h" @@ -10164,10 +35347,10 @@ index fe04555d0..fcd575ebe 100644 struct ovsdb_column_set; -diff --git a/ovsdb/server.c b/ovsdb/server.c -index e1a497d78..9b00617cc 100644 ---- a/ovsdb/server.c -+++ b/ovsdb/server.c +Index: openvswitch-2.17.2/ovsdb/server.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/server.c ++++ openvswitch-2.17.2/ovsdb/server.c @@ -17,9 +17,9 @@ #include "server.h" @@ -10180,10 +35363,10 @@ index e1a497d78..9b00617cc 100644 /* Initializes 'session' as a session within 'server'. */ void -diff --git a/ovsdb/storage.c b/ovsdb/storage.c -index d4984be25..dbbb3c032 100644 ---- a/ovsdb/storage.c -+++ b/ovsdb/storage.c +Index: openvswitch-2.17.2/ovsdb/storage.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/storage.c ++++ openvswitch-2.17.2/ovsdb/storage.c @@ -19,16 +19,16 @@ #include "storage.h" #include @@ -10206,10 +35389,10 @@ index d4984be25..dbbb3c032 100644 VLOG_DEFINE_THIS_MODULE(storage); -diff --git a/ovsdb/table.c b/ovsdb/table.c -index 455a3663f..df25fbe6d 100644 ---- a/ovsdb/table.c -+++ b/ovsdb/table.c +Index: openvswitch-2.17.2/ovsdb/table.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/table.c ++++ openvswitch-2.17.2/ovsdb/table.c @@ -21,9 +21,9 @@ #include "openvswitch/json.h" @@ -10223,10 +35406,10 @@ index 455a3663f..df25fbe6d 100644 #include "row.h" #include "transaction.h" -diff --git a/ovsdb/transaction-forward.c b/ovsdb/transaction-forward.c -index d15f2f1d6..7cddfd603 100644 ---- a/ovsdb/transaction-forward.c -+++ b/ovsdb/transaction-forward.c +Index: openvswitch-2.17.2/ovsdb/transaction-forward.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/transaction-forward.c ++++ openvswitch-2.17.2/ovsdb/transaction-forward.c @@ -18,16 +18,16 @@ #include "transaction-forward.h" @@ -10248,10 +35431,10 @@ index d15f2f1d6..7cddfd603 100644 VLOG_DEFINE_THIS_MODULE(transaction_forward); -diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c -index db86d847c..eabf1a2ae 100644 ---- a/ovsdb/transaction.c -+++ b/ovsdb/transaction.c +Index: openvswitch-2.17.2/ovsdb/transaction.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/transaction.c ++++ openvswitch-2.17.2/ovsdb/transaction.c @@ -17,22 +17,22 @@ #include "transaction.h" @@ -10279,10 +35462,10 @@ index db86d847c..eabf1a2ae 100644 VLOG_DEFINE_THIS_MODULE(transaction); -diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c -index 726c138bf..ebd7ff753 100644 ---- a/ovsdb/trigger.c -+++ b/ovsdb/trigger.c +Index: openvswitch-2.17.2/ovsdb/trigger.c +=================================================================== +--- openvswitch-2.17.2.orig/ovsdb/trigger.c ++++ openvswitch-2.17.2/ovsdb/trigger.c @@ -22,15 +22,15 @@ #include "file.h" @@ -10302,10 +35485,10 @@ index 726c138bf..ebd7ff753 100644 VLOG_DEFINE_THIS_MODULE(trigger); -diff --git a/tests/oss-fuzz/flow_extract_target.c b/tests/oss-fuzz/flow_extract_target.c -index 84a6c317d..d8ecc862e 100644 ---- a/tests/oss-fuzz/flow_extract_target.c -+++ b/tests/oss-fuzz/flow_extract_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/flow_extract_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/flow_extract_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/flow_extract_target.c @@ -1,9 +1,9 @@ #include -#include "classifier.h" @@ -10319,10 +35502,10 @@ index 84a6c317d..d8ecc862e 100644 #include "openvswitch/ofp-match.h" #include "openvswitch/ofp-print.h" #include "openvswitch/match.h" -diff --git a/tests/oss-fuzz/json_parser_target.c b/tests/oss-fuzz/json_parser_target.c -index e39e04a0d..b49efe633 100644 ---- a/tests/oss-fuzz/json_parser_target.c -+++ b/tests/oss-fuzz/json_parser_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/json_parser_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/json_parser_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/json_parser_target.c @@ -1,8 +1,8 @@ #include #include "fuzzer.h" @@ -10334,10 +35517,10 @@ index e39e04a0d..b49efe633 100644 #include "ovsdb/table.h" #include #include -diff --git a/tests/oss-fuzz/miniflow_target.c b/tests/oss-fuzz/miniflow_target.c -index 50b8b0e64..132d6bf68 100644 ---- a/tests/oss-fuzz/miniflow_target.c -+++ b/tests/oss-fuzz/miniflow_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/miniflow_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/miniflow_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/miniflow_target.c @@ -1,13 +1,13 @@ #include -#include "classifier.h" @@ -10356,10 +35539,10 @@ index 50b8b0e64..132d6bf68 100644 /* Returns a copy of 'src'. The caller must eventually free the returned * miniflow with free(). */ -diff --git a/tests/oss-fuzz/odp_target.c b/tests/oss-fuzz/odp_target.c -index ae61cdca3..71324741f 100644 ---- a/tests/oss-fuzz/odp_target.c -+++ b/tests/oss-fuzz/odp_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/odp_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/odp_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/odp_target.c @@ -4,10 +4,10 @@ #include "odp-util.h" #include @@ -10373,10 +35556,10 @@ index ae61cdca3..71324741f 100644 #include "openvswitch/ofp-flow.h" #include "openvswitch/vlog.h" -diff --git a/tests/oss-fuzz/ofctl_parse_target.c b/tests/oss-fuzz/ofctl_parse_target.c -index b4db52f7e..c4f64e457 100644 ---- a/tests/oss-fuzz/ofctl_parse_target.c -+++ b/tests/oss-fuzz/ofctl_parse_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/ofctl_parse_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/ofctl_parse_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/ofctl_parse_target.c @@ -6,7 +6,7 @@ #include "openflow/openflow.h" #include "openvswitch/ofpbuf.h" @@ -10386,10 +35569,10 @@ index b4db52f7e..c4f64e457 100644 static void ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms, -diff --git a/tests/oss-fuzz/ofp_print_target.c b/tests/oss-fuzz/ofp_print_target.c -index 126f2623f..3fbf40592 100644 ---- a/tests/oss-fuzz/ofp_print_target.c -+++ b/tests/oss-fuzz/ofp_print_target.c +Index: openvswitch-2.17.2/tests/oss-fuzz/ofp_print_target.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/oss-fuzz/ofp_print_target.c ++++ openvswitch-2.17.2/tests/oss-fuzz/ofp_print_target.c @@ -1,6 +1,6 @@ #include #include "fuzzer.h" @@ -10398,10 +35581,10 @@ index 126f2623f..3fbf40592 100644 #include "openvswitch/ofp-print.h" #include "openvswitch/ofpbuf.h" #include "openvswitch/vlog.h" -diff --git a/tests/ovstest.c b/tests/ovstest.c -index 068dcbb9b..52f19f99a 100644 ---- a/tests/ovstest.c -+++ b/tests/ovstest.c +Index: openvswitch-2.17.2/tests/ovstest.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/ovstest.c ++++ openvswitch-2.17.2/tests/ovstest.c @@ -21,10 +21,10 @@ #include #include @@ -10415,10 +35598,10 @@ index 068dcbb9b..52f19f99a 100644 static struct ovs_cmdl_command *commands = NULL; static size_t n_commands = 0; -diff --git a/tests/ovstest.h b/tests/ovstest.h -index 72fe6d152..87897499e 100644 ---- a/tests/ovstest.h -+++ b/tests/ovstest.h +Index: openvswitch-2.17.2/tests/ovstest.h +=================================================================== +--- openvswitch-2.17.2.orig/tests/ovstest.h ++++ openvswitch-2.17.2/tests/ovstest.h @@ -19,7 +19,7 @@ #include "openvswitch/compiler.h" @@ -10428,10 +35611,10 @@ index 72fe6d152..87897499e 100644 /* Overview * ======== -diff --git a/tests/test-aes128.c b/tests/test-aes128.c -index 7960551be..e534ad795 100644 ---- a/tests/test-aes128.c -+++ b/tests/test-aes128.c +Index: openvswitch-2.17.2/tests/test-aes128.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-aes128.c ++++ openvswitch-2.17.2/tests/test-aes128.c @@ -19,7 +19,7 @@ #include "aes128.h" #include @@ -10441,10 +35624,10 @@ index 7960551be..e534ad795 100644 static void hex_to_uint8(const char *input, uint8_t *output, size_t n) -diff --git a/tests/test-atomic.c b/tests/test-atomic.c -index 4b1374b70..d2a7c67aa 100644 ---- a/tests/test-atomic.c -+++ b/tests/test-atomic.c +Index: openvswitch-2.17.2/tests/test-atomic.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-atomic.c ++++ openvswitch-2.17.2/tests/test-atomic.c @@ -16,12 +16,12 @@ #include @@ -10463,10 +35646,10 @@ index 4b1374b70..d2a7c67aa 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(test_atomic); -diff --git a/tests/test-barrier.c b/tests/test-barrier.c -index 3bc5291cc..dca08b2ff 100644 ---- a/tests/test-barrier.c -+++ b/tests/test-barrier.c +Index: openvswitch-2.17.2/tests/test-barrier.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-barrier.c ++++ openvswitch-2.17.2/tests/test-barrier.c @@ -18,11 +18,11 @@ #include @@ -10483,10 +35666,10 @@ index 3bc5291cc..dca08b2ff 100644 #define DEFAULT_N_THREADS 4 #define NB_STEPS 4 -diff --git a/tests/test-bitmap.c b/tests/test-bitmap.c -index 484407b7d..3694ab203 100644 ---- a/tests/test-bitmap.c -+++ b/tests/test-bitmap.c +Index: openvswitch-2.17.2/tests/test-bitmap.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-bitmap.c ++++ openvswitch-2.17.2/tests/test-bitmap.c @@ -16,11 +16,11 @@ #include @@ -10502,10 +35685,10 @@ index 484407b7d..3694ab203 100644 enum { MAX_BITS = 20 * BITMAP_ULONG_BITS }; -diff --git a/tests/test-bundle.c b/tests/test-bundle.c -index 53f78e86f..c892bc110 100644 ---- a/tests/test-bundle.c -+++ b/tests/test-bundle.c +Index: openvswitch-2.17.2/tests/test-bundle.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-bundle.c ++++ openvswitch-2.17.2/tests/test-bundle.c @@ -17,12 +17,12 @@ #undef NDEBUG #include @@ -10522,10 +35705,10 @@ index 53f78e86f..c892bc110 100644 #define N_FLOWS 50000 #define MAX_MEMBERS 8 /* Maximum supported by this test framework. */ -diff --git a/tests/test-byte-order.c b/tests/test-byte-order.c -index 2b8edf35c..b6f6e8697 100644 ---- a/tests/test-byte-order.c -+++ b/tests/test-byte-order.c +Index: openvswitch-2.17.2/tests/test-byte-order.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-byte-order.c ++++ openvswitch-2.17.2/tests/test-byte-order.c @@ -16,7 +16,7 @@ #include @@ -10535,10 +35718,10 @@ index 2b8edf35c..b6f6e8697 100644 #include #include #include "ovstest.h" -diff --git a/tests/test-ccmap.c b/tests/test-ccmap.c -index 5c51bbe83..677e66cdd 100644 ---- a/tests/test-ccmap.c -+++ b/tests/test-ccmap.c +Index: openvswitch-2.17.2/tests/test-ccmap.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-ccmap.c ++++ openvswitch-2.17.2/tests/test-ccmap.c @@ -23,16 +23,16 @@ #include #include @@ -10563,10 +35746,10 @@ index 5c51bbe83..677e66cdd 100644 typedef size_t hash_func(int value); -diff --git a/tests/test-classifier.c b/tests/test-classifier.c -index cff00c8fa..eb6151dd2 100644 ---- a/tests/test-classifier.c -+++ b/tests/test-classifier.c +Index: openvswitch-2.17.2/tests/test-classifier.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-classifier.c ++++ openvswitch-2.17.2/tests/test-classifier.c @@ -28,23 +28,23 @@ #include @@ -10603,10 +35786,10 @@ index cff00c8fa..eb6151dd2 100644 static bool versioned = false; -diff --git a/tests/test-cmap.c b/tests/test-cmap.c -index 070547560..56be78f9c 100644 ---- a/tests/test-cmap.c -+++ b/tests/test-cmap.c +Index: openvswitch-2.17.2/tests/test-cmap.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-cmap.c ++++ openvswitch-2.17.2/tests/test-cmap.c @@ -19,20 +19,20 @@ #include @@ -10636,10 +35819,10 @@ index 070547560..56be78f9c 100644 /* Sample cmap element. */ struct element { -diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c -index 24c93e4a4..0b77269a6 100644 ---- a/tests/test-conntrack.c -+++ b/tests/test-conntrack.c +Index: openvswitch-2.17.2/tests/test-conntrack.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-conntrack.c ++++ openvswitch-2.17.2/tests/test-conntrack.c @@ -17,14 +17,14 @@ #include #include "conntrack.h" @@ -10661,10 +35844,10 @@ index 24c93e4a4..0b77269a6 100644 static const char payload[] = "50540000000a50540000000908004500001c0000000000" "11a4cd0a0101010a0101020001000200080000"; -diff --git a/tests/test-csum.c b/tests/test-csum.c -index b94bd6481..58f7edba6 100644 ---- a/tests/test-csum.c -+++ b/tests/test-csum.c +Index: openvswitch-2.17.2/tests/test-csum.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-csum.c ++++ openvswitch-2.17.2/tests/test-csum.c @@ -16,7 +16,7 @@ #include @@ -10692,10 +35875,10 @@ index b94bd6481..58f7edba6 100644 struct test_case { char *data; -diff --git a/tests/test-flows.c b/tests/test-flows.c -index 7adbe5dd9..64cc17dbb 100644 ---- a/tests/test-flows.c -+++ b/tests/test-flows.c +Index: openvswitch-2.17.2/tests/test-flows.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-flows.c ++++ openvswitch-2.17.2/tests/test-flows.c @@ -16,22 +16,22 @@ #include @@ -10724,10 +35907,10 @@ index 7adbe5dd9..64cc17dbb 100644 static void test_flows_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) -diff --git a/tests/test-hash.c b/tests/test-hash.c -index 5d3f8ea43..8d2552901 100644 ---- a/tests/test-hash.c -+++ b/tests/test-hash.c +Index: openvswitch-2.17.2/tests/test-hash.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-hash.c ++++ openvswitch-2.17.2/tests/test-hash.c @@ -16,7 +16,7 @@ #include @@ -10737,10 +35920,10 @@ index 5d3f8ea43..8d2552901 100644 #include #include #include -diff --git a/tests/test-heap.c b/tests/test-heap.c -index 88c9f25f7..8b365ea35 100644 ---- a/tests/test-heap.c -+++ b/tests/test-heap.c +Index: openvswitch-2.17.2/tests/test-heap.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-heap.c ++++ openvswitch-2.17.2/tests/test-heap.c @@ -23,10 +23,10 @@ #include #include @@ -10755,10 +35938,10 @@ index 88c9f25f7..8b365ea35 100644 /* Sample heap element. */ struct element { -diff --git a/tests/test-hindex.c b/tests/test-hindex.c -index af06be5fc..4908ebf0f 100644 ---- a/tests/test-hindex.c -+++ b/tests/test-hindex.c +Index: openvswitch-2.17.2/tests/test-hindex.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-hindex.c ++++ openvswitch-2.17.2/tests/test-hindex.c @@ -19,13 +19,13 @@ #include @@ -10777,10 +35960,10 @@ index af06be5fc..4908ebf0f 100644 /* Sample hindex element. */ struct element { -diff --git a/tests/test-hmap.c b/tests/test-hmap.c -index 9259b0b3f..a01e1b18a 100644 ---- a/tests/test-hmap.c -+++ b/tests/test-hmap.c +Index: openvswitch-2.17.2/tests/test-hmap.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-hmap.c ++++ openvswitch-2.17.2/tests/test-hmap.c @@ -22,10 +22,10 @@ #include "openvswitch/hmap.h" #include @@ -10795,10 +35978,10 @@ index 9259b0b3f..a01e1b18a 100644 /* Sample hmap element. */ struct element { -diff --git a/tests/test-id-fpool.c b/tests/test-id-fpool.c -index 25275d9ae..2d49a75d4 100644 ---- a/tests/test-id-fpool.c -+++ b/tests/test-id-fpool.c +Index: openvswitch-2.17.2/tests/test-id-fpool.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-id-fpool.c ++++ openvswitch-2.17.2/tests/test-id-fpool.c @@ -21,18 +21,18 @@ #include @@ -10826,10 +36009,10 @@ index 25275d9ae..2d49a75d4 100644 static void test_id_fpool_alloc(void) -diff --git a/tests/test-json.c b/tests/test-json.c -index 072a53725..2b704b8fe 100644 ---- a/tests/test-json.c -+++ b/tests/test-json.c +Index: openvswitch-2.17.2/tests/test-json.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-json.c ++++ openvswitch-2.17.2/tests/test-json.c @@ -22,9 +22,9 @@ #include #include @@ -10843,10 +36026,10 @@ index 072a53725..2b704b8fe 100644 /* --pretty: If set, the JSON output is pretty-printed, instead of printed as * compactly as possible. */ -diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c -index 04e941b14..28698de1a 100644 ---- a/tests/test-jsonrpc.c -+++ b/tests/test-jsonrpc.c +Index: openvswitch-2.17.2/tests/test-jsonrpc.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-jsonrpc.c ++++ openvswitch-2.17.2/tests/test-jsonrpc.c @@ -16,21 +16,21 @@ #include @@ -10876,10 +36059,10 @@ index 04e941b14..28698de1a 100644 #include "openvswitch/vlog.h" OVS_NO_RETURN static void usage(void); -diff --git a/tests/test-lockfile.c b/tests/test-lockfile.c -index d0c8dc480..ce17711ea 100644 ---- a/tests/test-lockfile.c -+++ b/tests/test-lockfile.c +Index: openvswitch-2.17.2/tests/test-lockfile.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-lockfile.c ++++ openvswitch-2.17.2/tests/test-lockfile.c @@ -23,9 +23,9 @@ #include #include @@ -10893,10 +36076,10 @@ index d0c8dc480..ce17711ea 100644 #include "openvswitch/vlog.h" struct test { -diff --git a/tests/test-mpsc-queue.c b/tests/test-mpsc-queue.c -index a38bf9e6d..7aa167a67 100644 ---- a/tests/test-mpsc-queue.c -+++ b/tests/test-mpsc-queue.c +Index: openvswitch-2.17.2/tests/test-mpsc-queue.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-mpsc-queue.c ++++ openvswitch-2.17.2/tests/test-mpsc-queue.c @@ -21,17 +21,17 @@ #include @@ -10920,10 +36103,10 @@ index a38bf9e6d..7aa167a67 100644 struct element { union { -diff --git a/tests/test-multipath.c b/tests/test-multipath.c -index 08d2cbaeb..4b2f58088 100644 ---- a/tests/test-multipath.c -+++ b/tests/test-multipath.c +Index: openvswitch-2.17.2/tests/test-multipath.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-multipath.c ++++ openvswitch-2.17.2/tests/test-multipath.c @@ -21,11 +21,11 @@ #include #include @@ -10938,10 +36121,10 @@ index 08d2cbaeb..4b2f58088 100644 static void test_multipath_main(int argc, char *argv[]) -diff --git a/tests/test-netflow.c b/tests/test-netflow.c -index d2322d450..8cd8ec59c 100644 ---- a/tests/test-netflow.c -+++ b/tests/test-netflow.c +Index: openvswitch-2.17.2/tests/test-netflow.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-netflow.c ++++ openvswitch-2.17.2/tests/test-netflow.c @@ -22,16 +22,16 @@ #include #include @@ -10965,10 +36148,10 @@ index d2322d450..8cd8ec59c 100644 #include "openvswitch/vlog.h" OVS_NO_RETURN static void usage(void); -diff --git a/tests/test-netlink-policy.c b/tests/test-netlink-policy.c -index 55083935a..60cd15db6 100644 ---- a/tests/test-netlink-policy.c -+++ b/tests/test-netlink-policy.c +Index: openvswitch-2.17.2/tests/test-netlink-policy.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-netlink-policy.c ++++ openvswitch-2.17.2/tests/test-netlink-policy.c @@ -18,11 +18,11 @@ #include @@ -10983,10 +36166,10 @@ index 55083935a..60cd15db6 100644 struct nlattr_fixture { struct nlattr nlattr; -diff --git a/tests/test-odp.c b/tests/test-odp.c -index 0ddfd4070..ceaf941ce 100644 ---- a/tests/test-odp.c -+++ b/tests/test-odp.c +Index: openvswitch-2.17.2/tests/test-odp.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-odp.c ++++ openvswitch-2.17.2/tests/test-odp.c @@ -19,11 +19,11 @@ #include "odp-util.h" #include @@ -11001,10 +36184,10 @@ index 0ddfd4070..ceaf941ce 100644 #include "openvswitch/ofp-flow.h" #include "openvswitch/vlog.h" -diff --git a/tests/test-ofpbuf.c b/tests/test-ofpbuf.c -index 3d7fab90f..a0f22a2f3 100644 ---- a/tests/test-ofpbuf.c -+++ b/tests/test-ofpbuf.c +Index: openvswitch-2.17.2/tests/test-ofpbuf.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-ofpbuf.c ++++ openvswitch-2.17.2/tests/test-ofpbuf.c @@ -19,7 +19,7 @@ #include #include "openvswitch/ofpbuf.h" @@ -11014,10 +36197,10 @@ index 3d7fab90f..a0f22a2f3 100644 #define BUF_SIZE 100 #define HDR_OFS 10 -diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c -index ca4e87b81..083c281d0 100644 ---- a/tests/test-ovsdb.c -+++ b/tests/test-ovsdb.c +Index: openvswitch-2.17.2/tests/test-ovsdb.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-ovsdb.c ++++ openvswitch-2.17.2/tests/test-ovsdb.c @@ -23,15 +23,15 @@ #include #include @@ -11057,10 +36240,10 @@ index ca4e87b81..083c281d0 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(test_ovsdb); -diff --git a/tests/test-packets.c b/tests/test-packets.c -index da074f74d..78c9a61f8 100644 ---- a/tests/test-packets.c -+++ b/tests/test-packets.c +Index: openvswitch-2.17.2/tests/test-packets.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-packets.c ++++ openvswitch-2.17.2/tests/test-packets.c @@ -16,7 +16,7 @@ #include @@ -11070,10 +36253,10 @@ index da074f74d..78c9a61f8 100644 #include #include #include -diff --git a/tests/test-random.c b/tests/test-random.c -index 542a49823..2eaba923d 100644 ---- a/tests/test-random.c -+++ b/tests/test-random.c +Index: openvswitch-2.17.2/tests/test-random.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-random.c ++++ openvswitch-2.17.2/tests/test-random.c @@ -16,7 +16,7 @@ #include @@ -11083,10 +36266,10 @@ index 542a49823..2eaba923d 100644 #include #include #include "ovstest.h" -diff --git a/tests/test-rcu.c b/tests/test-rcu.c -index 965f3c49f..0e2c263c7 100644 ---- a/tests/test-rcu.c -+++ b/tests/test-rcu.c +Index: openvswitch-2.17.2/tests/test-rcu.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-rcu.c ++++ openvswitch-2.17.2/tests/test-rcu.c @@ -16,11 +16,11 @@ #include @@ -11103,10 +36286,10 @@ index 965f3c49f..0e2c263c7 100644 static void * quiescer_main(void *aux OVS_UNUSED) -diff --git a/tests/test-reconnect.c b/tests/test-reconnect.c -index 7262ea774..c2b9b5804 100644 ---- a/tests/test-reconnect.c -+++ b/tests/test-reconnect.c +Index: openvswitch-2.17.2/tests/test-reconnect.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-reconnect.c ++++ openvswitch-2.17.2/tests/test-reconnect.c @@ -21,11 +21,11 @@ #include #include @@ -11122,10 +36305,10 @@ index 7262ea774..c2b9b5804 100644 #include "openvswitch/vlog.h" static struct reconnect *reconnect; -diff --git a/tests/test-rstp.c b/tests/test-rstp.c -index 01aeaf847..4a5d5d0e3 100644 ---- a/tests/test-rstp.c -+++ b/tests/test-rstp.c +Index: openvswitch-2.17.2/tests/test-rstp.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-rstp.c ++++ openvswitch-2.17.2/tests/test-rstp.c @@ -9,8 +9,8 @@ #include #include "openvswitch/ofpbuf.h" @@ -11137,10 +36320,10 @@ index 01aeaf847..4a5d5d0e3 100644 #include "openvswitch/vlog.h" #define MAX_PORTS 10 -diff --git a/tests/test-sflow.c b/tests/test-sflow.c -index 460d4d6c5..328f0d328 100644 ---- a/tests/test-sflow.c -+++ b/tests/test-sflow.c +Index: openvswitch-2.17.2/tests/test-sflow.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-sflow.c ++++ openvswitch-2.17.2/tests/test-sflow.c @@ -27,16 +27,16 @@ #include #include @@ -11164,10 +36347,10 @@ index 460d4d6c5..328f0d328 100644 #include "openvswitch/vlog.h" OVS_NO_RETURN static void usage(void); -diff --git a/tests/test-sha1.c b/tests/test-sha1.c -index cc80888a7..5b638a92f 100644 ---- a/tests/test-sha1.c -+++ b/tests/test-sha1.c +Index: openvswitch-2.17.2/tests/test-sha1.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-sha1.c ++++ openvswitch-2.17.2/tests/test-sha1.c @@ -23,8 +23,8 @@ #include #include @@ -11179,10 +36362,10 @@ index cc80888a7..5b638a92f 100644 struct test_vector { char *data; -diff --git a/tests/test-skiplist.c b/tests/test-skiplist.c -index 943d447fa..06a72ed7f 100644 ---- a/tests/test-skiplist.c -+++ b/tests/test-skiplist.c +Index: openvswitch-2.17.2/tests/test-skiplist.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-skiplist.c ++++ openvswitch-2.17.2/tests/test-skiplist.c @@ -22,9 +22,9 @@ #include #include @@ -11196,10 +36379,10 @@ index 943d447fa..06a72ed7f 100644 static void test_skiplist_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED); -diff --git a/tests/test-stopwatch.c b/tests/test-stopwatch.c -index 1270cd936..0c15298d4 100644 ---- a/tests/test-stopwatch.c -+++ b/tests/test-stopwatch.c +Index: openvswitch-2.17.2/tests/test-stopwatch.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-stopwatch.c ++++ openvswitch-2.17.2/tests/test-stopwatch.c @@ -16,12 +16,12 @@ #include @@ -11215,10 +36398,10 @@ index 1270cd936..0c15298d4 100644 #define MAX_SAMPLES 100 #define UNIT SW_MS -diff --git a/tests/test-stp.c b/tests/test-stp.c -index c85c99d67..501231be1 100644 ---- a/tests/test-stp.c -+++ b/tests/test-stp.c +Index: openvswitch-2.17.2/tests/test-stp.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-stp.c ++++ openvswitch-2.17.2/tests/test-stp.c @@ -23,10 +23,10 @@ #include #include @@ -11232,10 +36415,10 @@ index c85c99d67..501231be1 100644 #include "openvswitch/vlog.h" struct bpdu { -diff --git a/tests/test-stream.c b/tests/test-stream.c -index 68ce2c544..81d8cd37f 100644 ---- a/tests/test-stream.c -+++ b/tests/test-stream.c +Index: openvswitch-2.17.2/tests/test-stream.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-stream.c ++++ openvswitch-2.17.2/tests/test-stream.c @@ -16,10 +16,10 @@ #include @@ -11250,10 +36433,10 @@ index 68ce2c544..81d8cd37f 100644 VLOG_DEFINE_THIS_MODULE(test_stream); -diff --git a/tests/test-unix-socket.c b/tests/test-unix-socket.c -index 3175e8aff..397e2f5cb 100644 ---- a/tests/test-unix-socket.c -+++ b/tests/test-unix-socket.c +Index: openvswitch-2.17.2/tests/test-unix-socket.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-unix-socket.c ++++ openvswitch-2.17.2/tests/test-unix-socket.c @@ -16,12 +16,12 @@ #include @@ -11269,10 +36452,10 @@ index 3175e8aff..397e2f5cb 100644 static void test_unix_socket_main(int argc, char *argv[]) -diff --git a/tests/test-unixctl.c b/tests/test-unixctl.c -index 3eadf54cd..3852a37ce 100644 ---- a/tests/test-unixctl.c -+++ b/tests/test-unixctl.c +Index: openvswitch-2.17.2/tests/test-unixctl.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-unixctl.c ++++ openvswitch-2.17.2/tests/test-unixctl.c @@ -17,14 +17,14 @@ #include @@ -11293,10 +36476,10 @@ index 3eadf54cd..3852a37ce 100644 VLOG_DEFINE_THIS_MODULE(test_unixctl); -diff --git a/tests/test-util.c b/tests/test-util.c -index f0fd04210..46b94b070 100644 ---- a/tests/test-util.c -+++ b/tests/test-util.c +Index: openvswitch-2.17.2/tests/test-util.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-util.c ++++ openvswitch-2.17.2/tests/test-util.c @@ -16,17 +16,17 @@ #include @@ -11319,10 +36502,10 @@ index f0fd04210..46b94b070 100644 #include "sat-math.h" #include "openvswitch/vlog.h" -diff --git a/tests/test-uuid.c b/tests/test-uuid.c -index 3b47ab616..efa1a5f83 100644 ---- a/tests/test-uuid.c -+++ b/tests/test-uuid.c +Index: openvswitch-2.17.2/tests/test-uuid.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-uuid.c ++++ openvswitch-2.17.2/tests/test-uuid.c @@ -16,8 +16,8 @@ #include @@ -11334,10 +36517,10 @@ index 3b47ab616..efa1a5f83 100644 #include #include "ovstest.h" -diff --git a/tests/test-vconn.c b/tests/test-vconn.c -index fc8ce4a2c..d87f153b4 100644 ---- a/tests/test-vconn.c -+++ b/tests/test-vconn.c +Index: openvswitch-2.17.2/tests/test-vconn.c +=================================================================== +--- openvswitch-2.17.2.orig/tests/test-vconn.c ++++ openvswitch-2.17.2/tests/test-vconn.c @@ -22,8 +22,8 @@ #include #include @@ -11366,10 +36549,10 @@ index fc8ce4a2c..d87f153b4 100644 #define TIMEOUT 10 -diff --git a/utilities/nlmon.c b/utilities/nlmon.c -index 32aa948c6..5495d9b96 100644 ---- a/utilities/nlmon.c -+++ b/utilities/nlmon.c +Index: openvswitch-2.17.2/utilities/nlmon.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/nlmon.c ++++ openvswitch-2.17.2/utilities/nlmon.c @@ -23,13 +23,13 @@ #include #include @@ -11387,10 +36570,10 @@ index 32aa948c6..5495d9b96 100644 #include "openvswitch/vlog.h" static const struct nl_policy rtnlgrp_link_policy[] = { -diff --git a/utilities/ovs-appctl.c b/utilities/ovs-appctl.c -index ba0c172e6..997445ba3 100644 ---- a/utilities/ovs-appctl.c -+++ b/utilities/ovs-appctl.c +Index: openvswitch-2.17.2/utilities/ovs-appctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-appctl.c ++++ openvswitch-2.17.2/utilities/ovs-appctl.c @@ -22,15 +22,15 @@ #include #include @@ -11415,10 +36598,10 @@ index ba0c172e6..997445ba3 100644 #include "openvswitch/vlog.h" static void usage(void); -diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c -index 46d248694..3649cd305 100644 ---- a/utilities/ovs-dpctl.c -+++ b/utilities/ovs-dpctl.c +Index: openvswitch-2.17.2/utilities/ovs-dpctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-dpctl.c ++++ openvswitch-2.17.2/utilities/ovs-dpctl.c @@ -32,14 +32,14 @@ #include @@ -11440,10 +36623,10 @@ index 46d248694..3649cd305 100644 #include "openvswitch/vlog.h" static struct dpctl_params dpctl_p; -diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c -index 85df32d7e..402e6013b 100644 ---- a/utilities/ovs-ofctl.c -+++ b/utilities/ovs-ofctl.c +Index: openvswitch-2.17.2/utilities/ovs-ofctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-ofctl.c ++++ openvswitch-2.17.2/utilities/ovs-ofctl.c @@ -29,16 +29,16 @@ #include #include @@ -11495,10 +36678,10 @@ index 85df32d7e..402e6013b 100644 VLOG_DEFINE_THIS_MODULE(ofctl); -diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c -index c3d4bc7ff..c96bc2be2 100644 ---- a/utilities/ovs-testcontroller.c -+++ b/utilities/ovs-testcontroller.c +Index: openvswitch-2.17.2/utilities/ovs-testcontroller.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-testcontroller.c ++++ openvswitch-2.17.2/utilities/ovs-testcontroller.c @@ -24,25 +24,25 @@ #include #include @@ -11534,10 +36717,10 @@ index c3d4bc7ff..c96bc2be2 100644 VLOG_DEFINE_THIS_MODULE(controller); -diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c -index 6013e9f57..036c3a3b4 100644 ---- a/utilities/ovs-vsctl.c -+++ b/utilities/ovs-vsctl.c +Index: openvswitch-2.17.2/utilities/ovs-vsctl.c +=================================================================== +--- openvswitch-2.17.2.orig/utilities/ovs-vsctl.c ++++ openvswitch-2.17.2/utilities/ovs-vsctl.c @@ -27,32 +27,32 @@ #include #include @@ -11588,10 +36771,10 @@ index 6013e9f57..036c3a3b4 100644 VLOG_DEFINE_THIS_MODULE(vsctl); -diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c -index 5223aa897..070a4085f 100644 ---- a/vswitchd/bridge.c -+++ b/vswitchd/bridge.c +Index: openvswitch-2.17.2/vswitchd/bridge.c +=================================================================== +--- openvswitch-2.17.2.orig/vswitchd/bridge.c ++++ openvswitch-2.17.2/vswitchd/bridge.c @@ -21,25 +21,25 @@ #include "async-append.h" @@ -11664,10 +36847,10 @@ index 5223aa897..070a4085f 100644 #include "lib/vswitch-idl.h" #include "xenserver.h" #include "vlan-bitmap.h" -diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c -index 09004e79b..15aeded6e 100644 ---- a/vswitchd/ovs-vswitchd.c -+++ b/vswitchd/ovs-vswitchd.c +Index: openvswitch-2.17.2/vswitchd/ovs-vswitchd.c +=================================================================== +--- openvswitch-2.17.2.orig/vswitchd/ovs-vswitchd.c ++++ openvswitch-2.17.2/vswitchd/ovs-vswitchd.c @@ -27,32 +27,32 @@ #include "bridge.h" @@ -11717,10 +36900,10 @@ index 09004e79b..15aeded6e 100644 VLOG_DEFINE_THIS_MODULE(vswitchd); -diff --git a/vswitchd/system-stats.c b/vswitchd/system-stats.c -index aaab67656..1306f5c22 100644 ---- a/vswitchd/system-stats.c -+++ b/vswitchd/system-stats.c +Index: openvswitch-2.17.2/vswitchd/system-stats.c +=================================================================== +--- openvswitch-2.17.2.orig/vswitchd/system-stats.c ++++ openvswitch-2.17.2/vswitchd/system-stats.c @@ -31,19 +31,19 @@ #endif #include @@ -11749,10 +36932,10 @@ index aaab67656..1306f5c22 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(system_stats); -diff --git a/vswitchd/xenserver.c b/vswitchd/xenserver.c -index 9a0afea98..1cc024f35 100644 ---- a/vswitchd/xenserver.c -+++ b/vswitchd/xenserver.c +Index: openvswitch-2.17.2/vswitchd/xenserver.c +=================================================================== +--- openvswitch-2.17.2.orig/vswitchd/xenserver.c ++++ openvswitch-2.17.2/vswitchd/xenserver.c @@ -22,8 +22,8 @@ #include #include @@ -11764,10 +36947,10 @@ index 9a0afea98..1cc024f35 100644 #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(xenserver); -diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c -index 6c9259fba..f2b87fad8 100644 ---- a/vtep/vtep-ctl.c -+++ b/vtep/vtep-ctl.c +Index: openvswitch-2.17.2/vtep/vtep-ctl.c +=================================================================== +--- openvswitch-2.17.2.orig/vtep/vtep-ctl.c ++++ openvswitch-2.17.2/vtep/vtep-ctl.c @@ -27,27 +27,27 @@ #include #include @@ -11811,6 +36994,8805 @@ index 6c9259fba..f2b87fad8 100644 #include "openvswitch/vconn.h" #include "openvswitch/vlog.h" --- -2.35.1 - +Index: openvswitch-2.17.2/include/internal/bundle.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/bundle.h +@@ -0,0 +1,59 @@ ++/* Copyright (c) 2011, 2012, 2013, 2014, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef BUNDLE_H ++#define BUNDLE_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "openvswitch/compiler.h" ++#include "openflow/nicira-ext.h" ++#include "openvswitch/ofp-errors.h" ++#include "openvswitch/types.h" ++ ++struct ds; ++struct flow; ++struct flow_wildcards; ++struct match; ++struct ofpact_bundle; ++struct ofpbuf; ++struct ofputil_port_map; ++ ++/* NXAST_BUNDLE helper functions. ++ * ++ * See lib/ofp-actions.c for NXAST_BUNDLE specification. */ ++ ++#define BUNDLE_MAX_MEMBERS 2048 ++ ++ofp_port_t bundle_execute(const struct ofpact_bundle *, const struct flow *, ++ struct flow_wildcards *wc, ++ bool (*member_enabled)(ofp_port_t ofp_port, void *aux), ++ void *aux); ++enum ofperr bundle_check(const struct ofpact_bundle *, ofp_port_t max_ports, ++ const struct match *); ++char *bundle_parse(const char *, const struct ofputil_port_map *port_map, ++ struct ofpbuf *ofpacts) OVS_WARN_UNUSED_RESULT; ++char *bundle_parse_load(const char *, const struct ofputil_port_map *port_map, ++ struct ofpbuf *ofpacts) ++ OVS_WARN_UNUSED_RESULT; ++void bundle_format(const struct ofpact_bundle *, ++ const struct ofputil_port_map *, struct ds *); ++ ++#endif /* bundle.h */ +Index: openvswitch-2.17.2/include/internal/byte-order.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/byte-order.h +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (c) 2008, 2010, 2011, 2013, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#ifndef BYTE_ORDER_H ++#define BYTE_ORDER_H 1 ++ ++#include ++#include ++#include ++#include ++#include "openvswitch/types.h" ++ ++#ifndef __CHECKER__ ++#if !(defined(_WIN32) || defined(htonll)) ++static inline ovs_be64 ++htonll(uint64_t n) ++{ ++ return htonl(1) == 1 ? n : ((uint64_t) htonl(n) << 32) | htonl(n >> 32); ++} ++ ++static inline uint64_t ++ntohll(ovs_be64 n) ++{ ++ return htonl(1) == 1 ? n : ((uint64_t) ntohl(n) << 32) | ntohl(n >> 32); ++} ++#endif /* !(defined(_WIN32) || defined(htonll)) */ ++#else ++/* Making sparse happy with these functions also makes them unreadable, so ++ * don't bother to show it their implementations. */ ++ovs_be64 htonll(uint64_t); ++uint64_t ntohll(ovs_be64); ++#endif ++ ++static inline ovs_be128 ++hton128(const ovs_u128 src) ++{ ++ ovs_be128 dst; ++ ++ dst.be64.hi = htonll(src.u64.hi); ++ dst.be64.lo = htonll(src.u64.lo); ++ return dst; ++} ++ ++static inline ovs_u128 ++ntoh128(const ovs_be128 src) ++{ ++ ovs_u128 dst; ++ ++ dst.u64.hi = ntohll(src.be64.hi); ++ dst.u64.lo = ntohll(src.be64.lo); ++ return dst; ++} ++ ++static inline uint32_t ++uint32_byteswap(uint32_t crc) { ++ return (((crc & 0x000000ff) << 24) | ++ ((crc & 0x0000ff00) << 8) | ++ ((crc & 0x00ff0000) >> 8) | ++ ((crc & 0xff000000) >> 24)); ++} ++ ++/* These macros may substitute for htons(), htonl(), and htonll() in contexts ++ * where function calls are not allowed, such as case labels. They should not ++ * be used elsewhere because all of them evaluate their argument many times. */ ++#if defined(WORDS_BIGENDIAN) || __CHECKER__ ++#define CONSTANT_HTONS(VALUE) ((OVS_FORCE ovs_be16) ((VALUE) & 0xffff)) ++#define CONSTANT_HTONL(VALUE) ((OVS_FORCE ovs_be32) ((VALUE) & 0xffffffff)) ++#define CONSTANT_HTONLL(VALUE) \ ++ ((OVS_FORCE ovs_be64) ((VALUE) & UINT64_C(0xffffffffffffffff))) ++#else ++#define CONSTANT_HTONS(VALUE) \ ++ (((((ovs_be16) (VALUE)) & 0xff00) >> 8) | \ ++ ((((ovs_be16) (VALUE)) & 0x00ff) << 8)) ++#define CONSTANT_HTONL(VALUE) \ ++ (((((ovs_be32) (VALUE)) & 0x000000ff) << 24) | \ ++ ((((ovs_be32) (VALUE)) & 0x0000ff00) << 8) | \ ++ ((((ovs_be32) (VALUE)) & 0x00ff0000) >> 8) | \ ++ ((((ovs_be32) (VALUE)) & 0xff000000) >> 24)) ++#define CONSTANT_HTONLL(VALUE) \ ++ (((((ovs_be64) (VALUE)) & UINT64_C(0x00000000000000ff)) << 56) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x000000000000ff00)) << 40) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x0000000000ff0000)) << 24) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x00000000ff000000)) << 8) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x000000ff00000000)) >> 8) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x0000ff0000000000)) >> 24) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0x00ff000000000000)) >> 40) | \ ++ ((((ovs_be64) (VALUE)) & UINT64_C(0xff00000000000000)) >> 56)) ++#endif ++ ++/* Returns the ovs_be32 that you would get from: ++ * ++ * union { uint8_t b[4]; ovs_be32 be32; } x = { .b = { b0, b1, b2, b3 } }; ++ * return x.be32; ++ * ++ * but without the undefined behavior. */ ++static inline ovs_be32 ++bytes_to_be32(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) ++{ ++#if WORDS_BIGENDIAN ++ uint32_t x = ((uint32_t) b0 << 24) | (b1 << 16) | (b2 << 8) | b3; ++#else ++ uint32_t x = ((uint32_t) b3 << 24) | (b2 << 16) | (b1 << 8) | b0; ++#endif ++ return (OVS_FORCE ovs_be32) x; ++} ++ ++/* These functions zero-extend big-endian values to longer ones, ++ * or truncate long big-endian value to shorter ones. */ ++#ifndef __CHECKER__ ++#if WORDS_BIGENDIAN ++static inline ovs_be32 be16_to_be32(ovs_be16 x) { return x; } ++static inline ovs_be64 be16_to_be64(ovs_be16 x) { return x; } ++static inline ovs_be64 be32_to_be64(ovs_be32 x) { return x; } ++static inline ovs_be32 be64_to_be32(ovs_be64 x) { return x; } ++static inline ovs_be16 be64_to_be16(ovs_be64 x) { return x; } ++static inline ovs_be16 be32_to_be16(ovs_be32 x) { return x; } ++#else /* !WORDS_BIGENDIAN */ ++static inline ovs_be32 be16_to_be32(ovs_be16 x) { return (ovs_be32) x << 16; } ++static inline ovs_be64 be16_to_be64(ovs_be16 x) { return (ovs_be64) x << 48; } ++static inline ovs_be64 be32_to_be64(ovs_be32 x) { return (ovs_be64) x << 32; } ++static inline ovs_be32 be64_to_be32(ovs_be64 x) { return x >> 32; } ++static inline ovs_be16 be64_to_be16(ovs_be64 x) { return x >> 48; } ++static inline ovs_be16 be32_to_be16(ovs_be32 x) { return x >> 16; } ++#endif /* !WORDS_BIGENDIAN */ ++#else /* __CHECKER__ */ ++/* Making sparse happy with these functions also makes them unreadable, so ++ * don't bother to show it their implementations. */ ++ovs_be32 be16_to_be32(ovs_be16); ++ovs_be64 be16_to_be64(ovs_be16); ++ovs_be64 be32_to_be64(ovs_be32); ++ovs_be32 be64_to_be32(ovs_be64); ++ovs_be16 be64_to_be16(ovs_be64); ++ovs_be16 be32_to_be16(ovs_be32); ++#endif ++ ++#endif /* byte-order.h */ +Index: openvswitch-2.17.2/include/internal/colors.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/colors.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2016 6WIND S.A. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef COLORS_H ++#define COLORS_H 1 ++ ++#include ++ ++struct colors { ++ /* Color codes for various situation. Each of these is a fully formed ++ * Select Graphic Rendition (SGR, "\33[...m") start string for the ++ * appropriate color. ++ */ ++ char *actions; ++ char *drop; ++ char *learn; ++ char *param; ++ char *paren; ++ char *special; ++ char *value; ++ ++ /* SGR end string. */ ++ char *end; ++}; ++extern struct colors colors; ++ ++void colors_init(bool enable_color); ++ ++#endif /* colors.h */ +Index: openvswitch-2.17.2/include/internal/command-line.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/command-line.h +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef COMMAND_LINE_H ++#define COMMAND_LINE_H 1 ++ ++/* Utilities for command-line parsing. */ ++ ++#include "openvswitch/compiler.h" ++ ++struct option; ++ ++/* Command handler context */ ++struct ovs_cmdl_context { ++ /* number of command line arguments */ ++ int argc; ++ /* array of command line arguments */ ++ char **argv; ++ /* private context data defined by the API user */ ++ void *pvt; ++}; ++ ++typedef void (*ovs_cmdl_handler)(struct ovs_cmdl_context *); ++ ++struct ovs_cmdl_command { ++ const char *name; ++ const char *usage; ++ int min_args; ++ int max_args; ++ ovs_cmdl_handler handler; ++ enum { OVS_RO, OVS_RW } mode; /* Does this command modify things? */ ++}; ++ ++char *ovs_cmdl_long_options_to_short_options(const struct option *options); ++ ++struct ovs_cmdl_parsed_option { ++ const struct option *o; ++ char *arg; ++}; ++char *ovs_cmdl_parse_all(int argc, char *argv[], const struct option *, ++ struct ovs_cmdl_parsed_option **, size_t *) ++ OVS_WARN_UNUSED_RESULT; ++ ++char **ovs_cmdl_env_parse_all(int *argcp, char *argv_[], ++ const char *env_options); ++ ++void ovs_cmdl_print_options(const struct option *options); ++void ovs_cmdl_print_commands(const struct ovs_cmdl_command *commands); ++ ++void ovs_cmdl_run_command(struct ovs_cmdl_context *, ++ const struct ovs_cmdl_command[]); ++void ovs_cmdl_run_command_read_only(struct ovs_cmdl_context *, ++ const struct ovs_cmdl_command[]); ++ ++void ovs_cmdl_proctitle_init(int argc, char **argv); ++#if defined(__FreeBSD__) || defined(__NetBSD__) ++#define ovs_cmdl_proctitle_set setproctitle ++#else ++void ovs_cmdl_proctitle_set(const char *, ...) ++ OVS_PRINTF_FORMAT(1, 2); ++#endif ++void ovs_cmdl_proctitle_restore(void); ++ ++#endif /* command-line.h */ +Index: openvswitch-2.17.2/include/internal/crc32c.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/crc32c.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2012 The University of Waikato. ++ * Author: Joe Stringer ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef CRC32C_H ++#define CRC32C_H 1 ++ ++#include "openvswitch/types.h" ++ ++ovs_be32 crc32c(const uint8_t *data, size_t); ++ ++#endif /* crc32c.h */ +Index: openvswitch-2.17.2/include/internal/csum.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/csum.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2008, 2011, 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef CSUM_H ++#define CSUM_H 1 ++ ++#include ++#include ++#include "openvswitch/types.h" ++ ++struct in6_addr; ++ ++ovs_be16 csum(const void *, size_t); ++uint32_t csum_continue(uint32_t partial, const void *, size_t); ++ovs_be16 csum_finish(uint32_t partial); ++ovs_be16 recalc_csum16(ovs_be16 old_csum, ovs_be16 old_u16, ovs_be16 new_u16); ++ovs_be16 recalc_csum32(ovs_be16 old_csum, ovs_be32 old_u32, ovs_be32 new_u32); ++ovs_be16 recalc_csum48(ovs_be16 old_csum, const struct eth_addr old_mac, ++ const struct eth_addr new_mac); ++ovs_be16 recalc_csum128(ovs_be16 old_csum, ovs_16aligned_be32 old_u32[4], ++ const struct in6_addr *); ++ ++#ifndef __CHECKER__ ++/* Adds the 16 bits in 'new' to the partial IP checksum 'partial' and returns ++ * the updated checksum. (To start a new checksum, pass 0 for 'partial'. To ++ * obtain the finished checksum, pass the return value to csum_finish().) */ ++static inline uint32_t ++csum_add16(uint32_t partial, ovs_be16 new) ++{ ++ return partial + new; ++} ++ ++/* Adds the 32 bits in 'new' to the partial IP checksum 'partial' and returns ++ * the updated checksum. (To start a new checksum, pass 0 for 'partial'. To ++ * obtain the finished checksum, pass the return value to csum_finish().) */ ++static inline uint32_t ++csum_add32(uint32_t partial, ovs_be32 new) ++{ ++ return partial + (new >> 16) + (new & 0xffff); ++} ++#else ++uint32_t csum_add16(uint32_t partial, ovs_be16); ++uint32_t csum_add32(uint32_t partial, ovs_be32); ++#endif ++ ++#endif /* csum.h */ +Index: openvswitch-2.17.2/include/internal/daemon.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/daemon.h +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DAEMON_H ++#define DAEMON_H 1 ++ ++#include ++#include ++#include ++ ++/* This file provides an interface for utilities to run in the background ++ * as daemons on POSIX platforms like Linux or as services on Windows platform. ++ * Some of the functionalities defined in this file are only applicable to ++ * POSIX platforms and some are applicable only on Windows. As such, the ++ * function definitions unique to each platform are separated out with ++ * ifdef macros. More descriptive comments on individual functions are provided ++ * in daemon-unix.c (for POSIX platforms) and daemon-windows.c (for Windows). ++ ++ * The DAEMON_OPTION_ENUMS, DAEMON_LONG_OPTIONS and DAEMON_OPTION_HANDLERS ++ * macros are useful for parsing command-line options in individual utilities. ++ * For e.g., the command-line option "--monitor" is recognized on Linux ++ * and results in calling the daemon_set_monitor() function. The same option is ++ * not recognized on Windows platform. ++ */ ++ ++#ifndef _WIN32 ++#define DAEMON_OPTION_ENUMS \ ++ OPT_DETACH, \ ++ OPT_NO_SELF_CONFINEMENT, \ ++ OPT_NO_CHDIR, \ ++ OPT_OVERWRITE_PIDFILE, \ ++ OPT_PIDFILE, \ ++ OPT_MONITOR, \ ++ OPT_USER_GROUP ++ ++#define DAEMON_LONG_OPTIONS \ ++ {"detach", no_argument, NULL, OPT_DETACH}, \ ++ {"no-self-confinement", no_argument, NULL, OPT_NO_SELF_CONFINEMENT}, \ ++ {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ ++ {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ ++ {"overwrite-pidfile", no_argument, NULL, OPT_OVERWRITE_PIDFILE}, \ ++ {"monitor", no_argument, NULL, OPT_MONITOR}, \ ++ {"user", required_argument, NULL, OPT_USER_GROUP} ++ ++#define DAEMON_OPTION_HANDLERS \ ++ case OPT_DETACH: \ ++ set_detach(); \ ++ break; \ ++ \ ++ case OPT_NO_SELF_CONFINEMENT: \ ++ daemon_disable_self_confinement(); \ ++ break; \ ++ \ ++ case OPT_NO_CHDIR: \ ++ set_no_chdir(); \ ++ break; \ ++ \ ++ case OPT_PIDFILE: \ ++ set_pidfile(optarg); \ ++ break; \ ++ \ ++ case OPT_OVERWRITE_PIDFILE: \ ++ ignore_existing_pidfile(); \ ++ break; \ ++ \ ++ case OPT_MONITOR: \ ++ daemon_set_monitor(); \ ++ break; \ ++ \ ++ case OPT_USER_GROUP: \ ++ daemon_set_new_user(optarg); \ ++ break; ++ ++#define DAEMON_OPTION_CASES \ ++ case OPT_DETACH: \ ++ case OPT_NO_SELF_CONFINEMENT: \ ++ case OPT_NO_CHDIR: \ ++ case OPT_PIDFILE: \ ++ case OPT_OVERWRITE_PIDFILE: \ ++ case OPT_MONITOR: \ ++ case OPT_USER_GROUP: ++ ++void set_detach(void); ++void daemon_set_monitor(void); ++void set_no_chdir(void); ++void ignore_existing_pidfile(void); ++pid_t read_pidfile(const char *name); ++#else ++#define DAEMON_OPTION_ENUMS \ ++ OPT_DETACH, \ ++ OPT_NO_SELF_CONFINEMENT, \ ++ OPT_NO_CHDIR, \ ++ OPT_PIDFILE, \ ++ OPT_PIPE_HANDLE, \ ++ OPT_SERVICE, \ ++ OPT_SERVICE_MONITOR, \ ++ OPT_USER_GROUP ++ ++#define DAEMON_LONG_OPTIONS \ ++ {"detach", no_argument, NULL, OPT_DETACH}, \ ++ {"no-self-confinement", no_argument, NULL, OPT_NO_SELF_CONFINEMENT}, \ ++ {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ ++ {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ ++ {"pipe-handle", required_argument, NULL, OPT_PIPE_HANDLE}, \ ++ {"service", no_argument, NULL, OPT_SERVICE}, \ ++ {"service-monitor", no_argument, NULL, OPT_SERVICE_MONITOR}, \ ++ {"user", required_argument, NULL, OPT_USER_GROUP} ++ ++#define DAEMON_OPTION_HANDLERS \ ++ case OPT_DETACH: \ ++ set_detach(); \ ++ break; \ ++ \ ++ case OPT_NO_SELF_CONFINEMENT: \ ++ daemon_disable_self_confinement(); \ ++ break; \ ++ \ ++ case OPT_NO_CHDIR: \ ++ break; \ ++ \ ++ case OPT_PIDFILE: \ ++ set_pidfile(optarg); \ ++ break; \ ++ \ ++ case OPT_PIPE_HANDLE: \ ++ set_pipe_handle(optarg); \ ++ break; \ ++ \ ++ case OPT_SERVICE: \ ++ set_detach(); \ ++ break; \ ++ \ ++ case OPT_SERVICE_MONITOR: \ ++ break; \ ++ \ ++ case OPT_USER_GROUP: \ ++ daemon_set_new_user(optarg); ++ ++#define DAEMON_OPTION_CASES \ ++ case OPT_DETACH: \ ++ case OPT_NO_SELF_CONFINEMENT: \ ++ case OPT_NO_CHDIR: \ ++ case OPT_PIDFILE: \ ++ case OPT_PIPE_HANDLE: \ ++ case OPT_SERVICE: \ ++ case OPT_SERVICE_MONITOR: \ ++ case OPT_USER_GROUP: ++ ++void control_handler(DWORD request); ++void set_pipe_handle(const char *pipe_handle); ++void set_detach(void); ++#endif /* _WIN32 */ ++ ++bool get_detach(void); ++void daemon_save_fd(int fd); ++void daemonize(void); ++void daemonize_start(bool access_datapath); ++void daemonize_complete(void); ++void daemon_set_new_user(const char * user_spec); ++void daemon_become_new_user(bool access_datapath); ++void daemon_usage(void); ++void daemon_disable_self_confinement(void); ++bool daemon_should_self_confine(void); ++void service_start(int *argcp, char **argvp[]); ++void service_stop(void); ++bool should_service_stop(void); ++void set_pidfile(const char *name); ++void close_standard_fds(void); ++ ++#endif /* daemon.h */ +Index: openvswitch-2.17.2/include/internal/db-ctl-base.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/db-ctl-base.h +@@ -0,0 +1,282 @@ ++/* ++ * Copyright (c) 2015, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DB_CTL_BASE_H ++#define DB_CTL_BASE_H 1 ++ ++#include "openvswitch/compiler.h" ++#include "openvswitch/dynamic-string.h" ++#include "openvswitch/shash.h" ++ ++struct ctl_context; ++struct option; ++struct ovsdb_idl; ++struct ovsdb_idl_row; ++struct ovsdb_idl_txn; ++struct ovsdb_symbol_table; ++struct table; ++ ++/* This library module contains the common parts for ovsdb manipulation ++ * (structs, commands and functions). To utilize this module, user must ++ * define the following: ++ * ++ * - the command syntaxes for each command. (See 'struct ctl_command_syntax' ++ * for more info) and regiters them using ctl_register_commands(). ++ * ++ * - the *ctl command context by inheriting the 'struct ctl_context' for ++ * additional commands implemented by user. (See 'struct ctl_context' for ++ * more info) ++*/ ++ ++/* ctl_fatal() also logs the error, so it is preferred in this file. */ ++#define ovs_fatal please_use_ctl_fatal_instead_of_ovs_fatal ++ ++struct ctl_table_class; ++struct ovsdb_idl_class; ++struct ovsdb_idl_table_class; ++struct cmd_show_table; ++ ++/* ctl_init() figures out the number of tables on its own and flags an error if ++ * 'ctl_classes' was defined with the wrong number of elements. */ ++#define ctl_init(idl_class, table_classes, ctl_classes, cmd_show_table, \ ++ ctl_exit_func) \ ++ (BUILD_ASSERT(ARRAY_SIZE(table_classes) == ARRAY_SIZE(ctl_classes)), \ ++ ctl_init__(idl_class, ctl_classes, cmd_show_table, ctl_exit_func)) ++void ctl_init__(const struct ovsdb_idl_class *, const struct ctl_table_class *, ++ const struct cmd_show_table *cmd_show_tables, ++ void (*ctl_exit_func)(int status)); ++char *ctl_default_db(void); ++void ctl_error(struct ctl_context *, const char *, ...) ++OVS_PRINTF_FORMAT(2, 3); ++OVS_NO_RETURN void ctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2); ++ ++/* *ctl command syntax structure, to be defined by each command implementation. ++ * ++ * Execution Path ++ * ============== ++ * ++ * Three stylized functions accompany each of these data structures: ++ * ++ * "pre-run" "run" "post-run" ++ * --------------- ------------ ----------------- ++ * *ctl ->prerequisites ->run ->postprocess ++ * ++ * Any *ctl command implementation should go through the following execution ++ * path: ++ * ++ * 1. parses user command-line input and finds the corresponding syntax ++ * structures. ++ * ++ * 2. calls prerequisites() for getting the columns or tables used by each ++ * command. ++ * ++ * 3. calls run() to execute each command and to generate output. ++ * ++ * 4. calls postprocess() after output has been committed. (Only needed ++ * by 'create' command sofar) ++ * ++ * Execution Context ++ * ================= ++ * ++ * Each of the stylized functions requires the 'struct ctl_context' as input ++ * to provide context e.g. command-line arguments, table to be modified. User ++ * may define more specific context (by inheriting 'struct ctl_context') and ++ * write stylized functions that use it. In that case, CONTAINER_OF() can ++ * be used to cast the generic context to the specific one. ++ * ++ * */ ++struct ctl_command_syntax { ++ const char *name; /* e.g. "add-br" */ ++ int min_args; /* Min number of arguments following name. */ ++ int max_args; /* Max number of arguments following name. */ ++ ++ /* Names that roughly describe the arguments that the command ++ * uses. These should be similar to the names displayed in the ++ * man page or in the help output. */ ++ const char *arguments; ++ ++ /* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table() for ++ * each column or table in ctx->idl that it uses. */ ++ void (*prerequisites)(struct ctl_context *ctx); ++ ++ /* Does the actual work of the command and puts the command's output, if ++ * any, in ctx->output or ctx->table. ++ * ++ * Alternatively, if some prerequisite of the command is not met and the ++ * caller should wait for something to change and then retry, it may set ++ * ctx->try_again to true. (Only the "wait-until" command currently does ++ * this.) */ ++ void (*run)(struct ctl_context *ctx); ++ ++ /* If nonnull, called after the transaction has been successfully ++ * committed. ctx->output is the output from the "run" function, which ++ * this function may modify and otherwise postprocess as needed. (Only the ++ * "create" command currently does any postprocessing.) */ ++ void (*postprocess)(struct ctl_context *ctx); ++ ++ /* A comma-separated list of supported options, e.g. "--a,--b", or the ++ * empty string if the command does not support any options. ++ * ++ * Arguments are determined by appending special characters to option ++ * names: ++ * ++ * - Append "=" (e.g. "--id=") for a required argument. ++ * ++ * - Append "?" (e.g. "--ovs?") for an optional argument. ++ * ++ * - Otherwise an option does not accept an argument. */ ++ const char *options; ++ ++ enum { RO, RW } mode; /* Does this command modify the database? */ ++}; ++ ++/* A command extracted from command-line input plus the structs for ++ * output generation. */ ++struct ctl_command { ++ /* Data that remains constant after initialization. */ ++ const struct ctl_command_syntax *syntax; ++ int argc; ++ char **argv; ++ struct shash options; ++ ++ /* Data modified by commands. */ ++ struct ds output; ++ struct table *table; ++}; ++ ++bool ctl_might_write_to_db(const struct ctl_command *, size_t n); ++const char *ctl_get_db_cmd_usage(void); ++ ++const char *ctl_list_db_tables_usage(void); ++void ctl_print_commands(void); ++void ctl_print_options(const struct option *); ++void ctl_add_cmd_options(struct option **, size_t *n_options_p, ++ size_t *allocated_options_p, int opt_val); ++void ctl_register_commands(const struct ctl_command_syntax *); ++char * OVS_WARN_UNUSED_RESULT ctl_parse_commands( ++ int argc, char *argv[], struct shash *local_options, ++ struct ctl_command **commandsp, size_t *n_commandsp); ++ ++/* Sometimes, it is desirable to print the table with weak reference to ++ * rows in a 'cmd_show_table' table. In that case, the 'weak_ref_table' ++ * should be used and user must define all variables. */ ++struct weak_ref_table { ++ const struct ovsdb_idl_table_class *table; ++ const struct ovsdb_idl_column *name_column; ++ /* This colum must be a weak reference to the owning ++ * 'struct cmd_show_table''s table row. */ ++ const struct ovsdb_idl_column *wref_column; ++}; ++ ++/* This struct is for organizing the 'show' command output where: ++ * ++ * - 'table' is the table to show. ++ * ++ * - if 'name_column' is not null, it is used as the name for each row ++ * in 'table'. ++ * ++ * - 'columns[]' allows user to specify the print of additional columns ++ * in 'table'. ++ * ++ * - if 'wref_table' is populated, print 'wref_table.name_column' for ++ * each row in table 'wref_table.table' that has a reference to 'table' ++ * in 'wref_table.wref_column'. Every field must be populated. ++ * ++ * */ ++struct cmd_show_table { ++ const struct ovsdb_idl_table_class *table; ++ const struct ovsdb_idl_column *name_column; ++ const struct ovsdb_idl_column *columns[4]; /* Seems like a good number. */ ++ const struct weak_ref_table wref_table; ++}; ++ ++ ++/* The base context struct for conducting the common database ++ * operations (commands listed in 'db_ctl_commands'). User should ++ * define the per-schema context by inheriting this struct as base. ++ * ++ * Database Caches ++ * =============== ++ * ++ * User may implement caches for contents of the database to facilitate ++ * specific commands. In that case, the common commands defined in ++ * 'db_ctl_commands' that may invalidate the cache must call the ++ * invalidate_cache(). ++ * ++ **/ ++struct ctl_context { ++ /* Read-only. */ ++ int argc; ++ char **argv; ++ struct shash options; ++ ++ /* Modifiable state. */ ++ char *error; ++ struct ds output; ++ struct table *table; ++ struct ovsdb_idl *idl; ++ struct ovsdb_idl_txn *txn; ++ struct ovsdb_symbol_table *symtab; ++ ++ /* For implementation with a cache of the contents of the database, ++ * this function will be called when the database is changed and the ++ * change makes the cache no longer valid. */ ++ void (*invalidate_cache_cb)(struct ctl_context *); ++ ++ /* A command may set this member to true if some prerequisite is not met ++ * and the caller should wait for something to change and then retry. */ ++ bool try_again; ++}; ++ ++void ctl_context_init_command(struct ctl_context *, struct ctl_command *); ++void ctl_context_init(struct ctl_context *, struct ctl_command *, ++ struct ovsdb_idl *, struct ovsdb_idl_txn *, ++ struct ovsdb_symbol_table *, ++ void (*invalidate_cache)(struct ctl_context *)); ++void ctl_context_done_command(struct ctl_context *, struct ctl_command *); ++void ctl_context_done(struct ctl_context *, struct ctl_command *); ++ ++/* A way to identify a particular row in the database based on a user-provided ++ * string. If all fields are NULL, the struct is ignored. Otherwise, ++ * 'name_column' designates a column whose table is searched for rows that ++ * match with the user string. If 'key' is NULL, then 'name_column' should be ++ * a string or integer-valued column; otherwise it should be a map from a ++ * string to one of those types and the value corresponding to 'key' is what is ++ * matched. If a matching row is found, then: ++ * ++ * - If 'uuid_column' is NULL, the matching row is the final row. ++ * ++ * - Otherwise 'uuid_column' must designate a UUID-typed column whose value ++ * refers to exactly one row, which is the final row. ++ */ ++struct ctl_row_id { ++ const struct ovsdb_idl_column *name_column; ++ const char *key; ++ const struct ovsdb_idl_column *uuid_column; ++}; ++ ++struct ctl_table_class { ++ struct ctl_row_id row_ids[4]; ++}; ++ ++char *ctl_get_row(struct ctl_context *, const struct ovsdb_idl_table_class *, ++ const char *record_id, bool must_exist, ++ const struct ovsdb_idl_row **); ++ ++char *ctl_set_column(const char *table_name, const struct ovsdb_idl_row *, ++ const char *arg, struct ovsdb_symbol_table *); ++ ++#endif /* db-ctl-base.h */ +Index: openvswitch-2.17.2/include/internal/dhparams.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/dhparams.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (c) 2008, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DHPARAMS_H ++#define DHPARAMS_H 1 ++ ++#include ++#include ++ ++DH *get_dh2048(void); ++DH *get_dh4096(void); ++ ++#endif /* dhparams.h */ +Index: openvswitch-2.17.2/include/internal/dirs.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/dirs.h +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef DIRS_H ++#define DIRS_H 1 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++const char *ovs_sysconfdir(void); /* /usr/local/etc */ ++const char *ovs_pkgdatadir(void); /* /usr/local/share/openvswitch */ ++const char *ovs_rundir(void); /* /usr/local/var/run/openvswitch */ ++const char *ovs_logdir(void); /* /usr/local/var/log/openvswitch */ ++const char *ovs_dbdir(void); /* /usr/local/etc/openvswitch */ ++const char *ovs_bindir(void); /* /usr/local/bin */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* dirs.h */ +Index: openvswitch-2.17.2/include/internal/fatal-signal.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/fatal-signal.h +@@ -0,0 +1,52 @@ ++/* ++ * 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef FATAL_SIGNAL_H ++#define FATAL_SIGNAL_H 1 ++ ++#ifndef _WIN32 ++#include ++#endif ++#include ++ ++/* Basic interface. */ ++void fatal_signal_init(void); ++void fatal_signal_add_hook(void (*hook_cb)(void *aux), ++ void (*cancel_cb)(void *aux), void *aux, ++ bool run_at_exit); ++void fatal_signal_fork(void); ++void fatal_signal_run(void); ++void fatal_signal_wait(void); ++void fatal_ignore_sigpipe(void); ++void fatal_signal_atexit_handler(void); ++ ++/* Convenience functions for unlinking files upon termination. ++ * ++ * These functions also unlink the files upon normal process termination via ++ * exit(). */ ++void fatal_signal_add_file_to_unlink(const char *); ++void fatal_signal_remove_file_to_unlink(const char *); ++int fatal_signal_unlink_file_now(const char *); ++ ++/* Interface for other code that catches one of our signals and needs to pass ++ * it through. */ ++void fatal_signal_handler(int sig_nr); ++ ++#ifndef _WIN32 ++void fatal_signal_block(sigset_t *prev_mask); ++#endif ++ ++#endif /* fatal-signal.h */ +Index: openvswitch-2.17.2/include/internal/hash-aarch64.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/hash-aarch64.h +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (c) 2019 Arm Limited ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements HASH operation primitives on aarch64. */ ++#ifndef HASH_AARCH64_H ++#define HASH_AARCH64_H 1 ++ ++#ifndef HASH_H ++#error "This header should only be included indirectly via hash.h." ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++ ++static inline uint32_t hash_add(uint32_t hash, uint32_t data) ++{ ++ return __crc32cw(hash, data); ++} ++ ++/* Add the halves of 'data' in the memory order. */ ++static inline uint32_t hash_add64(uint32_t hash, uint64_t data) ++{ ++ return __crc32cd(hash, data); ++} ++ ++static inline uint32_t hash_finish(uint32_t hash, uint64_t final) ++{ ++ /* The finishing multiplier 0x805204f3 has been experimentally ++ * derived to pass the testsuite hash tests. */ ++ hash = __crc32cd(hash, final) * 0x805204f3; ++ return hash ^ hash >> 16; /* Increase entropy in LSBs. */ ++} ++ ++/* Returns the hash of the 'n' 32-bit words at 'p_', starting from 'basis'. ++ * We access 'p_' as a uint64_t pointer. ++ * ++ * This is inlined for the compiler to have access to the 'n_words', which ++ * in many cases is a constant. */ ++static inline uint32_t ++hash_words_inline(const uint32_t p_[], size_t n_words, uint32_t basis) ++{ ++ const uint64_t *p = (const void *)p_; ++ uint32_t hash1 = basis; ++ uint32_t hash2 = 0; ++ uint32_t hash3 = n_words; ++ const uint32_t *endp = (const uint32_t *)p + n_words; ++ const uint64_t *limit = p + n_words / 2 - 3; ++ ++ while (p <= limit) { ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cd(hash2, p[1]); ++ hash3 = __crc32cd(hash3, p[2]); ++ p += 3; ++ } ++ switch (endp - (const uint32_t *)p) { ++ case 1: ++ hash1 = __crc32cw(hash1, *(const uint32_t *)&p[0]); ++ break; ++ case 2: ++ hash1 = __crc32cd(hash1, p[0]); ++ break; ++ case 3: ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cw(hash2, *(const uint32_t *)&p[1]); ++ break; ++ case 4: ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cd(hash2, p[1]); ++ break; ++ case 5: ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cd(hash2, p[1]); ++ hash3 = __crc32cw(hash3, *(const uint32_t *)&p[2]); ++ break; ++ } ++ return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3); ++} ++ ++/* A simpler version for 64-bit data. ++ * 'n_words' is the count of 64-bit words, basis is 64 bits. */ ++static inline uint32_t ++hash_words64_inline(const uint64_t p[], size_t n_words, uint32_t basis) ++{ ++ uint32_t hash1 = basis; ++ uint32_t hash2 = 0; ++ uint32_t hash3 = n_words; ++ const uint64_t *endp = p + n_words; ++ const uint64_t *limit = endp - 3; ++ ++ while (p <= limit) { ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cd(hash2, p[1]); ++ hash3 = __crc32cd(hash3, p[2]); ++ p += 3; ++ } ++ switch (endp - p) { ++ case 1: ++ hash1 = __crc32cd(hash1, p[0]); ++ break; ++ case 2: ++ hash1 = __crc32cd(hash1, p[0]); ++ hash2 = __crc32cd(hash2, p[1]); ++ break; ++ } ++ return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3); ++} ++ ++static inline uint32_t hash_uint64_basis(const uint64_t x, ++ const uint32_t basis) ++{ ++ /* '23' chosen to mix bits enough for the test-hash to pass. */ ++ return hash_finish(hash_add64(basis, x), 23); ++} ++ ++static inline uint32_t hash_uint64(const uint64_t x) ++{ ++ return hash_uint64_basis(x, 0); ++} ++ ++static inline uint32_t hash_2words(uint32_t x, uint32_t y) ++{ ++ return hash_uint64((uint64_t)y << 32 | x); ++} ++ ++static inline uint32_t hash_pointer(const void *p, uint32_t basis) ++{ ++ return hash_uint64_basis((uint64_t) (uintptr_t) p, basis); ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* hash-aarch64.h */ +Index: openvswitch-2.17.2/include/internal/hmapx.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/hmapx.h +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (c) 2011, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef HMAPX_H ++#define HMAPX_H ++ ++#include "openvswitch/hmap.h" ++ ++struct hmapx_node { ++ struct hmap_node hmap_node; ++ void *data; ++}; ++ ++/* A set of "void *" pointers. */ ++struct hmapx { ++ struct hmap map; ++}; ++ ++#define HMAPX_INITIALIZER(HMAPX) { HMAP_INITIALIZER(&(HMAPX)->map) } ++ ++/* Basics. */ ++void hmapx_init(struct hmapx *); ++void hmapx_destroy(struct hmapx *); ++void hmapx_clone(struct hmapx *, const struct hmapx *); ++void hmapx_swap(struct hmapx *, struct hmapx *); ++void hmapx_moved(struct hmapx *); ++ ++/* Count. */ ++bool hmapx_is_empty(const struct hmapx *); ++size_t hmapx_count(const struct hmapx *); ++ ++/* Insertion. */ ++struct hmapx_node *hmapx_add(struct hmapx *, void *); ++void hmapx_add_assert(struct hmapx *, void *); ++ ++/* Deletion. */ ++void hmapx_clear(struct hmapx *); ++void hmapx_delete(struct hmapx *, struct hmapx_node *); ++bool hmapx_find_and_delete(struct hmapx *, const void *); ++void hmapx_find_and_delete_assert(struct hmapx *, const void *); ++ ++/* Search. */ ++struct hmapx_node *hmapx_find(const struct hmapx *, const void *); ++bool hmapx_contains(const struct hmapx *, const void *); ++bool hmapx_equals(const struct hmapx *, const struct hmapx *); ++ ++/* Iteration. */ ++ ++/* Iterates through every hmapx_node in HMAPX. */ ++#define HMAPX_FOR_EACH(NODE, HMAPX) \ ++ HMAP_FOR_EACH_INIT(NODE, hmap_node, &(HMAPX)->map, \ ++ BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ ++ BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) ++ ++/* Safe when NODE may be freed (not needed when NODE may be removed from the ++ * hash map but its members remain accessible and intact). */ ++#define HMAPX_FOR_EACH_SAFE_SHORT(NODE, HMAPX) \ ++ HMAP_FOR_EACH_SAFE_SHORT_INIT (NODE, hmap_node, &(HMAPX)->map, \ ++ BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ ++ BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) ++ ++#define HMAPX_FOR_EACH_SAFE_LONG(NODE, NEXT, HMAPX) \ ++ HMAP_FOR_EACH_SAFE_LONG_INIT (NODE, NEXT, hmap_node, &(HMAPX)->map, \ ++ BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ ++ BUILD_ASSERT_TYPE(NEXT, struct hmapx_node *), \ ++ BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) ++ ++#define HMAPX_FOR_EACH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(HMAPX_FOR_EACH_SAFE_LONG, \ ++ HMAPX_FOR_EACH_SAFE_SHORT, \ ++ 3, __VA_ARGS__) ++ ++#endif /* hmapx.h */ +Index: openvswitch-2.17.2/include/internal/id-pool.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/id-pool.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * Copyright (c) 2014 Netronome. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef ID_POOL_H ++#define ID_POOL_H ++ ++#include ++#include ++#include ++ ++struct id_pool; ++ ++struct id_pool *id_pool_create(uint32_t base, uint32_t n_ids); ++void id_pool_destroy(struct id_pool *); ++bool id_pool_alloc_id(struct id_pool *, uint32_t *id); ++void id_pool_free_id(struct id_pool *, uint32_t id); ++void id_pool_add(struct id_pool *, uint32_t id); ++ ++/* ++ * ID pool. ++ * ======== ++ * ++ * Pool of unique 32bit ids. ++ * Allocation always returns the lowest available id. ++ * ++ * Thread-safety ++ * ============= ++ * ++ * APIs are not thread safe. ++ */ ++#endif /* id-pool.h */ +Index: openvswitch-2.17.2/include/internal/jsonrpc.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/jsonrpc.h +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (c) 2009, 2010, 2012, 2013, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef JSONRPC_H ++#define JSONRPC_H 1 ++ ++/* This is an implementation of the JSON-RPC 1.0 specification defined at ++ * http://json-rpc.org/wiki/specification. */ ++ ++#include ++#include ++#include "openvswitch/types.h" ++ ++struct json; ++struct jsonrpc_msg; ++struct pstream; ++struct reconnect_stats; ++struct stream; ++struct svec; ++ ++/* API for a JSON-RPC stream. */ ++ ++/* Default port numbers. ++ * ++ * OVSDB_OLD_PORT defines the original port number used by OVS. ++ * OVSDB_PORT defines the official port number assigned by IANA. */ ++#define OVSDB_OLD_PORT 6632 ++#define OVSDB_PORT 6640 ++ ++int jsonrpc_stream_open(const char *name, struct stream **, uint8_t dscp); ++int jsonrpc_pstream_open(const char *name, struct pstream **, uint8_t dscp); ++ ++struct jsonrpc *jsonrpc_open(struct stream *); ++void jsonrpc_close(struct jsonrpc *); ++ ++void jsonrpc_run(struct jsonrpc *); ++void jsonrpc_wait(struct jsonrpc *); ++ ++int jsonrpc_get_status(const struct jsonrpc *); ++size_t jsonrpc_get_backlog(const struct jsonrpc *); ++void jsonrpc_set_backlog_threshold(struct jsonrpc *, size_t max_n_msgs, ++ size_t max_backlog_bytes); ++ ++unsigned int jsonrpc_get_received_bytes(const struct jsonrpc *); ++const char *jsonrpc_get_name(const struct jsonrpc *); ++ ++int jsonrpc_send(struct jsonrpc *, struct jsonrpc_msg *); ++int jsonrpc_recv(struct jsonrpc *, struct jsonrpc_msg **); ++void jsonrpc_recv_wait(struct jsonrpc *); ++ ++int jsonrpc_send_block(struct jsonrpc *, struct jsonrpc_msg *); ++int jsonrpc_recv_block(struct jsonrpc *, struct jsonrpc_msg **); ++int jsonrpc_transact_block(struct jsonrpc *, struct jsonrpc_msg *, ++ struct jsonrpc_msg **); ++ ++/* Messages. */ ++enum jsonrpc_msg_type { ++ JSONRPC_REQUEST, /* Request. */ ++ JSONRPC_NOTIFY, /* Notification. */ ++ JSONRPC_REPLY, /* Successful reply. */ ++ JSONRPC_ERROR /* Error reply. */ ++}; ++ ++struct jsonrpc_msg { ++ enum jsonrpc_msg_type type; ++ char *method; /* Request or notification only. */ ++ struct json *params; /* Request or notification only. */ ++ struct json *result; /* Successful reply only. */ ++ struct json *error; /* Error reply only. */ ++ struct json *id; /* Request or reply only. */ ++}; ++ ++struct jsonrpc_msg *jsonrpc_create_request(const char *method, ++ struct json *params, ++ struct json **idp); ++struct jsonrpc_msg *jsonrpc_create_notify(const char *method, ++ struct json *params); ++struct jsonrpc_msg *jsonrpc_create_reply(struct json *result, ++ const struct json *id); ++struct jsonrpc_msg *jsonrpc_create_error(struct json *error, ++ const struct json *id); ++ ++struct jsonrpc_msg *jsonrpc_msg_clone(const struct jsonrpc_msg *); ++ ++const char *jsonrpc_msg_type_to_string(enum jsonrpc_msg_type); ++char *jsonrpc_msg_is_valid(const struct jsonrpc_msg *); ++void jsonrpc_msg_destroy(struct jsonrpc_msg *); ++ ++char *jsonrpc_msg_from_json(struct json *, struct jsonrpc_msg **); ++struct json *jsonrpc_msg_to_json(struct jsonrpc_msg *); ++ ++char *jsonrpc_msg_to_string(const struct jsonrpc_msg *); ++ ++/* A JSON-RPC session with reconnection. */ ++ ++struct jsonrpc_session *jsonrpc_session_open(const char *name, bool retry); ++struct jsonrpc_session *jsonrpc_session_open_multiple(const struct svec *, ++ bool retry); ++struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *, ++ uint8_t); ++void jsonrpc_session_close(struct jsonrpc_session *); ++ ++struct jsonrpc *jsonrpc_session_steal(struct jsonrpc_session *); ++void jsonrpc_session_replace(struct jsonrpc_session *, struct jsonrpc *); ++ ++void jsonrpc_session_run(struct jsonrpc_session *); ++void jsonrpc_session_wait(struct jsonrpc_session *); ++ ++size_t jsonrpc_session_get_backlog(const struct jsonrpc_session *); ++const char *jsonrpc_session_get_name(const struct jsonrpc_session *); ++size_t jsonrpc_session_get_n_remotes(const struct jsonrpc_session *); ++ ++int jsonrpc_session_send(struct jsonrpc_session *, struct jsonrpc_msg *); ++struct jsonrpc_msg *jsonrpc_session_recv(struct jsonrpc_session *); ++void jsonrpc_session_recv_wait(struct jsonrpc_session *); ++ ++bool jsonrpc_session_is_alive(const struct jsonrpc_session *); ++bool jsonrpc_session_is_connected(const struct jsonrpc_session *); ++unsigned int jsonrpc_session_get_seqno(const struct jsonrpc_session *); ++int jsonrpc_session_get_status(const struct jsonrpc_session *); ++int jsonrpc_session_get_last_error(const struct jsonrpc_session *); ++void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *, ++ struct reconnect_stats *); ++ ++void jsonrpc_session_enable_reconnect(struct jsonrpc_session *); ++void jsonrpc_session_force_reconnect(struct jsonrpc_session *); ++void jsonrpc_session_reset_backoff(struct jsonrpc_session *); ++ ++void jsonrpc_session_set_max_backoff(struct jsonrpc_session *, ++ int max_backoff); ++void jsonrpc_session_set_probe_interval(struct jsonrpc_session *, ++ int probe_interval); ++void jsonrpc_session_set_dscp(struct jsonrpc_session *, ++ uint8_t dscp); ++void jsonrpc_session_set_backlog_threshold(struct jsonrpc_session *, ++ size_t max_n_msgs, ++ size_t max_backlog_bytes); ++const char *jsonrpc_session_get_id(const struct jsonrpc_session *); ++ ++#endif /* jsonrpc.h */ +Index: openvswitch-2.17.2/include/internal/memory.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/memory.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2012 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef MEMORY_H ++#define MEMORY_H 1 ++ ++/* Memory usage monitor. ++ * ++ * This is intended to be called as part of a daemon's main loop. After some ++ * time to allow the daemon to allocate an initial memory usage, it logs some ++ * memory usage information (most of which must actually be provided by the ++ * client). At intervals, if the daemon's memory usage has grown ++ * significantly, it again logs information. ++ * ++ * The monitor also has a unixctl interface. ++ * ++ * Intended usage in the program's main loop is like this: ++ * ++ * for (;;) { ++ * memory_run(); ++ * if (memory_should_report()) { ++ * struct simap usage; ++ * ++ * simap_init(&usage); ++ * ...fill in 'usage' with meaningful statistics... ++ * memory_report(&usage); ++ * simap_destroy(&usage); ++ * } ++ * ++ * ... ++ * ++ * memory_wait(); ++ * poll_block(); ++ * } ++ */ ++ ++#include ++ ++struct simap; ++ ++void memory_run(void); ++void memory_wait(void); ++ ++bool memory_should_report(void); ++void memory_report(const struct simap *usage); ++ ++#endif /* memory.h */ +Index: openvswitch-2.17.2/include/internal/netdev-afxdp.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/netdev-afxdp.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (c) 2018, 2019 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NETDEV_AFXDP_H ++#define NETDEV_AFXDP_H 1 ++ ++#ifdef HAVE_AF_XDP ++ ++#include ++#include ++ ++/* These functions are Linux AF_XDP specific, so they should be used directly ++ * only by Linux-specific code. */ ++ ++enum afxdp_mode { ++ OVS_AF_XDP_MODE_UNSPEC, ++ OVS_AF_XDP_MODE_BEST_EFFORT, ++ OVS_AF_XDP_MODE_NATIVE_ZC, ++ OVS_AF_XDP_MODE_NATIVE, ++ OVS_AF_XDP_MODE_GENERIC, ++ OVS_AF_XDP_MODE_MAX, ++}; ++ ++struct dp_packet; ++struct dp_packet_batch; ++struct netdev; ++struct netdev_afxdp_tx_lock; ++struct netdev_custom_stats; ++struct netdev_rxq; ++struct netdev_stats; ++struct smap; ++struct xdp_umem; ++struct xsk_socket_info; ++ ++int netdev_afxdp_rxq_construct(struct netdev_rxq *rxq_); ++void netdev_afxdp_rxq_destruct(struct netdev_rxq *rxq_); ++int netdev_afxdp_init(void); ++int netdev_afxdp_construct(struct netdev *netdev_); ++void netdev_afxdp_destruct(struct netdev *netdev_); ++int netdev_afxdp_verify_mtu_size(const struct netdev *netdev, int mtu); ++ ++int netdev_afxdp_rxq_recv(struct netdev_rxq *rxq_, ++ struct dp_packet_batch *batch, ++ int *qfill); ++int netdev_afxdp_batch_send(struct netdev *netdev_, int qid, ++ struct dp_packet_batch *batch, ++ bool concurrent_txq); ++int netdev_afxdp_set_config(struct netdev *netdev, const struct smap *args, ++ char **errp); ++int netdev_afxdp_get_config(const struct netdev *netdev, struct smap *args); ++int netdev_afxdp_get_stats(const struct netdev *netdev_, ++ struct netdev_stats *stats); ++int netdev_afxdp_get_custom_stats(const struct netdev *netdev, ++ struct netdev_custom_stats *custom_stats); ++ ++ ++void free_afxdp_buf(struct dp_packet *p); ++int netdev_afxdp_reconfigure(struct netdev *netdev); ++void signal_remove_xdp(struct netdev *netdev); ++ ++#else /* !HAVE_AF_XDP */ ++ ++#include "openvswitch/compiler.h" ++ ++struct dp_packet; ++ ++static inline void ++free_afxdp_buf(struct dp_packet *p OVS_UNUSED) ++{ ++ /* Nothing. */ ++} ++ ++#endif /* HAVE_AF_XDP */ ++#endif /* netdev-afxdp.h */ +Index: openvswitch-2.17.2/include/internal/netdev-dpdk.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/netdev-dpdk.h +@@ -0,0 +1,165 @@ ++/* ++ * Copyright (c) 2014, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef NETDEV_DPDK_H ++#define NETDEV_DPDK_H ++ ++#include ++ ++#include "openvswitch/compiler.h" ++ ++struct dp_packet; ++struct netdev; ++ ++#ifdef DPDK_NETDEV ++ ++#include ++ ++void netdev_dpdk_register(void); ++void free_dpdk_buf(struct dp_packet *); ++ ++bool netdev_dpdk_flow_api_supported(struct netdev *); ++ ++int ++netdev_dpdk_rte_flow_destroy(struct netdev *netdev, ++ struct rte_flow *rte_flow, ++ struct rte_flow_error *error); ++struct rte_flow * ++netdev_dpdk_rte_flow_create(struct netdev *netdev, ++ const struct rte_flow_attr *attr, ++ const struct rte_flow_item *items, ++ const struct rte_flow_action *actions, ++ struct rte_flow_error *error); ++int ++netdev_dpdk_rte_flow_query_count(struct netdev *netdev, ++ struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, ++ struct rte_flow_error *error); ++int ++netdev_dpdk_get_port_id(struct netdev *netdev); ++ ++#ifdef ALLOW_EXPERIMENTAL_API ++ ++int netdev_dpdk_rte_flow_tunnel_decap_set(struct netdev *, ++ struct rte_flow_tunnel *, ++ struct rte_flow_action **, ++ uint32_t *num_of_actions, ++ struct rte_flow_error *); ++int netdev_dpdk_rte_flow_tunnel_match(struct netdev *, ++ struct rte_flow_tunnel *, ++ struct rte_flow_item **, ++ uint32_t *num_of_items, ++ struct rte_flow_error *); ++int netdev_dpdk_rte_flow_get_restore_info(struct netdev *, ++ struct dp_packet *, ++ struct rte_flow_restore_info *, ++ struct rte_flow_error *); ++int netdev_dpdk_rte_flow_tunnel_action_decap_release(struct netdev *, ++ struct rte_flow_action *, ++ uint32_t num_of_actions, ++ struct rte_flow_error *); ++int netdev_dpdk_rte_flow_tunnel_item_release(struct netdev *, ++ struct rte_flow_item *, ++ uint32_t num_of_items, ++ struct rte_flow_error *); ++ ++#else ++ ++static inline void ++set_error(struct rte_flow_error *error, enum rte_flow_error_type type) ++{ ++ if (!error) { ++ return; ++ } ++ error->type = type; ++ error->cause = NULL; ++ error->message = NULL; ++} ++ ++static inline int ++netdev_dpdk_rte_flow_tunnel_decap_set( ++ struct netdev *netdev OVS_UNUSED, ++ struct rte_flow_tunnel *tunnel OVS_UNUSED, ++ struct rte_flow_action **actions OVS_UNUSED, ++ uint32_t *num_of_actions OVS_UNUSED, ++ struct rte_flow_error *error) ++{ ++ set_error(error, RTE_FLOW_ERROR_TYPE_ACTION); ++ return -1; ++} ++ ++static inline int ++netdev_dpdk_rte_flow_tunnel_match(struct netdev *netdev OVS_UNUSED, ++ struct rte_flow_tunnel *tunnel OVS_UNUSED, ++ struct rte_flow_item **items OVS_UNUSED, ++ uint32_t *num_of_items OVS_UNUSED, ++ struct rte_flow_error *error) ++{ ++ set_error(error, RTE_FLOW_ERROR_TYPE_ITEM); ++ return -1; ++} ++ ++static inline int ++netdev_dpdk_rte_flow_get_restore_info( ++ struct netdev *netdev OVS_UNUSED, ++ struct dp_packet *p OVS_UNUSED, ++ struct rte_flow_restore_info *info OVS_UNUSED, ++ struct rte_flow_error *error) ++{ ++ set_error(error, RTE_FLOW_ERROR_TYPE_ATTR); ++ return -1; ++} ++ ++static inline int ++netdev_dpdk_rte_flow_tunnel_action_decap_release( ++ struct netdev *netdev OVS_UNUSED, ++ struct rte_flow_action *actions OVS_UNUSED, ++ uint32_t num_of_actions OVS_UNUSED, ++ struct rte_flow_error *error) ++{ ++ set_error(error, RTE_FLOW_ERROR_TYPE_NONE); ++ return 0; ++} ++ ++static inline int ++netdev_dpdk_rte_flow_tunnel_item_release( ++ struct netdev *netdev OVS_UNUSED, ++ struct rte_flow_item *items OVS_UNUSED, ++ uint32_t num_of_items OVS_UNUSED, ++ struct rte_flow_error *error) ++{ ++ set_error(error, RTE_FLOW_ERROR_TYPE_NONE); ++ return 0; ++} ++ ++#endif /* ALLOW_EXPERIMENTAL_API */ ++ ++#else ++ ++static inline void ++netdev_dpdk_register(void) ++{ ++ /* Nothing */ ++} ++static inline void ++free_dpdk_buf(struct dp_packet *buf OVS_UNUSED) ++{ ++ /* Nothing */ ++} ++ ++#endif ++ ++#endif /* netdev-dpdk.h */ +Index: openvswitch-2.17.2/include/internal/ovs-atomic-c++.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-c++.h +@@ -0,0 +1,67 @@ ++/* This header implements atomic operation primitives on compilers that ++ * have built-in support for ++C11 */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#include ++ ++#define ATOMIC(TYPE) std::atomic ++ ++using std::atomic_init; ++ ++using std::memory_order_relaxed; ++using std::memory_order_consume; ++using std::memory_order_acquire; ++using std::memory_order_release; ++using std::memory_order_acq_rel; ++using std::memory_order_seq_cst; ++ ++using std::atomic_thread_fence; ++using std::atomic_signal_fence; ++using std::atomic_is_lock_free; ++ ++using std::atomic_store; ++using std::atomic_store_explicit; ++ ++using std::atomic_compare_exchange_strong; ++using std::atomic_compare_exchange_strong_explicit; ++using std::atomic_compare_exchange_weak; ++using std::atomic_compare_exchange_weak_explicit; ++ ++using std::atomic_exchange; ++using std::atomic_exchange_explicit; ++ ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ (*(DST) = std::atomic_load_explicit(SRC, ORDER), \ ++ (void) 0) ++ ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = (*(RMW)).fetch_add(ARG, ORDER), (void) 0) ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = (*(RMW)).fetch_sub(ARG, ORDER), (void) 0) ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = (*(RMW)).fetch_or(ARG, ORDER), (void) 0) ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = (*(RMW)).fetch_xor(ARG, ORDER), (void) 0) ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = (*(RMW)).fetch_and(ARG, ORDER), (void) 0) ++ ++using std::atomic_flag; ++using std::atomic_flag_test_and_set_explicit; ++using std::atomic_flag_test_and_set; ++using std::atomic_flag_clear_explicit; ++using std::atomic_flag_clear; +Index: openvswitch-2.17.2/include/internal/ovs-atomic-c11.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-c11.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on compilers that ++ * have built-in support for C11 */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#include ++ ++#define OMIT_STANDARD_ATOMIC_TYPES 1 ++#define ATOMIC(TYPE) _Atomic(TYPE) ++ ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ (*(DST) = atomic_load_explicit(SRC, ORDER), \ ++ (void) 0) ++ ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = atomic_fetch_add_explicit(RMW, ARG, ORDER), (void) 0) ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = atomic_fetch_sub_explicit(RMW, ARG, ORDER), (void) 0) ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = atomic_fetch_or_explicit(RMW, ARG, ORDER), (void) 0) ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = atomic_fetch_xor_explicit(RMW, ARG, ORDER), (void) 0) ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ (*(ORIG) = atomic_fetch_and_explicit(RMW, ARG, ORDER), (void) 0) +Index: openvswitch-2.17.2/include/internal/ovs-atomic-flag-gcc4.7+.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-flag-gcc4.7+.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2013, 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic_flag on Clang and on GCC 4.7 and later. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++/* atomic_flag */ ++ ++typedef struct { ++ unsigned char b; ++} atomic_flag; ++#define ATOMIC_FLAG_INIT { .b = false } ++ ++static inline bool ++atomic_flag_test_and_set_explicit(volatile atomic_flag *object, ++ memory_order order) ++{ ++ return __atomic_test_and_set(&object->b, order); ++} ++ ++static inline bool ++atomic_flag_test_and_set(volatile atomic_flag *object) ++{ ++ return atomic_flag_test_and_set_explicit(object, memory_order_seq_cst); ++} ++ ++static inline void ++atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order) ++{ ++ __atomic_clear(object, order); ++} ++ ++static inline void ++atomic_flag_clear(volatile atomic_flag *object) ++{ ++ atomic_flag_clear_explicit(object, memory_order_seq_cst); ++} +Index: openvswitch-2.17.2/include/internal/ovs-atomic-i586.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-i586.h +@@ -0,0 +1,489 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on 32-bit 586+ with GCC. ++ */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#define OVS_ATOMIC_I586_IMPL 1 ++ ++/* ++ * These assumptions have been adopted from the x86_64 Memory model: ++ * ++ * - 1, 2, and 4 byte loads and stores are atomic on aligned memory. ++ * - Loads are not reordered with other loads. ++ * - Stores are not reordered with OLDER loads. ++ * - Loads may be reordered with OLDER stores to a different memory location, ++ * but not with OLDER stores to the same memory location. ++ * - Stores are not reordered with other stores, except maybe for special ++ * instructions not emitted by compilers, or by the stores performed by ++ * a single fast string operation (e.g., "stos"). As long as the atomic ++ * stores are not combined with any other stores, even the allowed reordering ++ * of the stores by a single fast string operation is not a problem. ++ * - Neither loads nor stores are reordered with locked instructions. ++ * - Stores by a single processor are observed in the same order by all ++ * processors. ++ * - (Unlocked) Stores from different processors are NOT ordered. ++ * - Memory ordering obeys causality (memory ordering respects transitive ++ * visibility). ++ * - Any two stores are seen in a consistent order by processors other than ++ * the those performing the stores. ++ * - Locked instructions have total order. ++ * ++ * These rules imply that: ++ * ++ * - Locked instructions are not needed for aligned loads or stores to make ++ * them atomic for sizes upto 4 bytes. 8 byte objects need locked ++ * instructions. ++ * - All stores have release semantics; none of the preceding stores or loads ++ * can be reordered with following stores. Following loads could still be ++ * reordered to happen before the store, but that is not a violation of the ++ * release semantics. ++ * - All loads from a given memory location have acquire semantics with ++ * respect to the stores on the same memory location; none of the following ++ * loads or stores can be reordered with the load. Preceding stores to a ++ * different memory location MAY be reordered with the load, but that is not ++ * a violation of the acquire semantics (i.e., the loads and stores of two ++ * critical sections guarded by a different memory location can overlap). ++ * - Locked instructions serve as CPU memory barriers by themselves. ++ * - Locked stores implement the sequential consistency memory order. Using ++ * locked instructions when seq_cst memory order is requested allows normal ++ * loads to observe the stores in the same (total) order without using CPU ++ * memory barrier after the loads. ++ * ++ * NOTE: Some older AMD Opteron processors have a bug that violates the ++ * acquire semantics described above. The bug manifests as an unlocked ++ * read-modify-write operation following a "semaphore operation" operating ++ * on data that existed before entering the critical section; i.e., the ++ * preceding "semaphore operation" fails to function as an acquire barrier. ++ * The affected CPUs are AMD family 15, models 32 to 63. ++ * ++ * Ref. http://support.amd.com/TechDocs/25759.pdf errata #147. ++ */ ++ ++/* Barriers. */ ++ ++#define compiler_barrier() asm volatile(" " : : : "memory") ++#define cpu_barrier() asm volatile("lock; addl $0,(%%esp)" ::: "memory", "cc") ++ ++/* ++ * The 'volatile' keyword prevents the compiler from keeping the atomic ++ * value in a register, and generates a new memory access for each atomic ++ * operation. This allows the implementations of memory_order_relaxed and ++ * memory_order_consume to avoid issuing a compiler memory barrier, allowing ++ * full optimization of all surrounding non-atomic variables. ++ * ++ * The placement of the 'volatile' keyword after the 'TYPE' below is highly ++ * significant when the TYPE is a pointer type. In that case we want the ++ * pointer to be declared volatile, not the data type that is being pointed ++ * at! ++ * ++ * Attribute aligned is used to tell the compiler to align 64-bit data ++ * on a 8-byte boundary. This allows more efficient atomic access, as the ++ * the CPU guarantees such memory accesses to be atomic. */ ++#define ATOMIC(TYPE) TYPE volatile __attribute__((aligned(sizeof(TYPE)))) ++ ++/* Memory ordering. Must be passed in as a constant. */ ++typedef enum { ++ memory_order_relaxed, ++ memory_order_consume, ++ memory_order_acquire, ++ memory_order_release, ++ memory_order_acq_rel, ++ memory_order_seq_cst ++} memory_order; ++ ++#define ATOMIC_BOOL_LOCK_FREE 2 ++#define ATOMIC_CHAR_LOCK_FREE 2 ++#define ATOMIC_SHORT_LOCK_FREE 2 ++#define ATOMIC_INT_LOCK_FREE 2 ++#define ATOMIC_LONG_LOCK_FREE 2 ++#define ATOMIC_LLONG_LOCK_FREE 2 ++#define ATOMIC_POINTER_LOCK_FREE 2 ++ ++#define IS_LOCKLESS_ATOMIC(OBJECT) \ ++ (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) ++ ++#define ATOMIC_VAR_INIT(VALUE) VALUE ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++/* ++ * The memory_model_relaxed does not need a compiler barrier, if the ++ * atomic operation can otherwise be guaranteed to not be moved with ++ * respect to other atomic operations on the same memory location. Using ++ * the 'volatile' keyword in the definition of the atomic types ++ * accomplishes this, as memory accesses to volatile data may not be ++ * optimized away, or be reordered with other volatile accesses. ++ * ++ * On x86 also memory_order_consume is automatic, and data dependency on a ++ * volatile atomic variable means that the compiler optimizations should not ++ * cause problems. That is, the compiler should not speculate the value of ++ * the atomic_read, as it is going to read it from the memory anyway. ++ * This allows omiting the compiler memory barrier on atomic_reads with ++ * memory_order_consume. This matches the definition of ++ * smp_read_barrier_depends() in Linux kernel as a nop for x86, and its usage ++ * in rcu_dereference(). ++ * ++ * We use this same logic below to choose inline assembly statements with or ++ * without a compiler memory barrier. ++ */ ++static inline void ++atomic_compiler_barrier(memory_order order) ++{ ++ if (order > memory_order_consume) { ++ compiler_barrier(); ++ } ++} ++ ++static inline void ++atomic_thread_fence(memory_order order) ++{ ++ if (order == memory_order_seq_cst) { ++ cpu_barrier(); ++ } else { ++ atomic_compiler_barrier(order); ++ } ++} ++ ++static inline void ++atomic_signal_fence(memory_order order) ++{ ++ atomic_compiler_barrier(order); ++} ++ ++#define atomic_is_lock_free(OBJ) \ ++ ((void) *(OBJ), \ ++ IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) ++ ++/* The 8-byte atomic exchange uses cmpxchg8b with the SRC (ax:dx) as ++ * the expected value (bx:cx), which will get replaced by the current ++ * value in the likely case it did not match, after which we keep ++ * trying until the swap succeeds. */ ++ ++#if defined(__PIC__) ++/* ebx may not be clobbered when compiled with -fPIC, must save and ++ * restore it. Furthermore, 'DST' may be addressed via ebx, so the ++ * address must be passed via a register so that it remains valid also ++ * after changing ebx. */ ++#define atomic_exchange_8__(DST, SRC, CLOB) \ ++ uint32_t temp____; \ ++ \ ++ asm volatile(" movl %%ebx,%2 ; " \ ++ " movl %%eax,%%ebx ; " \ ++ " movl %%edx,%%ecx ; " \ ++ "1: " \ ++ "lock; cmpxchg8b (%0); " \ ++ " jne 1b ; " \ ++ " movl %2,%%ebx ; " \ ++ " # atomic_exchange_8__ " \ ++ : "+r" (DST), /* 0 */ \ ++ "+A" (SRC), /* 1 */ \ ++ "=mr" (temp____) /* 2 */ \ ++ :: "ecx", CLOB, "cc") ++ ++#else ++#define atomic_exchange_8__(DST, SRC, CLOB) \ ++ asm volatile(" movl %%eax,%%ebx ; " \ ++ " movl %%edx,%%ecx ; " \ ++ "1: " \ ++ "lock; cmpxchg8b %0 ; " \ ++ " jne 1b ; " \ ++ " # atomic_exchange_8__ " \ ++ : "+m" (*DST), /* 0 */ \ ++ "+A" (SRC) /* 1 */ \ ++ :: "ebx", "ecx", CLOB, "cc") ++#endif ++ ++#define atomic_exchange__(DST, SRC, ORDER) \ ++ ({ \ ++ typeof(DST) dst___ = (DST); \ ++ typeof(*(DST)) src___ = (SRC); \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ if (sizeof(*(DST)) == 8) { \ ++ atomic_exchange_8__(dst___, src___, "memory"); \ ++ } else { \ ++ asm volatile("xchg %1,%0 ; " \ ++ "# atomic_exchange__" \ ++ : "+r" (src___), /* 0 */ \ ++ "+m" (*dst___) /* 1 */ \ ++ :: "memory"); \ ++ } \ ++ } else { \ ++ if (sizeof(*(DST)) == 8) { \ ++ atomic_exchange_8__(dst___, src___, "cc"); \ ++ } else { \ ++ asm volatile("xchg %1,%0 ; " \ ++ "# atomic_exchange__" \ ++ : "+r" (src___), /* 0 */ \ ++ "+m" (*dst___)); /* 1 */ \ ++ } \ ++ } \ ++ src___; \ ++ }) ++ ++#if defined(__SSE__) ++/* SSE registers are 128-bit wide, and moving the lowest 64-bits of an SSE ++ * register to proerly aligned memory is atomic. See ATOMIC(TYPE) above. */ ++#define atomic_store_8__(DST, SRC) \ ++ asm volatile("movq %1,%0 ; # atomic_store_8__" \ ++ : "=m" (*DST) /* 0 */ \ ++ : "x" (SRC)) /* 1, SSE */ ++#else ++/* Locked 64-bit exchange is available on all i586 CPUs. */ ++#define atomic_store_8__(DST, SRC) \ ++ atomic_exchange_8__(DST, SRC, "cc") ++#endif ++ ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(*(DST)) src__ = (SRC); \ ++ \ ++ if ((ORDER) != memory_order_seq_cst) { \ ++ atomic_compiler_barrier(ORDER); \ ++ if (sizeof(*(DST)) == 8) { \ ++ atomic_store_8__(dst__, src__); \ ++ } else { \ ++ *dst__ = src__; \ ++ } \ ++ } else { \ ++ atomic_exchange__(dst__, src__, ORDER); \ ++ } \ ++ (void) 0; \ ++ }) ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++ ++#if defined(__SSE__) ++/* SSE registers are 128-bit wide, and moving 64-bits from properly aligned ++ * memory to an SSE register is atomic. See ATOMIC(TYPE) above. */ ++#define atomic_read_8__(SRC, DST) \ ++ ({ \ ++ typeof(*(DST)) res__; \ ++ \ ++ asm ("movq %1,%0 ; # atomic_read_8__" \ ++ : "=x" (res__) /* 0, SSE. */ \ ++ : "m" (*SRC)); /* 1 */ \ ++ *(DST) = res__; \ ++ }) ++#else ++/* Must use locked cmpxchg8b (available on all i586 CPUs) if compiled w/o sse ++ * support. Compare '*DST' to a random value in bx:cx and returns the actual ++ * value in ax:dx. The registers bx and cx are only read, so they are not ++ * clobbered. */ ++#define atomic_read_8__(SRC, DST) \ ++ ({ \ ++ typeof(*(DST)) res__; \ ++ \ ++ asm (" movl %%ebx,%%eax ; " \ ++ " movl %%ecx,%%edx ; " \ ++ "lock; cmpxchg8b %1 ; " \ ++ "# atomic_read_8__ " \ ++ : "=&A" (res__), /* 0 */ \ ++ "+m" (*SRC) /* 1 */ \ ++ : : "cc"); \ ++ *(DST) = res__; \ ++ }) ++#endif ++ ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(SRC) src__ = (SRC); \ ++ \ ++ if (sizeof(*(DST)) <= 4) { \ ++ *dst__ = *src__; \ ++ } else { \ ++ atomic_read_8__(SRC, DST); \ ++ } \ ++ atomic_compiler_barrier(ORDER); \ ++ (void) 0; \ ++ }) ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++ ++#if defined(__PIC__) ++/* ebx may not be used as an input when compiled with -fPIC, must save ++ * and restore it. Furthermore, 'DST' may be addressed via ebx, so ++ * the address must be passed via a register so that it remains valid ++ * also after changing ebx. */ ++#define atomic_compare_exchange_8__(DST, EXP, SRC, RES, CLOB) \ ++ asm volatile(" xchgl %%ebx,%3 ; " \ ++ "lock; cmpxchg8b (%1) ; " \ ++ " xchgl %3,%%ebx ; " \ ++ " sete %0 " \ ++ "# atomic_compare_exchange_8__" \ ++ : "=q" (RES), /* 0 */ \ ++ "+r" (DST), /* 1 */ \ ++ "+A" (EXP) /* 2 */ \ ++ : "r" ((uint32_t)SRC), /* 3 */ \ ++ "c" ((uint32_t)((uint64_t)SRC >> 32)) /* 4 */ \ ++ : CLOB, "cc") ++#else ++#define atomic_compare_exchange_8__(DST, EXP, SRC, RES, CLOB) \ ++ asm volatile("lock; cmpxchg8b %1 ; " \ ++ " sete %0 " \ ++ "# atomic_compare_exchange_8__" \ ++ : "=q" (RES), /* 0 */ \ ++ "+m" (*DST), /* 1 */ \ ++ "+A" (EXP) /* 2 */ \ ++ : "b" ((uint32_t)SRC), /* 3 */ \ ++ "c" ((uint32_t)((uint64_t)SRC >> 32)) /* 4 */ \ ++ : CLOB, "cc") ++#endif ++ ++#define atomic_compare_exchange__(DST, EXP, SRC, RES, CLOB) \ ++ asm volatile("lock; cmpxchg %3,%1 ; " \ ++ " sete %0 " \ ++ "# atomic_compare_exchange__" \ ++ : "=q" (RES), /* 0 */ \ ++ "+m" (*DST), /* 1 */ \ ++ "+a" (EXP) /* 2 */ \ ++ : "r" (SRC) /* 3 */ \ ++ : CLOB, "cc") ++ ++/* ORD_FAIL is ignored, as atomic_compare_exchange__ already implements ++ * at least as strong a barrier as allowed for ORD_FAIL in all cases. */ ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORDER, ORD_FAIL) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(DST) expp__ = (EXP); \ ++ typeof(*(DST)) src__ = (SRC); \ ++ typeof(*(DST)) exp__ = *expp__; \ ++ uint8_t res__; \ ++ (void)ORD_FAIL; \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ if (sizeof(*(DST)) <= 4) { \ ++ atomic_compare_exchange__(dst__, exp__, src__, res__, \ ++ "memory"); \ ++ } else { \ ++ atomic_compare_exchange_8__(dst__, exp__, src__, res__, \ ++ "memory"); \ ++ } \ ++ } else { \ ++ if (sizeof(*(DST)) <= 4) { \ ++ atomic_compare_exchange__(dst__, exp__, src__, res__, \ ++ "cc"); \ ++ } else { \ ++ atomic_compare_exchange_8__(dst__, exp__, src__, res__, \ ++ "cc"); \ ++ } \ ++ } \ ++ if (!res__) { \ ++ *expp__ = exp__; \ ++ } \ ++ (bool)res__; \ ++ }) ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_weak \ ++ atomic_compare_exchange_strong ++#define atomic_compare_exchange_weak_explicit \ ++ atomic_compare_exchange_strong_explicit ++ ++#define atomic_exchange_explicit(RMW, ARG, ORDER) \ ++ atomic_exchange__(RMW, ARG, ORDER) ++#define atomic_exchange(RMW, ARG) \ ++ atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) ++ ++#define atomic_add__(RMW, ARG, CLOB) \ ++ asm volatile("lock; xadd %0,%1 ; " \ ++ "# atomic_add__ " \ ++ : "+r" (ARG), /* 0 */ \ ++ "+m" (*RMW) /* 1 */ \ ++ :: CLOB, "cc") ++ ++#define atomic_add_32__(RMW, ARG, ORIG, ORDER) \ ++ ({ \ ++ typeof(RMW) rmw__ = (RMW); \ ++ typeof(*(RMW)) arg__ = (ARG); \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ atomic_add__(rmw__, arg__, "memory"); \ ++ } else { \ ++ atomic_add__(rmw__, arg__, "cc"); \ ++ } \ ++ *(ORIG) = arg__; \ ++ }) ++ ++/* We could use simple locked instructions if the original value was not ++ * needed. */ ++#define atomic_op__(RMW, OP, ARG, ORIG, ORDER) \ ++ ({ \ ++ typeof(RMW) rmw__ = (RMW); \ ++ typeof(ARG) arg__ = (ARG); \ ++ \ ++ typeof(*(RMW)) val__; \ ++ \ ++ atomic_read_explicit(rmw__, &val__, memory_order_relaxed); \ ++ do { \ ++ } while (!atomic_compare_exchange_weak_explicit(rmw__, &val__, \ ++ val__ OP arg__, \ ++ ORDER, \ ++ memory_order_relaxed)); \ ++ *(ORIG) = val__; \ ++ }) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ (sizeof(*(RMW)) <= 4 \ ++ ? atomic_add_32__(RMW, ARG, ORIG, ORDER) \ ++ : atomic_op__(RMW, +, ARG, ORIG, ORDER)) ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ (sizeof(*(RMW)) <= 4 \ ++ ? atomic_add_32__(RMW, -(ARG), ORIG, ORDER) \ ++ : atomic_op__(RMW, -, ARG, ORIG, ORDER)) ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, |, ARG, ORIG, ORDER) ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, ^, ARG, ORIG, ORDER) ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, &, ARG, ORIG, ORDER) ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++ ++/* atomic_flag */ ++ ++typedef ATOMIC(int) atomic_flag; ++#define ATOMIC_FLAG_INIT { false } ++ ++#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ ++ ((bool)atomic_exchange__(FLAG, 1, ORDER)) ++#define atomic_flag_test_and_set(FLAG) \ ++ atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) ++ ++#define atomic_flag_clear_explicit(FLAG, ORDER) \ ++ atomic_store_explicit(FLAG, 0, ORDER) ++#define atomic_flag_clear(FLAG) \ ++ atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/include/internal/ovs-atomic-locked.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-locked.h +@@ -0,0 +1,52 @@ ++/* This header implements atomic operation locking helpers. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#define OVS_ATOMIC_LOCKED_IMPL 1 ++ ++void atomic_lock__(void *); ++void atomic_unlock__(void *); ++ ++#define atomic_store_locked(DST, SRC) \ ++ (atomic_lock__(DST), \ ++ *(DST) = (SRC), \ ++ atomic_unlock__(DST), \ ++ (void) 0) ++ ++#define atomic_read_locked(SRC, DST) \ ++ (atomic_lock__(SRC), \ ++ *(DST) = *(SRC), \ ++ atomic_unlock__(SRC), \ ++ (void) 0) ++ ++/* XXX: Evaluates EXP multiple times. */ ++#define atomic_compare_exchange_locked(DST, EXP, SRC) \ ++ (atomic_lock__(DST), \ ++ (*(DST) == *(EXP) \ ++ ? (*(DST) = (SRC), \ ++ atomic_unlock__(DST), \ ++ true) \ ++ : (*(EXP) = *(DST), \ ++ atomic_unlock__(DST), \ ++ false))) ++ ++#define atomic_exchange_locked(DST, SRC) \ ++ ({ \ ++ atomic_lock__(DST); \ ++ typeof(*(DST)) __tmp = *(DST); \ ++ *(DST) = SRC; \ ++ atomic_unlock__(DST); \ ++ __tmp; \ ++ }) ++ ++#define atomic_op_locked_add += ++#define atomic_op_locked_sub -= ++#define atomic_op_locked_or |= ++#define atomic_op_locked_xor ^= ++#define atomic_op_locked_and &= ++#define atomic_op_locked(RMW, OP, OPERAND, ORIG) \ ++ (atomic_lock__(RMW), \ ++ *(ORIG) = *(RMW), \ ++ *(RMW) atomic_op_locked_##OP (OPERAND), \ ++ atomic_unlock__(RMW)) +Index: openvswitch-2.17.2/include/internal/ovs-atomic-msvc.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-msvc.h +@@ -0,0 +1,463 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives for MSVC ++ * on i586 or greater platforms (32 bit). */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++/* From msdn documentation: With Visual Studio 2003, volatile to volatile ++ * references are ordered; the compiler will not re-order volatile variable ++ * access. With Visual Studio 2005, the compiler also uses acquire semantics ++ * for read operations on volatile variables and release semantics for write ++ * operations on volatile variables (when supported by the CPU). ++ * ++ * Though there is no clear documentation that states that anything greater ++ * than VS 2005 has the same behavior as described above, looking through MSVCs ++ * C++ atomics library in VS2013 shows that the compiler still takes ++ * acquire/release semantics on volatile variables. */ ++#define ATOMIC(TYPE) TYPE volatile ++ ++typedef enum { ++ memory_order_relaxed, ++ memory_order_consume, ++ memory_order_acquire, ++ memory_order_release, ++ memory_order_acq_rel, ++ memory_order_seq_cst ++} memory_order; ++ ++#if _MSC_VER > 1800 && defined(_M_IX86) ++/* From WDK 10 _InlineInterlocked* functions are renamed to ++ * _InlineInterlocked* although the documentation does not specify it */ ++#define _InterlockedExchangeAdd64 _InlineInterlockedExchangeAdd64 ++#define _InterlockedExchange64 _InlineInterlockedExchange64 ++#endif ++ ++#define ATOMIC_BOOL_LOCK_FREE 2 ++#define ATOMIC_CHAR_LOCK_FREE 2 ++#define ATOMIC_SHORT_LOCK_FREE 2 ++#define ATOMIC_INT_LOCK_FREE 2 ++#define ATOMIC_LONG_LOCK_FREE 2 ++#define ATOMIC_LLONG_LOCK_FREE 2 ++#define ATOMIC_POINTER_LOCK_FREE 2 ++ ++#define IS_LOCKLESS_ATOMIC(OBJECT) \ ++ (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) ++ ++#define ATOMIC_VAR_INIT(VALUE) (VALUE) ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++static inline void ++atomic_compiler_barrier(memory_order order) ++{ ++ /* In case of 'memory_order_consume', it is implicitly assumed that ++ * the compiler will not move instructions that have data-dependency ++ * on the variable in question before the barrier. */ ++ if (order > memory_order_consume) { ++ _ReadWriteBarrier(); ++ } ++} ++ ++static inline void ++atomic_thread_fence(memory_order order) ++{ ++ /* x86 is strongly ordered and acquire/release semantics come ++ * automatically. */ ++ atomic_compiler_barrier(order); ++ if (order == memory_order_seq_cst) { ++ MemoryBarrier(); ++ atomic_compiler_barrier(order); ++ } ++} ++ ++static inline void ++atomic_signal_fence(memory_order order) ++{ ++ atomic_compiler_barrier(order); ++} ++ ++/* 1, 2 and 4 bytes loads and stores are atomic on aligned memory. In addition, ++ * since the compiler automatically takes acquire and release semantics on ++ * volatile variables, for any order lesser than 'memory_order_seq_cst', we ++ * can directly assign or read values. */ ++ ++#define atomic_store32(DST, SRC, ORDER) \ ++ if (ORDER == memory_order_seq_cst) { \ ++ InterlockedExchange((long volatile *) (DST), \ ++ (long) (SRC)); \ ++ } else { \ ++ *(DST) = (SRC); \ ++ } ++ ++/* MSVC converts 64 bit writes into two instructions. So there is ++ * a possibility that an interrupt can make a 64 bit write non-atomic even ++ * when 8 byte aligned. So use InterlockedExchange64(). ++ * ++ * For atomic stores, 'consume' and 'acquire' semantics are not valid. But we ++ * are using 'Exchange' to get atomic stores here and we only have ++ * InterlockedExchange64(), InterlockedExchangeNoFence64() and ++ * InterlockedExchange64Acquire() available. So we are forced to use ++ * InterlockedExchange64() which uses full memory barrier for everything ++ * greater than 'memory_order_relaxed'. */ ++#ifdef _M_IX86 ++#define atomic_store64(DST, SRC, ORDER) \ ++ if (ORDER == memory_order_relaxed) { \ ++ InterlockedExchangeNoFence64((int64_t volatile *) (DST), \ ++ (int64_t) (SRC)); \ ++ } else { \ ++ InterlockedExchange64((int64_t volatile *) (DST), (int64_t) (SRC));\ ++ } ++#elif _M_X64 ++/* 64 bit writes are atomic on amd64 if 64 bit aligned. */ ++#define atomic_store64(DST, SRC, ORDER) \ ++ if (ORDER == memory_order_seq_cst) { \ ++ InterlockedExchange64((int64_t volatile *) (DST), \ ++ (int64_t) (SRC)); \ ++ } else { \ ++ *(DST) = (SRC); \ ++ } ++#endif ++ ++#define atomic_store8(DST, SRC, ORDER) \ ++ if (ORDER == memory_order_seq_cst) { \ ++ InterlockedExchange8((char volatile *) (DST), (char) (SRC)); \ ++ } else { \ ++ *(DST) = (SRC); \ ++ } ++ ++#define atomic_store16(DST, SRC, ORDER) \ ++ if (ORDER == memory_order_seq_cst) { \ ++ InterlockedExchange16((short volatile *) (DST), (short) (SRC)); \ ++ } else { \ ++ *(DST) = (SRC); \ ++ } ++ ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++ ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ if (sizeof *(DST) == 1) { \ ++ atomic_store8(DST, SRC, ORDER) \ ++ } else if (sizeof *(DST) == 2) { \ ++ atomic_store16( DST, SRC, ORDER) \ ++ } else if (sizeof *(DST) == 4) { \ ++ atomic_store32(DST, SRC, ORDER) \ ++ } else if (sizeof *(DST) == 8) { \ ++ atomic_store64(DST, SRC, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++/* On x86, for 'memory_order_seq_cst', if stores are locked, the corresponding ++ * reads don't need to be locked (based on the following in Intel Developers ++ * manual: ++ * “Locked operations are atomic with respect to all other memory operations ++ * and all externally visible events. Only instruction fetch and page table ++ * accesses can pass locked instructions. Locked instructions can be used to ++ * synchronize data written by one processor and read by another processor. ++ * For the P6 family processors, locked operations serialize all outstanding ++ * load and store operations (that is, wait for them to complete). This rule ++ * is also true for the Pentium 4 and Intel Xeon processors, with one ++ * exception. Load operations that reference weakly ordered memory types ++ * (such as the WC memory type) may not be serialized."). */ ++ ++ /* For 8, 16 and 32 bit variations. */ ++#define atomic_readX(SRC, DST, ORDER) \ ++ *(DST) = *(SRC); ++ ++/* MSVC converts 64 bit reads into two instructions. So there is ++ * a possibility that an interrupt can make a 64 bit read non-atomic even ++ * when 8 byte aligned. So use fully memory barrier InterlockedOr64(). */ ++#ifdef _M_IX86 ++#define atomic_read64(SRC, DST, ORDER) \ ++ __pragma (warning(push)) \ ++ __pragma (warning(disable:4047)) \ ++ *(DST) = InterlockedOr64((int64_t volatile *) (SRC), 0); \ ++ __pragma (warning(pop)) ++#elif _M_X64 ++/* 64 bit reads are atomic on amd64 if 64 bit aligned. */ ++#define atomic_read64(SRC, DST, ORDER) \ ++ *(DST) = *(SRC); ++#endif ++ ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++ ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ if (sizeof *(DST) == 1 || sizeof *(DST) == 2 || sizeof *(DST) == 4) { \ ++ atomic_readX(SRC, DST, ORDER) \ ++ } else if (sizeof *(DST) == 8) { \ ++ atomic_read64(SRC, DST, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++/* For add, sub, and logical operations, for 8, 16 and 64 bit data types, ++ * functions for all the different memory orders does not exist ++ * (though documentation exists for some of them). The MSVC C++ library which ++ * implements the c11 atomics simply calls the full memory barrier function ++ * for everything in x86(see xatomic.h). So do the same here. */ ++ ++/* For 8, 16 and 64 bit variations. */ ++#define atomic_op(OP, X, RMW, ARG, ORIG, ORDER) \ ++ atomic_##OP##_generic(X, RMW, ARG, ORIG, ORDER) ++ ++/* Arithmetic addition calls. */ ++ ++#define atomic_add8(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = _InterlockedExchangeAdd8((char volatile *) (RMW), \ ++ (char) (ARG)); ++ ++#define atomic_add16(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = _InterlockedExchangeAdd16((short volatile *) (RMW), \ ++ (short) (ARG)); ++ ++#define atomic_add32(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedExchangeAdd((long volatile *) (RMW), \ ++ (long) (ARG)); ++#define atomic_add64(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = _InterlockedExchangeAdd64((int64_t volatile *) (RMW), \ ++ (int64_t) (ARG)); ++ ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ if (sizeof *(RMW) == 1) { \ ++ atomic_add8(RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 2) { \ ++ atomic_add16(RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 4) { \ ++ atomic_add32(RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 8) { \ ++ atomic_add64(RMW, ARG, ORIG, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++/* Arithmetic subtraction calls. */ ++ ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, (0 - (ARG)), ORIG, memory_order_seq_cst) ++ ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_add_explicit(RMW, (0 - (ARG)), ORIG, ORDER) ++ ++/* Logical 'and' calls. */ ++ ++#define atomic_and32(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedAnd((int32_t volatile *) (RMW), (int32_t) (ARG)); ++ ++/* For 8, 16 and 64 bit variations. */ ++#define atomic_and_generic(X, RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedAnd##X((int##X##_t volatile *) (RMW), \ ++ (int##X##_t) (ARG)); ++ ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ if (sizeof *(RMW) == 1) { \ ++ atomic_op(and, 8, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 2) { \ ++ atomic_op(and, 16, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 4) { \ ++ atomic_and32(RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 8) { \ ++ atomic_op(and, 64, RMW, ARG, ORIG, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++/* Logical 'Or' calls. */ ++ ++#define atomic_or32(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedOr((int32_t volatile *) (RMW), (int32_t) (ARG)); ++ ++/* For 8, 16 and 64 bit variations. */ ++#define atomic_or_generic(X, RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedOr##X((int##X##_t volatile *) (RMW), \ ++ (int##X##_t) (ARG)); ++ ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ if (sizeof *(RMW) == 1) { \ ++ atomic_op(or, 8, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 2) { \ ++ atomic_op(or, 16, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 4) { \ ++ atomic_or32(RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 8) { \ ++ atomic_op(or, 64, RMW, ARG, ORIG, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++/* Logical Xor calls. */ ++ ++#define atomic_xor32(RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedXor((int32_t volatile *) (RMW), (int32_t) (ARG)); ++ ++/* For 8, 16 and 64 bit variations. */ ++#define atomic_xor_generic(X, RMW, ARG, ORIG, ORDER) \ ++ *(ORIG) = InterlockedXor##X((int##X##_t volatile *) (RMW), \ ++ (int##X##_t) (ARG)); ++ ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ if (sizeof *(RMW) == 1) { \ ++ atomic_op(xor, 8, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 2) { \ ++ atomic_op(xor, 16, RMW, ARG, ORIG, ORDER) \ ++ } else if (sizeof *(RMW) == 4) { \ ++ atomic_xor32(RMW, ARG, ORIG, ORDER); \ ++ } else if (sizeof *(RMW) == 8) { \ ++ atomic_op(xor, 64, RMW, ARG, ORIG, ORDER) \ ++ } else { \ ++ abort(); \ ++ } ++ ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++ ++#define atomic_compare_exchange_weak atomic_compare_exchange_strong ++#define atomic_compare_exchange_weak_explicit \ ++ atomic_compare_exchange_strong_explicit ++ ++/* While intrinsics offering different memory ordering ++ * are available in MSVC C compiler, they are not defined ++ * in the C++ compiler. Ignore for compatibility. ++ * ++ * Use nested ternary operators as the GNU extension ({}) ++ * is not available. ++ */ ++ ++#define atomic_exchange_explicit(DST, SRC, ORDER) \ ++ ((sizeof *(DST) == 1) ? \ ++ _InterlockedExchange8((char volatile *) DST, SRC) \ ++ : (sizeof *(DST) == 2) ? \ ++ _InterlockedExchange16((short volatile *) DST, SRC) \ ++ : (sizeof *(DST) == 4) ? \ ++ _InterlockedExchange((long int volatile *) DST, SRC) \ ++ : (sizeof *(DST) == 8) ? \ ++ _InterlockedExchange64((__int64 volatile *) DST, SRC) \ ++ : (abort(), 0)) ++ ++#define atomic_exchange(DST, SRC) \ ++ atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) ++ ++/* MSVCs c++ compiler implements c11 atomics and looking through its ++ * implementation (in xatomic.h), orders are ignored for x86 platform. ++ * Do the same here. */ ++static inline bool ++atomic_compare_exchange8(int8_t volatile *dst, int8_t *expected, int8_t src) ++{ ++ int8_t previous = _InterlockedCompareExchange8((char volatile *)dst, ++ src, *expected); ++ if (previous == *expected) { ++ return true; ++ } else { ++ *expected = previous; ++ return false; ++ } ++} ++ ++static inline bool ++atomic_compare_exchange16(int16_t volatile *dst, int16_t *expected, ++ int16_t src) ++{ ++ int16_t previous = InterlockedCompareExchange16(dst, src, *expected); ++ if (previous == *expected) { ++ return true; ++ } else { ++ *expected = previous; ++ return false; ++ } ++} ++ ++static inline bool ++atomic_compare_exchange32(int32_t volatile *dst, int32_t *expected, ++ int32_t src) ++{ ++ int32_t previous = InterlockedCompareExchange((long volatile *)dst, ++ src, *expected); ++ if (previous == *expected) { ++ return true; ++ } else { ++ *expected = previous; ++ return false; ++ } ++} ++ ++static inline bool ++atomic_compare_exchange64(int64_t volatile *dst, int64_t *expected, ++ int64_t src) ++{ ++ int64_t previous = InterlockedCompareExchange64(dst, src, *expected); ++ if (previous == *expected) { ++ return true; ++ } else { ++ *expected = previous; ++ return false; ++ } ++} ++ ++static inline bool ++atomic_compare_unreachable() ++{ ++ return true; ++} ++ ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ ++ (sizeof *(DST) == 1 \ ++ ? atomic_compare_exchange8((int8_t volatile *) (DST), (int8_t *) (EXP), \ ++ (int8_t) (SRC)) \ ++ : (sizeof *(DST) == 2 \ ++ ? atomic_compare_exchange16((int16_t volatile *) (DST), \ ++ (int16_t *) (EXP), (int16_t) (SRC)) \ ++ : (sizeof *(DST) == 4 \ ++ ? atomic_compare_exchange32((int32_t volatile *) (DST), \ ++ (int32_t *) (EXP), (int32_t) (SRC)) \ ++ : (sizeof *(DST) == 8 \ ++ ? atomic_compare_exchange64((int64_t volatile *) (DST), \ ++ (int64_t *) (EXP), (int64_t) (SRC)) \ ++ : ovs_fatal(0, "atomic operation with size greater than 8 bytes"), \ ++ atomic_compare_unreachable())))) ++ ++ ++/* atomic_flag */ ++ ++typedef ATOMIC(int32_t) atomic_flag; ++#define ATOMIC_FLAG_INIT 0 ++ ++#define atomic_flag_test_and_set(FLAG) \ ++ (bool) InterlockedBitTestAndSet(FLAG, 0) ++ ++#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ ++ atomic_flag_test_and_set(FLAG) ++ ++#define atomic_flag_clear_explicit(FLAG, ORDER) \ ++ atomic_flag_clear() ++#define atomic_flag_clear(FLAG) \ ++ InterlockedBitTestAndReset(FLAG, 0) +Index: openvswitch-2.17.2/include/internal/ovs-atomic-x86_64.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/ovs-atomic-x86_64.h +@@ -0,0 +1,356 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++/* This header implements atomic operation primitives on x86_64 with GCC. */ ++#ifndef IN_OVS_ATOMIC_H ++#error "This header should only be included indirectly via ovs-atomic.h." ++#endif ++ ++#define OVS_ATOMIC_X86_64_IMPL 1 ++ ++/* ++ * x86_64 Memory model (http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html): ++ * ++ * - 1, 2, 4, and 8 byte loads and stores are atomic on aligned memory. ++ * - Loads are not reordered with other loads. ++ * - Stores are not reordered with OLDER loads. ++ * - Loads may be reordered with OLDER stores to a different memory location, ++ * but not with OLDER stores to the same memory location. ++ * - Stores are not reordered with other stores, except for special ++ * instructions (CLFLUSH, streaming stores, fast string operations). ++ * Most of these are not emitted by compilers, and as long as the ++ * atomic stores are not combined with any other stores, even the allowed ++ * reordering of the stores by a single fast string operation (e.g., "stos") ++ * is not a problem. ++ * - Neither loads nor stores are reordered with locked instructions. ++ * - Loads cannot pass earlier LFENCE or MFENCE instructions. ++ * - Stores cannot pass earlier LFENCE, SFENCE, or MFENCE instructions. ++ * - LFENCE instruction cannot pass earlier loads. ++ * - SFENCE instruction cannot pass earlier stores. ++ * - MFENCE instruction cannot pass earlier loads or stores. ++ * - Stores by a single processor are observed in the same order by all ++ * processors. ++ * - (Unlocked) Stores from different processors are NOT ordered. ++ * - Memory ordering obeys causality (memory ordering respects transitive ++ * visibility). ++ * - Any two stores are seen in a consistent order by processors other than ++ * the those performing the stores. ++ * - Locked instructions have total order. ++ * ++ * These rules imply that: ++ * ++ * - Locked instructions are not needed for aligned loads or stores to make ++ * them atomic. ++ * - All stores have release semantics; none of the preceding stores or loads ++ * can be reordered with following stores. Following loads could still be ++ * reordered to happen before the store, but that is not a violation of the ++ * release semantics. ++ * - All loads from a given memory location have acquire semantics with ++ * respect to the stores on the same memory location; none of the following ++ * loads or stores can be reordered with the load. Preceding stores to a ++ * different memory location MAY be reordered with the load, but that is not ++ * a violation of the acquire semantics (i.e., the loads and stores of two ++ * critical sections guarded by a different memory location can overlap). ++ * - Locked instructions serve as CPU memory barriers by themselves. ++ * - Locked stores implement the sequential consistency memory order. Using ++ * locked instructions when seq_cst memory order is requested allows normal ++ * loads to observe the stores in the same (total) order without using CPU ++ * memory barrier after the loads. ++ * ++ * NOTE: Some older AMD Opteron processors have a bug that violates the ++ * acquire semantics described above. The bug manifests as an unlocked ++ * read-modify-write operation following a "semaphore operation" operating ++ * on data that existed before entering the critical section; i.e., the ++ * preceding "semaphore operation" fails to function as an acquire barrier. ++ * The affected CPUs are AMD family 15, models 32 to 63. ++ * ++ * Ref. http://support.amd.com/TechDocs/25759.pdf errata #147. ++ */ ++ ++/* Barriers. */ ++ ++#define compiler_barrier() asm volatile(" " : : : "memory") ++#define cpu_barrier() asm volatile("mfence;" : : : "memory") ++ ++/* ++ * The 'volatile' keyword prevents the compiler from keeping the atomic ++ * value in a register, and generates a new memory access for each atomic ++ * operation. This allows the implementations of memory_order_relaxed and ++ * memory_order_consume to avoid issuing a compiler memory barrier, allowing ++ * full optimization of all surrounding non-atomic variables. ++ * ++ * The placement of the 'volatile' keyword after the 'TYPE' below is highly ++ * significant when the TYPE is a pointer type. In that case we want the ++ * pointer to be declared volatile, not the data type that is being pointed ++ * at! ++ */ ++#define ATOMIC(TYPE) TYPE volatile ++ ++/* Memory ordering. Must be passed in as a constant. */ ++typedef enum { ++ memory_order_relaxed, ++ memory_order_consume, ++ memory_order_acquire, ++ memory_order_release, ++ memory_order_acq_rel, ++ memory_order_seq_cst ++} memory_order; ++ ++#define ATOMIC_BOOL_LOCK_FREE 2 ++#define ATOMIC_CHAR_LOCK_FREE 2 ++#define ATOMIC_SHORT_LOCK_FREE 2 ++#define ATOMIC_INT_LOCK_FREE 2 ++#define ATOMIC_LONG_LOCK_FREE 2 ++#define ATOMIC_LLONG_LOCK_FREE 2 ++#define ATOMIC_POINTER_LOCK_FREE 2 ++ ++#define IS_LOCKLESS_ATOMIC(OBJECT) \ ++ (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) ++ ++#define ATOMIC_VAR_INIT(VALUE) VALUE ++#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) ++ ++/* ++ * The memory_model_relaxed does not need a compiler barrier, if the ++ * atomic operation can otherwise be guaranteed to not be moved with ++ * respect to other atomic operations on the same memory location. Using ++ * the 'volatile' keyword in the definition of the atomic types ++ * accomplishes this, as memory accesses to volatile data may not be ++ * optimized away, or be reordered with other volatile accesses. ++ * ++ * On x86 also memory_order_consume is automatic, and data dependency on a ++ * volatile atomic variable means that the compiler optimizations should not ++ * cause problems. That is, the compiler should not speculate the value of ++ * the atomic_read, as it is going to read it from the memory anyway. ++ * This allows omiting the compiler memory barrier on atomic_reads with ++ * memory_order_consume. This matches the definition of ++ * smp_read_barrier_depends() in Linux kernel as a nop for x86, and its usage ++ * in rcu_dereference(). ++ * ++ * We use this same logic below to choose inline assembly statements with or ++ * without a compiler memory barrier. ++ */ ++static inline void ++atomic_compiler_barrier(memory_order order) ++{ ++ if (order > memory_order_consume) { ++ compiler_barrier(); ++ } ++} ++ ++static inline void ++atomic_thread_fence(memory_order order) ++{ ++ if (order == memory_order_seq_cst) { ++ cpu_barrier(); ++ } else { ++ atomic_compiler_barrier(order); ++ } ++} ++ ++static inline void ++atomic_signal_fence(memory_order order) ++{ ++ atomic_compiler_barrier(order); ++} ++ ++#define atomic_is_lock_free(OBJ) \ ++ ((void) *(OBJ), \ ++ IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) ++ ++#define atomic_exchange__(DST, SRC, ORDER) \ ++ ({ \ ++ typeof(DST) dst___ = (DST); \ ++ typeof(*(DST)) src___ = (SRC); \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ asm volatile("xchg %1,%0 ; " \ ++ "# atomic_exchange__" \ ++ : "+r" (src___), /* 0 */ \ ++ "+m" (*dst___) /* 1 */ \ ++ :: "memory"); \ ++ } else { \ ++ asm volatile("xchg %1,%0 ; " \ ++ "# atomic_exchange__" \ ++ : "+r" (src___), /* 0 */ \ ++ "+m" (*dst___)); /* 1 */ \ ++ } \ ++ src___; \ ++ }) ++ ++/* Atomic store: Valid memory models are: ++ * ++ * memory_order_relaxed, memory_order_release, and ++ * memory_order_seq_cst. */ ++#define atomic_store_explicit(DST, SRC, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(*(DST)) src__ = (SRC); \ ++ \ ++ if ((ORDER) != memory_order_seq_cst) { \ ++ atomic_compiler_barrier(ORDER); \ ++ *dst__ = src__; \ ++ } else { \ ++ atomic_exchange__(dst__, src__, ORDER); \ ++ } \ ++ (void) 0; \ ++ }) ++#define atomic_store(DST, SRC) \ ++ atomic_store_explicit(DST, SRC, memory_order_seq_cst) ++ ++/* Atomic read: Valid memory models are: ++ * ++ * memory_order_relaxed, memory_order_consume, memory_model_acquire, ++ * and memory_order_seq_cst. */ ++#define atomic_read_explicit(SRC, DST, ORDER) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(SRC) src__ = (SRC); \ ++ \ ++ *dst__ = *src__; \ ++ atomic_compiler_barrier(ORDER); \ ++ (void) 0; \ ++ }) ++#define atomic_read(SRC, DST) \ ++ atomic_read_explicit(SRC, DST, memory_order_seq_cst) ++ ++#define atomic_compare_exchange__(DST, EXP, SRC, RES, CLOB) \ ++ asm volatile("lock; cmpxchg %3,%1 ; " \ ++ " sete %0 " \ ++ "# atomic_compare_exchange__" \ ++ : "=q" (RES), /* 0 */ \ ++ "+m" (*DST), /* 1 */ \ ++ "+a" (EXP) /* 2 */ \ ++ : "r" (SRC) /* 3 */ \ ++ : CLOB, "cc") ++ ++/* All memory models are valid for read-modify-write operations. ++ * ++ * Valid memory models for the read operation of the current value in ++ * the failure case are the same as for atomic read, but can not be ++ * stronger than the success memory model. ++ * ORD_FAIL is ignored, as atomic_compare_exchange__ already implements ++ * at least as strong a barrier as allowed for ORD_FAIL in all cases. */ ++#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORDER, ORD_FAIL) \ ++ ({ \ ++ typeof(DST) dst__ = (DST); \ ++ typeof(DST) expp__ = (EXP); \ ++ typeof(*(DST)) src__ = (SRC); \ ++ typeof(*(DST)) exp__ = *expp__; \ ++ uint8_t res__; \ ++ (void)ORD_FAIL; \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ atomic_compare_exchange__(dst__, exp__, src__, res__, \ ++ "memory"); \ ++ } else { \ ++ atomic_compare_exchange__(dst__, exp__, src__, res__, \ ++ "cc"); \ ++ } \ ++ if (!res__) { \ ++ *expp__ = exp__; \ ++ } \ ++ (bool)res__; \ ++ }) ++#define atomic_compare_exchange_strong(DST, EXP, SRC) \ ++ atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ ++ memory_order_seq_cst, \ ++ memory_order_seq_cst) ++#define atomic_compare_exchange_weak \ ++ atomic_compare_exchange_strong ++#define atomic_compare_exchange_weak_explicit \ ++ atomic_compare_exchange_strong_explicit ++ ++#define atomic_exchange_explicit(RMW, ARG, ORDER) \ ++ atomic_exchange__(RMW, ARG, ORDER) ++#define atomic_exchange(RMW, ARG) \ ++ atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) ++ ++#define atomic_add__(RMW, ARG, CLOB) \ ++ asm volatile("lock; xadd %0,%1 ; " \ ++ "# atomic_add__ " \ ++ : "+r" (ARG), /* 0 */ \ ++ "+m" (*RMW) /* 1 */ \ ++ :: CLOB, "cc") ++ ++#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ ++ ({ \ ++ typeof(RMW) rmw__ = (RMW); \ ++ typeof(*(RMW)) arg__ = (ARG); \ ++ \ ++ if ((ORDER) > memory_order_consume) { \ ++ atomic_add__(rmw__, arg__, "memory"); \ ++ } else { \ ++ atomic_add__(rmw__, arg__, "cc"); \ ++ } \ ++ *(ORIG) = arg__; \ ++ }) ++#define atomic_add(RMW, ARG, ORIG) \ ++ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_add_explicit(RMW, -(ARG), ORIG, ORDER) ++#define atomic_sub(RMW, ARG, ORIG) \ ++ atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++/* We could use simple locked instructions if the original value was not ++ * needed. */ ++#define atomic_op__(RMW, OP, ARG, ORIG, ORDER) \ ++ ({ \ ++ typeof(RMW) rmw__ = (RMW); \ ++ typeof(ARG) arg__ = (ARG); \ ++ \ ++ typeof(*(RMW)) val__; \ ++ \ ++ atomic_read_explicit(rmw__, &val__, memory_order_relaxed); \ ++ do { \ ++ } while (!atomic_compare_exchange_weak_explicit(rmw__, &val__, \ ++ val__ OP arg__, \ ++ ORDER, \ ++ memory_order_relaxed)); \ ++ *(ORIG) = val__; \ ++ }) ++ ++#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, |, ARG, ORIG, ORDER) ++#define atomic_or(RMW, ARG, ORIG) \ ++ atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, ^, ARG, ORIG, ORDER) ++#define atomic_xor(RMW, ARG, ORIG) \ ++ atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ ++ atomic_op__(RMW, &, ARG, ORIG, ORDER) ++#define atomic_and(RMW, ARG, ORIG) \ ++ atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) ++ ++ ++/* atomic_flag */ ++ ++typedef ATOMIC(int) atomic_flag; ++#define ATOMIC_FLAG_INIT { false } ++ ++#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ ++ ((bool)atomic_exchange__(FLAG, 1, ORDER)) ++#define atomic_flag_test_and_set(FLAG) \ ++ atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) ++ ++#define atomic_flag_clear_explicit(FLAG, ORDER) \ ++ atomic_store_explicit(FLAG, 0, ORDER) ++#define atomic_flag_clear(FLAG) \ ++ atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/include/internal/process.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/process.h +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (c) 2008, 2009, 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. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef PROCESS_H ++#define PROCESS_H 1 ++ ++#include ++#include ++ ++struct process; ++ ++struct process_info { ++ unsigned long int vsz; /* Virtual size, in kB. */ ++ unsigned long int rss; /* Resident set size, in kB. */ ++ long long int booted; /* ms since monitor started. */ ++ int crashes; /* # of crashes (usually 0). */ ++ long long int uptime; /* ms since last (re)started by monitor. */ ++ long long int cputime; /* ms of CPU used during 'uptime'. */ ++ int core_id; ++ char name[18]; ++}; ++ ++/* Starting and monitoring subprocesses. ++ * ++ * process_init() and process_start() may safely be called only from a ++ * single-threaded parent process. The parent process may safely create ++ * additional threads afterward, as long as the remaining functions in this ++ * group are called only from a single thread at any given time. */ ++void process_init(void); ++int process_start(char **argv, struct process **); ++void process_destroy(struct process *); ++int process_kill(const struct process *, int signr); ++pid_t process_pid(const struct process *); ++const char *process_name(const struct process *); ++bool process_exited(struct process *); ++int process_status(const struct process *); ++void process_run(void); ++void process_wait(struct process *); ++ ++int count_crashes(pid_t); ++bool get_process_info(pid_t, struct process_info *); ++ ++/* These functions are thread-safe. */ ++char *process_status_msg(int); ++char *process_escape_args(char **argv); ++char *process_search_path(const char *); ++ ++#endif /* process.h */ +Index: openvswitch-2.17.2/include/internal/random.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/random.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2012 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef RANDOM_H ++#define RANDOM_H 1 ++ ++#include ++#include ++ ++void random_init(void); ++void random_set_seed(uint32_t); ++ ++void random_bytes(void *, size_t); ++uint32_t random_uint32(void); ++uint64_t random_uint64(void); ++ ++static inline int ++random_range(int max) ++{ ++ return random_uint32() % max; ++} ++ ++static inline uint8_t ++random_uint8(void) ++{ ++ return random_uint32(); ++} ++ ++static inline uint16_t ++random_uint16(void) ++{ ++ return random_uint32(); ++} ++ ++#endif /* random.h */ +Index: openvswitch-2.17.2/include/internal/simap.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/simap.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2009, 2010, 2011, 2012, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SIMAP_H ++#define SIMAP_H 1 ++ ++#include "openvswitch/hmap.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* A map from strings to unsigned integers. */ ++struct simap { ++ struct hmap map; /* Contains "struct simap_node"s. */ ++}; ++ ++struct simap_node { ++ struct hmap_node node; /* In struct simap's 'map' hmap. */ ++ char *name; ++ unsigned int data; ++}; ++ ++#define SIMAP_INITIALIZER(SIMAP) { HMAP_INITIALIZER(&(SIMAP)->map) } ++ ++#define SIMAP_FOR_EACH(SIMAP_NODE, SIMAP) \ ++ HMAP_FOR_EACH_INIT (SIMAP_NODE, node, &(SIMAP)->map, \ ++ BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ ++ BUILD_ASSERT_TYPE(SIMAP, struct simap *)) ++ ++#define SIMAP_FOR_EACH_SAFE_SHORT(SIMAP_NODE, SIMAP) \ ++ HMAP_FOR_EACH_SAFE_SHORT_INIT (SIMAP_NODE, node, &(SIMAP)->map, \ ++ BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ ++ BUILD_ASSERT_TYPE(SIMAP, struct simap *)) ++ ++#define SIMAP_FOR_EACH_SAFE_LONG(SIMAP_NODE, NEXT, SIMAP) \ ++ HMAP_FOR_EACH_SAFE_LONG_INIT (SIMAP_NODE, NEXT, node, &(SIMAP)->map, \ ++ BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ ++ BUILD_ASSERT_TYPE(NEXT, struct simap_node *), \ ++ BUILD_ASSERT_TYPE(SIMAP, struct simap *)) ++ ++#define SIMAP_FOR_EACH_SAFE(...) \ ++ OVERLOAD_SAFE_MACRO(SIMAP_FOR_EACH_SAFE_LONG, \ ++ SIMAP_FOR_EACH_SAFE_SHORT, \ ++ 3, __VA_ARGS__) ++ ++void simap_init(struct simap *); ++void simap_destroy(struct simap *); ++void simap_swap(struct simap *, struct simap *); ++void simap_moved(struct simap *); ++void simap_clear(struct simap *); ++ ++bool simap_is_empty(const struct simap *); ++size_t simap_count(const struct simap *); ++ ++bool simap_put(struct simap *, const char *, unsigned int); ++unsigned int simap_increase(struct simap *, const char *, unsigned int); ++ ++unsigned int simap_get(const struct simap *, const char *); ++struct simap_node *simap_find(const struct simap *, const char *); ++struct simap_node *simap_find_len(const struct simap *, ++ const char *, size_t len); ++bool simap_contains(const struct simap *, const char *); ++ ++void simap_delete(struct simap *, struct simap_node *); ++bool simap_find_and_delete(struct simap *, const char *); ++ ++const struct simap_node **simap_sort(const struct simap *); ++bool simap_equal(const struct simap *, const struct simap *); ++uint32_t simap_hash(const struct simap *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* simap.h */ +Index: openvswitch-2.17.2/include/internal/skiplist.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/skiplist.h +@@ -0,0 +1,49 @@ ++/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP ++ * All Rights Reserved. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); you may ++ * not use this file except in compliance with the License. You may obtain ++ * a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++ ++#ifndef LIB_SKIPLIST_H_ ++#define LIB_SKIPLIST_H_ ++ ++#include ++#include ++#include ++ ++typedef int (skiplist_comparator)(const void *a, const void *b, ++ const void *conf); ++ ++struct skiplist_node; ++ ++struct skiplist; ++ ++#define SKIPLIST_FOR_EACH (SKIPLIST_NODE, SKIPLIST) \ ++ for (SKIPLIST_NODE = skiplist_first(SKIPLIST); \ ++ SKIPLIST_NODE; \ ++ SKIPLIST_NODE = skiplist_next(SKIPLIST_NODE)) ++ ++struct skiplist *skiplist_create(skiplist_comparator *object_comparator, ++ void *configuration); ++void skiplist_insert(struct skiplist *sl, const void *object); ++void *skiplist_delete(struct skiplist *sl, const void *object); ++struct skiplist_node *skiplist_find(struct skiplist *sl, const void *value); ++void *skiplist_get_data(struct skiplist_node *node); ++uint32_t skiplist_get_size(struct skiplist *sl); ++struct skiplist_node *skiplist_forward_to(struct skiplist *sl, ++ const void *value); ++struct skiplist_node *skiplist_first(struct skiplist *sl); ++struct skiplist_node *skiplist_next(struct skiplist_node *node); ++void skiplist_destroy(struct skiplist *sl, void (*func)(void *)); ++ ++#endif /* LIB_SKIPLIST_H_ */ +Index: openvswitch-2.17.2/include/internal/socket-util.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/socket-util.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SOCKET_UTIL_H ++#define SOCKET_UTIL_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "openvswitch/types.h" ++#include ++#include ++ ++struct ds; ++ ++int set_nonblocking(int fd); ++void xset_nonblocking(int fd); ++void setsockopt_tcp_nodelay(int fd); ++int set_dscp(int fd, int family, uint8_t dscp); ++ ++bool addr_is_ipv6(const char *host_name); ++int lookup_ip(const char *host_name, struct in_addr *address); ++int lookup_ipv6(const char *host_name, struct in6_addr *address); ++ ++int lookup_hostname(const char *host_name, struct in_addr *); ++ ++int get_socket_rcvbuf(int sock); ++int check_connection_completion(int fd); ++void drain_fd(int fd, size_t n_packets); ++ovs_be32 guess_netmask(ovs_be32 ip); ++ ++void inet_parse_host_port_tokens(char *s, char **hostp, char **portp); ++void inet_parse_port_host_tokens(char *s, char **portp, char **hostp); ++bool inet_parse_active(const char *target, int default_port, ++ struct sockaddr_storage *ssp, ++ bool resolve_host, bool *dns_failure); ++int inet_open_active(int style, const char *target, int default_port, ++ struct sockaddr_storage *ssp, int *fdp, uint8_t dscp); ++ ++bool inet_parse_passive(const char *target, int default_port, ++ struct sockaddr_storage *ssp); ++int inet_open_passive(int style, const char *target, int default_port, ++ struct sockaddr_storage *ssp, uint8_t dscp, ++ bool kernel_print_port); ++ ++bool inet_parse_address(const char *target, struct sockaddr_storage *); ++ ++int read_fully(int fd, void *, size_t, size_t *bytes_read); ++int write_fully(int fd, const void *, size_t, size_t *bytes_written); ++ ++int fsync_parent_dir(const char *file_name); ++int get_mtime(const char *file_name, struct timespec *mtime); ++ ++char *describe_fd(int fd); ++ ++/* Default value of dscp bits for connection between controller and manager. ++ * Value of IPTOS_PREC_INTERNETCONTROL = 0xc0 which is defined ++ * in is used. */ ++#define DSCP_DEFAULT (IPTOS_PREC_INTERNETCONTROL >> 2) ++ ++/* Functions for working with sockaddr that might contain an IPv4 or ++ * IPv6 address. */ ++bool sa_is_ip(const struct sockaddr *); ++uint16_t sa_get_port(const struct sockaddr *); ++struct in6_addr sa_get_address(const struct sockaddr *); ++void sa_format_address(const struct sockaddr *, struct ds *); ++void sa_format_address_nobracks(const struct sockaddr *, struct ds *); ++size_t sa_length(const struct sockaddr *); ++ ++/* Functions for working with sockaddr_storage that might contain an IPv4 or ++ * IPv6 address. */ ++bool ss_is_ip(const struct sockaddr_storage *); ++uint16_t ss_get_port(const struct sockaddr_storage *); ++struct in6_addr ss_get_address(const struct sockaddr_storage *); ++void ss_format_address(const struct sockaddr_storage *, struct ds *); ++void ss_format_address_nobracks(const struct sockaddr_storage *, struct ds *); ++size_t ss_length(const struct sockaddr_storage *); ++ ++const char *sock_strerror(int error); ++ ++#ifndef _WIN32 ++void xpipe(int fds[2]); ++void xpipe_nonblocking(int fds[2]); ++ ++int drain_rcvbuf(int fd); ++ ++int make_unix_socket(int style, bool nonblock, ++ const char *bind_path, const char *connect_path); ++int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len); ++ ++/* Universal sendmmsg and recvmmsg support on Linux. ++ * ++ * New enough Linux supports sendmmsg and recvmmsg, but older versions do not. ++ * We add the following infrastructure to allow all code on Linux to use ++ * sendmmsg and recvmmsg, regardless of platform support: ++ * ++ * - For platforms that lack these functions entirely, we emulate them. ++ * ++ * - With newer glibc but an old kernel, sendmmsg() and recvmmsg() fail with ++ * ENOSYS. To compensate, even if these functions appear to be available, we ++ * wrap them with handlers that use our emulation in this case. ++ */ ++#ifdef __linux__ ++#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN ++struct mmsghdr { ++ struct msghdr msg_hdr; ++ unsigned int msg_len; ++}; ++#endif ++ ++#ifndef HAVE_SENDMMSG ++int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int); ++int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *); ++#else ++#define sendmmsg wrap_sendmmsg ++int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int); ++#define recvmmsg wrap_recvmmsg ++int wrap_recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *); ++#endif ++#endif /* __linux__ */ ++ ++/* Helpers for calling ioctl() on an AF_INET socket. */ ++struct ifreq; ++int af_inet_ioctl(unsigned long int command, const void *arg); ++int af_inet_ifreq_ioctl(const char *name, struct ifreq *, ++ unsigned long int cmd, const char *cmd_name); ++ ++#define closesocket close ++#endif ++ ++#ifdef _WIN32 ++static inline int make_unix_socket(int style, bool nonblock, ++ const char *bind_path, ++ const char *connect_path) ++{ ++ return -EINVAL; ++} ++ ++/* Windows defines the 'optval' argument as char * instead of void *. */ ++#define setsockopt(sock, level, optname, optval, optlen) \ ++ rpl_setsockopt(sock, level, optname, optval, optlen) ++static inline int rpl_setsockopt(int sock, int level, int optname, ++ const void *optval, socklen_t optlen) ++{ ++ return (setsockopt)(sock, level, optname, (const char *)optval, optlen); ++} ++ ++#define getsockopt(sock, level, optname, optval, optlen) \ ++ rpl_getsockopt(sock, level, optname, optval, optlen) ++static inline int rpl_getsockopt(int sock, int level, int optname, ++ void *optval, socklen_t *optlen) ++{ ++ return (getsockopt)(sock, level, optname, (char *)optval, optlen); ++} ++#endif ++ ++/* In Windows platform, errno is not set for socket calls. ++ * The last error has to be gotten from WSAGetLastError(). */ ++static inline int sock_errno(void) ++{ ++#ifdef _WIN32 ++ return WSAGetLastError(); ++#else ++ return errno; ++#endif ++} ++ ++#endif /* socket-util.h */ +Index: openvswitch-2.17.2/include/internal/sort.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/sort.h +@@ -0,0 +1,26 @@ ++/* Copyright (c) 2009 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SORT_H ++#define SORT_H 1 ++ ++#include ++ ++void sort(size_t count, ++ int (*compare)(size_t a, size_t b, void *aux), ++ void (*swap)(size_t a, size_t b, void *aux), ++ void *aux); ++ ++#endif /* sort.h */ +Index: openvswitch-2.17.2/include/internal/stopwatch.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/stopwatch.h +@@ -0,0 +1,59 @@ ++/* Copyright (c) 2017 Red Hat, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef STOPWATCH_H ++#define STOPWATCH_H 1 ++ ++#include ++ ++enum stopwatch_units { ++ SW_MS, ++ SW_US, ++ SW_NS, ++}; ++ ++struct stopwatch_stats { ++ unsigned long long count; /* Total number of samples. */ ++ enum stopwatch_units unit; /* Unit of following values. */ ++ unsigned long long max; /* Maximum value. */ ++ unsigned long long min; /* Minimum value. */ ++ double pctl_95; /* 95th percentile. */ ++ double ewma_50; /* Exponentially weighted moving average ++ (alpha 0.50). */ ++ double ewma_1; /* Exponentially weighted moving average ++ (alpha 0.01). */ ++}; ++ ++/* Create a new stopwatch. ++ * The "units" are not used for any calculations but are printed when ++ * statistics are requested. ++ */ ++void stopwatch_create(const char *name, enum stopwatch_units units); ++ ++/* Start a stopwatch. */ ++void stopwatch_start(const char *name, unsigned long long ts); ++ ++/* Stop a stopwatch. The elapsed time will be used for updating statistics ++ * for this stopwatch. ++ */ ++void stopwatch_stop(const char *name, unsigned long long ts); ++ ++/* Retrieve statistics calculated from collected samples */ ++bool stopwatch_get_stats(const char *name, struct stopwatch_stats *stats); ++ ++/* Block until all enqueued samples have been processed. */ ++void stopwatch_sync(void); ++ ++#endif /* stopwatch.h */ +Index: openvswitch-2.17.2/include/internal/stream-ssl.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/stream-ssl.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#ifndef STREAM_SSL_H ++#define STREAM_SSL_H 1 ++ ++#include ++ ++bool stream_ssl_is_configured(void); ++void stream_ssl_set_private_key_file(const char *file_name); ++void stream_ssl_set_certificate_file(const char *file_name); ++void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap); ++void stream_ssl_set_peer_ca_cert_file(const char *file_name); ++void stream_ssl_set_key_and_cert(const char *private_key_file, ++ const char *certificate_file); ++void stream_ssl_set_protocols(const char *arg); ++void stream_ssl_set_ciphers(const char *arg); ++ ++#define SSL_OPTION_ENUMS \ ++ OPT_SSL_PROTOCOLS, \ ++ OPT_SSL_CIPHERS ++ ++#define STREAM_SSL_LONG_OPTIONS \ ++ {"private-key", required_argument, NULL, 'p'}, \ ++ {"certificate", required_argument, NULL, 'c'}, \ ++ {"ca-cert", required_argument, NULL, 'C'}, \ ++ {"ssl-protocols", required_argument, NULL, OPT_SSL_PROTOCOLS}, \ ++ {"ssl-ciphers", required_argument, NULL, OPT_SSL_CIPHERS} ++ ++#define STREAM_SSL_OPTION_HANDLERS \ ++ case 'p': \ ++ stream_ssl_set_private_key_file(optarg); \ ++ break; \ ++ \ ++ case 'c': \ ++ stream_ssl_set_certificate_file(optarg); \ ++ break; \ ++ \ ++ case 'C': \ ++ stream_ssl_set_ca_cert_file(optarg, false); \ ++ break; \ ++ \ ++ case OPT_SSL_PROTOCOLS: \ ++ stream_ssl_set_protocols(optarg); \ ++ break; \ ++ \ ++ case OPT_SSL_CIPHERS: \ ++ stream_ssl_set_ciphers(optarg); \ ++ break; ++ ++#define STREAM_SSL_CASES \ ++ case 'p': case 'c': case 'C': case OPT_SSL_PROTOCOLS: case OPT_SSL_CIPHERS: ++ ++#endif /* stream-ssl.h */ +Index: openvswitch-2.17.2/include/internal/svec.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/svec.h +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2008, 2009, 2011 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef SVEC_H ++#define SVEC_H 1 ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct svec { ++ char **names; ++ size_t n; ++ size_t allocated; ++}; ++ ++#define SVEC_EMPTY_INITIALIZER { NULL, 0, 0 } ++ ++void svec_init(struct svec *); ++void svec_clone(struct svec *, const struct svec *); ++void svec_destroy(struct svec *); ++void svec_clear(struct svec *); ++bool svec_is_empty(const struct svec *); ++void svec_add(struct svec *, const char *); ++void svec_add_nocopy(struct svec *, char *); ++void svec_del(struct svec *, const char *); ++void svec_append(struct svec *, const struct svec *); ++void svec_terminate(struct svec *); ++void svec_sort(struct svec *); ++void svec_sort_unique(struct svec *); ++void svec_unique(struct svec *); ++void svec_compact(struct svec *); ++void svec_shuffle(struct svec *); ++void svec_diff(const struct svec *a, const struct svec *b, ++ struct svec *a_only, struct svec *both, struct svec *b_only); ++bool svec_contains(const struct svec *, const char *); ++bool svec_contains_unsorted(const struct svec *, const char *); ++size_t svec_find(const struct svec *, const char *); ++bool svec_is_sorted(const struct svec *); ++bool svec_is_unique(const struct svec *); ++const char *svec_get_duplicate(const struct svec *); ++void svec_swap(struct svec *a, struct svec *b); ++void svec_print(const struct svec *svec, const char *title); ++void svec_parse_words(struct svec *svec, const char *words); ++bool svec_equal(const struct svec *, const struct svec *); ++char *svec_join(const struct svec *, ++ const char *delimiter, const char *terminator); ++const char *svec_back(const struct svec *); ++void svec_pop_back(struct svec *); ++ ++/* Iterates over the names in SVEC, assigning each name in turn to NAME and its ++ * index to INDEX. */ ++#define SVEC_FOR_EACH(INDEX, NAME, SVEC) \ ++ for ((INDEX) = 0; \ ++ ((INDEX) < (SVEC)->n \ ++ ? (NAME) = (SVEC)->names[INDEX], 1 \ ++ : 0); \ ++ (INDEX)++) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* svec.h */ +Index: openvswitch-2.17.2/include/internal/table.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/table.h +@@ -0,0 +1,139 @@ ++/* ++ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef TABLE_H ++#define TABLE_H 1 ++ ++#include ++#include ++#include "openvswitch/compiler.h" ++#include "openvswitch/json.h" ++ ++struct ds; ++struct table_style; ++ ++/* Manipulating tables and their rows and columns. */ ++ ++struct table { ++ struct cell *cells; ++ struct column *columns; ++ size_t n_columns, allocated_columns; ++ size_t n_rows, allocated_rows; ++ size_t current_column; ++ char *caption; ++ bool timestamp; ++}; ++ ++void table_init(struct table *); ++void table_destroy(struct table *); ++void table_set_caption(struct table *, char *caption); ++void table_set_timestamp(struct table *, bool timestamp); ++ ++void table_add_column(struct table *, const char *heading, ...) ++ OVS_PRINTF_FORMAT(2, 3); ++void table_add_row(struct table *); ++ ++/* Table cells. */ ++ ++struct cell { ++ /* Literal text. */ ++ char *text; ++ ++ /* JSON. */ ++ struct json *json; ++ const struct ovsdb_type *type; ++}; ++ ++struct cell *table_add_cell(struct table *); ++ ++/* Table formatting. */ ++ ++enum table_format { ++ TF_TABLE, /* 2-d table. */ ++ TF_LIST, /* One cell per line, one row per paragraph. */ ++ TF_HTML, /* HTML table. */ ++ TF_CSV, /* Comma-separated lines. */ ++ TF_JSON /* JSON. */ ++}; ++ ++enum cell_format { ++ CF_STRING, /* String format. */ ++ CF_BARE, /* String format without most punctuation. */ ++ CF_JSON /* JSON. */ ++}; ++ ++struct table_style { ++ enum table_format format; /* TF_*. */ ++ enum cell_format cell_format; /* CF_*. */ ++ bool headings; /* Include headings? */ ++ int json_flags; /* CF_JSON: Flags for json_to_string(). */ ++ int max_column_width; /* CF_STRING: Limit for column width. */ ++}; ++ ++#define TABLE_STYLE_DEFAULT { TF_LIST, CF_STRING, true, JSSF_SORT, 0 } ++static const struct table_style table_style_default = TABLE_STYLE_DEFAULT; ++ ++#define TABLE_OPTION_ENUMS \ ++ OPT_NO_HEADINGS, \ ++ OPT_PRETTY, \ ++ OPT_BARE, \ ++ OPT_MAX_COLUMN_WIDTH ++ ++#define TABLE_LONG_OPTIONS \ ++ {"format", required_argument, NULL, 'f'}, \ ++ {"data", required_argument, NULL, 'd'}, \ ++ {"no-headings", no_argument, NULL, OPT_NO_HEADINGS}, \ ++ {"pretty", no_argument, NULL, OPT_PRETTY}, \ ++ {"bare", no_argument, NULL, OPT_BARE}, \ ++ {"max-column-width", required_argument, NULL, OPT_MAX_COLUMN_WIDTH} ++ ++#define TABLE_OPTION_HANDLERS(STYLE) \ ++ case 'f': \ ++ table_parse_format(STYLE, optarg); \ ++ break; \ ++ \ ++ case 'd': \ ++ table_parse_cell_format(STYLE, optarg); \ ++ break; \ ++ \ ++ case OPT_NO_HEADINGS: \ ++ (STYLE)->headings = false; \ ++ break; \ ++ \ ++ case OPT_PRETTY: \ ++ (STYLE)->json_flags |= JSSF_PRETTY; \ ++ break; \ ++ \ ++ case OPT_BARE: \ ++ (STYLE)->format = TF_LIST; \ ++ (STYLE)->cell_format = CF_BARE; \ ++ (STYLE)->headings = false; \ ++ break; \ ++ \ ++ case OPT_MAX_COLUMN_WIDTH: \ ++ (STYLE)->max_column_width = atoi(optarg); \ ++ break; ++ ++void table_parse_format(struct table_style *, const char *format); ++void table_parse_cell_format(struct table_style *, const char *format); ++ ++void table_print(const struct table *, const struct table_style *); ++void table_format(const struct table *, const struct table_style *, ++ struct ds *); ++void table_format_reset(void); ++void table_usage(void); ++ ++#endif /* table.h */ +Index: openvswitch-2.17.2/include/internal/unixctl.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/unixctl.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2008, 2009, 2011 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef UNIXCTL_H ++#define UNIXCTL_H 1 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Server for Unix domain socket control connection. */ ++struct unixctl_server; ++int unixctl_server_create(const char *path, struct unixctl_server **); ++void unixctl_server_run(struct unixctl_server *); ++void unixctl_server_wait(struct unixctl_server *); ++void unixctl_server_destroy(struct unixctl_server *); ++ ++const char *unixctl_server_get_path(const struct unixctl_server *); ++ ++/* Client for Unix domain socket control connection. */ ++struct jsonrpc; ++int unixctl_client_create(const char *path, struct jsonrpc **client); ++int unixctl_client_transact(struct jsonrpc *client, ++ const char *command, ++ int argc, char *argv[], ++ char **result, char **error); ++ ++/* Command registration. */ ++struct unixctl_conn; ++typedef void unixctl_cb_func(struct unixctl_conn *, ++ int argc, const char *argv[], void *aux); ++void unixctl_command_register(const char *name, const char *usage, ++ int min_args, int max_args, ++ unixctl_cb_func *cb, void *aux); ++void unixctl_command_reply_error(struct unixctl_conn *, const char *error); ++void unixctl_command_reply(struct unixctl_conn *, const char *body); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* unixctl.h */ +Index: openvswitch-2.17.2/include/internal/uuid.h +=================================================================== +--- /dev/null ++++ openvswitch-2.17.2/include/internal/uuid.h +@@ -0,0 +1,92 @@ ++/* Copyright (c) 2008, 2009, 2010, 2016, 2017 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef UUID_H ++#define UUID_H 1 ++ ++#include "openvswitch/uuid.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* An initializer or expression for an all-zero UUID. */ ++#define UUID_ZERO ((struct uuid) { .parts = { 0, 0, 0, 0 } }) ++ ++/* Formats a UUID as a string, in the conventional format. ++ * ++ * Example: ++ * struct uuid uuid = ...; ++ * printf("This UUID is "UUID_FMT"\n", UUID_ARGS(&uuid)); ++ * ++ */ ++#define UUID_LEN 36 ++#define UUID_FMT "%08x-%04x-%04x-%04x-%04x%08x" ++#define UUID_ARGS(UUID) \ ++ ((unsigned int) ((UUID)->parts[0])), \ ++ ((unsigned int) ((UUID)->parts[1] >> 16)), \ ++ ((unsigned int) ((UUID)->parts[1] & 0xffff)), \ ++ ((unsigned int) ((UUID)->parts[2] >> 16)), \ ++ ((unsigned int) ((UUID)->parts[2] & 0xffff)), \ ++ ((unsigned int) ((UUID)->parts[3])) ++ ++/* Returns a hash value for 'uuid'. This hash value is the same regardless of ++ * whether we are running on a 32-bit or 64-bit or big-endian or little-endian ++ * architecture. */ ++static inline size_t ++uuid_hash(const struct uuid *uuid) ++{ ++ return uuid->parts[0]; ++} ++ ++/* Returns true if 'a == b', false otherwise. */ ++static inline bool ++uuid_equals(const struct uuid *a, const struct uuid *b) ++{ ++ return (a->parts[0] == b->parts[0] ++ && a->parts[1] == b->parts[1] ++ && a->parts[2] == b->parts[2] ++ && a->parts[3] == b->parts[3]); ++} ++ ++/* Returns the first 'n' hex digits of 'uuid', for 0 < 'n' <= 8. ++ * ++ * This is useful for displaying a few leading digits of the uuid, e.g. to ++ * display 4 digits: ++ * printf("%04x", uuid_prefix(uuid, 4)); ++ */ ++static inline unsigned int ++uuid_prefix(const struct uuid *uuid, int digits) ++{ ++ return (uuid->parts[0] >> (32 - 4 * digits)); ++} ++ ++void uuid_init(void); ++void uuid_generate(struct uuid *); ++struct uuid uuid_random(void); ++void uuid_zero(struct uuid *); ++bool uuid_is_zero(const struct uuid *); ++int uuid_compare_3way(const struct uuid *, const struct uuid *); ++bool uuid_from_string(struct uuid *, const char *); ++bool uuid_from_string_prefix(struct uuid *, const char *); ++int uuid_is_partial_string(const char *); ++int uuid_is_partial_match(const struct uuid *, const char *match); ++void uuid_set_bits_v4(struct uuid *); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* uuid.h */ +Index: openvswitch-2.17.2/lib/bundle.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/bundle.h ++++ /dev/null +@@ -1,59 +0,0 @@ +-/* Copyright (c) 2011, 2012, 2013, 2014, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef BUNDLE_H +-#define BUNDLE_H 1 +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "openvswitch/compiler.h" +-#include "openflow/nicira-ext.h" +-#include "openvswitch/ofp-errors.h" +-#include "openvswitch/types.h" +- +-struct ds; +-struct flow; +-struct flow_wildcards; +-struct match; +-struct ofpact_bundle; +-struct ofpbuf; +-struct ofputil_port_map; +- +-/* NXAST_BUNDLE helper functions. +- * +- * See lib/ofp-actions.c for NXAST_BUNDLE specification. */ +- +-#define BUNDLE_MAX_MEMBERS 2048 +- +-ofp_port_t bundle_execute(const struct ofpact_bundle *, const struct flow *, +- struct flow_wildcards *wc, +- bool (*member_enabled)(ofp_port_t ofp_port, void *aux), +- void *aux); +-enum ofperr bundle_check(const struct ofpact_bundle *, ofp_port_t max_ports, +- const struct match *); +-char *bundle_parse(const char *, const struct ofputil_port_map *port_map, +- struct ofpbuf *ofpacts) OVS_WARN_UNUSED_RESULT; +-char *bundle_parse_load(const char *, const struct ofputil_port_map *port_map, +- struct ofpbuf *ofpacts) +- OVS_WARN_UNUSED_RESULT; +-void bundle_format(const struct ofpact_bundle *, +- const struct ofputil_port_map *, struct ds *); +- +-#endif /* bundle.h */ +Index: openvswitch-2.17.2/lib/byte-order.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/byte-order.h ++++ /dev/null +@@ -1,148 +0,0 @@ +-/* +- * Copyright (c) 2008, 2010, 2011, 2013, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-#ifndef BYTE_ORDER_H +-#define BYTE_ORDER_H 1 +- +-#include +-#include +-#include +-#include +-#include "openvswitch/types.h" +- +-#ifndef __CHECKER__ +-#if !(defined(_WIN32) || defined(htonll)) +-static inline ovs_be64 +-htonll(uint64_t n) +-{ +- return htonl(1) == 1 ? n : ((uint64_t) htonl(n) << 32) | htonl(n >> 32); +-} +- +-static inline uint64_t +-ntohll(ovs_be64 n) +-{ +- return htonl(1) == 1 ? n : ((uint64_t) ntohl(n) << 32) | ntohl(n >> 32); +-} +-#endif /* !(defined(_WIN32) || defined(htonll)) */ +-#else +-/* Making sparse happy with these functions also makes them unreadable, so +- * don't bother to show it their implementations. */ +-ovs_be64 htonll(uint64_t); +-uint64_t ntohll(ovs_be64); +-#endif +- +-static inline ovs_be128 +-hton128(const ovs_u128 src) +-{ +- ovs_be128 dst; +- +- dst.be64.hi = htonll(src.u64.hi); +- dst.be64.lo = htonll(src.u64.lo); +- return dst; +-} +- +-static inline ovs_u128 +-ntoh128(const ovs_be128 src) +-{ +- ovs_u128 dst; +- +- dst.u64.hi = ntohll(src.be64.hi); +- dst.u64.lo = ntohll(src.be64.lo); +- return dst; +-} +- +-static inline uint32_t +-uint32_byteswap(uint32_t crc) { +- return (((crc & 0x000000ff) << 24) | +- ((crc & 0x0000ff00) << 8) | +- ((crc & 0x00ff0000) >> 8) | +- ((crc & 0xff000000) >> 24)); +-} +- +-/* These macros may substitute for htons(), htonl(), and htonll() in contexts +- * where function calls are not allowed, such as case labels. They should not +- * be used elsewhere because all of them evaluate their argument many times. */ +-#if defined(WORDS_BIGENDIAN) || __CHECKER__ +-#define CONSTANT_HTONS(VALUE) ((OVS_FORCE ovs_be16) ((VALUE) & 0xffff)) +-#define CONSTANT_HTONL(VALUE) ((OVS_FORCE ovs_be32) ((VALUE) & 0xffffffff)) +-#define CONSTANT_HTONLL(VALUE) \ +- ((OVS_FORCE ovs_be64) ((VALUE) & UINT64_C(0xffffffffffffffff))) +-#else +-#define CONSTANT_HTONS(VALUE) \ +- (((((ovs_be16) (VALUE)) & 0xff00) >> 8) | \ +- ((((ovs_be16) (VALUE)) & 0x00ff) << 8)) +-#define CONSTANT_HTONL(VALUE) \ +- (((((ovs_be32) (VALUE)) & 0x000000ff) << 24) | \ +- ((((ovs_be32) (VALUE)) & 0x0000ff00) << 8) | \ +- ((((ovs_be32) (VALUE)) & 0x00ff0000) >> 8) | \ +- ((((ovs_be32) (VALUE)) & 0xff000000) >> 24)) +-#define CONSTANT_HTONLL(VALUE) \ +- (((((ovs_be64) (VALUE)) & UINT64_C(0x00000000000000ff)) << 56) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x000000000000ff00)) << 40) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x0000000000ff0000)) << 24) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x00000000ff000000)) << 8) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x000000ff00000000)) >> 8) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x0000ff0000000000)) >> 24) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0x00ff000000000000)) >> 40) | \ +- ((((ovs_be64) (VALUE)) & UINT64_C(0xff00000000000000)) >> 56)) +-#endif +- +-/* Returns the ovs_be32 that you would get from: +- * +- * union { uint8_t b[4]; ovs_be32 be32; } x = { .b = { b0, b1, b2, b3 } }; +- * return x.be32; +- * +- * but without the undefined behavior. */ +-static inline ovs_be32 +-bytes_to_be32(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) +-{ +-#if WORDS_BIGENDIAN +- uint32_t x = ((uint32_t) b0 << 24) | (b1 << 16) | (b2 << 8) | b3; +-#else +- uint32_t x = ((uint32_t) b3 << 24) | (b2 << 16) | (b1 << 8) | b0; +-#endif +- return (OVS_FORCE ovs_be32) x; +-} +- +-/* These functions zero-extend big-endian values to longer ones, +- * or truncate long big-endian value to shorter ones. */ +-#ifndef __CHECKER__ +-#if WORDS_BIGENDIAN +-static inline ovs_be32 be16_to_be32(ovs_be16 x) { return x; } +-static inline ovs_be64 be16_to_be64(ovs_be16 x) { return x; } +-static inline ovs_be64 be32_to_be64(ovs_be32 x) { return x; } +-static inline ovs_be32 be64_to_be32(ovs_be64 x) { return x; } +-static inline ovs_be16 be64_to_be16(ovs_be64 x) { return x; } +-static inline ovs_be16 be32_to_be16(ovs_be32 x) { return x; } +-#else /* !WORDS_BIGENDIAN */ +-static inline ovs_be32 be16_to_be32(ovs_be16 x) { return (ovs_be32) x << 16; } +-static inline ovs_be64 be16_to_be64(ovs_be16 x) { return (ovs_be64) x << 48; } +-static inline ovs_be64 be32_to_be64(ovs_be32 x) { return (ovs_be64) x << 32; } +-static inline ovs_be32 be64_to_be32(ovs_be64 x) { return x >> 32; } +-static inline ovs_be16 be64_to_be16(ovs_be64 x) { return x >> 48; } +-static inline ovs_be16 be32_to_be16(ovs_be32 x) { return x >> 16; } +-#endif /* !WORDS_BIGENDIAN */ +-#else /* __CHECKER__ */ +-/* Making sparse happy with these functions also makes them unreadable, so +- * don't bother to show it their implementations. */ +-ovs_be32 be16_to_be32(ovs_be16); +-ovs_be64 be16_to_be64(ovs_be16); +-ovs_be64 be32_to_be64(ovs_be32); +-ovs_be32 be64_to_be32(ovs_be64); +-ovs_be16 be64_to_be16(ovs_be64); +-ovs_be16 be32_to_be16(ovs_be32); +-#endif +- +-#endif /* byte-order.h */ +Index: openvswitch-2.17.2/lib/colors.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/colors.h ++++ /dev/null +@@ -1,42 +0,0 @@ +-/* +- * Copyright (c) 2016 6WIND S.A. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef COLORS_H +-#define COLORS_H 1 +- +-#include +- +-struct colors { +- /* Color codes for various situation. Each of these is a fully formed +- * Select Graphic Rendition (SGR, "\33[...m") start string for the +- * appropriate color. +- */ +- char *actions; +- char *drop; +- char *learn; +- char *param; +- char *paren; +- char *special; +- char *value; +- +- /* SGR end string. */ +- char *end; +-}; +-extern struct colors colors; +- +-void colors_init(bool enable_color); +- +-#endif /* colors.h */ +Index: openvswitch-2.17.2/lib/command-line.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/command-line.h ++++ /dev/null +@@ -1,77 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef COMMAND_LINE_H +-#define COMMAND_LINE_H 1 +- +-/* Utilities for command-line parsing. */ +- +-#include "openvswitch/compiler.h" +- +-struct option; +- +-/* Command handler context */ +-struct ovs_cmdl_context { +- /* number of command line arguments */ +- int argc; +- /* array of command line arguments */ +- char **argv; +- /* private context data defined by the API user */ +- void *pvt; +-}; +- +-typedef void (*ovs_cmdl_handler)(struct ovs_cmdl_context *); +- +-struct ovs_cmdl_command { +- const char *name; +- const char *usage; +- int min_args; +- int max_args; +- ovs_cmdl_handler handler; +- enum { OVS_RO, OVS_RW } mode; /* Does this command modify things? */ +-}; +- +-char *ovs_cmdl_long_options_to_short_options(const struct option *options); +- +-struct ovs_cmdl_parsed_option { +- const struct option *o; +- char *arg; +-}; +-char *ovs_cmdl_parse_all(int argc, char *argv[], const struct option *, +- struct ovs_cmdl_parsed_option **, size_t *) +- OVS_WARN_UNUSED_RESULT; +- +-char **ovs_cmdl_env_parse_all(int *argcp, char *argv_[], +- const char *env_options); +- +-void ovs_cmdl_print_options(const struct option *options); +-void ovs_cmdl_print_commands(const struct ovs_cmdl_command *commands); +- +-void ovs_cmdl_run_command(struct ovs_cmdl_context *, +- const struct ovs_cmdl_command[]); +-void ovs_cmdl_run_command_read_only(struct ovs_cmdl_context *, +- const struct ovs_cmdl_command[]); +- +-void ovs_cmdl_proctitle_init(int argc, char **argv); +-#if defined(__FreeBSD__) || defined(__NetBSD__) +-#define ovs_cmdl_proctitle_set setproctitle +-#else +-void ovs_cmdl_proctitle_set(const char *, ...) +- OVS_PRINTF_FORMAT(1, 2); +-#endif +-void ovs_cmdl_proctitle_restore(void); +- +-#endif /* command-line.h */ +Index: openvswitch-2.17.2/lib/crc32c.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/crc32c.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- * Copyright (c) 2012 The University of Waikato. +- * Author: Joe Stringer +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef CRC32C_H +-#define CRC32C_H 1 +- +-#include "openvswitch/types.h" +- +-ovs_be32 crc32c(const uint8_t *data, size_t); +- +-#endif /* crc32c.h */ +Index: openvswitch-2.17.2/lib/csum.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/csum.h ++++ /dev/null +@@ -1,59 +0,0 @@ +-/* +- * Copyright (c) 2008, 2011, 2015 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef CSUM_H +-#define CSUM_H 1 +- +-#include +-#include +-#include "openvswitch/types.h" +- +-struct in6_addr; +- +-ovs_be16 csum(const void *, size_t); +-uint32_t csum_continue(uint32_t partial, const void *, size_t); +-ovs_be16 csum_finish(uint32_t partial); +-ovs_be16 recalc_csum16(ovs_be16 old_csum, ovs_be16 old_u16, ovs_be16 new_u16); +-ovs_be16 recalc_csum32(ovs_be16 old_csum, ovs_be32 old_u32, ovs_be32 new_u32); +-ovs_be16 recalc_csum48(ovs_be16 old_csum, const struct eth_addr old_mac, +- const struct eth_addr new_mac); +-ovs_be16 recalc_csum128(ovs_be16 old_csum, ovs_16aligned_be32 old_u32[4], +- const struct in6_addr *); +- +-#ifndef __CHECKER__ +-/* Adds the 16 bits in 'new' to the partial IP checksum 'partial' and returns +- * the updated checksum. (To start a new checksum, pass 0 for 'partial'. To +- * obtain the finished checksum, pass the return value to csum_finish().) */ +-static inline uint32_t +-csum_add16(uint32_t partial, ovs_be16 new) +-{ +- return partial + new; +-} +- +-/* Adds the 32 bits in 'new' to the partial IP checksum 'partial' and returns +- * the updated checksum. (To start a new checksum, pass 0 for 'partial'. To +- * obtain the finished checksum, pass the return value to csum_finish().) */ +-static inline uint32_t +-csum_add32(uint32_t partial, ovs_be32 new) +-{ +- return partial + (new >> 16) + (new & 0xffff); +-} +-#else +-uint32_t csum_add16(uint32_t partial, ovs_be16); +-uint32_t csum_add32(uint32_t partial, ovs_be32); +-#endif +- +-#endif /* csum.h */ +Index: openvswitch-2.17.2/lib/daemon.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/daemon.h ++++ /dev/null +@@ -1,183 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DAEMON_H +-#define DAEMON_H 1 +- +-#include +-#include +-#include +- +-/* This file provides an interface for utilities to run in the background +- * as daemons on POSIX platforms like Linux or as services on Windows platform. +- * Some of the functionalities defined in this file are only applicable to +- * POSIX platforms and some are applicable only on Windows. As such, the +- * function definitions unique to each platform are separated out with +- * ifdef macros. More descriptive comments on individual functions are provided +- * in daemon-unix.c (for POSIX platforms) and daemon-windows.c (for Windows). +- +- * The DAEMON_OPTION_ENUMS, DAEMON_LONG_OPTIONS and DAEMON_OPTION_HANDLERS +- * macros are useful for parsing command-line options in individual utilities. +- * For e.g., the command-line option "--monitor" is recognized on Linux +- * and results in calling the daemon_set_monitor() function. The same option is +- * not recognized on Windows platform. +- */ +- +-#ifndef _WIN32 +-#define DAEMON_OPTION_ENUMS \ +- OPT_DETACH, \ +- OPT_NO_SELF_CONFINEMENT, \ +- OPT_NO_CHDIR, \ +- OPT_OVERWRITE_PIDFILE, \ +- OPT_PIDFILE, \ +- OPT_MONITOR, \ +- OPT_USER_GROUP +- +-#define DAEMON_LONG_OPTIONS \ +- {"detach", no_argument, NULL, OPT_DETACH}, \ +- {"no-self-confinement", no_argument, NULL, OPT_NO_SELF_CONFINEMENT}, \ +- {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ +- {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ +- {"overwrite-pidfile", no_argument, NULL, OPT_OVERWRITE_PIDFILE}, \ +- {"monitor", no_argument, NULL, OPT_MONITOR}, \ +- {"user", required_argument, NULL, OPT_USER_GROUP} +- +-#define DAEMON_OPTION_HANDLERS \ +- case OPT_DETACH: \ +- set_detach(); \ +- break; \ +- \ +- case OPT_NO_SELF_CONFINEMENT: \ +- daemon_disable_self_confinement(); \ +- break; \ +- \ +- case OPT_NO_CHDIR: \ +- set_no_chdir(); \ +- break; \ +- \ +- case OPT_PIDFILE: \ +- set_pidfile(optarg); \ +- break; \ +- \ +- case OPT_OVERWRITE_PIDFILE: \ +- ignore_existing_pidfile(); \ +- break; \ +- \ +- case OPT_MONITOR: \ +- daemon_set_monitor(); \ +- break; \ +- \ +- case OPT_USER_GROUP: \ +- daemon_set_new_user(optarg); \ +- break; +- +-#define DAEMON_OPTION_CASES \ +- case OPT_DETACH: \ +- case OPT_NO_SELF_CONFINEMENT: \ +- case OPT_NO_CHDIR: \ +- case OPT_PIDFILE: \ +- case OPT_OVERWRITE_PIDFILE: \ +- case OPT_MONITOR: \ +- case OPT_USER_GROUP: +- +-void set_detach(void); +-void daemon_set_monitor(void); +-void set_no_chdir(void); +-void ignore_existing_pidfile(void); +-pid_t read_pidfile(const char *name); +-#else +-#define DAEMON_OPTION_ENUMS \ +- OPT_DETACH, \ +- OPT_NO_SELF_CONFINEMENT, \ +- OPT_NO_CHDIR, \ +- OPT_PIDFILE, \ +- OPT_PIPE_HANDLE, \ +- OPT_SERVICE, \ +- OPT_SERVICE_MONITOR, \ +- OPT_USER_GROUP +- +-#define DAEMON_LONG_OPTIONS \ +- {"detach", no_argument, NULL, OPT_DETACH}, \ +- {"no-self-confinement", no_argument, NULL, OPT_NO_SELF_CONFINEMENT}, \ +- {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ +- {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ +- {"pipe-handle", required_argument, NULL, OPT_PIPE_HANDLE}, \ +- {"service", no_argument, NULL, OPT_SERVICE}, \ +- {"service-monitor", no_argument, NULL, OPT_SERVICE_MONITOR}, \ +- {"user", required_argument, NULL, OPT_USER_GROUP} +- +-#define DAEMON_OPTION_HANDLERS \ +- case OPT_DETACH: \ +- set_detach(); \ +- break; \ +- \ +- case OPT_NO_SELF_CONFINEMENT: \ +- daemon_disable_self_confinement(); \ +- break; \ +- \ +- case OPT_NO_CHDIR: \ +- break; \ +- \ +- case OPT_PIDFILE: \ +- set_pidfile(optarg); \ +- break; \ +- \ +- case OPT_PIPE_HANDLE: \ +- set_pipe_handle(optarg); \ +- break; \ +- \ +- case OPT_SERVICE: \ +- set_detach(); \ +- break; \ +- \ +- case OPT_SERVICE_MONITOR: \ +- break; \ +- \ +- case OPT_USER_GROUP: \ +- daemon_set_new_user(optarg); +- +-#define DAEMON_OPTION_CASES \ +- case OPT_DETACH: \ +- case OPT_NO_SELF_CONFINEMENT: \ +- case OPT_NO_CHDIR: \ +- case OPT_PIDFILE: \ +- case OPT_PIPE_HANDLE: \ +- case OPT_SERVICE: \ +- case OPT_SERVICE_MONITOR: \ +- case OPT_USER_GROUP: +- +-void control_handler(DWORD request); +-void set_pipe_handle(const char *pipe_handle); +-void set_detach(void); +-#endif /* _WIN32 */ +- +-bool get_detach(void); +-void daemon_save_fd(int fd); +-void daemonize(void); +-void daemonize_start(bool access_datapath); +-void daemonize_complete(void); +-void daemon_set_new_user(const char * user_spec); +-void daemon_become_new_user(bool access_datapath); +-void daemon_usage(void); +-void daemon_disable_self_confinement(void); +-bool daemon_should_self_confine(void); +-void service_start(int *argcp, char **argvp[]); +-void service_stop(void); +-bool should_service_stop(void); +-void set_pidfile(const char *name); +-void close_standard_fds(void); +- +-#endif /* daemon.h */ +Index: openvswitch-2.17.2/lib/db-ctl-base.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/db-ctl-base.h ++++ /dev/null +@@ -1,282 +0,0 @@ +-/* +- * Copyright (c) 2015, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DB_CTL_BASE_H +-#define DB_CTL_BASE_H 1 +- +-#include "openvswitch/compiler.h" +-#include "openvswitch/dynamic-string.h" +-#include "openvswitch/shash.h" +- +-struct ctl_context; +-struct option; +-struct ovsdb_idl; +-struct ovsdb_idl_row; +-struct ovsdb_idl_txn; +-struct ovsdb_symbol_table; +-struct table; +- +-/* This library module contains the common parts for ovsdb manipulation +- * (structs, commands and functions). To utilize this module, user must +- * define the following: +- * +- * - the command syntaxes for each command. (See 'struct ctl_command_syntax' +- * for more info) and regiters them using ctl_register_commands(). +- * +- * - the *ctl command context by inheriting the 'struct ctl_context' for +- * additional commands implemented by user. (See 'struct ctl_context' for +- * more info) +-*/ +- +-/* ctl_fatal() also logs the error, so it is preferred in this file. */ +-#define ovs_fatal please_use_ctl_fatal_instead_of_ovs_fatal +- +-struct ctl_table_class; +-struct ovsdb_idl_class; +-struct ovsdb_idl_table_class; +-struct cmd_show_table; +- +-/* ctl_init() figures out the number of tables on its own and flags an error if +- * 'ctl_classes' was defined with the wrong number of elements. */ +-#define ctl_init(idl_class, table_classes, ctl_classes, cmd_show_table, \ +- ctl_exit_func) \ +- (BUILD_ASSERT(ARRAY_SIZE(table_classes) == ARRAY_SIZE(ctl_classes)), \ +- ctl_init__(idl_class, ctl_classes, cmd_show_table, ctl_exit_func)) +-void ctl_init__(const struct ovsdb_idl_class *, const struct ctl_table_class *, +- const struct cmd_show_table *cmd_show_tables, +- void (*ctl_exit_func)(int status)); +-char *ctl_default_db(void); +-void ctl_error(struct ctl_context *, const char *, ...) +-OVS_PRINTF_FORMAT(2, 3); +-OVS_NO_RETURN void ctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2); +- +-/* *ctl command syntax structure, to be defined by each command implementation. +- * +- * Execution Path +- * ============== +- * +- * Three stylized functions accompany each of these data structures: +- * +- * "pre-run" "run" "post-run" +- * --------------- ------------ ----------------- +- * *ctl ->prerequisites ->run ->postprocess +- * +- * Any *ctl command implementation should go through the following execution +- * path: +- * +- * 1. parses user command-line input and finds the corresponding syntax +- * structures. +- * +- * 2. calls prerequisites() for getting the columns or tables used by each +- * command. +- * +- * 3. calls run() to execute each command and to generate output. +- * +- * 4. calls postprocess() after output has been committed. (Only needed +- * by 'create' command sofar) +- * +- * Execution Context +- * ================= +- * +- * Each of the stylized functions requires the 'struct ctl_context' as input +- * to provide context e.g. command-line arguments, table to be modified. User +- * may define more specific context (by inheriting 'struct ctl_context') and +- * write stylized functions that use it. In that case, CONTAINER_OF() can +- * be used to cast the generic context to the specific one. +- * +- * */ +-struct ctl_command_syntax { +- const char *name; /* e.g. "add-br" */ +- int min_args; /* Min number of arguments following name. */ +- int max_args; /* Max number of arguments following name. */ +- +- /* Names that roughly describe the arguments that the command +- * uses. These should be similar to the names displayed in the +- * man page or in the help output. */ +- const char *arguments; +- +- /* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table() for +- * each column or table in ctx->idl that it uses. */ +- void (*prerequisites)(struct ctl_context *ctx); +- +- /* Does the actual work of the command and puts the command's output, if +- * any, in ctx->output or ctx->table. +- * +- * Alternatively, if some prerequisite of the command is not met and the +- * caller should wait for something to change and then retry, it may set +- * ctx->try_again to true. (Only the "wait-until" command currently does +- * this.) */ +- void (*run)(struct ctl_context *ctx); +- +- /* If nonnull, called after the transaction has been successfully +- * committed. ctx->output is the output from the "run" function, which +- * this function may modify and otherwise postprocess as needed. (Only the +- * "create" command currently does any postprocessing.) */ +- void (*postprocess)(struct ctl_context *ctx); +- +- /* A comma-separated list of supported options, e.g. "--a,--b", or the +- * empty string if the command does not support any options. +- * +- * Arguments are determined by appending special characters to option +- * names: +- * +- * - Append "=" (e.g. "--id=") for a required argument. +- * +- * - Append "?" (e.g. "--ovs?") for an optional argument. +- * +- * - Otherwise an option does not accept an argument. */ +- const char *options; +- +- enum { RO, RW } mode; /* Does this command modify the database? */ +-}; +- +-/* A command extracted from command-line input plus the structs for +- * output generation. */ +-struct ctl_command { +- /* Data that remains constant after initialization. */ +- const struct ctl_command_syntax *syntax; +- int argc; +- char **argv; +- struct shash options; +- +- /* Data modified by commands. */ +- struct ds output; +- struct table *table; +-}; +- +-bool ctl_might_write_to_db(const struct ctl_command *, size_t n); +-const char *ctl_get_db_cmd_usage(void); +- +-const char *ctl_list_db_tables_usage(void); +-void ctl_print_commands(void); +-void ctl_print_options(const struct option *); +-void ctl_add_cmd_options(struct option **, size_t *n_options_p, +- size_t *allocated_options_p, int opt_val); +-void ctl_register_commands(const struct ctl_command_syntax *); +-char * OVS_WARN_UNUSED_RESULT ctl_parse_commands( +- int argc, char *argv[], struct shash *local_options, +- struct ctl_command **commandsp, size_t *n_commandsp); +- +-/* Sometimes, it is desirable to print the table with weak reference to +- * rows in a 'cmd_show_table' table. In that case, the 'weak_ref_table' +- * should be used and user must define all variables. */ +-struct weak_ref_table { +- const struct ovsdb_idl_table_class *table; +- const struct ovsdb_idl_column *name_column; +- /* This colum must be a weak reference to the owning +- * 'struct cmd_show_table''s table row. */ +- const struct ovsdb_idl_column *wref_column; +-}; +- +-/* This struct is for organizing the 'show' command output where: +- * +- * - 'table' is the table to show. +- * +- * - if 'name_column' is not null, it is used as the name for each row +- * in 'table'. +- * +- * - 'columns[]' allows user to specify the print of additional columns +- * in 'table'. +- * +- * - if 'wref_table' is populated, print 'wref_table.name_column' for +- * each row in table 'wref_table.table' that has a reference to 'table' +- * in 'wref_table.wref_column'. Every field must be populated. +- * +- * */ +-struct cmd_show_table { +- const struct ovsdb_idl_table_class *table; +- const struct ovsdb_idl_column *name_column; +- const struct ovsdb_idl_column *columns[4]; /* Seems like a good number. */ +- const struct weak_ref_table wref_table; +-}; +- +- +-/* The base context struct for conducting the common database +- * operations (commands listed in 'db_ctl_commands'). User should +- * define the per-schema context by inheriting this struct as base. +- * +- * Database Caches +- * =============== +- * +- * User may implement caches for contents of the database to facilitate +- * specific commands. In that case, the common commands defined in +- * 'db_ctl_commands' that may invalidate the cache must call the +- * invalidate_cache(). +- * +- **/ +-struct ctl_context { +- /* Read-only. */ +- int argc; +- char **argv; +- struct shash options; +- +- /* Modifiable state. */ +- char *error; +- struct ds output; +- struct table *table; +- struct ovsdb_idl *idl; +- struct ovsdb_idl_txn *txn; +- struct ovsdb_symbol_table *symtab; +- +- /* For implementation with a cache of the contents of the database, +- * this function will be called when the database is changed and the +- * change makes the cache no longer valid. */ +- void (*invalidate_cache_cb)(struct ctl_context *); +- +- /* A command may set this member to true if some prerequisite is not met +- * and the caller should wait for something to change and then retry. */ +- bool try_again; +-}; +- +-void ctl_context_init_command(struct ctl_context *, struct ctl_command *); +-void ctl_context_init(struct ctl_context *, struct ctl_command *, +- struct ovsdb_idl *, struct ovsdb_idl_txn *, +- struct ovsdb_symbol_table *, +- void (*invalidate_cache)(struct ctl_context *)); +-void ctl_context_done_command(struct ctl_context *, struct ctl_command *); +-void ctl_context_done(struct ctl_context *, struct ctl_command *); +- +-/* A way to identify a particular row in the database based on a user-provided +- * string. If all fields are NULL, the struct is ignored. Otherwise, +- * 'name_column' designates a column whose table is searched for rows that +- * match with the user string. If 'key' is NULL, then 'name_column' should be +- * a string or integer-valued column; otherwise it should be a map from a +- * string to one of those types and the value corresponding to 'key' is what is +- * matched. If a matching row is found, then: +- * +- * - If 'uuid_column' is NULL, the matching row is the final row. +- * +- * - Otherwise 'uuid_column' must designate a UUID-typed column whose value +- * refers to exactly one row, which is the final row. +- */ +-struct ctl_row_id { +- const struct ovsdb_idl_column *name_column; +- const char *key; +- const struct ovsdb_idl_column *uuid_column; +-}; +- +-struct ctl_table_class { +- struct ctl_row_id row_ids[4]; +-}; +- +-char *ctl_get_row(struct ctl_context *, const struct ovsdb_idl_table_class *, +- const char *record_id, bool must_exist, +- const struct ovsdb_idl_row **); +- +-char *ctl_set_column(const char *table_name, const struct ovsdb_idl_row *, +- const char *arg, struct ovsdb_symbol_table *); +- +-#endif /* db-ctl-base.h */ +Index: openvswitch-2.17.2/lib/dhparams.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dhparams.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* +- * Copyright (c) 2008, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DHPARAMS_H +-#define DHPARAMS_H 1 +- +-#include +-#include +- +-DH *get_dh2048(void); +-DH *get_dh4096(void); +- +-#endif /* dhparams.h */ +Index: openvswitch-2.17.2/lib/dirs.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/dirs.h ++++ /dev/null +@@ -1,35 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef DIRS_H +-#define DIRS_H 1 +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-const char *ovs_sysconfdir(void); /* /usr/local/etc */ +-const char *ovs_pkgdatadir(void); /* /usr/local/share/openvswitch */ +-const char *ovs_rundir(void); /* /usr/local/var/run/openvswitch */ +-const char *ovs_logdir(void); /* /usr/local/var/log/openvswitch */ +-const char *ovs_dbdir(void); /* /usr/local/etc/openvswitch */ +-const char *ovs_bindir(void); /* /usr/local/bin */ +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* dirs.h */ +Index: openvswitch-2.17.2/lib/fatal-signal.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/fatal-signal.h ++++ /dev/null +@@ -1,52 +0,0 @@ +-/* +- * 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef FATAL_SIGNAL_H +-#define FATAL_SIGNAL_H 1 +- +-#ifndef _WIN32 +-#include +-#endif +-#include +- +-/* Basic interface. */ +-void fatal_signal_init(void); +-void fatal_signal_add_hook(void (*hook_cb)(void *aux), +- void (*cancel_cb)(void *aux), void *aux, +- bool run_at_exit); +-void fatal_signal_fork(void); +-void fatal_signal_run(void); +-void fatal_signal_wait(void); +-void fatal_ignore_sigpipe(void); +-void fatal_signal_atexit_handler(void); +- +-/* Convenience functions for unlinking files upon termination. +- * +- * These functions also unlink the files upon normal process termination via +- * exit(). */ +-void fatal_signal_add_file_to_unlink(const char *); +-void fatal_signal_remove_file_to_unlink(const char *); +-int fatal_signal_unlink_file_now(const char *); +- +-/* Interface for other code that catches one of our signals and needs to pass +- * it through. */ +-void fatal_signal_handler(int sig_nr); +- +-#ifndef _WIN32 +-void fatal_signal_block(sigset_t *prev_mask); +-#endif +- +-#endif /* fatal-signal.h */ +Index: openvswitch-2.17.2/lib/hash-aarch64.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/hash-aarch64.h ++++ /dev/null +@@ -1,150 +0,0 @@ +-/* +- * Copyright (c) 2019 Arm Limited +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements HASH operation primitives on aarch64. */ +-#ifndef HASH_AARCH64_H +-#define HASH_AARCH64_H 1 +- +-#ifndef HASH_H +-#error "This header should only be included indirectly via hash.h." +-#endif +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#include +- +-static inline uint32_t hash_add(uint32_t hash, uint32_t data) +-{ +- return __crc32cw(hash, data); +-} +- +-/* Add the halves of 'data' in the memory order. */ +-static inline uint32_t hash_add64(uint32_t hash, uint64_t data) +-{ +- return __crc32cd(hash, data); +-} +- +-static inline uint32_t hash_finish(uint32_t hash, uint64_t final) +-{ +- /* The finishing multiplier 0x805204f3 has been experimentally +- * derived to pass the testsuite hash tests. */ +- hash = __crc32cd(hash, final) * 0x805204f3; +- return hash ^ hash >> 16; /* Increase entropy in LSBs. */ +-} +- +-/* Returns the hash of the 'n' 32-bit words at 'p_', starting from 'basis'. +- * We access 'p_' as a uint64_t pointer. +- * +- * This is inlined for the compiler to have access to the 'n_words', which +- * in many cases is a constant. */ +-static inline uint32_t +-hash_words_inline(const uint32_t p_[], size_t n_words, uint32_t basis) +-{ +- const uint64_t *p = (const void *)p_; +- uint32_t hash1 = basis; +- uint32_t hash2 = 0; +- uint32_t hash3 = n_words; +- const uint32_t *endp = (const uint32_t *)p + n_words; +- const uint64_t *limit = p + n_words / 2 - 3; +- +- while (p <= limit) { +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cd(hash2, p[1]); +- hash3 = __crc32cd(hash3, p[2]); +- p += 3; +- } +- switch (endp - (const uint32_t *)p) { +- case 1: +- hash1 = __crc32cw(hash1, *(const uint32_t *)&p[0]); +- break; +- case 2: +- hash1 = __crc32cd(hash1, p[0]); +- break; +- case 3: +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cw(hash2, *(const uint32_t *)&p[1]); +- break; +- case 4: +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cd(hash2, p[1]); +- break; +- case 5: +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cd(hash2, p[1]); +- hash3 = __crc32cw(hash3, *(const uint32_t *)&p[2]); +- break; +- } +- return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3); +-} +- +-/* A simpler version for 64-bit data. +- * 'n_words' is the count of 64-bit words, basis is 64 bits. */ +-static inline uint32_t +-hash_words64_inline(const uint64_t p[], size_t n_words, uint32_t basis) +-{ +- uint32_t hash1 = basis; +- uint32_t hash2 = 0; +- uint32_t hash3 = n_words; +- const uint64_t *endp = p + n_words; +- const uint64_t *limit = endp - 3; +- +- while (p <= limit) { +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cd(hash2, p[1]); +- hash3 = __crc32cd(hash3, p[2]); +- p += 3; +- } +- switch (endp - p) { +- case 1: +- hash1 = __crc32cd(hash1, p[0]); +- break; +- case 2: +- hash1 = __crc32cd(hash1, p[0]); +- hash2 = __crc32cd(hash2, p[1]); +- break; +- } +- return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3); +-} +- +-static inline uint32_t hash_uint64_basis(const uint64_t x, +- const uint32_t basis) +-{ +- /* '23' chosen to mix bits enough for the test-hash to pass. */ +- return hash_finish(hash_add64(basis, x), 23); +-} +- +-static inline uint32_t hash_uint64(const uint64_t x) +-{ +- return hash_uint64_basis(x, 0); +-} +- +-static inline uint32_t hash_2words(uint32_t x, uint32_t y) +-{ +- return hash_uint64((uint64_t)y << 32 | x); +-} +- +-static inline uint32_t hash_pointer(const void *p, uint32_t basis) +-{ +- return hash_uint64_basis((uint64_t) (uintptr_t) p, basis); +-} +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* hash-aarch64.h */ +Index: openvswitch-2.17.2/lib/hmapx.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/hmapx.h ++++ /dev/null +@@ -1,86 +0,0 @@ +-/* +- * Copyright (c) 2011, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef HMAPX_H +-#define HMAPX_H +- +-#include "openvswitch/hmap.h" +- +-struct hmapx_node { +- struct hmap_node hmap_node; +- void *data; +-}; +- +-/* A set of "void *" pointers. */ +-struct hmapx { +- struct hmap map; +-}; +- +-#define HMAPX_INITIALIZER(HMAPX) { HMAP_INITIALIZER(&(HMAPX)->map) } +- +-/* Basics. */ +-void hmapx_init(struct hmapx *); +-void hmapx_destroy(struct hmapx *); +-void hmapx_clone(struct hmapx *, const struct hmapx *); +-void hmapx_swap(struct hmapx *, struct hmapx *); +-void hmapx_moved(struct hmapx *); +- +-/* Count. */ +-bool hmapx_is_empty(const struct hmapx *); +-size_t hmapx_count(const struct hmapx *); +- +-/* Insertion. */ +-struct hmapx_node *hmapx_add(struct hmapx *, void *); +-void hmapx_add_assert(struct hmapx *, void *); +- +-/* Deletion. */ +-void hmapx_clear(struct hmapx *); +-void hmapx_delete(struct hmapx *, struct hmapx_node *); +-bool hmapx_find_and_delete(struct hmapx *, const void *); +-void hmapx_find_and_delete_assert(struct hmapx *, const void *); +- +-/* Search. */ +-struct hmapx_node *hmapx_find(const struct hmapx *, const void *); +-bool hmapx_contains(const struct hmapx *, const void *); +-bool hmapx_equals(const struct hmapx *, const struct hmapx *); +- +-/* Iteration. */ +- +-/* Iterates through every hmapx_node in HMAPX. */ +-#define HMAPX_FOR_EACH(NODE, HMAPX) \ +- HMAP_FOR_EACH_INIT(NODE, hmap_node, &(HMAPX)->map, \ +- BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ +- BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) +- +-/* Safe when NODE may be freed (not needed when NODE may be removed from the +- * hash map but its members remain accessible and intact). */ +-#define HMAPX_FOR_EACH_SAFE_SHORT(NODE, HMAPX) \ +- HMAP_FOR_EACH_SAFE_SHORT_INIT (NODE, hmap_node, &(HMAPX)->map, \ +- BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ +- BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) +- +-#define HMAPX_FOR_EACH_SAFE_LONG(NODE, NEXT, HMAPX) \ +- HMAP_FOR_EACH_SAFE_LONG_INIT (NODE, NEXT, hmap_node, &(HMAPX)->map, \ +- BUILD_ASSERT_TYPE(NODE, struct hmapx_node *), \ +- BUILD_ASSERT_TYPE(NEXT, struct hmapx_node *), \ +- BUILD_ASSERT_TYPE(HMAPX, struct hmapx *)) +- +-#define HMAPX_FOR_EACH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(HMAPX_FOR_EACH_SAFE_LONG, \ +- HMAPX_FOR_EACH_SAFE_SHORT, \ +- 3, __VA_ARGS__) +- +-#endif /* hmapx.h */ +Index: openvswitch-2.17.2/lib/id-pool.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/id-pool.h ++++ /dev/null +@@ -1,45 +0,0 @@ +-/* +- * Copyright (c) 2014 Nicira, Inc. +- * Copyright (c) 2014 Netronome. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef ID_POOL_H +-#define ID_POOL_H +- +-#include +-#include +-#include +- +-struct id_pool; +- +-struct id_pool *id_pool_create(uint32_t base, uint32_t n_ids); +-void id_pool_destroy(struct id_pool *); +-bool id_pool_alloc_id(struct id_pool *, uint32_t *id); +-void id_pool_free_id(struct id_pool *, uint32_t id); +-void id_pool_add(struct id_pool *, uint32_t id); +- +-/* +- * ID pool. +- * ======== +- * +- * Pool of unique 32bit ids. +- * Allocation always returns the lowest available id. +- * +- * Thread-safety +- * ============= +- * +- * APIs are not thread safe. +- */ +-#endif /* id-pool.h */ +Index: openvswitch-2.17.2/lib/jsonrpc.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/jsonrpc.h ++++ /dev/null +@@ -1,153 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2012, 2013, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef JSONRPC_H +-#define JSONRPC_H 1 +- +-/* This is an implementation of the JSON-RPC 1.0 specification defined at +- * http://json-rpc.org/wiki/specification. */ +- +-#include +-#include +-#include "openvswitch/types.h" +- +-struct json; +-struct jsonrpc_msg; +-struct pstream; +-struct reconnect_stats; +-struct stream; +-struct svec; +- +-/* API for a JSON-RPC stream. */ +- +-/* Default port numbers. +- * +- * OVSDB_OLD_PORT defines the original port number used by OVS. +- * OVSDB_PORT defines the official port number assigned by IANA. */ +-#define OVSDB_OLD_PORT 6632 +-#define OVSDB_PORT 6640 +- +-int jsonrpc_stream_open(const char *name, struct stream **, uint8_t dscp); +-int jsonrpc_pstream_open(const char *name, struct pstream **, uint8_t dscp); +- +-struct jsonrpc *jsonrpc_open(struct stream *); +-void jsonrpc_close(struct jsonrpc *); +- +-void jsonrpc_run(struct jsonrpc *); +-void jsonrpc_wait(struct jsonrpc *); +- +-int jsonrpc_get_status(const struct jsonrpc *); +-size_t jsonrpc_get_backlog(const struct jsonrpc *); +-void jsonrpc_set_backlog_threshold(struct jsonrpc *, size_t max_n_msgs, +- size_t max_backlog_bytes); +- +-unsigned int jsonrpc_get_received_bytes(const struct jsonrpc *); +-const char *jsonrpc_get_name(const struct jsonrpc *); +- +-int jsonrpc_send(struct jsonrpc *, struct jsonrpc_msg *); +-int jsonrpc_recv(struct jsonrpc *, struct jsonrpc_msg **); +-void jsonrpc_recv_wait(struct jsonrpc *); +- +-int jsonrpc_send_block(struct jsonrpc *, struct jsonrpc_msg *); +-int jsonrpc_recv_block(struct jsonrpc *, struct jsonrpc_msg **); +-int jsonrpc_transact_block(struct jsonrpc *, struct jsonrpc_msg *, +- struct jsonrpc_msg **); +- +-/* Messages. */ +-enum jsonrpc_msg_type { +- JSONRPC_REQUEST, /* Request. */ +- JSONRPC_NOTIFY, /* Notification. */ +- JSONRPC_REPLY, /* Successful reply. */ +- JSONRPC_ERROR /* Error reply. */ +-}; +- +-struct jsonrpc_msg { +- enum jsonrpc_msg_type type; +- char *method; /* Request or notification only. */ +- struct json *params; /* Request or notification only. */ +- struct json *result; /* Successful reply only. */ +- struct json *error; /* Error reply only. */ +- struct json *id; /* Request or reply only. */ +-}; +- +-struct jsonrpc_msg *jsonrpc_create_request(const char *method, +- struct json *params, +- struct json **idp); +-struct jsonrpc_msg *jsonrpc_create_notify(const char *method, +- struct json *params); +-struct jsonrpc_msg *jsonrpc_create_reply(struct json *result, +- const struct json *id); +-struct jsonrpc_msg *jsonrpc_create_error(struct json *error, +- const struct json *id); +- +-struct jsonrpc_msg *jsonrpc_msg_clone(const struct jsonrpc_msg *); +- +-const char *jsonrpc_msg_type_to_string(enum jsonrpc_msg_type); +-char *jsonrpc_msg_is_valid(const struct jsonrpc_msg *); +-void jsonrpc_msg_destroy(struct jsonrpc_msg *); +- +-char *jsonrpc_msg_from_json(struct json *, struct jsonrpc_msg **); +-struct json *jsonrpc_msg_to_json(struct jsonrpc_msg *); +- +-char *jsonrpc_msg_to_string(const struct jsonrpc_msg *); +- +-/* A JSON-RPC session with reconnection. */ +- +-struct jsonrpc_session *jsonrpc_session_open(const char *name, bool retry); +-struct jsonrpc_session *jsonrpc_session_open_multiple(const struct svec *, +- bool retry); +-struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *, +- uint8_t); +-void jsonrpc_session_close(struct jsonrpc_session *); +- +-struct jsonrpc *jsonrpc_session_steal(struct jsonrpc_session *); +-void jsonrpc_session_replace(struct jsonrpc_session *, struct jsonrpc *); +- +-void jsonrpc_session_run(struct jsonrpc_session *); +-void jsonrpc_session_wait(struct jsonrpc_session *); +- +-size_t jsonrpc_session_get_backlog(const struct jsonrpc_session *); +-const char *jsonrpc_session_get_name(const struct jsonrpc_session *); +-size_t jsonrpc_session_get_n_remotes(const struct jsonrpc_session *); +- +-int jsonrpc_session_send(struct jsonrpc_session *, struct jsonrpc_msg *); +-struct jsonrpc_msg *jsonrpc_session_recv(struct jsonrpc_session *); +-void jsonrpc_session_recv_wait(struct jsonrpc_session *); +- +-bool jsonrpc_session_is_alive(const struct jsonrpc_session *); +-bool jsonrpc_session_is_connected(const struct jsonrpc_session *); +-unsigned int jsonrpc_session_get_seqno(const struct jsonrpc_session *); +-int jsonrpc_session_get_status(const struct jsonrpc_session *); +-int jsonrpc_session_get_last_error(const struct jsonrpc_session *); +-void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *, +- struct reconnect_stats *); +- +-void jsonrpc_session_enable_reconnect(struct jsonrpc_session *); +-void jsonrpc_session_force_reconnect(struct jsonrpc_session *); +-void jsonrpc_session_reset_backoff(struct jsonrpc_session *); +- +-void jsonrpc_session_set_max_backoff(struct jsonrpc_session *, +- int max_backoff); +-void jsonrpc_session_set_probe_interval(struct jsonrpc_session *, +- int probe_interval); +-void jsonrpc_session_set_dscp(struct jsonrpc_session *, +- uint8_t dscp); +-void jsonrpc_session_set_backlog_threshold(struct jsonrpc_session *, +- size_t max_n_msgs, +- size_t max_backlog_bytes); +-const char *jsonrpc_session_get_id(const struct jsonrpc_session *); +- +-#endif /* jsonrpc.h */ +Index: openvswitch-2.17.2/lib/memory.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/memory.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* +- * Copyright (c) 2012 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef MEMORY_H +-#define MEMORY_H 1 +- +-/* Memory usage monitor. +- * +- * This is intended to be called as part of a daemon's main loop. After some +- * time to allow the daemon to allocate an initial memory usage, it logs some +- * memory usage information (most of which must actually be provided by the +- * client). At intervals, if the daemon's memory usage has grown +- * significantly, it again logs information. +- * +- * The monitor also has a unixctl interface. +- * +- * Intended usage in the program's main loop is like this: +- * +- * for (;;) { +- * memory_run(); +- * if (memory_should_report()) { +- * struct simap usage; +- * +- * simap_init(&usage); +- * ...fill in 'usage' with meaningful statistics... +- * memory_report(&usage); +- * simap_destroy(&usage); +- * } +- * +- * ... +- * +- * memory_wait(); +- * poll_block(); +- * } +- */ +- +-#include +- +-struct simap; +- +-void memory_run(void); +-void memory_wait(void); +- +-bool memory_should_report(void); +-void memory_report(const struct simap *usage); +- +-#endif /* memory.h */ +Index: openvswitch-2.17.2/lib/netdev-afxdp.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-afxdp.h ++++ /dev/null +@@ -1,87 +0,0 @@ +-/* +- * Copyright (c) 2018, 2019 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NETDEV_AFXDP_H +-#define NETDEV_AFXDP_H 1 +- +-#ifdef HAVE_AF_XDP +- +-#include +-#include +- +-/* These functions are Linux AF_XDP specific, so they should be used directly +- * only by Linux-specific code. */ +- +-enum afxdp_mode { +- OVS_AF_XDP_MODE_UNSPEC, +- OVS_AF_XDP_MODE_BEST_EFFORT, +- OVS_AF_XDP_MODE_NATIVE_ZC, +- OVS_AF_XDP_MODE_NATIVE, +- OVS_AF_XDP_MODE_GENERIC, +- OVS_AF_XDP_MODE_MAX, +-}; +- +-struct dp_packet; +-struct dp_packet_batch; +-struct netdev; +-struct netdev_afxdp_tx_lock; +-struct netdev_custom_stats; +-struct netdev_rxq; +-struct netdev_stats; +-struct smap; +-struct xdp_umem; +-struct xsk_socket_info; +- +-int netdev_afxdp_rxq_construct(struct netdev_rxq *rxq_); +-void netdev_afxdp_rxq_destruct(struct netdev_rxq *rxq_); +-int netdev_afxdp_init(void); +-int netdev_afxdp_construct(struct netdev *netdev_); +-void netdev_afxdp_destruct(struct netdev *netdev_); +-int netdev_afxdp_verify_mtu_size(const struct netdev *netdev, int mtu); +- +-int netdev_afxdp_rxq_recv(struct netdev_rxq *rxq_, +- struct dp_packet_batch *batch, +- int *qfill); +-int netdev_afxdp_batch_send(struct netdev *netdev_, int qid, +- struct dp_packet_batch *batch, +- bool concurrent_txq); +-int netdev_afxdp_set_config(struct netdev *netdev, const struct smap *args, +- char **errp); +-int netdev_afxdp_get_config(const struct netdev *netdev, struct smap *args); +-int netdev_afxdp_get_stats(const struct netdev *netdev_, +- struct netdev_stats *stats); +-int netdev_afxdp_get_custom_stats(const struct netdev *netdev, +- struct netdev_custom_stats *custom_stats); +- +- +-void free_afxdp_buf(struct dp_packet *p); +-int netdev_afxdp_reconfigure(struct netdev *netdev); +-void signal_remove_xdp(struct netdev *netdev); +- +-#else /* !HAVE_AF_XDP */ +- +-#include "openvswitch/compiler.h" +- +-struct dp_packet; +- +-static inline void +-free_afxdp_buf(struct dp_packet *p OVS_UNUSED) +-{ +- /* Nothing. */ +-} +- +-#endif /* HAVE_AF_XDP */ +-#endif /* netdev-afxdp.h */ +Index: openvswitch-2.17.2/lib/netdev-dpdk.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/netdev-dpdk.h ++++ /dev/null +@@ -1,165 +0,0 @@ +-/* +- * Copyright (c) 2014, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef NETDEV_DPDK_H +-#define NETDEV_DPDK_H +- +-#include +- +-#include "openvswitch/compiler.h" +- +-struct dp_packet; +-struct netdev; +- +-#ifdef DPDK_NETDEV +- +-#include +- +-void netdev_dpdk_register(void); +-void free_dpdk_buf(struct dp_packet *); +- +-bool netdev_dpdk_flow_api_supported(struct netdev *); +- +-int +-netdev_dpdk_rte_flow_destroy(struct netdev *netdev, +- struct rte_flow *rte_flow, +- struct rte_flow_error *error); +-struct rte_flow * +-netdev_dpdk_rte_flow_create(struct netdev *netdev, +- const struct rte_flow_attr *attr, +- const struct rte_flow_item *items, +- const struct rte_flow_action *actions, +- struct rte_flow_error *error); +-int +-netdev_dpdk_rte_flow_query_count(struct netdev *netdev, +- struct rte_flow *rte_flow, +- struct rte_flow_query_count *query, +- struct rte_flow_error *error); +-int +-netdev_dpdk_get_port_id(struct netdev *netdev); +- +-#ifdef ALLOW_EXPERIMENTAL_API +- +-int netdev_dpdk_rte_flow_tunnel_decap_set(struct netdev *, +- struct rte_flow_tunnel *, +- struct rte_flow_action **, +- uint32_t *num_of_actions, +- struct rte_flow_error *); +-int netdev_dpdk_rte_flow_tunnel_match(struct netdev *, +- struct rte_flow_tunnel *, +- struct rte_flow_item **, +- uint32_t *num_of_items, +- struct rte_flow_error *); +-int netdev_dpdk_rte_flow_get_restore_info(struct netdev *, +- struct dp_packet *, +- struct rte_flow_restore_info *, +- struct rte_flow_error *); +-int netdev_dpdk_rte_flow_tunnel_action_decap_release(struct netdev *, +- struct rte_flow_action *, +- uint32_t num_of_actions, +- struct rte_flow_error *); +-int netdev_dpdk_rte_flow_tunnel_item_release(struct netdev *, +- struct rte_flow_item *, +- uint32_t num_of_items, +- struct rte_flow_error *); +- +-#else +- +-static inline void +-set_error(struct rte_flow_error *error, enum rte_flow_error_type type) +-{ +- if (!error) { +- return; +- } +- error->type = type; +- error->cause = NULL; +- error->message = NULL; +-} +- +-static inline int +-netdev_dpdk_rte_flow_tunnel_decap_set( +- struct netdev *netdev OVS_UNUSED, +- struct rte_flow_tunnel *tunnel OVS_UNUSED, +- struct rte_flow_action **actions OVS_UNUSED, +- uint32_t *num_of_actions OVS_UNUSED, +- struct rte_flow_error *error) +-{ +- set_error(error, RTE_FLOW_ERROR_TYPE_ACTION); +- return -1; +-} +- +-static inline int +-netdev_dpdk_rte_flow_tunnel_match(struct netdev *netdev OVS_UNUSED, +- struct rte_flow_tunnel *tunnel OVS_UNUSED, +- struct rte_flow_item **items OVS_UNUSED, +- uint32_t *num_of_items OVS_UNUSED, +- struct rte_flow_error *error) +-{ +- set_error(error, RTE_FLOW_ERROR_TYPE_ITEM); +- return -1; +-} +- +-static inline int +-netdev_dpdk_rte_flow_get_restore_info( +- struct netdev *netdev OVS_UNUSED, +- struct dp_packet *p OVS_UNUSED, +- struct rte_flow_restore_info *info OVS_UNUSED, +- struct rte_flow_error *error) +-{ +- set_error(error, RTE_FLOW_ERROR_TYPE_ATTR); +- return -1; +-} +- +-static inline int +-netdev_dpdk_rte_flow_tunnel_action_decap_release( +- struct netdev *netdev OVS_UNUSED, +- struct rte_flow_action *actions OVS_UNUSED, +- uint32_t num_of_actions OVS_UNUSED, +- struct rte_flow_error *error) +-{ +- set_error(error, RTE_FLOW_ERROR_TYPE_NONE); +- return 0; +-} +- +-static inline int +-netdev_dpdk_rte_flow_tunnel_item_release( +- struct netdev *netdev OVS_UNUSED, +- struct rte_flow_item *items OVS_UNUSED, +- uint32_t num_of_items OVS_UNUSED, +- struct rte_flow_error *error) +-{ +- set_error(error, RTE_FLOW_ERROR_TYPE_NONE); +- return 0; +-} +- +-#endif /* ALLOW_EXPERIMENTAL_API */ +- +-#else +- +-static inline void +-netdev_dpdk_register(void) +-{ +- /* Nothing */ +-} +-static inline void +-free_dpdk_buf(struct dp_packet *buf OVS_UNUSED) +-{ +- /* Nothing */ +-} +- +-#endif +- +-#endif /* netdev-dpdk.h */ +Index: openvswitch-2.17.2/lib/ovs-atomic-c++.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-c++.h ++++ /dev/null +@@ -1,67 +0,0 @@ +-/* This header implements atomic operation primitives on compilers that +- * have built-in support for ++C11 */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#include +- +-#define ATOMIC(TYPE) std::atomic +- +-using std::atomic_init; +- +-using std::memory_order_relaxed; +-using std::memory_order_consume; +-using std::memory_order_acquire; +-using std::memory_order_release; +-using std::memory_order_acq_rel; +-using std::memory_order_seq_cst; +- +-using std::atomic_thread_fence; +-using std::atomic_signal_fence; +-using std::atomic_is_lock_free; +- +-using std::atomic_store; +-using std::atomic_store_explicit; +- +-using std::atomic_compare_exchange_strong; +-using std::atomic_compare_exchange_strong_explicit; +-using std::atomic_compare_exchange_weak; +-using std::atomic_compare_exchange_weak_explicit; +- +-using std::atomic_exchange; +-using std::atomic_exchange_explicit; +- +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- (*(DST) = std::atomic_load_explicit(SRC, ORDER), \ +- (void) 0) +- +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = (*(RMW)).fetch_add(ARG, ORDER), (void) 0) +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = (*(RMW)).fetch_sub(ARG, ORDER), (void) 0) +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = (*(RMW)).fetch_or(ARG, ORDER), (void) 0) +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = (*(RMW)).fetch_xor(ARG, ORDER), (void) 0) +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = (*(RMW)).fetch_and(ARG, ORDER), (void) 0) +- +-using std::atomic_flag; +-using std::atomic_flag_test_and_set_explicit; +-using std::atomic_flag_test_and_set; +-using std::atomic_flag_clear_explicit; +-using std::atomic_flag_clear; +Index: openvswitch-2.17.2/lib/ovs-atomic-c11.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-c11.h ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on compilers that +- * have built-in support for C11 */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#include +- +-#define OMIT_STANDARD_ATOMIC_TYPES 1 +-#define ATOMIC(TYPE) _Atomic(TYPE) +- +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- (*(DST) = atomic_load_explicit(SRC, ORDER), \ +- (void) 0) +- +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = atomic_fetch_add_explicit(RMW, ARG, ORDER), (void) 0) +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = atomic_fetch_sub_explicit(RMW, ARG, ORDER), (void) 0) +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = atomic_fetch_or_explicit(RMW, ARG, ORDER), (void) 0) +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = atomic_fetch_xor_explicit(RMW, ARG, ORDER), (void) 0) +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- (*(ORIG) = atomic_fetch_and_explicit(RMW, ARG, ORDER), (void) 0) +Index: openvswitch-2.17.2/lib/ovs-atomic-flag-gcc4.7+.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-flag-gcc4.7+.h ++++ /dev/null +@@ -1,52 +0,0 @@ +-/* +- * Copyright (c) 2013, 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic_flag on Clang and on GCC 4.7 and later. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-/* atomic_flag */ +- +-typedef struct { +- unsigned char b; +-} atomic_flag; +-#define ATOMIC_FLAG_INIT { .b = false } +- +-static inline bool +-atomic_flag_test_and_set_explicit(volatile atomic_flag *object, +- memory_order order) +-{ +- return __atomic_test_and_set(&object->b, order); +-} +- +-static inline bool +-atomic_flag_test_and_set(volatile atomic_flag *object) +-{ +- return atomic_flag_test_and_set_explicit(object, memory_order_seq_cst); +-} +- +-static inline void +-atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order) +-{ +- __atomic_clear(object, order); +-} +- +-static inline void +-atomic_flag_clear(volatile atomic_flag *object) +-{ +- atomic_flag_clear_explicit(object, memory_order_seq_cst); +-} +Index: openvswitch-2.17.2/lib/ovs-atomic-i586.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-i586.h ++++ /dev/null +@@ -1,489 +0,0 @@ +-/* +- * Copyright (c) 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on 32-bit 586+ with GCC. +- */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#define OVS_ATOMIC_I586_IMPL 1 +- +-/* +- * These assumptions have been adopted from the x86_64 Memory model: +- * +- * - 1, 2, and 4 byte loads and stores are atomic on aligned memory. +- * - Loads are not reordered with other loads. +- * - Stores are not reordered with OLDER loads. +- * - Loads may be reordered with OLDER stores to a different memory location, +- * but not with OLDER stores to the same memory location. +- * - Stores are not reordered with other stores, except maybe for special +- * instructions not emitted by compilers, or by the stores performed by +- * a single fast string operation (e.g., "stos"). As long as the atomic +- * stores are not combined with any other stores, even the allowed reordering +- * of the stores by a single fast string operation is not a problem. +- * - Neither loads nor stores are reordered with locked instructions. +- * - Stores by a single processor are observed in the same order by all +- * processors. +- * - (Unlocked) Stores from different processors are NOT ordered. +- * - Memory ordering obeys causality (memory ordering respects transitive +- * visibility). +- * - Any two stores are seen in a consistent order by processors other than +- * the those performing the stores. +- * - Locked instructions have total order. +- * +- * These rules imply that: +- * +- * - Locked instructions are not needed for aligned loads or stores to make +- * them atomic for sizes upto 4 bytes. 8 byte objects need locked +- * instructions. +- * - All stores have release semantics; none of the preceding stores or loads +- * can be reordered with following stores. Following loads could still be +- * reordered to happen before the store, but that is not a violation of the +- * release semantics. +- * - All loads from a given memory location have acquire semantics with +- * respect to the stores on the same memory location; none of the following +- * loads or stores can be reordered with the load. Preceding stores to a +- * different memory location MAY be reordered with the load, but that is not +- * a violation of the acquire semantics (i.e., the loads and stores of two +- * critical sections guarded by a different memory location can overlap). +- * - Locked instructions serve as CPU memory barriers by themselves. +- * - Locked stores implement the sequential consistency memory order. Using +- * locked instructions when seq_cst memory order is requested allows normal +- * loads to observe the stores in the same (total) order without using CPU +- * memory barrier after the loads. +- * +- * NOTE: Some older AMD Opteron processors have a bug that violates the +- * acquire semantics described above. The bug manifests as an unlocked +- * read-modify-write operation following a "semaphore operation" operating +- * on data that existed before entering the critical section; i.e., the +- * preceding "semaphore operation" fails to function as an acquire barrier. +- * The affected CPUs are AMD family 15, models 32 to 63. +- * +- * Ref. http://support.amd.com/TechDocs/25759.pdf errata #147. +- */ +- +-/* Barriers. */ +- +-#define compiler_barrier() asm volatile(" " : : : "memory") +-#define cpu_barrier() asm volatile("lock; addl $0,(%%esp)" ::: "memory", "cc") +- +-/* +- * The 'volatile' keyword prevents the compiler from keeping the atomic +- * value in a register, and generates a new memory access for each atomic +- * operation. This allows the implementations of memory_order_relaxed and +- * memory_order_consume to avoid issuing a compiler memory barrier, allowing +- * full optimization of all surrounding non-atomic variables. +- * +- * The placement of the 'volatile' keyword after the 'TYPE' below is highly +- * significant when the TYPE is a pointer type. In that case we want the +- * pointer to be declared volatile, not the data type that is being pointed +- * at! +- * +- * Attribute aligned is used to tell the compiler to align 64-bit data +- * on a 8-byte boundary. This allows more efficient atomic access, as the +- * the CPU guarantees such memory accesses to be atomic. */ +-#define ATOMIC(TYPE) TYPE volatile __attribute__((aligned(sizeof(TYPE)))) +- +-/* Memory ordering. Must be passed in as a constant. */ +-typedef enum { +- memory_order_relaxed, +- memory_order_consume, +- memory_order_acquire, +- memory_order_release, +- memory_order_acq_rel, +- memory_order_seq_cst +-} memory_order; +- +-#define ATOMIC_BOOL_LOCK_FREE 2 +-#define ATOMIC_CHAR_LOCK_FREE 2 +-#define ATOMIC_SHORT_LOCK_FREE 2 +-#define ATOMIC_INT_LOCK_FREE 2 +-#define ATOMIC_LONG_LOCK_FREE 2 +-#define ATOMIC_LLONG_LOCK_FREE 2 +-#define ATOMIC_POINTER_LOCK_FREE 2 +- +-#define IS_LOCKLESS_ATOMIC(OBJECT) \ +- (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) +- +-#define ATOMIC_VAR_INIT(VALUE) VALUE +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-/* +- * The memory_model_relaxed does not need a compiler barrier, if the +- * atomic operation can otherwise be guaranteed to not be moved with +- * respect to other atomic operations on the same memory location. Using +- * the 'volatile' keyword in the definition of the atomic types +- * accomplishes this, as memory accesses to volatile data may not be +- * optimized away, or be reordered with other volatile accesses. +- * +- * On x86 also memory_order_consume is automatic, and data dependency on a +- * volatile atomic variable means that the compiler optimizations should not +- * cause problems. That is, the compiler should not speculate the value of +- * the atomic_read, as it is going to read it from the memory anyway. +- * This allows omiting the compiler memory barrier on atomic_reads with +- * memory_order_consume. This matches the definition of +- * smp_read_barrier_depends() in Linux kernel as a nop for x86, and its usage +- * in rcu_dereference(). +- * +- * We use this same logic below to choose inline assembly statements with or +- * without a compiler memory barrier. +- */ +-static inline void +-atomic_compiler_barrier(memory_order order) +-{ +- if (order > memory_order_consume) { +- compiler_barrier(); +- } +-} +- +-static inline void +-atomic_thread_fence(memory_order order) +-{ +- if (order == memory_order_seq_cst) { +- cpu_barrier(); +- } else { +- atomic_compiler_barrier(order); +- } +-} +- +-static inline void +-atomic_signal_fence(memory_order order) +-{ +- atomic_compiler_barrier(order); +-} +- +-#define atomic_is_lock_free(OBJ) \ +- ((void) *(OBJ), \ +- IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) +- +-/* The 8-byte atomic exchange uses cmpxchg8b with the SRC (ax:dx) as +- * the expected value (bx:cx), which will get replaced by the current +- * value in the likely case it did not match, after which we keep +- * trying until the swap succeeds. */ +- +-#if defined(__PIC__) +-/* ebx may not be clobbered when compiled with -fPIC, must save and +- * restore it. Furthermore, 'DST' may be addressed via ebx, so the +- * address must be passed via a register so that it remains valid also +- * after changing ebx. */ +-#define atomic_exchange_8__(DST, SRC, CLOB) \ +- uint32_t temp____; \ +- \ +- asm volatile(" movl %%ebx,%2 ; " \ +- " movl %%eax,%%ebx ; " \ +- " movl %%edx,%%ecx ; " \ +- "1: " \ +- "lock; cmpxchg8b (%0); " \ +- " jne 1b ; " \ +- " movl %2,%%ebx ; " \ +- " # atomic_exchange_8__ " \ +- : "+r" (DST), /* 0 */ \ +- "+A" (SRC), /* 1 */ \ +- "=mr" (temp____) /* 2 */ \ +- :: "ecx", CLOB, "cc") +- +-#else +-#define atomic_exchange_8__(DST, SRC, CLOB) \ +- asm volatile(" movl %%eax,%%ebx ; " \ +- " movl %%edx,%%ecx ; " \ +- "1: " \ +- "lock; cmpxchg8b %0 ; " \ +- " jne 1b ; " \ +- " # atomic_exchange_8__ " \ +- : "+m" (*DST), /* 0 */ \ +- "+A" (SRC) /* 1 */ \ +- :: "ebx", "ecx", CLOB, "cc") +-#endif +- +-#define atomic_exchange__(DST, SRC, ORDER) \ +- ({ \ +- typeof(DST) dst___ = (DST); \ +- typeof(*(DST)) src___ = (SRC); \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- if (sizeof(*(DST)) == 8) { \ +- atomic_exchange_8__(dst___, src___, "memory"); \ +- } else { \ +- asm volatile("xchg %1,%0 ; " \ +- "# atomic_exchange__" \ +- : "+r" (src___), /* 0 */ \ +- "+m" (*dst___) /* 1 */ \ +- :: "memory"); \ +- } \ +- } else { \ +- if (sizeof(*(DST)) == 8) { \ +- atomic_exchange_8__(dst___, src___, "cc"); \ +- } else { \ +- asm volatile("xchg %1,%0 ; " \ +- "# atomic_exchange__" \ +- : "+r" (src___), /* 0 */ \ +- "+m" (*dst___)); /* 1 */ \ +- } \ +- } \ +- src___; \ +- }) +- +-#if defined(__SSE__) +-/* SSE registers are 128-bit wide, and moving the lowest 64-bits of an SSE +- * register to proerly aligned memory is atomic. See ATOMIC(TYPE) above. */ +-#define atomic_store_8__(DST, SRC) \ +- asm volatile("movq %1,%0 ; # atomic_store_8__" \ +- : "=m" (*DST) /* 0 */ \ +- : "x" (SRC)) /* 1, SSE */ +-#else +-/* Locked 64-bit exchange is available on all i586 CPUs. */ +-#define atomic_store_8__(DST, SRC) \ +- atomic_exchange_8__(DST, SRC, "cc") +-#endif +- +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(*(DST)) src__ = (SRC); \ +- \ +- if ((ORDER) != memory_order_seq_cst) { \ +- atomic_compiler_barrier(ORDER); \ +- if (sizeof(*(DST)) == 8) { \ +- atomic_store_8__(dst__, src__); \ +- } else { \ +- *dst__ = src__; \ +- } \ +- } else { \ +- atomic_exchange__(dst__, src__, ORDER); \ +- } \ +- (void) 0; \ +- }) +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +- +-#if defined(__SSE__) +-/* SSE registers are 128-bit wide, and moving 64-bits from properly aligned +- * memory to an SSE register is atomic. See ATOMIC(TYPE) above. */ +-#define atomic_read_8__(SRC, DST) \ +- ({ \ +- typeof(*(DST)) res__; \ +- \ +- asm ("movq %1,%0 ; # atomic_read_8__" \ +- : "=x" (res__) /* 0, SSE. */ \ +- : "m" (*SRC)); /* 1 */ \ +- *(DST) = res__; \ +- }) +-#else +-/* Must use locked cmpxchg8b (available on all i586 CPUs) if compiled w/o sse +- * support. Compare '*DST' to a random value in bx:cx and returns the actual +- * value in ax:dx. The registers bx and cx are only read, so they are not +- * clobbered. */ +-#define atomic_read_8__(SRC, DST) \ +- ({ \ +- typeof(*(DST)) res__; \ +- \ +- asm (" movl %%ebx,%%eax ; " \ +- " movl %%ecx,%%edx ; " \ +- "lock; cmpxchg8b %1 ; " \ +- "# atomic_read_8__ " \ +- : "=&A" (res__), /* 0 */ \ +- "+m" (*SRC) /* 1 */ \ +- : : "cc"); \ +- *(DST) = res__; \ +- }) +-#endif +- +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(SRC) src__ = (SRC); \ +- \ +- if (sizeof(*(DST)) <= 4) { \ +- *dst__ = *src__; \ +- } else { \ +- atomic_read_8__(SRC, DST); \ +- } \ +- atomic_compiler_barrier(ORDER); \ +- (void) 0; \ +- }) +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +- +-#if defined(__PIC__) +-/* ebx may not be used as an input when compiled with -fPIC, must save +- * and restore it. Furthermore, 'DST' may be addressed via ebx, so +- * the address must be passed via a register so that it remains valid +- * also after changing ebx. */ +-#define atomic_compare_exchange_8__(DST, EXP, SRC, RES, CLOB) \ +- asm volatile(" xchgl %%ebx,%3 ; " \ +- "lock; cmpxchg8b (%1) ; " \ +- " xchgl %3,%%ebx ; " \ +- " sete %0 " \ +- "# atomic_compare_exchange_8__" \ +- : "=q" (RES), /* 0 */ \ +- "+r" (DST), /* 1 */ \ +- "+A" (EXP) /* 2 */ \ +- : "r" ((uint32_t)SRC), /* 3 */ \ +- "c" ((uint32_t)((uint64_t)SRC >> 32)) /* 4 */ \ +- : CLOB, "cc") +-#else +-#define atomic_compare_exchange_8__(DST, EXP, SRC, RES, CLOB) \ +- asm volatile("lock; cmpxchg8b %1 ; " \ +- " sete %0 " \ +- "# atomic_compare_exchange_8__" \ +- : "=q" (RES), /* 0 */ \ +- "+m" (*DST), /* 1 */ \ +- "+A" (EXP) /* 2 */ \ +- : "b" ((uint32_t)SRC), /* 3 */ \ +- "c" ((uint32_t)((uint64_t)SRC >> 32)) /* 4 */ \ +- : CLOB, "cc") +-#endif +- +-#define atomic_compare_exchange__(DST, EXP, SRC, RES, CLOB) \ +- asm volatile("lock; cmpxchg %3,%1 ; " \ +- " sete %0 " \ +- "# atomic_compare_exchange__" \ +- : "=q" (RES), /* 0 */ \ +- "+m" (*DST), /* 1 */ \ +- "+a" (EXP) /* 2 */ \ +- : "r" (SRC) /* 3 */ \ +- : CLOB, "cc") +- +-/* ORD_FAIL is ignored, as atomic_compare_exchange__ already implements +- * at least as strong a barrier as allowed for ORD_FAIL in all cases. */ +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORDER, ORD_FAIL) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(DST) expp__ = (EXP); \ +- typeof(*(DST)) src__ = (SRC); \ +- typeof(*(DST)) exp__ = *expp__; \ +- uint8_t res__; \ +- (void)ORD_FAIL; \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- if (sizeof(*(DST)) <= 4) { \ +- atomic_compare_exchange__(dst__, exp__, src__, res__, \ +- "memory"); \ +- } else { \ +- atomic_compare_exchange_8__(dst__, exp__, src__, res__, \ +- "memory"); \ +- } \ +- } else { \ +- if (sizeof(*(DST)) <= 4) { \ +- atomic_compare_exchange__(dst__, exp__, src__, res__, \ +- "cc"); \ +- } else { \ +- atomic_compare_exchange_8__(dst__, exp__, src__, res__, \ +- "cc"); \ +- } \ +- } \ +- if (!res__) { \ +- *expp__ = exp__; \ +- } \ +- (bool)res__; \ +- }) +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_weak \ +- atomic_compare_exchange_strong +-#define atomic_compare_exchange_weak_explicit \ +- atomic_compare_exchange_strong_explicit +- +-#define atomic_exchange_explicit(RMW, ARG, ORDER) \ +- atomic_exchange__(RMW, ARG, ORDER) +-#define atomic_exchange(RMW, ARG) \ +- atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) +- +-#define atomic_add__(RMW, ARG, CLOB) \ +- asm volatile("lock; xadd %0,%1 ; " \ +- "# atomic_add__ " \ +- : "+r" (ARG), /* 0 */ \ +- "+m" (*RMW) /* 1 */ \ +- :: CLOB, "cc") +- +-#define atomic_add_32__(RMW, ARG, ORIG, ORDER) \ +- ({ \ +- typeof(RMW) rmw__ = (RMW); \ +- typeof(*(RMW)) arg__ = (ARG); \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- atomic_add__(rmw__, arg__, "memory"); \ +- } else { \ +- atomic_add__(rmw__, arg__, "cc"); \ +- } \ +- *(ORIG) = arg__; \ +- }) +- +-/* We could use simple locked instructions if the original value was not +- * needed. */ +-#define atomic_op__(RMW, OP, ARG, ORIG, ORDER) \ +- ({ \ +- typeof(RMW) rmw__ = (RMW); \ +- typeof(ARG) arg__ = (ARG); \ +- \ +- typeof(*(RMW)) val__; \ +- \ +- atomic_read_explicit(rmw__, &val__, memory_order_relaxed); \ +- do { \ +- } while (!atomic_compare_exchange_weak_explicit(rmw__, &val__, \ +- val__ OP arg__, \ +- ORDER, \ +- memory_order_relaxed)); \ +- *(ORIG) = val__; \ +- }) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- (sizeof(*(RMW)) <= 4 \ +- ? atomic_add_32__(RMW, ARG, ORIG, ORDER) \ +- : atomic_op__(RMW, +, ARG, ORIG, ORDER)) +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- (sizeof(*(RMW)) <= 4 \ +- ? atomic_add_32__(RMW, -(ARG), ORIG, ORDER) \ +- : atomic_op__(RMW, -, ARG, ORIG, ORDER)) +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, |, ARG, ORIG, ORDER) +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, ^, ARG, ORIG, ORDER) +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, &, ARG, ORIG, ORDER) +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +- +-/* atomic_flag */ +- +-typedef ATOMIC(int) atomic_flag; +-#define ATOMIC_FLAG_INIT { false } +- +-#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ +- ((bool)atomic_exchange__(FLAG, 1, ORDER)) +-#define atomic_flag_test_and_set(FLAG) \ +- atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) +- +-#define atomic_flag_clear_explicit(FLAG, ORDER) \ +- atomic_store_explicit(FLAG, 0, ORDER) +-#define atomic_flag_clear(FLAG) \ +- atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/lib/ovs-atomic-locked.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-locked.h ++++ /dev/null +@@ -1,52 +0,0 @@ +-/* This header implements atomic operation locking helpers. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#define OVS_ATOMIC_LOCKED_IMPL 1 +- +-void atomic_lock__(void *); +-void atomic_unlock__(void *); +- +-#define atomic_store_locked(DST, SRC) \ +- (atomic_lock__(DST), \ +- *(DST) = (SRC), \ +- atomic_unlock__(DST), \ +- (void) 0) +- +-#define atomic_read_locked(SRC, DST) \ +- (atomic_lock__(SRC), \ +- *(DST) = *(SRC), \ +- atomic_unlock__(SRC), \ +- (void) 0) +- +-/* XXX: Evaluates EXP multiple times. */ +-#define atomic_compare_exchange_locked(DST, EXP, SRC) \ +- (atomic_lock__(DST), \ +- (*(DST) == *(EXP) \ +- ? (*(DST) = (SRC), \ +- atomic_unlock__(DST), \ +- true) \ +- : (*(EXP) = *(DST), \ +- atomic_unlock__(DST), \ +- false))) +- +-#define atomic_exchange_locked(DST, SRC) \ +- ({ \ +- atomic_lock__(DST); \ +- typeof(*(DST)) __tmp = *(DST); \ +- *(DST) = SRC; \ +- atomic_unlock__(DST); \ +- __tmp; \ +- }) +- +-#define atomic_op_locked_add += +-#define atomic_op_locked_sub -= +-#define atomic_op_locked_or |= +-#define atomic_op_locked_xor ^= +-#define atomic_op_locked_and &= +-#define atomic_op_locked(RMW, OP, OPERAND, ORIG) \ +- (atomic_lock__(RMW), \ +- *(ORIG) = *(RMW), \ +- *(RMW) atomic_op_locked_##OP (OPERAND), \ +- atomic_unlock__(RMW)) +Index: openvswitch-2.17.2/lib/ovs-atomic-msvc.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-msvc.h ++++ /dev/null +@@ -1,463 +0,0 @@ +-/* +- * Copyright (c) 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives for MSVC +- * on i586 or greater platforms (32 bit). */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-/* From msdn documentation: With Visual Studio 2003, volatile to volatile +- * references are ordered; the compiler will not re-order volatile variable +- * access. With Visual Studio 2005, the compiler also uses acquire semantics +- * for read operations on volatile variables and release semantics for write +- * operations on volatile variables (when supported by the CPU). +- * +- * Though there is no clear documentation that states that anything greater +- * than VS 2005 has the same behavior as described above, looking through MSVCs +- * C++ atomics library in VS2013 shows that the compiler still takes +- * acquire/release semantics on volatile variables. */ +-#define ATOMIC(TYPE) TYPE volatile +- +-typedef enum { +- memory_order_relaxed, +- memory_order_consume, +- memory_order_acquire, +- memory_order_release, +- memory_order_acq_rel, +- memory_order_seq_cst +-} memory_order; +- +-#if _MSC_VER > 1800 && defined(_M_IX86) +-/* From WDK 10 _InlineInterlocked* functions are renamed to +- * _InlineInterlocked* although the documentation does not specify it */ +-#define _InterlockedExchangeAdd64 _InlineInterlockedExchangeAdd64 +-#define _InterlockedExchange64 _InlineInterlockedExchange64 +-#endif +- +-#define ATOMIC_BOOL_LOCK_FREE 2 +-#define ATOMIC_CHAR_LOCK_FREE 2 +-#define ATOMIC_SHORT_LOCK_FREE 2 +-#define ATOMIC_INT_LOCK_FREE 2 +-#define ATOMIC_LONG_LOCK_FREE 2 +-#define ATOMIC_LLONG_LOCK_FREE 2 +-#define ATOMIC_POINTER_LOCK_FREE 2 +- +-#define IS_LOCKLESS_ATOMIC(OBJECT) \ +- (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) +- +-#define ATOMIC_VAR_INIT(VALUE) (VALUE) +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-static inline void +-atomic_compiler_barrier(memory_order order) +-{ +- /* In case of 'memory_order_consume', it is implicitly assumed that +- * the compiler will not move instructions that have data-dependency +- * on the variable in question before the barrier. */ +- if (order > memory_order_consume) { +- _ReadWriteBarrier(); +- } +-} +- +-static inline void +-atomic_thread_fence(memory_order order) +-{ +- /* x86 is strongly ordered and acquire/release semantics come +- * automatically. */ +- atomic_compiler_barrier(order); +- if (order == memory_order_seq_cst) { +- MemoryBarrier(); +- atomic_compiler_barrier(order); +- } +-} +- +-static inline void +-atomic_signal_fence(memory_order order) +-{ +- atomic_compiler_barrier(order); +-} +- +-/* 1, 2 and 4 bytes loads and stores are atomic on aligned memory. In addition, +- * since the compiler automatically takes acquire and release semantics on +- * volatile variables, for any order lesser than 'memory_order_seq_cst', we +- * can directly assign or read values. */ +- +-#define atomic_store32(DST, SRC, ORDER) \ +- if (ORDER == memory_order_seq_cst) { \ +- InterlockedExchange((long volatile *) (DST), \ +- (long) (SRC)); \ +- } else { \ +- *(DST) = (SRC); \ +- } +- +-/* MSVC converts 64 bit writes into two instructions. So there is +- * a possibility that an interrupt can make a 64 bit write non-atomic even +- * when 8 byte aligned. So use InterlockedExchange64(). +- * +- * For atomic stores, 'consume' and 'acquire' semantics are not valid. But we +- * are using 'Exchange' to get atomic stores here and we only have +- * InterlockedExchange64(), InterlockedExchangeNoFence64() and +- * InterlockedExchange64Acquire() available. So we are forced to use +- * InterlockedExchange64() which uses full memory barrier for everything +- * greater than 'memory_order_relaxed'. */ +-#ifdef _M_IX86 +-#define atomic_store64(DST, SRC, ORDER) \ +- if (ORDER == memory_order_relaxed) { \ +- InterlockedExchangeNoFence64((int64_t volatile *) (DST), \ +- (int64_t) (SRC)); \ +- } else { \ +- InterlockedExchange64((int64_t volatile *) (DST), (int64_t) (SRC));\ +- } +-#elif _M_X64 +-/* 64 bit writes are atomic on amd64 if 64 bit aligned. */ +-#define atomic_store64(DST, SRC, ORDER) \ +- if (ORDER == memory_order_seq_cst) { \ +- InterlockedExchange64((int64_t volatile *) (DST), \ +- (int64_t) (SRC)); \ +- } else { \ +- *(DST) = (SRC); \ +- } +-#endif +- +-#define atomic_store8(DST, SRC, ORDER) \ +- if (ORDER == memory_order_seq_cst) { \ +- InterlockedExchange8((char volatile *) (DST), (char) (SRC)); \ +- } else { \ +- *(DST) = (SRC); \ +- } +- +-#define atomic_store16(DST, SRC, ORDER) \ +- if (ORDER == memory_order_seq_cst) { \ +- InterlockedExchange16((short volatile *) (DST), (short) (SRC)); \ +- } else { \ +- *(DST) = (SRC); \ +- } +- +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +- +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- if (sizeof *(DST) == 1) { \ +- atomic_store8(DST, SRC, ORDER) \ +- } else if (sizeof *(DST) == 2) { \ +- atomic_store16( DST, SRC, ORDER) \ +- } else if (sizeof *(DST) == 4) { \ +- atomic_store32(DST, SRC, ORDER) \ +- } else if (sizeof *(DST) == 8) { \ +- atomic_store64(DST, SRC, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-/* On x86, for 'memory_order_seq_cst', if stores are locked, the corresponding +- * reads don't need to be locked (based on the following in Intel Developers +- * manual: +- * “Locked operations are atomic with respect to all other memory operations +- * and all externally visible events. Only instruction fetch and page table +- * accesses can pass locked instructions. Locked instructions can be used to +- * synchronize data written by one processor and read by another processor. +- * For the P6 family processors, locked operations serialize all outstanding +- * load and store operations (that is, wait for them to complete). This rule +- * is also true for the Pentium 4 and Intel Xeon processors, with one +- * exception. Load operations that reference weakly ordered memory types +- * (such as the WC memory type) may not be serialized."). */ +- +- /* For 8, 16 and 32 bit variations. */ +-#define atomic_readX(SRC, DST, ORDER) \ +- *(DST) = *(SRC); +- +-/* MSVC converts 64 bit reads into two instructions. So there is +- * a possibility that an interrupt can make a 64 bit read non-atomic even +- * when 8 byte aligned. So use fully memory barrier InterlockedOr64(). */ +-#ifdef _M_IX86 +-#define atomic_read64(SRC, DST, ORDER) \ +- __pragma (warning(push)) \ +- __pragma (warning(disable:4047)) \ +- *(DST) = InterlockedOr64((int64_t volatile *) (SRC), 0); \ +- __pragma (warning(pop)) +-#elif _M_X64 +-/* 64 bit reads are atomic on amd64 if 64 bit aligned. */ +-#define atomic_read64(SRC, DST, ORDER) \ +- *(DST) = *(SRC); +-#endif +- +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +- +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- if (sizeof *(DST) == 1 || sizeof *(DST) == 2 || sizeof *(DST) == 4) { \ +- atomic_readX(SRC, DST, ORDER) \ +- } else if (sizeof *(DST) == 8) { \ +- atomic_read64(SRC, DST, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-/* For add, sub, and logical operations, for 8, 16 and 64 bit data types, +- * functions for all the different memory orders does not exist +- * (though documentation exists for some of them). The MSVC C++ library which +- * implements the c11 atomics simply calls the full memory barrier function +- * for everything in x86(see xatomic.h). So do the same here. */ +- +-/* For 8, 16 and 64 bit variations. */ +-#define atomic_op(OP, X, RMW, ARG, ORIG, ORDER) \ +- atomic_##OP##_generic(X, RMW, ARG, ORIG, ORDER) +- +-/* Arithmetic addition calls. */ +- +-#define atomic_add8(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = _InterlockedExchangeAdd8((char volatile *) (RMW), \ +- (char) (ARG)); +- +-#define atomic_add16(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = _InterlockedExchangeAdd16((short volatile *) (RMW), \ +- (short) (ARG)); +- +-#define atomic_add32(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedExchangeAdd((long volatile *) (RMW), \ +- (long) (ARG)); +-#define atomic_add64(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = _InterlockedExchangeAdd64((int64_t volatile *) (RMW), \ +- (int64_t) (ARG)); +- +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- if (sizeof *(RMW) == 1) { \ +- atomic_add8(RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 2) { \ +- atomic_add16(RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 4) { \ +- atomic_add32(RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 8) { \ +- atomic_add64(RMW, ARG, ORIG, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-/* Arithmetic subtraction calls. */ +- +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, (0 - (ARG)), ORIG, memory_order_seq_cst) +- +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_add_explicit(RMW, (0 - (ARG)), ORIG, ORDER) +- +-/* Logical 'and' calls. */ +- +-#define atomic_and32(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedAnd((int32_t volatile *) (RMW), (int32_t) (ARG)); +- +-/* For 8, 16 and 64 bit variations. */ +-#define atomic_and_generic(X, RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedAnd##X((int##X##_t volatile *) (RMW), \ +- (int##X##_t) (ARG)); +- +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- if (sizeof *(RMW) == 1) { \ +- atomic_op(and, 8, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 2) { \ +- atomic_op(and, 16, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 4) { \ +- atomic_and32(RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 8) { \ +- atomic_op(and, 64, RMW, ARG, ORIG, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-/* Logical 'Or' calls. */ +- +-#define atomic_or32(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedOr((int32_t volatile *) (RMW), (int32_t) (ARG)); +- +-/* For 8, 16 and 64 bit variations. */ +-#define atomic_or_generic(X, RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedOr##X((int##X##_t volatile *) (RMW), \ +- (int##X##_t) (ARG)); +- +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- if (sizeof *(RMW) == 1) { \ +- atomic_op(or, 8, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 2) { \ +- atomic_op(or, 16, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 4) { \ +- atomic_or32(RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 8) { \ +- atomic_op(or, 64, RMW, ARG, ORIG, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-/* Logical Xor calls. */ +- +-#define atomic_xor32(RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedXor((int32_t volatile *) (RMW), (int32_t) (ARG)); +- +-/* For 8, 16 and 64 bit variations. */ +-#define atomic_xor_generic(X, RMW, ARG, ORIG, ORDER) \ +- *(ORIG) = InterlockedXor##X((int##X##_t volatile *) (RMW), \ +- (int##X##_t) (ARG)); +- +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- if (sizeof *(RMW) == 1) { \ +- atomic_op(xor, 8, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 2) { \ +- atomic_op(xor, 16, RMW, ARG, ORIG, ORDER) \ +- } else if (sizeof *(RMW) == 4) { \ +- atomic_xor32(RMW, ARG, ORIG, ORDER); \ +- } else if (sizeof *(RMW) == 8) { \ +- atomic_op(xor, 64, RMW, ARG, ORIG, ORDER) \ +- } else { \ +- abort(); \ +- } +- +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +- +-#define atomic_compare_exchange_weak atomic_compare_exchange_strong +-#define atomic_compare_exchange_weak_explicit \ +- atomic_compare_exchange_strong_explicit +- +-/* While intrinsics offering different memory ordering +- * are available in MSVC C compiler, they are not defined +- * in the C++ compiler. Ignore for compatibility. +- * +- * Use nested ternary operators as the GNU extension ({}) +- * is not available. +- */ +- +-#define atomic_exchange_explicit(DST, SRC, ORDER) \ +- ((sizeof *(DST) == 1) ? \ +- _InterlockedExchange8((char volatile *) DST, SRC) \ +- : (sizeof *(DST) == 2) ? \ +- _InterlockedExchange16((short volatile *) DST, SRC) \ +- : (sizeof *(DST) == 4) ? \ +- _InterlockedExchange((long int volatile *) DST, SRC) \ +- : (sizeof *(DST) == 8) ? \ +- _InterlockedExchange64((__int64 volatile *) DST, SRC) \ +- : (abort(), 0)) +- +-#define atomic_exchange(DST, SRC) \ +- atomic_exchange_explicit(DST, SRC, memory_order_seq_cst) +- +-/* MSVCs c++ compiler implements c11 atomics and looking through its +- * implementation (in xatomic.h), orders are ignored for x86 platform. +- * Do the same here. */ +-static inline bool +-atomic_compare_exchange8(int8_t volatile *dst, int8_t *expected, int8_t src) +-{ +- int8_t previous = _InterlockedCompareExchange8((char volatile *)dst, +- src, *expected); +- if (previous == *expected) { +- return true; +- } else { +- *expected = previous; +- return false; +- } +-} +- +-static inline bool +-atomic_compare_exchange16(int16_t volatile *dst, int16_t *expected, +- int16_t src) +-{ +- int16_t previous = InterlockedCompareExchange16(dst, src, *expected); +- if (previous == *expected) { +- return true; +- } else { +- *expected = previous; +- return false; +- } +-} +- +-static inline bool +-atomic_compare_exchange32(int32_t volatile *dst, int32_t *expected, +- int32_t src) +-{ +- int32_t previous = InterlockedCompareExchange((long volatile *)dst, +- src, *expected); +- if (previous == *expected) { +- return true; +- } else { +- *expected = previous; +- return false; +- } +-} +- +-static inline bool +-atomic_compare_exchange64(int64_t volatile *dst, int64_t *expected, +- int64_t src) +-{ +- int64_t previous = InterlockedCompareExchange64(dst, src, *expected); +- if (previous == *expected) { +- return true; +- } else { +- *expected = previous; +- return false; +- } +-} +- +-static inline bool +-atomic_compare_unreachable() +-{ +- return true; +-} +- +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ +- (sizeof *(DST) == 1 \ +- ? atomic_compare_exchange8((int8_t volatile *) (DST), (int8_t *) (EXP), \ +- (int8_t) (SRC)) \ +- : (sizeof *(DST) == 2 \ +- ? atomic_compare_exchange16((int16_t volatile *) (DST), \ +- (int16_t *) (EXP), (int16_t) (SRC)) \ +- : (sizeof *(DST) == 4 \ +- ? atomic_compare_exchange32((int32_t volatile *) (DST), \ +- (int32_t *) (EXP), (int32_t) (SRC)) \ +- : (sizeof *(DST) == 8 \ +- ? atomic_compare_exchange64((int64_t volatile *) (DST), \ +- (int64_t *) (EXP), (int64_t) (SRC)) \ +- : ovs_fatal(0, "atomic operation with size greater than 8 bytes"), \ +- atomic_compare_unreachable())))) +- +- +-/* atomic_flag */ +- +-typedef ATOMIC(int32_t) atomic_flag; +-#define ATOMIC_FLAG_INIT 0 +- +-#define atomic_flag_test_and_set(FLAG) \ +- (bool) InterlockedBitTestAndSet(FLAG, 0) +- +-#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ +- atomic_flag_test_and_set(FLAG) +- +-#define atomic_flag_clear_explicit(FLAG, ORDER) \ +- atomic_flag_clear() +-#define atomic_flag_clear(FLAG) \ +- InterlockedBitTestAndReset(FLAG, 0) +Index: openvswitch-2.17.2/lib/ovs-atomic-x86_64.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/ovs-atomic-x86_64.h ++++ /dev/null +@@ -1,356 +0,0 @@ +-/* +- * Copyright (c) 2014 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* This header implements atomic operation primitives on x86_64 with GCC. */ +-#ifndef IN_OVS_ATOMIC_H +-#error "This header should only be included indirectly via ovs-atomic.h." +-#endif +- +-#define OVS_ATOMIC_X86_64_IMPL 1 +- +-/* +- * x86_64 Memory model (http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html): +- * +- * - 1, 2, 4, and 8 byte loads and stores are atomic on aligned memory. +- * - Loads are not reordered with other loads. +- * - Stores are not reordered with OLDER loads. +- * - Loads may be reordered with OLDER stores to a different memory location, +- * but not with OLDER stores to the same memory location. +- * - Stores are not reordered with other stores, except for special +- * instructions (CLFLUSH, streaming stores, fast string operations). +- * Most of these are not emitted by compilers, and as long as the +- * atomic stores are not combined with any other stores, even the allowed +- * reordering of the stores by a single fast string operation (e.g., "stos") +- * is not a problem. +- * - Neither loads nor stores are reordered with locked instructions. +- * - Loads cannot pass earlier LFENCE or MFENCE instructions. +- * - Stores cannot pass earlier LFENCE, SFENCE, or MFENCE instructions. +- * - LFENCE instruction cannot pass earlier loads. +- * - SFENCE instruction cannot pass earlier stores. +- * - MFENCE instruction cannot pass earlier loads or stores. +- * - Stores by a single processor are observed in the same order by all +- * processors. +- * - (Unlocked) Stores from different processors are NOT ordered. +- * - Memory ordering obeys causality (memory ordering respects transitive +- * visibility). +- * - Any two stores are seen in a consistent order by processors other than +- * the those performing the stores. +- * - Locked instructions have total order. +- * +- * These rules imply that: +- * +- * - Locked instructions are not needed for aligned loads or stores to make +- * them atomic. +- * - All stores have release semantics; none of the preceding stores or loads +- * can be reordered with following stores. Following loads could still be +- * reordered to happen before the store, but that is not a violation of the +- * release semantics. +- * - All loads from a given memory location have acquire semantics with +- * respect to the stores on the same memory location; none of the following +- * loads or stores can be reordered with the load. Preceding stores to a +- * different memory location MAY be reordered with the load, but that is not +- * a violation of the acquire semantics (i.e., the loads and stores of two +- * critical sections guarded by a different memory location can overlap). +- * - Locked instructions serve as CPU memory barriers by themselves. +- * - Locked stores implement the sequential consistency memory order. Using +- * locked instructions when seq_cst memory order is requested allows normal +- * loads to observe the stores in the same (total) order without using CPU +- * memory barrier after the loads. +- * +- * NOTE: Some older AMD Opteron processors have a bug that violates the +- * acquire semantics described above. The bug manifests as an unlocked +- * read-modify-write operation following a "semaphore operation" operating +- * on data that existed before entering the critical section; i.e., the +- * preceding "semaphore operation" fails to function as an acquire barrier. +- * The affected CPUs are AMD family 15, models 32 to 63. +- * +- * Ref. http://support.amd.com/TechDocs/25759.pdf errata #147. +- */ +- +-/* Barriers. */ +- +-#define compiler_barrier() asm volatile(" " : : : "memory") +-#define cpu_barrier() asm volatile("mfence;" : : : "memory") +- +-/* +- * The 'volatile' keyword prevents the compiler from keeping the atomic +- * value in a register, and generates a new memory access for each atomic +- * operation. This allows the implementations of memory_order_relaxed and +- * memory_order_consume to avoid issuing a compiler memory barrier, allowing +- * full optimization of all surrounding non-atomic variables. +- * +- * The placement of the 'volatile' keyword after the 'TYPE' below is highly +- * significant when the TYPE is a pointer type. In that case we want the +- * pointer to be declared volatile, not the data type that is being pointed +- * at! +- */ +-#define ATOMIC(TYPE) TYPE volatile +- +-/* Memory ordering. Must be passed in as a constant. */ +-typedef enum { +- memory_order_relaxed, +- memory_order_consume, +- memory_order_acquire, +- memory_order_release, +- memory_order_acq_rel, +- memory_order_seq_cst +-} memory_order; +- +-#define ATOMIC_BOOL_LOCK_FREE 2 +-#define ATOMIC_CHAR_LOCK_FREE 2 +-#define ATOMIC_SHORT_LOCK_FREE 2 +-#define ATOMIC_INT_LOCK_FREE 2 +-#define ATOMIC_LONG_LOCK_FREE 2 +-#define ATOMIC_LLONG_LOCK_FREE 2 +-#define ATOMIC_POINTER_LOCK_FREE 2 +- +-#define IS_LOCKLESS_ATOMIC(OBJECT) \ +- (sizeof(OBJECT) <= 8 && IS_POW2(sizeof(OBJECT))) +- +-#define ATOMIC_VAR_INIT(VALUE) VALUE +-#define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0) +- +-/* +- * The memory_model_relaxed does not need a compiler barrier, if the +- * atomic operation can otherwise be guaranteed to not be moved with +- * respect to other atomic operations on the same memory location. Using +- * the 'volatile' keyword in the definition of the atomic types +- * accomplishes this, as memory accesses to volatile data may not be +- * optimized away, or be reordered with other volatile accesses. +- * +- * On x86 also memory_order_consume is automatic, and data dependency on a +- * volatile atomic variable means that the compiler optimizations should not +- * cause problems. That is, the compiler should not speculate the value of +- * the atomic_read, as it is going to read it from the memory anyway. +- * This allows omiting the compiler memory barrier on atomic_reads with +- * memory_order_consume. This matches the definition of +- * smp_read_barrier_depends() in Linux kernel as a nop for x86, and its usage +- * in rcu_dereference(). +- * +- * We use this same logic below to choose inline assembly statements with or +- * without a compiler memory barrier. +- */ +-static inline void +-atomic_compiler_barrier(memory_order order) +-{ +- if (order > memory_order_consume) { +- compiler_barrier(); +- } +-} +- +-static inline void +-atomic_thread_fence(memory_order order) +-{ +- if (order == memory_order_seq_cst) { +- cpu_barrier(); +- } else { +- atomic_compiler_barrier(order); +- } +-} +- +-static inline void +-atomic_signal_fence(memory_order order) +-{ +- atomic_compiler_barrier(order); +-} +- +-#define atomic_is_lock_free(OBJ) \ +- ((void) *(OBJ), \ +- IS_LOCKLESS_ATOMIC(*(OBJ)) ? 2 : 0) +- +-#define atomic_exchange__(DST, SRC, ORDER) \ +- ({ \ +- typeof(DST) dst___ = (DST); \ +- typeof(*(DST)) src___ = (SRC); \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- asm volatile("xchg %1,%0 ; " \ +- "# atomic_exchange__" \ +- : "+r" (src___), /* 0 */ \ +- "+m" (*dst___) /* 1 */ \ +- :: "memory"); \ +- } else { \ +- asm volatile("xchg %1,%0 ; " \ +- "# atomic_exchange__" \ +- : "+r" (src___), /* 0 */ \ +- "+m" (*dst___)); /* 1 */ \ +- } \ +- src___; \ +- }) +- +-/* Atomic store: Valid memory models are: +- * +- * memory_order_relaxed, memory_order_release, and +- * memory_order_seq_cst. */ +-#define atomic_store_explicit(DST, SRC, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(*(DST)) src__ = (SRC); \ +- \ +- if ((ORDER) != memory_order_seq_cst) { \ +- atomic_compiler_barrier(ORDER); \ +- *dst__ = src__; \ +- } else { \ +- atomic_exchange__(dst__, src__, ORDER); \ +- } \ +- (void) 0; \ +- }) +-#define atomic_store(DST, SRC) \ +- atomic_store_explicit(DST, SRC, memory_order_seq_cst) +- +-/* Atomic read: Valid memory models are: +- * +- * memory_order_relaxed, memory_order_consume, memory_model_acquire, +- * and memory_order_seq_cst. */ +-#define atomic_read_explicit(SRC, DST, ORDER) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(SRC) src__ = (SRC); \ +- \ +- *dst__ = *src__; \ +- atomic_compiler_barrier(ORDER); \ +- (void) 0; \ +- }) +-#define atomic_read(SRC, DST) \ +- atomic_read_explicit(SRC, DST, memory_order_seq_cst) +- +-#define atomic_compare_exchange__(DST, EXP, SRC, RES, CLOB) \ +- asm volatile("lock; cmpxchg %3,%1 ; " \ +- " sete %0 " \ +- "# atomic_compare_exchange__" \ +- : "=q" (RES), /* 0 */ \ +- "+m" (*DST), /* 1 */ \ +- "+a" (EXP) /* 2 */ \ +- : "r" (SRC) /* 3 */ \ +- : CLOB, "cc") +- +-/* All memory models are valid for read-modify-write operations. +- * +- * Valid memory models for the read operation of the current value in +- * the failure case are the same as for atomic read, but can not be +- * stronger than the success memory model. +- * ORD_FAIL is ignored, as atomic_compare_exchange__ already implements +- * at least as strong a barrier as allowed for ORD_FAIL in all cases. */ +-#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORDER, ORD_FAIL) \ +- ({ \ +- typeof(DST) dst__ = (DST); \ +- typeof(DST) expp__ = (EXP); \ +- typeof(*(DST)) src__ = (SRC); \ +- typeof(*(DST)) exp__ = *expp__; \ +- uint8_t res__; \ +- (void)ORD_FAIL; \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- atomic_compare_exchange__(dst__, exp__, src__, res__, \ +- "memory"); \ +- } else { \ +- atomic_compare_exchange__(dst__, exp__, src__, res__, \ +- "cc"); \ +- } \ +- if (!res__) { \ +- *expp__ = exp__; \ +- } \ +- (bool)res__; \ +- }) +-#define atomic_compare_exchange_strong(DST, EXP, SRC) \ +- atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ +- memory_order_seq_cst, \ +- memory_order_seq_cst) +-#define atomic_compare_exchange_weak \ +- atomic_compare_exchange_strong +-#define atomic_compare_exchange_weak_explicit \ +- atomic_compare_exchange_strong_explicit +- +-#define atomic_exchange_explicit(RMW, ARG, ORDER) \ +- atomic_exchange__(RMW, ARG, ORDER) +-#define atomic_exchange(RMW, ARG) \ +- atomic_exchange_explicit(RMW, ARG, memory_order_seq_cst) +- +-#define atomic_add__(RMW, ARG, CLOB) \ +- asm volatile("lock; xadd %0,%1 ; " \ +- "# atomic_add__ " \ +- : "+r" (ARG), /* 0 */ \ +- "+m" (*RMW) /* 1 */ \ +- :: CLOB, "cc") +- +-#define atomic_add_explicit(RMW, ARG, ORIG, ORDER) \ +- ({ \ +- typeof(RMW) rmw__ = (RMW); \ +- typeof(*(RMW)) arg__ = (ARG); \ +- \ +- if ((ORDER) > memory_order_consume) { \ +- atomic_add__(rmw__, arg__, "memory"); \ +- } else { \ +- atomic_add__(rmw__, arg__, "cc"); \ +- } \ +- *(ORIG) = arg__; \ +- }) +-#define atomic_add(RMW, ARG, ORIG) \ +- atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_sub_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_add_explicit(RMW, -(ARG), ORIG, ORDER) +-#define atomic_sub(RMW, ARG, ORIG) \ +- atomic_sub_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-/* We could use simple locked instructions if the original value was not +- * needed. */ +-#define atomic_op__(RMW, OP, ARG, ORIG, ORDER) \ +- ({ \ +- typeof(RMW) rmw__ = (RMW); \ +- typeof(ARG) arg__ = (ARG); \ +- \ +- typeof(*(RMW)) val__; \ +- \ +- atomic_read_explicit(rmw__, &val__, memory_order_relaxed); \ +- do { \ +- } while (!atomic_compare_exchange_weak_explicit(rmw__, &val__, \ +- val__ OP arg__, \ +- ORDER, \ +- memory_order_relaxed)); \ +- *(ORIG) = val__; \ +- }) +- +-#define atomic_or_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, |, ARG, ORIG, ORDER) +-#define atomic_or(RMW, ARG, ORIG) \ +- atomic_or_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_xor_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, ^, ARG, ORIG, ORDER) +-#define atomic_xor(RMW, ARG, ORIG) \ +- atomic_xor_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +-#define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \ +- atomic_op__(RMW, &, ARG, ORIG, ORDER) +-#define atomic_and(RMW, ARG, ORIG) \ +- atomic_and_explicit(RMW, ARG, ORIG, memory_order_seq_cst) +- +- +-/* atomic_flag */ +- +-typedef ATOMIC(int) atomic_flag; +-#define ATOMIC_FLAG_INIT { false } +- +-#define atomic_flag_test_and_set_explicit(FLAG, ORDER) \ +- ((bool)atomic_exchange__(FLAG, 1, ORDER)) +-#define atomic_flag_test_and_set(FLAG) \ +- atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst) +- +-#define atomic_flag_clear_explicit(FLAG, ORDER) \ +- atomic_store_explicit(FLAG, 0, ORDER) +-#define atomic_flag_clear(FLAG) \ +- atomic_flag_clear_explicit(FLAG, memory_order_seq_cst) +Index: openvswitch-2.17.2/lib/process.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/process.h ++++ /dev/null +@@ -1,61 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 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. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef PROCESS_H +-#define PROCESS_H 1 +- +-#include +-#include +- +-struct process; +- +-struct process_info { +- unsigned long int vsz; /* Virtual size, in kB. */ +- unsigned long int rss; /* Resident set size, in kB. */ +- long long int booted; /* ms since monitor started. */ +- int crashes; /* # of crashes (usually 0). */ +- long long int uptime; /* ms since last (re)started by monitor. */ +- long long int cputime; /* ms of CPU used during 'uptime'. */ +- int core_id; +- char name[18]; +-}; +- +-/* Starting and monitoring subprocesses. +- * +- * process_init() and process_start() may safely be called only from a +- * single-threaded parent process. The parent process may safely create +- * additional threads afterward, as long as the remaining functions in this +- * group are called only from a single thread at any given time. */ +-void process_init(void); +-int process_start(char **argv, struct process **); +-void process_destroy(struct process *); +-int process_kill(const struct process *, int signr); +-pid_t process_pid(const struct process *); +-const char *process_name(const struct process *); +-bool process_exited(struct process *); +-int process_status(const struct process *); +-void process_run(void); +-void process_wait(struct process *); +- +-int count_crashes(pid_t); +-bool get_process_info(pid_t, struct process_info *); +- +-/* These functions are thread-safe. */ +-char *process_status_msg(int); +-char *process_escape_args(char **argv); +-char *process_search_path(const char *); +- +-#endif /* process.h */ +Index: openvswitch-2.17.2/lib/random.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/random.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2012 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef RANDOM_H +-#define RANDOM_H 1 +- +-#include +-#include +- +-void random_init(void); +-void random_set_seed(uint32_t); +- +-void random_bytes(void *, size_t); +-uint32_t random_uint32(void); +-uint64_t random_uint64(void); +- +-static inline int +-random_range(int max) +-{ +- return random_uint32() % max; +-} +- +-static inline uint8_t +-random_uint8(void) +-{ +- return random_uint32(); +-} +- +-static inline uint16_t +-random_uint16(void) +-{ +- return random_uint32(); +-} +- +-#endif /* random.h */ +Index: openvswitch-2.17.2/lib/simap.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/simap.h ++++ /dev/null +@@ -1,89 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2011, 2012, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SIMAP_H +-#define SIMAP_H 1 +- +-#include "openvswitch/hmap.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* A map from strings to unsigned integers. */ +-struct simap { +- struct hmap map; /* Contains "struct simap_node"s. */ +-}; +- +-struct simap_node { +- struct hmap_node node; /* In struct simap's 'map' hmap. */ +- char *name; +- unsigned int data; +-}; +- +-#define SIMAP_INITIALIZER(SIMAP) { HMAP_INITIALIZER(&(SIMAP)->map) } +- +-#define SIMAP_FOR_EACH(SIMAP_NODE, SIMAP) \ +- HMAP_FOR_EACH_INIT (SIMAP_NODE, node, &(SIMAP)->map, \ +- BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ +- BUILD_ASSERT_TYPE(SIMAP, struct simap *)) +- +-#define SIMAP_FOR_EACH_SAFE_SHORT(SIMAP_NODE, SIMAP) \ +- HMAP_FOR_EACH_SAFE_SHORT_INIT (SIMAP_NODE, node, &(SIMAP)->map, \ +- BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ +- BUILD_ASSERT_TYPE(SIMAP, struct simap *)) +- +-#define SIMAP_FOR_EACH_SAFE_LONG(SIMAP_NODE, NEXT, SIMAP) \ +- HMAP_FOR_EACH_SAFE_LONG_INIT (SIMAP_NODE, NEXT, node, &(SIMAP)->map, \ +- BUILD_ASSERT_TYPE(SIMAP_NODE, struct simap_node *), \ +- BUILD_ASSERT_TYPE(NEXT, struct simap_node *), \ +- BUILD_ASSERT_TYPE(SIMAP, struct simap *)) +- +-#define SIMAP_FOR_EACH_SAFE(...) \ +- OVERLOAD_SAFE_MACRO(SIMAP_FOR_EACH_SAFE_LONG, \ +- SIMAP_FOR_EACH_SAFE_SHORT, \ +- 3, __VA_ARGS__) +- +-void simap_init(struct simap *); +-void simap_destroy(struct simap *); +-void simap_swap(struct simap *, struct simap *); +-void simap_moved(struct simap *); +-void simap_clear(struct simap *); +- +-bool simap_is_empty(const struct simap *); +-size_t simap_count(const struct simap *); +- +-bool simap_put(struct simap *, const char *, unsigned int); +-unsigned int simap_increase(struct simap *, const char *, unsigned int); +- +-unsigned int simap_get(const struct simap *, const char *); +-struct simap_node *simap_find(const struct simap *, const char *); +-struct simap_node *simap_find_len(const struct simap *, +- const char *, size_t len); +-bool simap_contains(const struct simap *, const char *); +- +-void simap_delete(struct simap *, struct simap_node *); +-bool simap_find_and_delete(struct simap *, const char *); +- +-const struct simap_node **simap_sort(const struct simap *); +-bool simap_equal(const struct simap *, const struct simap *); +-uint32_t simap_hash(const struct simap *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* simap.h */ +Index: openvswitch-2.17.2/lib/skiplist.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/skiplist.h ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP +- * All Rights Reserved. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); you may +- * not use this file except in compliance with the License. You may obtain +- * a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +- * License for the specific language governing permissions and limitations +- * under the License. +- */ +- +-#ifndef LIB_SKIPLIST_H_ +-#define LIB_SKIPLIST_H_ +- +-#include +-#include +-#include +- +-typedef int (skiplist_comparator)(const void *a, const void *b, +- const void *conf); +- +-struct skiplist_node; +- +-struct skiplist; +- +-#define SKIPLIST_FOR_EACH (SKIPLIST_NODE, SKIPLIST) \ +- for (SKIPLIST_NODE = skiplist_first(SKIPLIST); \ +- SKIPLIST_NODE; \ +- SKIPLIST_NODE = skiplist_next(SKIPLIST_NODE)) +- +-struct skiplist *skiplist_create(skiplist_comparator *object_comparator, +- void *configuration); +-void skiplist_insert(struct skiplist *sl, const void *object); +-void *skiplist_delete(struct skiplist *sl, const void *object); +-struct skiplist_node *skiplist_find(struct skiplist *sl, const void *value); +-void *skiplist_get_data(struct skiplist_node *node); +-uint32_t skiplist_get_size(struct skiplist *sl); +-struct skiplist_node *skiplist_forward_to(struct skiplist *sl, +- const void *value); +-struct skiplist_node *skiplist_first(struct skiplist *sl); +-struct skiplist_node *skiplist_next(struct skiplist_node *node); +-void skiplist_destroy(struct skiplist *sl, void (*func)(void *)); +- +-#endif /* LIB_SKIPLIST_H_ */ +Index: openvswitch-2.17.2/lib/socket-util.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/socket-util.h ++++ /dev/null +@@ -1,185 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SOCKET_UTIL_H +-#define SOCKET_UTIL_H 1 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "openvswitch/types.h" +-#include +-#include +- +-struct ds; +- +-int set_nonblocking(int fd); +-void xset_nonblocking(int fd); +-void setsockopt_tcp_nodelay(int fd); +-int set_dscp(int fd, int family, uint8_t dscp); +- +-bool addr_is_ipv6(const char *host_name); +-int lookup_ip(const char *host_name, struct in_addr *address); +-int lookup_ipv6(const char *host_name, struct in6_addr *address); +- +-int lookup_hostname(const char *host_name, struct in_addr *); +- +-int get_socket_rcvbuf(int sock); +-int check_connection_completion(int fd); +-void drain_fd(int fd, size_t n_packets); +-ovs_be32 guess_netmask(ovs_be32 ip); +- +-void inet_parse_host_port_tokens(char *s, char **hostp, char **portp); +-void inet_parse_port_host_tokens(char *s, char **portp, char **hostp); +-bool inet_parse_active(const char *target, int default_port, +- struct sockaddr_storage *ssp, +- bool resolve_host, bool *dns_failure); +-int inet_open_active(int style, const char *target, int default_port, +- struct sockaddr_storage *ssp, int *fdp, uint8_t dscp); +- +-bool inet_parse_passive(const char *target, int default_port, +- struct sockaddr_storage *ssp); +-int inet_open_passive(int style, const char *target, int default_port, +- struct sockaddr_storage *ssp, uint8_t dscp, +- bool kernel_print_port); +- +-bool inet_parse_address(const char *target, struct sockaddr_storage *); +- +-int read_fully(int fd, void *, size_t, size_t *bytes_read); +-int write_fully(int fd, const void *, size_t, size_t *bytes_written); +- +-int fsync_parent_dir(const char *file_name); +-int get_mtime(const char *file_name, struct timespec *mtime); +- +-char *describe_fd(int fd); +- +-/* Default value of dscp bits for connection between controller and manager. +- * Value of IPTOS_PREC_INTERNETCONTROL = 0xc0 which is defined +- * in is used. */ +-#define DSCP_DEFAULT (IPTOS_PREC_INTERNETCONTROL >> 2) +- +-/* Functions for working with sockaddr that might contain an IPv4 or +- * IPv6 address. */ +-bool sa_is_ip(const struct sockaddr *); +-uint16_t sa_get_port(const struct sockaddr *); +-struct in6_addr sa_get_address(const struct sockaddr *); +-void sa_format_address(const struct sockaddr *, struct ds *); +-void sa_format_address_nobracks(const struct sockaddr *, struct ds *); +-size_t sa_length(const struct sockaddr *); +- +-/* Functions for working with sockaddr_storage that might contain an IPv4 or +- * IPv6 address. */ +-bool ss_is_ip(const struct sockaddr_storage *); +-uint16_t ss_get_port(const struct sockaddr_storage *); +-struct in6_addr ss_get_address(const struct sockaddr_storage *); +-void ss_format_address(const struct sockaddr_storage *, struct ds *); +-void ss_format_address_nobracks(const struct sockaddr_storage *, struct ds *); +-size_t ss_length(const struct sockaddr_storage *); +- +-const char *sock_strerror(int error); +- +-#ifndef _WIN32 +-void xpipe(int fds[2]); +-void xpipe_nonblocking(int fds[2]); +- +-int drain_rcvbuf(int fd); +- +-int make_unix_socket(int style, bool nonblock, +- const char *bind_path, const char *connect_path); +-int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len); +- +-/* Universal sendmmsg and recvmmsg support on Linux. +- * +- * New enough Linux supports sendmmsg and recvmmsg, but older versions do not. +- * We add the following infrastructure to allow all code on Linux to use +- * sendmmsg and recvmmsg, regardless of platform support: +- * +- * - For platforms that lack these functions entirely, we emulate them. +- * +- * - With newer glibc but an old kernel, sendmmsg() and recvmmsg() fail with +- * ENOSYS. To compensate, even if these functions appear to be available, we +- * wrap them with handlers that use our emulation in this case. +- */ +-#ifdef __linux__ +-#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN +-struct mmsghdr { +- struct msghdr msg_hdr; +- unsigned int msg_len; +-}; +-#endif +- +-#ifndef HAVE_SENDMMSG +-int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int); +-int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *); +-#else +-#define sendmmsg wrap_sendmmsg +-int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int); +-#define recvmmsg wrap_recvmmsg +-int wrap_recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *); +-#endif +-#endif /* __linux__ */ +- +-/* Helpers for calling ioctl() on an AF_INET socket. */ +-struct ifreq; +-int af_inet_ioctl(unsigned long int command, const void *arg); +-int af_inet_ifreq_ioctl(const char *name, struct ifreq *, +- unsigned long int cmd, const char *cmd_name); +- +-#define closesocket close +-#endif +- +-#ifdef _WIN32 +-static inline int make_unix_socket(int style, bool nonblock, +- const char *bind_path, +- const char *connect_path) +-{ +- return -EINVAL; +-} +- +-/* Windows defines the 'optval' argument as char * instead of void *. */ +-#define setsockopt(sock, level, optname, optval, optlen) \ +- rpl_setsockopt(sock, level, optname, optval, optlen) +-static inline int rpl_setsockopt(int sock, int level, int optname, +- const void *optval, socklen_t optlen) +-{ +- return (setsockopt)(sock, level, optname, (const char *)optval, optlen); +-} +- +-#define getsockopt(sock, level, optname, optval, optlen) \ +- rpl_getsockopt(sock, level, optname, optval, optlen) +-static inline int rpl_getsockopt(int sock, int level, int optname, +- void *optval, socklen_t *optlen) +-{ +- return (getsockopt)(sock, level, optname, (char *)optval, optlen); +-} +-#endif +- +-/* In Windows platform, errno is not set for socket calls. +- * The last error has to be gotten from WSAGetLastError(). */ +-static inline int sock_errno(void) +-{ +-#ifdef _WIN32 +- return WSAGetLastError(); +-#else +- return errno; +-#endif +-} +- +-#endif /* socket-util.h */ +Index: openvswitch-2.17.2/lib/sort.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/sort.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* Copyright (c) 2009 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SORT_H +-#define SORT_H 1 +- +-#include +- +-void sort(size_t count, +- int (*compare)(size_t a, size_t b, void *aux), +- void (*swap)(size_t a, size_t b, void *aux), +- void *aux); +- +-#endif /* sort.h */ +Index: openvswitch-2.17.2/lib/stopwatch.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stopwatch.h ++++ /dev/null +@@ -1,59 +0,0 @@ +-/* Copyright (c) 2017 Red Hat, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef STOPWATCH_H +-#define STOPWATCH_H 1 +- +-#include +- +-enum stopwatch_units { +- SW_MS, +- SW_US, +- SW_NS, +-}; +- +-struct stopwatch_stats { +- unsigned long long count; /* Total number of samples. */ +- enum stopwatch_units unit; /* Unit of following values. */ +- unsigned long long max; /* Maximum value. */ +- unsigned long long min; /* Minimum value. */ +- double pctl_95; /* 95th percentile. */ +- double ewma_50; /* Exponentially weighted moving average +- (alpha 0.50). */ +- double ewma_1; /* Exponentially weighted moving average +- (alpha 0.01). */ +-}; +- +-/* Create a new stopwatch. +- * The "units" are not used for any calculations but are printed when +- * statistics are requested. +- */ +-void stopwatch_create(const char *name, enum stopwatch_units units); +- +-/* Start a stopwatch. */ +-void stopwatch_start(const char *name, unsigned long long ts); +- +-/* Stop a stopwatch. The elapsed time will be used for updating statistics +- * for this stopwatch. +- */ +-void stopwatch_stop(const char *name, unsigned long long ts); +- +-/* Retrieve statistics calculated from collected samples */ +-bool stopwatch_get_stats(const char *name, struct stopwatch_stats *stats); +- +-/* Block until all enqueued samples have been processed. */ +-void stopwatch_sync(void); +- +-#endif /* stopwatch.h */ +Index: openvswitch-2.17.2/lib/stream-ssl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/stream-ssl.h ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-#ifndef STREAM_SSL_H +-#define STREAM_SSL_H 1 +- +-#include +- +-bool stream_ssl_is_configured(void); +-void stream_ssl_set_private_key_file(const char *file_name); +-void stream_ssl_set_certificate_file(const char *file_name); +-void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap); +-void stream_ssl_set_peer_ca_cert_file(const char *file_name); +-void stream_ssl_set_key_and_cert(const char *private_key_file, +- const char *certificate_file); +-void stream_ssl_set_protocols(const char *arg); +-void stream_ssl_set_ciphers(const char *arg); +- +-#define SSL_OPTION_ENUMS \ +- OPT_SSL_PROTOCOLS, \ +- OPT_SSL_CIPHERS +- +-#define STREAM_SSL_LONG_OPTIONS \ +- {"private-key", required_argument, NULL, 'p'}, \ +- {"certificate", required_argument, NULL, 'c'}, \ +- {"ca-cert", required_argument, NULL, 'C'}, \ +- {"ssl-protocols", required_argument, NULL, OPT_SSL_PROTOCOLS}, \ +- {"ssl-ciphers", required_argument, NULL, OPT_SSL_CIPHERS} +- +-#define STREAM_SSL_OPTION_HANDLERS \ +- case 'p': \ +- stream_ssl_set_private_key_file(optarg); \ +- break; \ +- \ +- case 'c': \ +- stream_ssl_set_certificate_file(optarg); \ +- break; \ +- \ +- case 'C': \ +- stream_ssl_set_ca_cert_file(optarg, false); \ +- break; \ +- \ +- case OPT_SSL_PROTOCOLS: \ +- stream_ssl_set_protocols(optarg); \ +- break; \ +- \ +- case OPT_SSL_CIPHERS: \ +- stream_ssl_set_ciphers(optarg); \ +- break; +- +-#define STREAM_SSL_CASES \ +- case 'p': case 'c': case 'C': case OPT_SSL_PROTOCOLS: case OPT_SSL_CIPHERS: +- +-#endif /* stream-ssl.h */ +Index: openvswitch-2.17.2/lib/svec.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/svec.h ++++ /dev/null +@@ -1,80 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2011 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef SVEC_H +-#define SVEC_H 1 +- +-#include +-#include +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct svec { +- char **names; +- size_t n; +- size_t allocated; +-}; +- +-#define SVEC_EMPTY_INITIALIZER { NULL, 0, 0 } +- +-void svec_init(struct svec *); +-void svec_clone(struct svec *, const struct svec *); +-void svec_destroy(struct svec *); +-void svec_clear(struct svec *); +-bool svec_is_empty(const struct svec *); +-void svec_add(struct svec *, const char *); +-void svec_add_nocopy(struct svec *, char *); +-void svec_del(struct svec *, const char *); +-void svec_append(struct svec *, const struct svec *); +-void svec_terminate(struct svec *); +-void svec_sort(struct svec *); +-void svec_sort_unique(struct svec *); +-void svec_unique(struct svec *); +-void svec_compact(struct svec *); +-void svec_shuffle(struct svec *); +-void svec_diff(const struct svec *a, const struct svec *b, +- struct svec *a_only, struct svec *both, struct svec *b_only); +-bool svec_contains(const struct svec *, const char *); +-bool svec_contains_unsorted(const struct svec *, const char *); +-size_t svec_find(const struct svec *, const char *); +-bool svec_is_sorted(const struct svec *); +-bool svec_is_unique(const struct svec *); +-const char *svec_get_duplicate(const struct svec *); +-void svec_swap(struct svec *a, struct svec *b); +-void svec_print(const struct svec *svec, const char *title); +-void svec_parse_words(struct svec *svec, const char *words); +-bool svec_equal(const struct svec *, const struct svec *); +-char *svec_join(const struct svec *, +- const char *delimiter, const char *terminator); +-const char *svec_back(const struct svec *); +-void svec_pop_back(struct svec *); +- +-/* Iterates over the names in SVEC, assigning each name in turn to NAME and its +- * index to INDEX. */ +-#define SVEC_FOR_EACH(INDEX, NAME, SVEC) \ +- for ((INDEX) = 0; \ +- ((INDEX) < (SVEC)->n \ +- ? (NAME) = (SVEC)->names[INDEX], 1 \ +- : 0); \ +- (INDEX)++) +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* svec.h */ +Index: openvswitch-2.17.2/lib/table.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/table.h ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* +- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef TABLE_H +-#define TABLE_H 1 +- +-#include +-#include +-#include "openvswitch/compiler.h" +-#include "openvswitch/json.h" +- +-struct ds; +-struct table_style; +- +-/* Manipulating tables and their rows and columns. */ +- +-struct table { +- struct cell *cells; +- struct column *columns; +- size_t n_columns, allocated_columns; +- size_t n_rows, allocated_rows; +- size_t current_column; +- char *caption; +- bool timestamp; +-}; +- +-void table_init(struct table *); +-void table_destroy(struct table *); +-void table_set_caption(struct table *, char *caption); +-void table_set_timestamp(struct table *, bool timestamp); +- +-void table_add_column(struct table *, const char *heading, ...) +- OVS_PRINTF_FORMAT(2, 3); +-void table_add_row(struct table *); +- +-/* Table cells. */ +- +-struct cell { +- /* Literal text. */ +- char *text; +- +- /* JSON. */ +- struct json *json; +- const struct ovsdb_type *type; +-}; +- +-struct cell *table_add_cell(struct table *); +- +-/* Table formatting. */ +- +-enum table_format { +- TF_TABLE, /* 2-d table. */ +- TF_LIST, /* One cell per line, one row per paragraph. */ +- TF_HTML, /* HTML table. */ +- TF_CSV, /* Comma-separated lines. */ +- TF_JSON /* JSON. */ +-}; +- +-enum cell_format { +- CF_STRING, /* String format. */ +- CF_BARE, /* String format without most punctuation. */ +- CF_JSON /* JSON. */ +-}; +- +-struct table_style { +- enum table_format format; /* TF_*. */ +- enum cell_format cell_format; /* CF_*. */ +- bool headings; /* Include headings? */ +- int json_flags; /* CF_JSON: Flags for json_to_string(). */ +- int max_column_width; /* CF_STRING: Limit for column width. */ +-}; +- +-#define TABLE_STYLE_DEFAULT { TF_LIST, CF_STRING, true, JSSF_SORT, 0 } +-static const struct table_style table_style_default = TABLE_STYLE_DEFAULT; +- +-#define TABLE_OPTION_ENUMS \ +- OPT_NO_HEADINGS, \ +- OPT_PRETTY, \ +- OPT_BARE, \ +- OPT_MAX_COLUMN_WIDTH +- +-#define TABLE_LONG_OPTIONS \ +- {"format", required_argument, NULL, 'f'}, \ +- {"data", required_argument, NULL, 'd'}, \ +- {"no-headings", no_argument, NULL, OPT_NO_HEADINGS}, \ +- {"pretty", no_argument, NULL, OPT_PRETTY}, \ +- {"bare", no_argument, NULL, OPT_BARE}, \ +- {"max-column-width", required_argument, NULL, OPT_MAX_COLUMN_WIDTH} +- +-#define TABLE_OPTION_HANDLERS(STYLE) \ +- case 'f': \ +- table_parse_format(STYLE, optarg); \ +- break; \ +- \ +- case 'd': \ +- table_parse_cell_format(STYLE, optarg); \ +- break; \ +- \ +- case OPT_NO_HEADINGS: \ +- (STYLE)->headings = false; \ +- break; \ +- \ +- case OPT_PRETTY: \ +- (STYLE)->json_flags |= JSSF_PRETTY; \ +- break; \ +- \ +- case OPT_BARE: \ +- (STYLE)->format = TF_LIST; \ +- (STYLE)->cell_format = CF_BARE; \ +- (STYLE)->headings = false; \ +- break; \ +- \ +- case OPT_MAX_COLUMN_WIDTH: \ +- (STYLE)->max_column_width = atoi(optarg); \ +- break; +- +-void table_parse_format(struct table_style *, const char *format); +-void table_parse_cell_format(struct table_style *, const char *format); +- +-void table_print(const struct table *, const struct table_style *); +-void table_format(const struct table *, const struct table_style *, +- struct ds *); +-void table_format_reset(void); +-void table_usage(void); +- +-#endif /* table.h */ +Index: openvswitch-2.17.2/lib/unixctl.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/unixctl.h ++++ /dev/null +@@ -1,55 +0,0 @@ +-/* +- * Copyright (c) 2008, 2009, 2011 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef UNIXCTL_H +-#define UNIXCTL_H 1 +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* Server for Unix domain socket control connection. */ +-struct unixctl_server; +-int unixctl_server_create(const char *path, struct unixctl_server **); +-void unixctl_server_run(struct unixctl_server *); +-void unixctl_server_wait(struct unixctl_server *); +-void unixctl_server_destroy(struct unixctl_server *); +- +-const char *unixctl_server_get_path(const struct unixctl_server *); +- +-/* Client for Unix domain socket control connection. */ +-struct jsonrpc; +-int unixctl_client_create(const char *path, struct jsonrpc **client); +-int unixctl_client_transact(struct jsonrpc *client, +- const char *command, +- int argc, char *argv[], +- char **result, char **error); +- +-/* Command registration. */ +-struct unixctl_conn; +-typedef void unixctl_cb_func(struct unixctl_conn *, +- int argc, const char *argv[], void *aux); +-void unixctl_command_register(const char *name, const char *usage, +- int min_args, int max_args, +- unixctl_cb_func *cb, void *aux); +-void unixctl_command_reply_error(struct unixctl_conn *, const char *error); +-void unixctl_command_reply(struct unixctl_conn *, const char *body); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* unixctl.h */ +Index: openvswitch-2.17.2/lib/uuid.h +=================================================================== +--- openvswitch-2.17.2.orig/lib/uuid.h ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* Copyright (c) 2008, 2009, 2010, 2016, 2017 Nicira, Inc. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at: +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef UUID_H +-#define UUID_H 1 +- +-#include "openvswitch/uuid.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* An initializer or expression for an all-zero UUID. */ +-#define UUID_ZERO ((struct uuid) { .parts = { 0, 0, 0, 0 } }) +- +-/* Formats a UUID as a string, in the conventional format. +- * +- * Example: +- * struct uuid uuid = ...; +- * printf("This UUID is "UUID_FMT"\n", UUID_ARGS(&uuid)); +- * +- */ +-#define UUID_LEN 36 +-#define UUID_FMT "%08x-%04x-%04x-%04x-%04x%08x" +-#define UUID_ARGS(UUID) \ +- ((unsigned int) ((UUID)->parts[0])), \ +- ((unsigned int) ((UUID)->parts[1] >> 16)), \ +- ((unsigned int) ((UUID)->parts[1] & 0xffff)), \ +- ((unsigned int) ((UUID)->parts[2] >> 16)), \ +- ((unsigned int) ((UUID)->parts[2] & 0xffff)), \ +- ((unsigned int) ((UUID)->parts[3])) +- +-/* Returns a hash value for 'uuid'. This hash value is the same regardless of +- * whether we are running on a 32-bit or 64-bit or big-endian or little-endian +- * architecture. */ +-static inline size_t +-uuid_hash(const struct uuid *uuid) +-{ +- return uuid->parts[0]; +-} +- +-/* Returns true if 'a == b', false otherwise. */ +-static inline bool +-uuid_equals(const struct uuid *a, const struct uuid *b) +-{ +- return (a->parts[0] == b->parts[0] +- && a->parts[1] == b->parts[1] +- && a->parts[2] == b->parts[2] +- && a->parts[3] == b->parts[3]); +-} +- +-/* Returns the first 'n' hex digits of 'uuid', for 0 < 'n' <= 8. +- * +- * This is useful for displaying a few leading digits of the uuid, e.g. to +- * display 4 digits: +- * printf("%04x", uuid_prefix(uuid, 4)); +- */ +-static inline unsigned int +-uuid_prefix(const struct uuid *uuid, int digits) +-{ +- return (uuid->parts[0] >> (32 - 4 * digits)); +-} +- +-void uuid_init(void); +-void uuid_generate(struct uuid *); +-struct uuid uuid_random(void); +-void uuid_zero(struct uuid *); +-bool uuid_is_zero(const struct uuid *); +-int uuid_compare_3way(const struct uuid *, const struct uuid *); +-bool uuid_from_string(struct uuid *, const char *); +-bool uuid_from_string_prefix(struct uuid *, const char *); +-int uuid_is_partial_string(const char *); +-int uuid_is_partial_match(const struct uuid *, const char *match); +-void uuid_set_bits_v4(struct uuid *); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* uuid.h */ diff --git a/openvswitch-2.17.0.tar.gz b/openvswitch-2.17.0.tar.gz deleted file mode 100644 index 939da01..0000000 --- a/openvswitch-2.17.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e03bfab7ca82d81a7d3a36de4f390a3b5210e3f39657671f922877cd4ea6dc73 -size 7729001 diff --git a/openvswitch-2.17.2.tar.gz b/openvswitch-2.17.2.tar.gz new file mode 100644 index 0000000..da901de --- /dev/null +++ b/openvswitch-2.17.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a2e0db42badb8cbcaf7f3bebd5b5e9a2701319df1d04294e9a7a79e94504d69 +size 7955727 diff --git a/openvswitch.changes b/openvswitch.changes index f8f31a0..c83646b 100644 --- a/openvswitch.changes +++ b/openvswitch.changes @@ -1,3 +1,26 @@ +------------------------------------------------------------------- +Wed Aug 3 11:11:36 UTC 2022 - Dirk Müller + +- update to 2.17.2: + - Bug fixes + - DPDK: + * OVS validated with DPDK 21.11.1. It is recommended to use this version + until further releases. + - Bug fixes + - libopenvswitch API change: + * To fix the Undefined Behavior issue causing the compiler to incorrectly + optimize important parts of code, container iteration macros (e.g., + LIST_FOR_EACH) have been re-implemented in a UB-safe way. + * Backwards compatibility has mostly been preserved, however the + user-provided pointer is now set to NULL after the loop (unless it + exited via "break;") + * Users of libopenvswitch will need to double-check the use of such loop + macros before compiling with a new version. + * Since the change is limited to the definitions within the headers, the + ABI is not affected. +- refresh 0001-openvswitch-merge-compiler.h-files-into-one-file.patch + 0002-build-Seperated-common-used-headers.patch + ------------------------------------------------------------------- Fri May 13 15:52:24 UTC 2022 - Dominique Leuenberger diff --git a/openvswitch.spec b/openvswitch.spec index ec307f9..9ed163d 100644 --- a/openvswitch.spec +++ b/openvswitch.spec @@ -35,7 +35,7 @@ %bcond_with kmp %define lname libopenvswitch-2_17-0 Name: openvswitch -Version: 2.17.0 +Version: 2.17.2 Release: 0 Summary: A multilayer virtual network switch # All code is Apache-2.0 except @@ -43,8 +43,8 @@ Summary: A multilayer virtual network switch # - utilities/bugtool which is LGPL-2.1 License: Apache-2.0 AND LGPL-2.1-only AND SISSL Group: Productivity/Networking/System -URL: http://openvswitch.org/ -Source0: http://openvswitch.org/releases/openvswitch-%{version}.tar.gz +URL: https://www.openvswitch.org/ +Source0: https://openvswitch.org/releases/openvswitch-%{version}.tar.gz Source2: preamble Source89: Module.supported.updates Source99: openvswitch-rpmlintrc