From 4584e7e5b973d897790697780d4414f5adf32c84 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Wed, 27 Aug 2014 08:17:36 -0500 Subject: [PATCH 01/10] Move src/* to hwloc/ to prepare for netloc addition Also move tests/* to tests/hwloc/ Utils were already in specific directories. --- .gitignore | 149 ++++++++-------- Makefile.am | 45 ++--- VERSION | 4 +- config/hwloc.m4 | 8 +- config/hwloc_internal.m4 | 68 +++++--- configure.ac | 4 +- contrib/update-my-copyright.pl | 2 +- doc/Makefile.am | 38 ++-- doc/examples/Makefile.am | 2 +- {src => hwloc}/Makefile.am | 0 {src => hwloc}/base64.c | 0 {src => hwloc}/bind.c | 0 {src => hwloc}/bitmap.c | 0 {src => hwloc}/components.c | 0 {src => hwloc}/diff.c | 0 {src => hwloc}/distances.c | 0 {src => hwloc}/dolib.c | 0 {src => hwloc}/hwloc.dtd | 0 {src => hwloc}/misc.c | 0 {src => hwloc}/pci-common.c | 0 {src => hwloc}/topology-aix.c | 0 {src => hwloc}/topology-bgq.c | 0 {src => hwloc}/topology-cuda.c | 0 {src => hwloc}/topology-custom.c | 0 {src => hwloc}/topology-darwin.c | 0 {src => hwloc}/topology-fake.c | 0 {src => hwloc}/topology-freebsd.c | 0 {src => hwloc}/topology-gl.c | 0 {src => hwloc}/topology-hpux.c | 0 {src => hwloc}/topology-linux.c | 0 {src => hwloc}/topology-netbsd.c | 0 {src => hwloc}/topology-noos.c | 0 {src => hwloc}/topology-nvml.c | 0 {src => hwloc}/topology-opencl.c | 0 {src => hwloc}/topology-osf.c | 0 {src => hwloc}/topology-pci.c | 0 {src => hwloc}/topology-solaris-chiptype.c | 0 {src => hwloc}/topology-solaris.c | 0 {src => hwloc}/topology-synthetic.c | 0 {src => hwloc}/topology-windows.c | 0 {src => hwloc}/topology-x86.c | 0 {src => hwloc}/topology-xml-libxml.c | 0 {src => hwloc}/topology-xml-nolibxml.c | 0 {src => hwloc}/topology-xml.c | 0 {src => hwloc}/topology.c | 0 {src => hwloc}/traversal.c | 0 tests/Makefile.am | 122 +------------ tests/hwloc/Makefile.am | 121 +++++++++++++ tests/{ => hwloc}/cuda.c | 0 tests/{ => hwloc}/cudart.c | 0 tests/{ => hwloc}/embedded/Makefile.am | 0 tests/{ => hwloc}/embedded/README.txt | 0 tests/{ => hwloc}/embedded/autogen.sh | 0 tests/{ => hwloc}/embedded/config/README.txt | 0 tests/{ => hwloc}/embedded/configure.ac | 0 tests/{ => hwloc}/embedded/do_test.c | 0 tests/{ => hwloc}/embedded/main.c | 0 .../embedded/run-embedded-tests.sh | 0 tests/{ => hwloc}/gl.c | 0 tests/{ => hwloc}/glibc-sched.c | 0 tests/{ => hwloc}/hwloc_backends.c | 0 tests/{ => hwloc}/hwloc_bind.c | 0 tests/{ => hwloc}/hwloc_bitmap.c | 0 .../hwloc_bitmap_first_last_weight.c | 0 tests/{ => hwloc}/hwloc_bitmap_singlify.c | 0 tests/{ => hwloc}/hwloc_bitmap_string.c | 0 tests/{ => hwloc}/hwloc_custom.c | 0 tests/{ => hwloc}/hwloc_distances.c | 0 .../hwloc_get_cache_covering_cpuset.c | 0 tests/{ => hwloc}/hwloc_get_closest_objs.c | 0 .../hwloc_get_largest_objs_inside_cpuset.c | 0 .../{ => hwloc}/hwloc_get_last_cpu_location.c | 0 .../hwloc_get_next_obj_covering_cpuset.c | 0 .../hwloc_get_obj_below_array_by_type.c | 0 .../hwloc_get_obj_covering_cpuset.c | 0 .../{ => hwloc}/hwloc_get_obj_inside_cpuset.c | 0 .../hwloc_get_shared_cache_covering_obj.c | 0 tests/{ => hwloc}/hwloc_groups.c | 0 tests/{ => hwloc}/hwloc_groups2.c | 0 tests/{ => hwloc}/hwloc_insert_misc.c | 0 tests/{ => hwloc}/hwloc_iodevs.c | 0 tests/{ => hwloc}/hwloc_is_thissystem.c | 0 tests/{ => hwloc}/hwloc_list_components.c | 0 tests/{ => hwloc}/hwloc_obj_infos.c | 0 tests/{ => hwloc}/hwloc_object_userdata.c | 0 tests/{ => hwloc}/hwloc_pci_backend.c | 0 tests/{ => hwloc}/hwloc_synthetic.c | 0 tests/{ => hwloc}/hwloc_topology_diff.c | 0 tests/{ => hwloc}/hwloc_topology_dup.c | 0 tests/{ => hwloc}/hwloc_topology_restrict.c | 0 tests/{ => hwloc}/hwloc_type_depth.c | 0 tests/{ => hwloc}/intel-mic.c | 0 tests/{ => hwloc}/linux-libnuma.c | 0 .../{ => hwloc}/linux/128ia64-17n4s2c.output | 0 .../{ => hwloc}/linux/128ia64-17n4s2c.tar.bz2 | Bin ...16amd64-4n4c-cgroup-distance-merge.options | 0 .../16amd64-4n4c-cgroup-distance-merge.output | 0 ...16amd64-4n4c-cgroup-distance-merge.tar.bz2 | Bin .../linux/16amd64-8n2c-cpusets.output | 0 .../linux/16amd64-8n2c-cpusets.tar.bz2 | Bin .../linux/16amd64-8n2c-cpusets.xml.options | 0 .../linux/16amd64-8n2c-cpusets.xml.output | 0 .../linux/16amd64-8n2c-cpusets.xml.source | 0 .../16amd64-8n2c-cpusets_noadmin.options | 0 .../linux/16amd64-8n2c-cpusets_noadmin.output | 0 .../linux/16amd64-8n2c-cpusets_noadmin.source | 0 tests/{ => hwloc}/linux/16amd64-8n2c.output | 0 tests/{ => hwloc}/linux/16amd64-8n2c.tar.bz2 | Bin tests/{ => hwloc}/linux/16em64t-2m4c2t.output | 0 .../{ => hwloc}/linux/16em64t-2m4c2t.tar.bz2 | Bin .../linux/16em64t-4s2c2t-offlines.output | 0 .../linux/16em64t-4s2c2t-offlines.tar.bz2 | Bin .../linux/16em64t-4s2c2t-offlines.xml.options | 0 .../linux/16em64t-4s2c2t-offlines.xml.output | 0 .../linux/16em64t-4s2c2t-offlines.xml.source | 0 .../16em64t-4s2c2t-offlines_noadmin.options | 0 .../16em64t-4s2c2t-offlines_noadmin.output | 0 .../16em64t-4s2c2t-offlines_noadmin.source | 0 tests/{ => hwloc}/linux/16em64t-4s2c2t.output | 0 .../{ => hwloc}/linux/16em64t-4s2c2t.tar.bz2 | Bin .../linux/16em64t-4s2c2t.xml.options | 0 .../linux/16em64t-4s2c2t.xml.output | 0 .../linux/16em64t-4s2c2t.xml.source | 0 .../linux/16em64t-4s2c2t_merge.options | 0 .../linux/16em64t-4s2c2t_merge.output | 0 .../linux/16em64t-4s2c2t_merge.source | 0 .../linux/16em64t-4s2c2t_ncaches.options | 0 .../linux/16em64t-4s2c2t_ncaches.output | 0 .../linux/16em64t-4s2c2t_ncaches.source | 0 .../16em64t-4s2ca2c-cpusetreorder.output | 0 .../16em64t-4s2ca2c-cpusetreorder.tar.bz2 | Bin tests/{ => hwloc}/linux/16ia64-8n2s.output | 0 tests/{ => hwloc}/linux/16ia64-8n2s.tar.bz2 | Bin tests/{ => hwloc}/linux/1alpha.output | 0 tests/{ => hwloc}/linux/1alpha.tar.bz2 | Bin tests/{ => hwloc}/linux/20s390-2g6s4c.output | 0 tests/{ => hwloc}/linux/20s390-2g6s4c.tar.bz2 | Bin .../24em64t-2n6c2t+2mic.olddriver.options | 0 .../24em64t-2n6c2t+2mic.olddriver.output | 0 .../24em64t-2n6c2t+2mic.olddriver.tar.bz2 | Bin .../{ => hwloc}/linux/256ia64-64n2s2c.output | 0 .../{ => hwloc}/linux/256ia64-64n2s2c.tar.bz2 | Bin .../linux/256ppc-8n8s4t-nocache.exclude | 0 .../linux/256ppc-8n8s4t-nocache.output | 0 .../linux/256ppc-8n8s4t-nocache.source | 0 .../linux/256ppc-8n8s4t-nosys.exclude | 0 .../linux/256ppc-8n8s4t-nosys.output | 0 .../linux/256ppc-8n8s4t-nosys.source | 0 tests/{ => hwloc}/linux/256ppc-8n8s4t.output | 0 tests/{ => hwloc}/linux/256ppc-8n8s4t.tar.bz2 | Bin .../28em64t-2s2n7c-buggycoresiblings.output | 0 .../28em64t-2s2n7c-buggycoresiblings.tar.bz2 | Bin tests/{ => hwloc}/linux/2amd64-2n.output | 0 tests/{ => hwloc}/linux/2amd64-2n.tar.bz2 | Bin tests/{ => hwloc}/linux/2arm-2c.output | 0 tests/{ => hwloc}/linux/2arm-2c.tar.bz2 | Bin .../linux/2i386-2c-nohugepage.tar.bz2 | Bin .../linux/2i386-2c-nohugepage.xml.options | 0 .../linux/2i386-2c-nohugepage.xml.output | 0 .../linux/2i386-2c-nohugepage.xml.source | 0 .../linux/2i386-2t-hugepagesizecount.tar.bz2 | Bin .../linux/2i386-2t-hugepagesizecount.xml.env | 0 .../2i386-2t-hugepagesizecount.xml.options | 0 .../2i386-2t-hugepagesizecount.xml.output | 0 .../2i386-2t-hugepagesizecount.xml.source | 0 tests/{ => hwloc}/linux/2ps3-2t.output | 0 tests/{ => hwloc}/linux/2ps3-2t.tar.bz2 | Bin tests/{ => hwloc}/linux/2s390-2c.output | 0 tests/{ => hwloc}/linux/2s390-2c.tar.bz2 | Bin .../linux/32amd64-4s2n4c-cgroup.env | 0 .../linux/32amd64-4s2n4c-cgroup.output | 0 .../linux/32amd64-4s2n4c-cgroup.tar.bz2 | Bin .../linux/32amd64-4s2n4c-cgroup.xml.env | 0 .../linux/32amd64-4s2n4c-cgroup.xml.options | 0 .../linux/32amd64-4s2n4c-cgroup.xml.output | 0 .../linux/32amd64-4s2n4c-cgroup.xml.source | 0 .../linux/32em64t-2n8c+1mic.options | 0 .../linux/32em64t-2n8c+1mic.output | 0 .../linux/32em64t-2n8c+1mic.tar.bz2 | Bin tests/{ => hwloc}/linux/32ppc-4n4c2c.output | 0 tests/{ => hwloc}/linux/32ppc-4n4c2c.tar.bz2 | Bin .../linux/40intel64-2g2n4c+pci.env | 0 .../linux/40intel64-2g2n4c+pci.options | 0 .../linux/40intel64-2g2n4c+pci.output | 0 .../linux/40intel64-2g2n4c+pci.tar.bz2 | Bin .../linux/40intel64-4n10c+pci-conflicts.env | 0 .../40intel64-4n10c+pci-conflicts.output | 0 .../40intel64-4n10c+pci-conflicts.tar.bz2 | Bin .../linux/48amd64-4d2n6c-sparse.output | 0 .../linux/48amd64-4d2n6c-sparse.tar.bz2 | Bin .../linux/4em64t-2c2t-ignore-reorder.options | 0 .../linux/4em64t-2c2t-ignore-reorder.output | 0 .../linux/4em64t-2c2t-ignore-reorder.tar.bz2 | Bin tests/{ => hwloc}/linux/4ia64-4s.output | 0 tests/{ => hwloc}/linux/4ia64-4s.tar.bz2 | Bin tests/{ => hwloc}/linux/4ppc-4c.output | 0 tests/{ => hwloc}/linux/4ppc-4c.tar.bz2 | Bin tests/{ => hwloc}/linux/4qs22-2s2t.output | 0 tests/{ => hwloc}/linux/4qs22-2s2t.tar.bz2 | Bin .../linux/64amd64-4s2n4ca2co.output | 0 .../linux/64amd64-4s2n4ca2co.tar.bz2 | Bin .../linux/64fake-4n2s2ca2c2t.output | 0 .../linux/64fake-4n2s2ca2c2t.tar.bz2 | Bin tests/{ => hwloc}/linux/8amd64-4n2c.output | 0 tests/{ => hwloc}/linux/8amd64-4n2c.tar.bz2 | Bin .../linux/8em64t-2s2ca2c-buggynuma.output | 0 .../linux/8em64t-2s2ca2c-buggynuma.tar.bz2 | Bin tests/{ => hwloc}/linux/8em64t-2s2ca2c.output | 0 .../{ => hwloc}/linux/8em64t-2s2ca2c.tar.bz2 | Bin .../linux/8em64t-2s4c-heterogeneous.output | 0 .../linux/8em64t-2s4c-heterogeneous.tar.bz2 | Bin tests/{ => hwloc}/linux/8em64t-4c2t.output | 0 tests/{ => hwloc}/linux/8em64t-4c2t.tar.bz2 | Bin tests/{ => hwloc}/linux/8ia64-2n2s2c.output | 0 tests/{ => hwloc}/linux/8ia64-2n2s2c.tar.bz2 | Bin tests/{ => hwloc}/linux/8ia64-2s2c2t.output | 0 tests/{ => hwloc}/linux/8ia64-2s2c2t.tar.bz2 | Bin tests/{ => hwloc}/linux/8ia64-4s2c.output | 0 tests/{ => hwloc}/linux/8ia64-4s2c.tar.bz2 | Bin .../linux/96em64t-4n4d3ca2co-forcecpuinfo.env | 0 .../96em64t-4n4d3ca2co-forcecpuinfo.output | 0 .../96em64t-4n4d3ca2co-forcecpuinfo.source | 0 .../linux/96em64t-4n4d3ca2co.output | 0 .../linux/96em64t-4n4d3ca2co.tar.bz2 | Bin tests/{ => hwloc}/linux/Makefile.am | 0 tests/{ => hwloc}/linux/README | 0 tests/{ => hwloc}/linux/gather/Makefile.am | 0 .../linux/gather/test-gather-topology.sh.in | 6 +- .../linux/hwloc-gather-topology.in | 1 + tests/{ => hwloc}/linux/test-topology.sh.in | 8 +- tests/{ => hwloc}/myriexpress.c | 0 tests/{ => hwloc}/nvml.c | 0 tests/{ => hwloc}/opencl.c | 0 tests/{ => hwloc}/openfabrics-verbs.c | 0 tests/hwloc/ports/Makefile.am | 165 ++++++++++++++++++ .../{ => hwloc}/ports/include/aix/procinfo.h | 0 .../ports/include/aix/sys/processor.h | 0 .../{ => hwloc}/ports/include/aix/sys/rset.h | 0 .../ports/include/aix/sys/systemcfg.h | 0 .../ports/include/aix/sys/thread.h | 0 .../include/bgq/spi/include/kernel/location.h | 0 .../include/bgq/spi/include/kernel/process.h | 0 .../ports/include/cuda/cuda_runtime_api.h | 0 .../ports/include/darwin/sys/sysctl.h | 0 .../ports/include/freebsd/pthread.h | 0 .../ports/include/freebsd/pthread_np.h | 0 .../ports/include/freebsd/sys/cpuset.h | 0 .../ports/include/freebsd/sys/sysctl.h | 0 .../ports/include/gl/NVCtrl/NVCtrl.h | 0 .../ports/include/gl/NVCtrl/NVCtrlLib.h | 0 tests/{ => hwloc}/ports/include/gl/X11/Xlib.h | 0 .../ports/include/hpux/sys/mpctl.h | 0 .../ports/include/netbsd/pthread.h | 0 .../{ => hwloc}/ports/include/netbsd/sched.h | 0 tests/{ => hwloc}/ports/include/nvml/nvml.h | 0 .../ports/include/opencl/CL/cl_ext.h | 0 tests/{ => hwloc}/ports/include/osf/cpuset.h | 0 tests/{ => hwloc}/ports/include/osf/numa.h | 0 tests/{ => hwloc}/ports/include/osf/radset.h | 0 .../{ => hwloc}/ports/include/solaris/kstat.h | 0 .../{ => hwloc}/ports/include/solaris/picl.h | 0 .../ports/include/solaris/sys/lgrp_user.h | 0 .../ports/include/solaris/sys/processor.h | 0 .../ports/include/solaris/sys/procset.h | 0 .../ports/include/solaris/sys/systeminfo.h | 0 .../ports/include/windows/windows.h | 0 tests/{ => hwloc}/rename/Makefile.am | 0 tests/{ => hwloc}/rename/main.c | 0 tests/{ => hwloc}/wrapper.sh.in | 0 .../{ => hwloc}/xml/16amd64-8n2c-cpusets.xml | 0 .../xml/16em64t-4s2c2t-offlines.xml | 0 tests/{ => hwloc}/xml/16em64t-4s2c2t.xml | 0 .../192em64t-12gr2n8c2t-distancegroups.env | 0 .../192em64t-12gr2n8c2t-distancegroups.xml | 0 .../xml/192em64t-24n8c2t-distancegroups.env | 0 .../192em64t-24n8c2t-distancegroups.source | 0 .../xml/192em64t-24n8c2t-distancegroups.xml | 0 .../xml/192em64t-24n8c2t-nodistancegroups.env | 0 .../xml/192em64t-24n8c2t-nodistancegroups.xml | 0 tests/{ => hwloc}/xml/24em64t-2n6c2t-pci.xml | 0 .../xml/32em64t-2n8c2t-pci-noio.options | 0 .../xml/32em64t-2n8c2t-pci-noio.source | 0 .../xml/32em64t-2n8c2t-pci-noio.xml | 0 .../xml/32em64t-2n8c2t-pci-normalio.source | 0 .../xml/32em64t-2n8c2t-pci-normalio.xml | 0 .../xml/32em64t-2n8c2t-pci-wholeio.options | 0 .../xml/32em64t-2n8c2t-pci-wholeio.xml | 0 tests/{ => hwloc}/xml/8em64t-2mi2ma2c.xml | 0 .../xml/96em64t-4n4d3ca2co-pci.xml | 0 tests/hwloc/xml/Makefile.am | 51 ++++++ tests/{ => hwloc}/xml/test-topology.sh.in | 8 +- tests/{ => hwloc}/xmlbuffer.c | 0 tests/ports/Makefile.am | 165 ------------------ tests/xml/Makefile.am | 51 ------ utils/.gitignore | 1 - utils/hwloc/Makefile.am | 2 +- utils/hwloc/hwloc-compress-dir.in | 0 utils/hwloc/test-fake-plugin.sh.in | 6 +- utils/hwloc/test-hwloc-annotate.sh.in | 13 +- utils/hwloc/test-hwloc-assembler.sh.in | 17 +- utils/hwloc/test-hwloc-calc.sh.in | 28 +-- utils/hwloc/test-hwloc-compress-dir.sh.in | 13 +- utils/hwloc/test-hwloc-diffpatch.sh.in | 24 +-- utils/hwloc/test-hwloc-distances.sh.in | 11 +- utils/hwloc/test-hwloc-distrib.sh.in | 11 +- utils/hwloc/test-hwloc-info.sh.in | 11 +- utils/lstopo/Makefile.am | 2 +- utils/lstopo/test-hwloc-ls.sh.in | 10 +- 308 files changed, 616 insertions(+), 551 deletions(-) rename {src => hwloc}/Makefile.am (100%) rename {src => hwloc}/base64.c (100%) rename {src => hwloc}/bind.c (100%) rename {src => hwloc}/bitmap.c (100%) rename {src => hwloc}/components.c (100%) rename {src => hwloc}/diff.c (100%) rename {src => hwloc}/distances.c (100%) rename {src => hwloc}/dolib.c (100%) rename {src => hwloc}/hwloc.dtd (100%) rename {src => hwloc}/misc.c (100%) rename {src => hwloc}/pci-common.c (100%) rename {src => hwloc}/topology-aix.c (100%) rename {src => hwloc}/topology-bgq.c (100%) rename {src => hwloc}/topology-cuda.c (100%) rename {src => hwloc}/topology-custom.c (100%) rename {src => hwloc}/topology-darwin.c (100%) rename {src => hwloc}/topology-fake.c (100%) rename {src => hwloc}/topology-freebsd.c (100%) rename {src => hwloc}/topology-gl.c (100%) rename {src => hwloc}/topology-hpux.c (100%) rename {src => hwloc}/topology-linux.c (100%) rename {src => hwloc}/topology-netbsd.c (100%) rename {src => hwloc}/topology-noos.c (100%) rename {src => hwloc}/topology-nvml.c (100%) rename {src => hwloc}/topology-opencl.c (100%) rename {src => hwloc}/topology-osf.c (100%) rename {src => hwloc}/topology-pci.c (100%) rename {src => hwloc}/topology-solaris-chiptype.c (100%) rename {src => hwloc}/topology-solaris.c (100%) rename {src => hwloc}/topology-synthetic.c (100%) rename {src => hwloc}/topology-windows.c (100%) rename {src => hwloc}/topology-x86.c (100%) rename {src => hwloc}/topology-xml-libxml.c (100%) rename {src => hwloc}/topology-xml-nolibxml.c (100%) rename {src => hwloc}/topology-xml.c (100%) rename {src => hwloc}/topology.c (100%) rename {src => hwloc}/traversal.c (100%) create mode 100644 tests/hwloc/Makefile.am rename tests/{ => hwloc}/cuda.c (100%) rename tests/{ => hwloc}/cudart.c (100%) rename tests/{ => hwloc}/embedded/Makefile.am (100%) rename tests/{ => hwloc}/embedded/README.txt (100%) rename tests/{ => hwloc}/embedded/autogen.sh (100%) rename tests/{ => hwloc}/embedded/config/README.txt (100%) rename tests/{ => hwloc}/embedded/configure.ac (100%) rename tests/{ => hwloc}/embedded/do_test.c (100%) rename tests/{ => hwloc}/embedded/main.c (100%) rename tests/{ => hwloc}/embedded/run-embedded-tests.sh (100%) rename tests/{ => hwloc}/gl.c (100%) rename tests/{ => hwloc}/glibc-sched.c (100%) rename tests/{ => hwloc}/hwloc_backends.c (100%) rename tests/{ => hwloc}/hwloc_bind.c (100%) rename tests/{ => hwloc}/hwloc_bitmap.c (100%) rename tests/{ => hwloc}/hwloc_bitmap_first_last_weight.c (100%) rename tests/{ => hwloc}/hwloc_bitmap_singlify.c (100%) rename tests/{ => hwloc}/hwloc_bitmap_string.c (100%) rename tests/{ => hwloc}/hwloc_custom.c (100%) rename tests/{ => hwloc}/hwloc_distances.c (100%) rename tests/{ => hwloc}/hwloc_get_cache_covering_cpuset.c (100%) rename tests/{ => hwloc}/hwloc_get_closest_objs.c (100%) rename tests/{ => hwloc}/hwloc_get_largest_objs_inside_cpuset.c (100%) rename tests/{ => hwloc}/hwloc_get_last_cpu_location.c (100%) rename tests/{ => hwloc}/hwloc_get_next_obj_covering_cpuset.c (100%) rename tests/{ => hwloc}/hwloc_get_obj_below_array_by_type.c (100%) rename tests/{ => hwloc}/hwloc_get_obj_covering_cpuset.c (100%) rename tests/{ => hwloc}/hwloc_get_obj_inside_cpuset.c (100%) rename tests/{ => hwloc}/hwloc_get_shared_cache_covering_obj.c (100%) rename tests/{ => hwloc}/hwloc_groups.c (100%) rename tests/{ => hwloc}/hwloc_groups2.c (100%) rename tests/{ => hwloc}/hwloc_insert_misc.c (100%) rename tests/{ => hwloc}/hwloc_iodevs.c (100%) rename tests/{ => hwloc}/hwloc_is_thissystem.c (100%) rename tests/{ => hwloc}/hwloc_list_components.c (100%) rename tests/{ => hwloc}/hwloc_obj_infos.c (100%) rename tests/{ => hwloc}/hwloc_object_userdata.c (100%) rename tests/{ => hwloc}/hwloc_pci_backend.c (100%) rename tests/{ => hwloc}/hwloc_synthetic.c (100%) rename tests/{ => hwloc}/hwloc_topology_diff.c (100%) rename tests/{ => hwloc}/hwloc_topology_dup.c (100%) rename tests/{ => hwloc}/hwloc_topology_restrict.c (100%) rename tests/{ => hwloc}/hwloc_type_depth.c (100%) rename tests/{ => hwloc}/intel-mic.c (100%) rename tests/{ => hwloc}/linux-libnuma.c (100%) rename tests/{ => hwloc}/linux/128ia64-17n4s2c.output (100%) rename tests/{ => hwloc}/linux/128ia64-17n4s2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16amd64-4n4c-cgroup-distance-merge.options (100%) rename tests/{ => hwloc}/linux/16amd64-4n4c-cgroup-distance-merge.output (100%) rename tests/{ => hwloc}/linux/16amd64-4n4c-cgroup-distance-merge.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets.output (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets.xml.options (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets.xml.output (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets.xml.source (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets_noadmin.options (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets_noadmin.output (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c-cpusets_noadmin.source (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c.output (100%) rename tests/{ => hwloc}/linux/16amd64-8n2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16em64t-2m4c2t.output (100%) rename tests/{ => hwloc}/linux/16em64t-2m4c2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines.xml.options (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines.xml.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines.xml.source (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines_noadmin.options (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines_noadmin.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t-offlines_noadmin.source (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t.xml.options (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t.xml.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t.xml.source (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_merge.options (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_merge.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_merge.source (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_ncaches.options (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_ncaches.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2c2t_ncaches.source (100%) rename tests/{ => hwloc}/linux/16em64t-4s2ca2c-cpusetreorder.output (100%) rename tests/{ => hwloc}/linux/16em64t-4s2ca2c-cpusetreorder.tar.bz2 (100%) rename tests/{ => hwloc}/linux/16ia64-8n2s.output (100%) rename tests/{ => hwloc}/linux/16ia64-8n2s.tar.bz2 (100%) rename tests/{ => hwloc}/linux/1alpha.output (100%) rename tests/{ => hwloc}/linux/1alpha.tar.bz2 (100%) rename tests/{ => hwloc}/linux/20s390-2g6s4c.output (100%) rename tests/{ => hwloc}/linux/20s390-2g6s4c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/24em64t-2n6c2t+2mic.olddriver.options (100%) rename tests/{ => hwloc}/linux/24em64t-2n6c2t+2mic.olddriver.output (100%) rename tests/{ => hwloc}/linux/24em64t-2n6c2t+2mic.olddriver.tar.bz2 (100%) rename tests/{ => hwloc}/linux/256ia64-64n2s2c.output (100%) rename tests/{ => hwloc}/linux/256ia64-64n2s2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nocache.exclude (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nocache.output (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nocache.source (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nosys.exclude (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nosys.output (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t-nosys.source (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t.output (100%) rename tests/{ => hwloc}/linux/256ppc-8n8s4t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/28em64t-2s2n7c-buggycoresiblings.output (100%) rename tests/{ => hwloc}/linux/28em64t-2s2n7c-buggycoresiblings.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2amd64-2n.output (100%) rename tests/{ => hwloc}/linux/2amd64-2n.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2arm-2c.output (100%) rename tests/{ => hwloc}/linux/2arm-2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2i386-2c-nohugepage.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2i386-2c-nohugepage.xml.options (100%) rename tests/{ => hwloc}/linux/2i386-2c-nohugepage.xml.output (100%) rename tests/{ => hwloc}/linux/2i386-2c-nohugepage.xml.source (100%) rename tests/{ => hwloc}/linux/2i386-2t-hugepagesizecount.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2i386-2t-hugepagesizecount.xml.env (100%) rename tests/{ => hwloc}/linux/2i386-2t-hugepagesizecount.xml.options (100%) rename tests/{ => hwloc}/linux/2i386-2t-hugepagesizecount.xml.output (100%) rename tests/{ => hwloc}/linux/2i386-2t-hugepagesizecount.xml.source (100%) rename tests/{ => hwloc}/linux/2ps3-2t.output (100%) rename tests/{ => hwloc}/linux/2ps3-2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/2s390-2c.output (100%) rename tests/{ => hwloc}/linux/2s390-2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.env (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.output (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.tar.bz2 (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.xml.env (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.xml.options (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.xml.output (100%) rename tests/{ => hwloc}/linux/32amd64-4s2n4c-cgroup.xml.source (100%) rename tests/{ => hwloc}/linux/32em64t-2n8c+1mic.options (100%) rename tests/{ => hwloc}/linux/32em64t-2n8c+1mic.output (100%) rename tests/{ => hwloc}/linux/32em64t-2n8c+1mic.tar.bz2 (100%) rename tests/{ => hwloc}/linux/32ppc-4n4c2c.output (100%) rename tests/{ => hwloc}/linux/32ppc-4n4c2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/40intel64-2g2n4c+pci.env (100%) rename tests/{ => hwloc}/linux/40intel64-2g2n4c+pci.options (100%) rename tests/{ => hwloc}/linux/40intel64-2g2n4c+pci.output (100%) rename tests/{ => hwloc}/linux/40intel64-2g2n4c+pci.tar.bz2 (100%) rename tests/{ => hwloc}/linux/40intel64-4n10c+pci-conflicts.env (100%) rename tests/{ => hwloc}/linux/40intel64-4n10c+pci-conflicts.output (100%) rename tests/{ => hwloc}/linux/40intel64-4n10c+pci-conflicts.tar.bz2 (100%) rename tests/{ => hwloc}/linux/48amd64-4d2n6c-sparse.output (100%) rename tests/{ => hwloc}/linux/48amd64-4d2n6c-sparse.tar.bz2 (100%) rename tests/{ => hwloc}/linux/4em64t-2c2t-ignore-reorder.options (100%) rename tests/{ => hwloc}/linux/4em64t-2c2t-ignore-reorder.output (100%) rename tests/{ => hwloc}/linux/4em64t-2c2t-ignore-reorder.tar.bz2 (100%) rename tests/{ => hwloc}/linux/4ia64-4s.output (100%) rename tests/{ => hwloc}/linux/4ia64-4s.tar.bz2 (100%) rename tests/{ => hwloc}/linux/4ppc-4c.output (100%) rename tests/{ => hwloc}/linux/4ppc-4c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/4qs22-2s2t.output (100%) rename tests/{ => hwloc}/linux/4qs22-2s2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/64amd64-4s2n4ca2co.output (100%) rename tests/{ => hwloc}/linux/64amd64-4s2n4ca2co.tar.bz2 (100%) rename tests/{ => hwloc}/linux/64fake-4n2s2ca2c2t.output (100%) rename tests/{ => hwloc}/linux/64fake-4n2s2ca2c2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8amd64-4n2c.output (100%) rename tests/{ => hwloc}/linux/8amd64-4n2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8em64t-2s2ca2c-buggynuma.output (100%) rename tests/{ => hwloc}/linux/8em64t-2s2ca2c-buggynuma.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8em64t-2s2ca2c.output (100%) rename tests/{ => hwloc}/linux/8em64t-2s2ca2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8em64t-2s4c-heterogeneous.output (100%) rename tests/{ => hwloc}/linux/8em64t-2s4c-heterogeneous.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8em64t-4c2t.output (100%) rename tests/{ => hwloc}/linux/8em64t-4c2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8ia64-2n2s2c.output (100%) rename tests/{ => hwloc}/linux/8ia64-2n2s2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8ia64-2s2c2t.output (100%) rename tests/{ => hwloc}/linux/8ia64-2s2c2t.tar.bz2 (100%) rename tests/{ => hwloc}/linux/8ia64-4s2c.output (100%) rename tests/{ => hwloc}/linux/8ia64-4s2c.tar.bz2 (100%) rename tests/{ => hwloc}/linux/96em64t-4n4d3ca2co-forcecpuinfo.env (100%) rename tests/{ => hwloc}/linux/96em64t-4n4d3ca2co-forcecpuinfo.output (100%) rename tests/{ => hwloc}/linux/96em64t-4n4d3ca2co-forcecpuinfo.source (100%) rename tests/{ => hwloc}/linux/96em64t-4n4d3ca2co.output (100%) rename tests/{ => hwloc}/linux/96em64t-4n4d3ca2co.tar.bz2 (100%) rename tests/{ => hwloc}/linux/Makefile.am (100%) rename tests/{ => hwloc}/linux/README (100%) rename tests/{ => hwloc}/linux/gather/Makefile.am (100%) rename tests/{ => hwloc}/linux/gather/test-gather-topology.sh.in (92%) mode change 100755 => 100644 rename tests/{ => hwloc}/linux/hwloc-gather-topology.in (98%) mode change 100755 => 100644 rename tests/{ => hwloc}/linux/test-topology.sh.in (90%) rename tests/{ => hwloc}/myriexpress.c (100%) rename tests/{ => hwloc}/nvml.c (100%) rename tests/{ => hwloc}/opencl.c (100%) rename tests/{ => hwloc}/openfabrics-verbs.c (100%) create mode 100644 tests/hwloc/ports/Makefile.am rename tests/{ => hwloc}/ports/include/aix/procinfo.h (100%) rename tests/{ => hwloc}/ports/include/aix/sys/processor.h (100%) rename tests/{ => hwloc}/ports/include/aix/sys/rset.h (100%) rename tests/{ => hwloc}/ports/include/aix/sys/systemcfg.h (100%) rename tests/{ => hwloc}/ports/include/aix/sys/thread.h (100%) rename tests/{ => hwloc}/ports/include/bgq/spi/include/kernel/location.h (100%) rename tests/{ => hwloc}/ports/include/bgq/spi/include/kernel/process.h (100%) rename tests/{ => hwloc}/ports/include/cuda/cuda_runtime_api.h (100%) rename tests/{ => hwloc}/ports/include/darwin/sys/sysctl.h (100%) rename tests/{ => hwloc}/ports/include/freebsd/pthread.h (100%) rename tests/{ => hwloc}/ports/include/freebsd/pthread_np.h (100%) rename tests/{ => hwloc}/ports/include/freebsd/sys/cpuset.h (100%) rename tests/{ => hwloc}/ports/include/freebsd/sys/sysctl.h (100%) rename tests/{ => hwloc}/ports/include/gl/NVCtrl/NVCtrl.h (100%) rename tests/{ => hwloc}/ports/include/gl/NVCtrl/NVCtrlLib.h (100%) rename tests/{ => hwloc}/ports/include/gl/X11/Xlib.h (100%) rename tests/{ => hwloc}/ports/include/hpux/sys/mpctl.h (100%) rename tests/{ => hwloc}/ports/include/netbsd/pthread.h (100%) rename tests/{ => hwloc}/ports/include/netbsd/sched.h (100%) rename tests/{ => hwloc}/ports/include/nvml/nvml.h (100%) rename tests/{ => hwloc}/ports/include/opencl/CL/cl_ext.h (100%) rename tests/{ => hwloc}/ports/include/osf/cpuset.h (100%) rename tests/{ => hwloc}/ports/include/osf/numa.h (100%) rename tests/{ => hwloc}/ports/include/osf/radset.h (100%) rename tests/{ => hwloc}/ports/include/solaris/kstat.h (100%) rename tests/{ => hwloc}/ports/include/solaris/picl.h (100%) rename tests/{ => hwloc}/ports/include/solaris/sys/lgrp_user.h (100%) rename tests/{ => hwloc}/ports/include/solaris/sys/processor.h (100%) rename tests/{ => hwloc}/ports/include/solaris/sys/procset.h (100%) rename tests/{ => hwloc}/ports/include/solaris/sys/systeminfo.h (100%) rename tests/{ => hwloc}/ports/include/windows/windows.h (100%) rename tests/{ => hwloc}/rename/Makefile.am (100%) rename tests/{ => hwloc}/rename/main.c (100%) rename tests/{ => hwloc}/wrapper.sh.in (100%) rename tests/{ => hwloc}/xml/16amd64-8n2c-cpusets.xml (100%) rename tests/{ => hwloc}/xml/16em64t-4s2c2t-offlines.xml (100%) rename tests/{ => hwloc}/xml/16em64t-4s2c2t.xml (100%) rename tests/{ => hwloc}/xml/192em64t-12gr2n8c2t-distancegroups.env (100%) rename tests/{ => hwloc}/xml/192em64t-12gr2n8c2t-distancegroups.xml (100%) rename tests/{ => hwloc}/xml/192em64t-24n8c2t-distancegroups.env (100%) rename tests/{ => hwloc}/xml/192em64t-24n8c2t-distancegroups.source (100%) rename tests/{ => hwloc}/xml/192em64t-24n8c2t-distancegroups.xml (100%) rename tests/{ => hwloc}/xml/192em64t-24n8c2t-nodistancegroups.env (100%) rename tests/{ => hwloc}/xml/192em64t-24n8c2t-nodistancegroups.xml (100%) rename tests/{ => hwloc}/xml/24em64t-2n6c2t-pci.xml (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-noio.options (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-noio.source (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-noio.xml (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-normalio.source (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-normalio.xml (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-wholeio.options (100%) rename tests/{ => hwloc}/xml/32em64t-2n8c2t-pci-wholeio.xml (100%) rename tests/{ => hwloc}/xml/8em64t-2mi2ma2c.xml (100%) rename tests/{ => hwloc}/xml/96em64t-4n4d3ca2co-pci.xml (100%) create mode 100644 tests/hwloc/xml/Makefile.am rename tests/{ => hwloc}/xml/test-topology.sh.in (90%) mode change 100755 => 100644 rename tests/{ => hwloc}/xmlbuffer.c (100%) delete mode 100644 tests/ports/Makefile.am delete mode 100644 tests/xml/Makefile.am delete mode 100644 utils/.gitignore mode change 100755 => 100644 utils/hwloc/hwloc-compress-dir.in mode change 100755 => 100644 utils/hwloc/test-hwloc-assembler.sh.in mode change 100755 => 100644 utils/hwloc/test-hwloc-calc.sh.in mode change 100755 => 100644 utils/hwloc/test-hwloc-compress-dir.sh.in mode change 100755 => 100644 utils/hwloc/test-hwloc-distrib.sh.in mode change 100755 => 100644 utils/hwloc/test-hwloc-info.sh.in mode change 100755 => 100644 utils/lstopo/test-hwloc-ls.sh.in diff --git a/.gitignore b/.gitignore index 99d4e38e85..2b2d3656ff 100644 --- a/.gitignore +++ b/.gitignore @@ -28,14 +28,15 @@ test-suite.log /autom4te.cache /aclocal.m4 /tags -/hwloc.pc /libtool +/hwloc.pc + /include/hwloc/autogen/config.h -/include/hwloc/autogen/stamp-h2 +/include/hwloc/autogen/stamp-h? /include/private/autogen/config.h /include/private/autogen/config.h.in -/include/private/autogen/stamp-h1 +/include/private/autogen/stamp-h? /doc/doxygen-config.cfg /doc/doxygen-doc/ @@ -44,82 +45,89 @@ test-suite.log /doc/hwloc-hello /doc/hwloc-hello-cpp /doc/hwloc-hello-cpp.cpp -/doc/*.o -/doc/*.log -/doc/*.trs /doc/doc.out /doc/readme.out -/src/static-components.h -/src/*.lo -/src/libhwloc.la -/src/libltdl/ +/hwloc/static-components.h +/hwloc/libhwloc.la -/tests/wrapper.sh -/tests/hwloc_list_components -/tests/hwloc_bitmap -/tests/hwloc_bitmap_string -/tests/hwloc_get_closest_objs -/tests/hwloc_get_obj_covering_cpuset -/tests/hwloc_get_cache_covering_cpuset -/tests/hwloc_get_largest_objs_inside_cpuset -/tests/hwloc_get_next_obj_covering_cpuset -/tests/hwloc_get_obj_inside_cpuset -/tests/hwloc_get_shared_cache_covering_obj -/tests/hwloc_get_obj_below_array_by_type -/tests/hwloc_bitmap_first_last_weight -/tests/hwloc_bitmap_singlify -/tests/hwloc_type_depth -/tests/hwloc_bind -/tests/hwloc_get_last_cpu_location -/tests/hwloc_object_userdata -/tests/hwloc_synthetic -/tests/hwloc_custom -/tests/hwloc_backends -/tests/hwloc_pci_backend -/tests/hwloc_is_thissystem -/tests/hwloc_distances -/tests/hwloc_groups -/tests/hwloc_groups2 -/tests/hwloc_insert_misc -/tests/hwloc_topology_restrict -/tests/hwloc_obj_infos -/tests/hwloc_iodevs -/tests/hwloc_topology_diff -/tests/hwloc_topology_dup -/tests/xmlbuffer -/tests/gl -/tests/intel-mic -/tests/linux-libnuma -/tests/glibc-sched -/tests/openfabrics-verbs -/tests/myriexpress -/tests/opencl -/tests/cuda -/tests/cudart -/tests/nvml -/tests/*.o -/tests/*.log -/tests/*.trs +/tests/hwloc/wrapper.sh +/tests/hwloc/hwloc_list_components +/tests/hwloc/hwloc_bitmap +/tests/hwloc/hwloc_bitmap_string +/tests/hwloc/hwloc_get_closest_objs +/tests/hwloc/hwloc_get_obj_covering_cpuset +/tests/hwloc/hwloc_get_cache_covering_cpuset +/tests/hwloc/hwloc_get_largest_objs_inside_cpuset +/tests/hwloc/hwloc_get_next_obj_covering_cpuset +/tests/hwloc/hwloc_get_obj_inside_cpuset +/tests/hwloc/hwloc_get_shared_cache_covering_obj +/tests/hwloc/hwloc_get_obj_below_array_by_type +/tests/hwloc/hwloc_bitmap_first_last_weight +/tests/hwloc/hwloc_bitmap_singlify +/tests/hwloc/hwloc_type_depth +/tests/hwloc/hwloc_bind +/tests/hwloc/hwloc_get_last_cpu_location +/tests/hwloc/hwloc_object_userdata +/tests/hwloc/hwloc_synthetic +/tests/hwloc/hwloc_custom +/tests/hwloc/hwloc_backends +/tests/hwloc/hwloc_pci_backend +/tests/hwloc/hwloc_is_thissystem +/tests/hwloc/hwloc_distances +/tests/hwloc/hwloc_groups +/tests/hwloc/hwloc_groups2 +/tests/hwloc/hwloc_insert_misc +/tests/hwloc/hwloc_topology_diff +/tests/hwloc/hwloc_topology_dup +/tests/hwloc/hwloc_topology_restrict +/tests/hwloc/hwloc_obj_infos +/tests/hwloc/hwloc_iodevs +/tests/hwloc/xmlbuffer +/tests/hwloc/gl +/tests/hwloc/intel-mic +/tests/hwloc/linux-libnuma +/tests/hwloc/glibc-sched +/tests/hwloc/openfabrics-verbs +/tests/hwloc/myriexpress +/tests/hwloc/opencl +/tests/hwloc/cuda +/tests/hwloc/cudart +/tests/hwloc/nvml -/tests/linux/hwloc-gather-topology -/tests/linux/test-topology.sh -/tests/linux/*.log -/tests/linux/*.trs +/tests/hwloc/linux/hwloc-gather-topology +/tests/hwloc/linux/test-topology.sh -/tests/linux/gather/test-gather-topology.sh -/tests/linux/gather/*.log -/tests/linux/gather/*.trs +/tests/hwloc/linux/gather/test-gather-topology.sh -/tests/ports/*.c -/tests/ports/*.la -/tests/ports/*.lo +/tests/hwloc/ports/*.c -/tests/xml/test-topology.sh -/tests/xml/*.log -/tests/xml/*.trs +/tests/hwloc/xml/test-topology.sh + +/tests/hwloc/embedded/aclocal.m4 +/tests/hwloc/embedded/autom4te.cache +/tests/hwloc/embedded/check.out +/tests/hwloc/embedded/clean.out +/tests/hwloc/embedded/config.out +/tests/hwloc/embedded/config/ar-lib +/tests/hwloc/embedded/config/compile +/tests/hwloc/embedded/config/config.guess +/tests/hwloc/embedded/config/config.sub +/tests/hwloc/embedded/config/depcomp +/tests/hwloc/embedded/config/install-sh +/tests/hwloc/embedded/config/libtool.m4 +/tests/hwloc/embedded/config/ltmain.sh +/tests/hwloc/embedded/config/ltoptions.m4 +/tests/hwloc/embedded/config/ltsugar.m4 +/tests/hwloc/embedded/config/ltversion.m4 +/tests/hwloc/embedded/config/lt~obsolete.m4 +/tests/hwloc/embedded/config/missing +/tests/hwloc/embedded/config/test-driver +/tests/hwloc/embedded/configure +/tests/hwloc/embedded/distclean.out +/tests/hwloc/embedded/hwloc-tree/ +/tests/hwloc/embedded/make.out -/utils/hwloc/*.o /utils/hwloc/hwloc-annotate /utils/hwloc/hwloc-annotate.1 /utils/hwloc/hwloc-assembler @@ -165,4 +173,3 @@ test-suite.log /utils/lstopo/test-hwloc-ls.sh /utils/lstopo/test-*.sh.log /utils/lstopo/test-*.sh.trs - diff --git a/Makefile.am b/Makefile.am index f49011ff52..1fd76032d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,17 @@ # via AC_CONFIG_MACRO_DIR in configure.ac. ACLOCAL_AMFLAGS = -I ./config -SUBDIRS = src include +# +# "make distcheck" requires that tarballs are able to be able to "make +# dist", so we have to include config/distscript.sh. +# +EXTRA_DIST = \ + README VERSION COPYING AUTHORS \ + config/hwloc_get_version.sh \ + config/distscript.sh + +SUBDIRS = include hwloc + if HWLOC_BUILD_STANDALONE SUBDIRS += utils tests # We need doc/ if HWLOC_BUILD_DOXYGEN, or during make install if HWLOC_INSTALL_DOXYGEN. @@ -27,21 +37,14 @@ pkgconfig_DATA = hwloc.pc endif endif -# Only install the valgrind suppressions file if we're building in standalone mode +# Only install the valgrind suppressions file if we're building in +# standalone mode if HWLOC_BUILD_STANDALONE dist_pkgdata_DATA = contrib/hwloc-valgrind.supp endif -# -# "make distcheck" requires that tarballs are able to be able to "make -# dist", so we have to include config/distscript.sh. -# -EXTRA_DIST = \ - README VERSION COPYING AUTHORS \ - config/hwloc_get_version.sh \ - config/distscript.sh - -# Only install entire visual studio subdirectory if we're building in standalone mode +# Only install entire visual studio subdirectory if we're building in +# standalone mode if HWLOC_BUILD_STANDALONE EXTRA_DIST += contrib/windows endif @@ -51,15 +54,6 @@ dist-hook: sh "$(top_srcdir)/config/distscript.sh" "$(top_srcdir)" "$(distdir)" "$(HWLOC_VERSION)" endif HWLOC_BUILD_STANDALONE -# -# Build the documenation and top-level README file -# -if HWLOC_BUILD_STANDALONE -.PHONY: doc readme -doc readme: - $(MAKE) -C doc -endif HWLOC_BUILD_STANDALONE - if HWLOC_BUILD_STANDALONE if HWLOC_HAVE_WINDOWS # @@ -73,3 +67,12 @@ uninstall-local: rm -f $(DESTDIR)$(prefix)/README.txt $(DESTDIR)$(prefix)/NEWS.txt $(DESTDIR)$(prefix)/COPYING.txt endif HWLOC_HAVE_WINDOWS endif HWLOC_BUILD_STANDALONE + +# +# Build the documenation and top-level README file +# +if HWLOC_BUILD_STANDALONE +.PHONY: doc readme +doc readme: + $(MAKE) -C doc +endif HWLOC_BUILD_STANDALONE diff --git a/VERSION b/VERSION index de4977a2a3..3f94570b9a 100644 --- a/VERSION +++ b/VERSION @@ -11,8 +11,8 @@ snapshot_version=gitclone # major, minor, and release are generally combined in the form # ... If release is zero, then it is omitted. -major=1 -minor=10 +major=2 +minor=0 release=0 # greek is used for alpha or beta release tags. If it is non-empty, diff --git a/config/hwloc.m4 b/config/hwloc.m4 index 8053ea7d21..3292941381 100644 --- a/config/hwloc.m4 +++ b/config/hwloc.m4 @@ -903,7 +903,7 @@ EOF]) AC_MSG_CHECKING([for x86 cpuid]) old_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$HWLOC_top_srcdir/include" - # We need hwloc_uint64_t but we can't use hwloc/autogen/config.h before configure ends. + # We need hwloc_uint64_t but we can't use autogen/config.h before configure ends. # So pass #include/#define manually here for now. CPUID_CHECK_HEADERS= CPUID_CHECK_DEFINE= @@ -1012,7 +1012,7 @@ EOF]) AC_SUBST(HWLOC_PLUGINS_DIR) # Static components output file - hwloc_static_components_dir=${HWLOC_top_builddir}/src + hwloc_static_components_dir=${HWLOC_top_builddir}/hwloc mkdir -p ${hwloc_static_components_dir} hwloc_static_components_file=${hwloc_static_components_dir}/static-components.h rm -f ${hwloc_static_components_file} @@ -1078,7 +1078,7 @@ EOF]) AS_IF([test "$hwloc_mode" = "embedded"], [HWLOC_EMBEDDED_CFLAGS=$HWLOC_CFLAGS HWLOC_EMBEDDED_CPPFLAGS=$HWLOC_CPPFLAGS - HWLOC_EMBEDDED_LDADD='$(HWLOC_top_builddir)/src/libhwloc_embedded.la' + HWLOC_EMBEDDED_LDADD='$(HWLOC_top_builddir)/hwloc/libhwloc_embedded.la' HWLOC_EMBEDDED_LIBS=$HWLOC_LIBS HWLOC_LIBS=]) AC_SUBST(HWLOC_EMBEDDED_CFLAGS) @@ -1090,7 +1090,7 @@ EOF]) AC_CONFIG_FILES( hwloc_config_prefix[Makefile] hwloc_config_prefix[include/Makefile] - hwloc_config_prefix[src/Makefile ] + hwloc_config_prefix[hwloc/Makefile ] ) # Cleanup diff --git a/config/hwloc_internal.m4 b/config/hwloc_internal.m4 index a17ebd792a..2feadc81d7 100644 --- a/config/hwloc_internal.m4 +++ b/config/hwloc_internal.m4 @@ -380,16 +380,17 @@ int foo(void) { # Only generate these files if we're making the tests AC_CONFIG_FILES( hwloc_config_prefix[tests/Makefile] - hwloc_config_prefix[tests/linux/Makefile] - hwloc_config_prefix[tests/linux/gather/Makefile] - hwloc_config_prefix[tests/xml/Makefile] - hwloc_config_prefix[tests/ports/Makefile] - hwloc_config_prefix[tests/rename/Makefile] - hwloc_config_prefix[tests/linux/hwloc-gather-topology] - hwloc_config_prefix[tests/linux/gather/test-gather-topology.sh] - hwloc_config_prefix[tests/linux/test-topology.sh] - hwloc_config_prefix[tests/xml/test-topology.sh] - hwloc_config_prefix[tests/wrapper.sh] + hwloc_config_prefix[tests/hwloc/Makefile] + hwloc_config_prefix[tests/hwloc/linux/Makefile] + hwloc_config_prefix[tests/hwloc/linux/gather/Makefile] + hwloc_config_prefix[tests/hwloc/xml/Makefile] + hwloc_config_prefix[tests/hwloc/ports/Makefile] + hwloc_config_prefix[tests/hwloc/rename/Makefile] + hwloc_config_prefix[tests/hwloc/linux/hwloc-gather-topology] + hwloc_config_prefix[tests/hwloc/linux/gather/test-gather-topology.sh] + hwloc_config_prefix[tests/hwloc/linux/test-topology.sh] + hwloc_config_prefix[tests/hwloc/xml/test-topology.sh] + hwloc_config_prefix[tests/hwloc/wrapper.sh] hwloc_config_prefix[utils/hwloc/hwloc-assembler-remote] hwloc_config_prefix[utils/hwloc/hwloc-compress-dir] hwloc_config_prefix[utils/hwloc/test-hwloc-annotate.sh] @@ -403,7 +404,24 @@ int foo(void) { hwloc_config_prefix[utils/hwloc/test-fake-plugin.sh] hwloc_config_prefix[utils/lstopo/test-hwloc-ls.sh]) - AC_CONFIG_COMMANDS([chmoding-scripts], [chmod +x ]hwloc_config_prefix[tests/linux/test-topology.sh ]hwloc_config_prefix[tests/xml/test-topology.sh ]hwloc_config_prefix[tests/linux/hwloc-gather-topology ]hwloc_config_prefix[tests/linux/gather/test-gather-topology.sh ]hwloc_config_prefix[tests/wrapper.sh ]hwloc_config_prefix[utils/hwloc/hwloc-assembler-remote ]hwloc_config_prefix[utils/hwloc/hwloc-compress-dir ]hwloc_config_prefix[utils/hwloc/test-hwloc-annotate.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-assembler.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-calc.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-compress-dir.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-diffpatch.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-distances.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-distrib.sh ]hwloc_config_prefix[utils/hwloc/test-hwloc-info.sh ]hwloc_config_prefix[utils/hwloc/test-fake-plugin.sh ]hwloc_config_prefix[utils/lstopo/test-hwloc-ls.sh]) + AC_CONFIG_COMMANDS([chmoding-scripts], [ +chmod +x ]hwloc_config_prefix[tests/hwloc/linux/test-topology.sh \ + ]hwloc_config_prefix[tests/hwloc/xml/test-topology.sh \ + ]hwloc_config_prefix[tests/hwloc/linux/hwloc-gather-topology \ + ]hwloc_config_prefix[tests/hwloc/linux/gather/test-gather-topology.sh \ + ]hwloc_config_prefix[tests/hwloc/wrapper.sh \ + ]hwloc_config_prefix[utils/hwloc/hwloc-assembler-remote \ + ]hwloc_config_prefix[utils/hwloc/hwloc-compress-dir \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-annotate.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-assembler.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-calc.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-compress-dir.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-diffpatch.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-distances.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-distrib.sh \ + ]hwloc_config_prefix[utils/hwloc/test-hwloc-info.sh \ + ]hwloc_config_prefix[utils/hwloc/test-fake-plugin.sh \ + ]hwloc_config_prefix[utils/lstopo/test-hwloc-ls.sh]) # These links are only needed in standalone mode. It would # be nice to m4 foreach this somehow, but whenever I tried @@ -412,19 +430,19 @@ int foo(void) { # built in standalone mode, only generate them in # standalone mode. AC_CONFIG_LINKS( - hwloc_config_prefix[tests/ports/topology-solaris.c]:hwloc_config_prefix[src/topology-solaris.c] - hwloc_config_prefix[tests/ports/topology-solaris-chiptype.c]:hwloc_config_prefix[src/topology-solaris-chiptype.c] - hwloc_config_prefix[tests/ports/topology-aix.c]:hwloc_config_prefix[src/topology-aix.c] - hwloc_config_prefix[tests/ports/topology-osf.c]:hwloc_config_prefix[src/topology-osf.c] - hwloc_config_prefix[tests/ports/topology-windows.c]:hwloc_config_prefix[src/topology-windows.c] - hwloc_config_prefix[tests/ports/topology-darwin.c]:hwloc_config_prefix[src/topology-darwin.c] - hwloc_config_prefix[tests/ports/topology-freebsd.c]:hwloc_config_prefix[src/topology-freebsd.c] - hwloc_config_prefix[tests/ports/topology-netbsd.c]:hwloc_config_prefix[src/topology-netbsd.c] - hwloc_config_prefix[tests/ports/topology-hpux.c]:hwloc_config_prefix[src/topology-hpux.c] - hwloc_config_prefix[tests/ports/topology-bgq.c]:hwloc_config_prefix[src/topology-bgq.c] - hwloc_config_prefix[tests/ports/topology-opencl.c]:hwloc_config_prefix[src/topology-opencl.c] - hwloc_config_prefix[tests/ports/topology-cuda.c]:hwloc_config_prefix[src/topology-cuda.c] - hwloc_config_prefix[tests/ports/topology-nvml.c]:hwloc_config_prefix[src/topology-nvml.c] - hwloc_config_prefix[tests/ports/topology-gl.c]:hwloc_config_prefix[src/topology-gl.c]) + hwloc_config_prefix[tests/hwloc/ports/topology-solaris.c]:hwloc_config_prefix[hwloc/topology-solaris.c] + hwloc_config_prefix[tests/hwloc/ports/topology-solaris-chiptype.c]:hwloc_config_prefix[hwloc/topology-solaris-chiptype.c] + hwloc_config_prefix[tests/hwloc/ports/topology-aix.c]:hwloc_config_prefix[hwloc/topology-aix.c] + hwloc_config_prefix[tests/hwloc/ports/topology-osf.c]:hwloc_config_prefix[hwloc/topology-osf.c] + hwloc_config_prefix[tests/hwloc/ports/topology-windows.c]:hwloc_config_prefix[hwloc/topology-windows.c] + hwloc_config_prefix[tests/hwloc/ports/topology-darwin.c]:hwloc_config_prefix[hwloc/topology-darwin.c] + hwloc_config_prefix[tests/hwloc/ports/topology-freebsd.c]:hwloc_config_prefix[hwloc/topology-freebsd.c] + hwloc_config_prefix[tests/hwloc/ports/topology-netbsd.c]:hwloc_config_prefix[hwloc/topology-netbsd.c] + hwloc_config_prefix[tests/hwloc/ports/topology-hpux.c]:hwloc_config_prefix[hwloc/topology-hpux.c] + hwloc_config_prefix[tests/hwloc/ports/topology-bgq.c]:hwloc_config_prefix[hwloc/topology-bgq.c] + hwloc_config_prefix[tests/hwloc/ports/topology-opencl.c]:hwloc_config_prefix[hwloc/topology-opencl.c] + hwloc_config_prefix[tests/hwloc/ports/topology-cuda.c]:hwloc_config_prefix[hwloc/topology-cuda.c] + hwloc_config_prefix[tests/hwloc/ports/topology-nvml.c]:hwloc_config_prefix[hwloc/topology-nvml.c] + hwloc_config_prefix[tests/hwloc/ports/topology-gl.c]:hwloc_config_prefix[hwloc/topology-gl.c]) ]) ])dnl diff --git a/configure.ac b/configure.ac index a8ac749325..94b3bc485c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ # Copyright © 2009 CNRS # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009, 2011-2012 Université Bordeaux 1 -# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# Copyright © 2009 Cisco Systems, Inc. All rights reserved. # # See COPYING in top-level directory. # @@ -89,7 +89,7 @@ AC_SUBST([libhwloc_so_version]) AH_TOP([/* -*- c -*- * * Copyright © 2009, 2011, 2012 CNRS, inria., Université Bordeaux 1 All rights reserved. - * Copyright © 2009 Cisco Systems, Inc. All rights reserved. + * Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow diff --git a/contrib/update-my-copyright.pl b/contrib/update-my-copyright.pl index 8727832fc5..060cedd9cf 100755 --- a/contrib/update-my-copyright.pl +++ b/contrib/update-my-copyright.pl @@ -121,7 +121,7 @@ sub quiet_print { # Find the top-level HWLOC source tree dir my $start = cwd(); my $top = $start; -while (! -d "$top/src") { +while (! -d "$top/hwloc") { chdir(".."); $top = cwd(); die "Can't find top-level hwloc directory" diff --git a/doc/Makefile.am b/doc/Makefile.am index eb9a920b26..d45c954504 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,6 +1,6 @@ # Copyright © 2009-2014 Inria. All rights reserved. # Copyright © 2009-2013 Université Bordeaux 1 -# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. AM_CPPFLAGS = $(HWLOC_CPPFLAGS) @@ -62,24 +62,26 @@ if HWLOC_BUILD_DOXYGEN # change. # +hwloc_include_dir = $(HWLOC_top_srcdir)/include + dox_inputs = $(DOX_CONFIG) \ $(srcdir)/hwloc.doxy \ - $(HWLOC_top_srcdir)/include/hwloc.h \ - $(HWLOC_top_srcdir)/include/hwloc/helper.h \ - $(HWLOC_top_srcdir)/include/hwloc/bitmap.h \ - $(HWLOC_top_srcdir)/include/hwloc/diff.h \ - $(HWLOC_top_srcdir)/include/hwloc/plugins.h \ - $(HWLOC_top_srcdir)/include/hwloc/glibc-sched.h \ - $(HWLOC_top_srcdir)/include/hwloc/linux.h \ - $(HWLOC_top_srcdir)/include/hwloc/linux-libnuma.h \ - $(HWLOC_top_srcdir)/include/hwloc/opencl.h \ - $(HWLOC_top_srcdir)/include/hwloc/cuda.h \ - $(HWLOC_top_srcdir)/include/hwloc/cudart.h \ - $(HWLOC_top_srcdir)/include/hwloc/nvml.h \ - $(HWLOC_top_srcdir)/include/hwloc/gl.h \ - $(HWLOC_top_srcdir)/include/hwloc/intel-mic.h \ - $(HWLOC_top_srcdir)/include/hwloc/openfabrics-verbs.h \ - $(HWLOC_top_srcdir)/include/hwloc/myriexpress.h + $(hwloc_include_dir)/hwloc.h \ + $(hwloc_include_dir)/hwloc/helper.h \ + $(hwloc_include_dir)/hwloc/bitmap.h \ + $(hwloc_include_dir)/hwloc/diff.h \ + $(hwloc_include_dir)/hwloc/plugins.h \ + $(hwloc_include_dir)/hwloc/glibc-sched.h \ + $(hwloc_include_dir)/hwloc/linux.h \ + $(hwloc_include_dir)/hwloc/linux-libnuma.h \ + $(hwloc_include_dir)/hwloc/opencl.h \ + $(hwloc_include_dir)/hwloc/cuda.h \ + $(hwloc_include_dir)/hwloc/cudart.h \ + $(hwloc_include_dir)/hwloc/nvml.h \ + $(hwloc_include_dir)/hwloc/gl.h \ + $(hwloc_include_dir)/hwloc/intel-mic.h \ + $(hwloc_include_dir)/hwloc/openfabrics-verbs.h \ + $(hwloc_include_dir)/hwloc/myriexpress.h # # Create the images that we need for the PDF output and the HTML @@ -773,7 +775,7 @@ if HWLOC_BUILD_README # Rules for creating the top-level README file. There does not appear # to be an easy way to know if AC_PATH_PROG found something in # configure.ac (!), so put a run-time check here to see if we have -# w3c. +# w3c. # # Just like BUILD_DOXYGEN, BUILD_README will automatically be false if # we're not building standalone. diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index faeaa3398a..79948290ec 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -11,7 +11,7 @@ AM_CFLAGS = $(HWLOC_CFLAGS) AM_CPPFLAGS = $(HWLOC_CPPFLAGS) AM_LDFLAGS = $(HWLOC_LDFLAGS) -LDADD = $(HWLOC_top_builddir)/src/libhwloc.la +LDADD = $(HWLOC_top_builddir)/hwloc/libhwloc.la DEPENDENCIES = $(LDADD) TESTS = hwloc-hello diff --git a/src/Makefile.am b/hwloc/Makefile.am similarity index 100% rename from src/Makefile.am rename to hwloc/Makefile.am diff --git a/src/base64.c b/hwloc/base64.c similarity index 100% rename from src/base64.c rename to hwloc/base64.c diff --git a/src/bind.c b/hwloc/bind.c similarity index 100% rename from src/bind.c rename to hwloc/bind.c diff --git a/src/bitmap.c b/hwloc/bitmap.c similarity index 100% rename from src/bitmap.c rename to hwloc/bitmap.c diff --git a/src/components.c b/hwloc/components.c similarity index 100% rename from src/components.c rename to hwloc/components.c diff --git a/src/diff.c b/hwloc/diff.c similarity index 100% rename from src/diff.c rename to hwloc/diff.c diff --git a/src/distances.c b/hwloc/distances.c similarity index 100% rename from src/distances.c rename to hwloc/distances.c diff --git a/src/dolib.c b/hwloc/dolib.c similarity index 100% rename from src/dolib.c rename to hwloc/dolib.c diff --git a/src/hwloc.dtd b/hwloc/hwloc.dtd similarity index 100% rename from src/hwloc.dtd rename to hwloc/hwloc.dtd diff --git a/src/misc.c b/hwloc/misc.c similarity index 100% rename from src/misc.c rename to hwloc/misc.c diff --git a/src/pci-common.c b/hwloc/pci-common.c similarity index 100% rename from src/pci-common.c rename to hwloc/pci-common.c diff --git a/src/topology-aix.c b/hwloc/topology-aix.c similarity index 100% rename from src/topology-aix.c rename to hwloc/topology-aix.c diff --git a/src/topology-bgq.c b/hwloc/topology-bgq.c similarity index 100% rename from src/topology-bgq.c rename to hwloc/topology-bgq.c diff --git a/src/topology-cuda.c b/hwloc/topology-cuda.c similarity index 100% rename from src/topology-cuda.c rename to hwloc/topology-cuda.c diff --git a/src/topology-custom.c b/hwloc/topology-custom.c similarity index 100% rename from src/topology-custom.c rename to hwloc/topology-custom.c diff --git a/src/topology-darwin.c b/hwloc/topology-darwin.c similarity index 100% rename from src/topology-darwin.c rename to hwloc/topology-darwin.c diff --git a/src/topology-fake.c b/hwloc/topology-fake.c similarity index 100% rename from src/topology-fake.c rename to hwloc/topology-fake.c diff --git a/src/topology-freebsd.c b/hwloc/topology-freebsd.c similarity index 100% rename from src/topology-freebsd.c rename to hwloc/topology-freebsd.c diff --git a/src/topology-gl.c b/hwloc/topology-gl.c similarity index 100% rename from src/topology-gl.c rename to hwloc/topology-gl.c diff --git a/src/topology-hpux.c b/hwloc/topology-hpux.c similarity index 100% rename from src/topology-hpux.c rename to hwloc/topology-hpux.c diff --git a/src/topology-linux.c b/hwloc/topology-linux.c similarity index 100% rename from src/topology-linux.c rename to hwloc/topology-linux.c diff --git a/src/topology-netbsd.c b/hwloc/topology-netbsd.c similarity index 100% rename from src/topology-netbsd.c rename to hwloc/topology-netbsd.c diff --git a/src/topology-noos.c b/hwloc/topology-noos.c similarity index 100% rename from src/topology-noos.c rename to hwloc/topology-noos.c diff --git a/src/topology-nvml.c b/hwloc/topology-nvml.c similarity index 100% rename from src/topology-nvml.c rename to hwloc/topology-nvml.c diff --git a/src/topology-opencl.c b/hwloc/topology-opencl.c similarity index 100% rename from src/topology-opencl.c rename to hwloc/topology-opencl.c diff --git a/src/topology-osf.c b/hwloc/topology-osf.c similarity index 100% rename from src/topology-osf.c rename to hwloc/topology-osf.c diff --git a/src/topology-pci.c b/hwloc/topology-pci.c similarity index 100% rename from src/topology-pci.c rename to hwloc/topology-pci.c diff --git a/src/topology-solaris-chiptype.c b/hwloc/topology-solaris-chiptype.c similarity index 100% rename from src/topology-solaris-chiptype.c rename to hwloc/topology-solaris-chiptype.c diff --git a/src/topology-solaris.c b/hwloc/topology-solaris.c similarity index 100% rename from src/topology-solaris.c rename to hwloc/topology-solaris.c diff --git a/src/topology-synthetic.c b/hwloc/topology-synthetic.c similarity index 100% rename from src/topology-synthetic.c rename to hwloc/topology-synthetic.c diff --git a/src/topology-windows.c b/hwloc/topology-windows.c similarity index 100% rename from src/topology-windows.c rename to hwloc/topology-windows.c diff --git a/src/topology-x86.c b/hwloc/topology-x86.c similarity index 100% rename from src/topology-x86.c rename to hwloc/topology-x86.c diff --git a/src/topology-xml-libxml.c b/hwloc/topology-xml-libxml.c similarity index 100% rename from src/topology-xml-libxml.c rename to hwloc/topology-xml-libxml.c diff --git a/src/topology-xml-nolibxml.c b/hwloc/topology-xml-nolibxml.c similarity index 100% rename from src/topology-xml-nolibxml.c rename to hwloc/topology-xml-nolibxml.c diff --git a/src/topology-xml.c b/hwloc/topology-xml.c similarity index 100% rename from src/topology-xml.c rename to hwloc/topology-xml.c diff --git a/src/topology.c b/hwloc/topology.c similarity index 100% rename from src/topology.c rename to hwloc/topology.c diff --git a/src/traversal.c b/hwloc/traversal.c similarity index 100% rename from src/traversal.c rename to hwloc/traversal.c diff --git a/tests/Makefile.am b/tests/Makefile.am index eb791a5031..aa01af4df0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,121 +1,5 @@ -# Copyright © 2009-2013 Inria. All rights reserved. -# Copyright © 2009-2012 Université Bordeaux 1 -# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. +# # See COPYING in top-level directory. -AM_CFLAGS = $(HWLOC_CFLAGS) -AM_CPPFLAGS = $(HWLOC_CPPFLAGS) -AM_LDFLAGS = $(HWLOC_LDFLAGS) - -SUBDIRS = ports xml -DIST_SUBDIRS = ports xml linux rename - -if HWLOC_HAVE_LINUX -SUBDIRS += linux -endif HWLOC_HAVE_LINUX - -LDADD = - -LOG_COMPILER = $(builddir)/wrapper.sh - -check_PROGRAMS = hwloc_list_components \ - hwloc_bitmap \ - hwloc_bitmap_string \ - hwloc_get_closest_objs \ - hwloc_get_obj_covering_cpuset \ - hwloc_get_cache_covering_cpuset \ - hwloc_get_largest_objs_inside_cpuset \ - hwloc_get_next_obj_covering_cpuset \ - hwloc_get_obj_inside_cpuset \ - hwloc_get_shared_cache_covering_obj \ - hwloc_get_obj_below_array_by_type \ - hwloc_bitmap_first_last_weight \ - hwloc_bitmap_singlify \ - hwloc_type_depth \ - hwloc_bind \ - hwloc_get_last_cpu_location \ - hwloc_object_userdata \ - hwloc_synthetic \ - hwloc_custom \ - hwloc_backends \ - hwloc_pci_backend \ - hwloc_is_thissystem \ - hwloc_distances \ - hwloc_groups \ - hwloc_groups2 \ - hwloc_insert_misc \ - hwloc_topology_restrict \ - hwloc_topology_dup \ - hwloc_topology_diff \ - hwloc_obj_infos \ - hwloc_iodevs \ - xmlbuffer \ - gl \ - intel-mic - -if HWLOC_HAVE_LINUX_LIBNUMA -check_PROGRAMS += linux-libnuma -endif HWLOC_HAVE_LINUX_LIBNUMA - -if HWLOC_HAVE_SCHED_SETAFFINITY -check_PROGRAMS += glibc-sched -endif HWLOC_HAVE_SCHED_SETAFFINITY - -if HWLOC_HAVE_LIBIBVERBS -check_PROGRAMS += openfabrics-verbs -endif HWLOC_HAVE_LIBIBVERBS - -if HWLOC_HAVE_MYRIEXPRESS -check_PROGRAMS += myriexpress -endif HWLOC_HAVE_MYRIEXPRESS - -if HWLOC_HAVE_OPENCL -check_PROGRAMS += opencl -endif HWLOC_HAVE_OPENCL - -if HWLOC_HAVE_CUDA -check_PROGRAMS += cuda -endif HWLOC_HAVE_CUDA - -if HWLOC_HAVE_CUDART -check_PROGRAMS += cudart -endif HWLOC_HAVE_CUDART - -if HWLOC_HAVE_NVML -check_PROGRAMS += nvml -endif HWLOC_HAVE_NVML - -TESTS = $(check_PROGRAMS) - -# The library has a different name depending on whether we are -# building in standalone or embedded mode. -if HWLOC_BUILD_STANDALONE -hwloc_lib = libhwloc.la -else -hwloc_lib = libhwloc_embedded.la -endif - -LDADD += $(HWLOC_top_builddir)/src/$(hwloc_lib) - -linux_libnuma_LDADD = $(LDADD) -lnuma -openfabrics_verbs_LDADD = $(LDADD) -libverbs -myriexpress_LDADD = $(LDADD) -lmyriexpress -opencl_LDADD = $(LDADD) -lOpenCL -cuda_LDADD = $(LDADD) -lcuda -cudart_LDADD = $(LDADD) -lcuda -lcudart -nvml_LDADD = $(LDADD) -lnvidia-ml -hwloc_bind_LDADD = $(LDADD) -if HWLOC_HAVE_PTHREAD -hwloc_bind_LDADD += -lpthread -endif - -# ship the embedded test code but don't actually let automake ever -# look at it because we have another configure stuff in there -EXTRA_DIST = embedded/autogen.sh \ - embedded/configure.ac \ - embedded/Makefile.am \ - embedded/do_test.c \ - embedded/main.c \ - embedded/run-embedded-tests.sh \ - embedded/README.txt \ - embedded/config/README.txt +SUBDIRS = hwloc diff --git a/tests/hwloc/Makefile.am b/tests/hwloc/Makefile.am new file mode 100644 index 0000000000..e017165192 --- /dev/null +++ b/tests/hwloc/Makefile.am @@ -0,0 +1,121 @@ +# Copyright © 2009-2013 Inria. All rights reserved. +# Copyright © 2009-2012 Université Bordeaux 1 +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. + +AM_CFLAGS = $(HWLOC_CFLAGS) +AM_CPPFLAGS = $(HWLOC_CPPFLAGS) +AM_LDFLAGS = $(HWLOC_LDFLAGS) + +SUBDIRS = ports xml +DIST_SUBDIRS = ports xml linux rename + +if HWLOC_HAVE_LINUX +SUBDIRS += linux +endif HWLOC_HAVE_LINUX + +LDADD = + +LOG_COMPILER = $(builddir)/wrapper.sh + +check_PROGRAMS = hwloc_list_components \ + hwloc_bitmap \ + hwloc_bitmap_string \ + hwloc_get_closest_objs \ + hwloc_get_obj_covering_cpuset \ + hwloc_get_cache_covering_cpuset \ + hwloc_get_largest_objs_inside_cpuset \ + hwloc_get_next_obj_covering_cpuset \ + hwloc_get_obj_inside_cpuset \ + hwloc_get_shared_cache_covering_obj \ + hwloc_get_obj_below_array_by_type \ + hwloc_bitmap_first_last_weight \ + hwloc_bitmap_singlify \ + hwloc_type_depth \ + hwloc_bind \ + hwloc_get_last_cpu_location \ + hwloc_object_userdata \ + hwloc_synthetic \ + hwloc_custom \ + hwloc_backends \ + hwloc_pci_backend \ + hwloc_is_thissystem \ + hwloc_distances \ + hwloc_groups \ + hwloc_groups2 \ + hwloc_insert_misc \ + hwloc_topology_restrict \ + hwloc_topology_dup \ + hwloc_topology_diff \ + hwloc_obj_infos \ + hwloc_iodevs \ + xmlbuffer \ + gl \ + intel-mic + +if HWLOC_HAVE_LINUX_LIBNUMA +check_PROGRAMS += linux-libnuma +endif HWLOC_HAVE_LINUX_LIBNUMA + +if HWLOC_HAVE_SCHED_SETAFFINITY +check_PROGRAMS += glibc-sched +endif HWLOC_HAVE_SCHED_SETAFFINITY + +if HWLOC_HAVE_LIBIBVERBS +check_PROGRAMS += openfabrics-verbs +endif HWLOC_HAVE_LIBIBVERBS + +if HWLOC_HAVE_MYRIEXPRESS +check_PROGRAMS += myriexpress +endif HWLOC_HAVE_MYRIEXPRESS + +if HWLOC_HAVE_OPENCL +check_PROGRAMS += opencl +endif HWLOC_HAVE_OPENCL + +if HWLOC_HAVE_CUDA +check_PROGRAMS += cuda +endif HWLOC_HAVE_CUDA + +if HWLOC_HAVE_CUDART +check_PROGRAMS += cudart +endif HWLOC_HAVE_CUDART + +if HWLOC_HAVE_NVML +check_PROGRAMS += nvml +endif HWLOC_HAVE_NVML + +TESTS = $(check_PROGRAMS) + +# The library has a different name depending on whether we are +# building in standalone or embedded mode. +if HWLOC_BUILD_STANDALONE +hwloc_lib = libhwloc.la +else +hwloc_lib = libhwloc_embedded.la +endif + +LDADD += $(HWLOC_top_builddir)/hwloc/$(hwloc_lib) + +linux_libnuma_LDADD = $(LDADD) -lnuma +openfabrics_verbs_LDADD = $(LDADD) -libverbs +myriexpress_LDADD = $(LDADD) -lmyriexpress +opencl_LDADD = $(LDADD) -lOpenCL +cuda_LDADD = $(LDADD) -lcuda +cudart_LDADD = $(LDADD) -lcuda -lcudart +nvml_LDADD = $(LDADD) -lnvidia-ml +hwloc_bind_LDADD = $(LDADD) +if HWLOC_HAVE_PTHREAD +hwloc_bind_LDADD += -lpthread +endif + +# ship the embedded test code but don't actually let automake ever +# look at it because we have another configure stuff in there +EXTRA_DIST = embedded/autogen.sh \ + embedded/configure.ac \ + embedded/Makefile.am \ + embedded/do_test.c \ + embedded/main.c \ + embedded/run-embedded-tests.sh \ + embedded/README.txt \ + embedded/config/README.txt diff --git a/tests/cuda.c b/tests/hwloc/cuda.c similarity index 100% rename from tests/cuda.c rename to tests/hwloc/cuda.c diff --git a/tests/cudart.c b/tests/hwloc/cudart.c similarity index 100% rename from tests/cudart.c rename to tests/hwloc/cudart.c diff --git a/tests/embedded/Makefile.am b/tests/hwloc/embedded/Makefile.am similarity index 100% rename from tests/embedded/Makefile.am rename to tests/hwloc/embedded/Makefile.am diff --git a/tests/embedded/README.txt b/tests/hwloc/embedded/README.txt similarity index 100% rename from tests/embedded/README.txt rename to tests/hwloc/embedded/README.txt diff --git a/tests/embedded/autogen.sh b/tests/hwloc/embedded/autogen.sh similarity index 100% rename from tests/embedded/autogen.sh rename to tests/hwloc/embedded/autogen.sh diff --git a/tests/embedded/config/README.txt b/tests/hwloc/embedded/config/README.txt similarity index 100% rename from tests/embedded/config/README.txt rename to tests/hwloc/embedded/config/README.txt diff --git a/tests/embedded/configure.ac b/tests/hwloc/embedded/configure.ac similarity index 100% rename from tests/embedded/configure.ac rename to tests/hwloc/embedded/configure.ac diff --git a/tests/embedded/do_test.c b/tests/hwloc/embedded/do_test.c similarity index 100% rename from tests/embedded/do_test.c rename to tests/hwloc/embedded/do_test.c diff --git a/tests/embedded/main.c b/tests/hwloc/embedded/main.c similarity index 100% rename from tests/embedded/main.c rename to tests/hwloc/embedded/main.c diff --git a/tests/embedded/run-embedded-tests.sh b/tests/hwloc/embedded/run-embedded-tests.sh similarity index 100% rename from tests/embedded/run-embedded-tests.sh rename to tests/hwloc/embedded/run-embedded-tests.sh diff --git a/tests/gl.c b/tests/hwloc/gl.c similarity index 100% rename from tests/gl.c rename to tests/hwloc/gl.c diff --git a/tests/glibc-sched.c b/tests/hwloc/glibc-sched.c similarity index 100% rename from tests/glibc-sched.c rename to tests/hwloc/glibc-sched.c diff --git a/tests/hwloc_backends.c b/tests/hwloc/hwloc_backends.c similarity index 100% rename from tests/hwloc_backends.c rename to tests/hwloc/hwloc_backends.c diff --git a/tests/hwloc_bind.c b/tests/hwloc/hwloc_bind.c similarity index 100% rename from tests/hwloc_bind.c rename to tests/hwloc/hwloc_bind.c diff --git a/tests/hwloc_bitmap.c b/tests/hwloc/hwloc_bitmap.c similarity index 100% rename from tests/hwloc_bitmap.c rename to tests/hwloc/hwloc_bitmap.c diff --git a/tests/hwloc_bitmap_first_last_weight.c b/tests/hwloc/hwloc_bitmap_first_last_weight.c similarity index 100% rename from tests/hwloc_bitmap_first_last_weight.c rename to tests/hwloc/hwloc_bitmap_first_last_weight.c diff --git a/tests/hwloc_bitmap_singlify.c b/tests/hwloc/hwloc_bitmap_singlify.c similarity index 100% rename from tests/hwloc_bitmap_singlify.c rename to tests/hwloc/hwloc_bitmap_singlify.c diff --git a/tests/hwloc_bitmap_string.c b/tests/hwloc/hwloc_bitmap_string.c similarity index 100% rename from tests/hwloc_bitmap_string.c rename to tests/hwloc/hwloc_bitmap_string.c diff --git a/tests/hwloc_custom.c b/tests/hwloc/hwloc_custom.c similarity index 100% rename from tests/hwloc_custom.c rename to tests/hwloc/hwloc_custom.c diff --git a/tests/hwloc_distances.c b/tests/hwloc/hwloc_distances.c similarity index 100% rename from tests/hwloc_distances.c rename to tests/hwloc/hwloc_distances.c diff --git a/tests/hwloc_get_cache_covering_cpuset.c b/tests/hwloc/hwloc_get_cache_covering_cpuset.c similarity index 100% rename from tests/hwloc_get_cache_covering_cpuset.c rename to tests/hwloc/hwloc_get_cache_covering_cpuset.c diff --git a/tests/hwloc_get_closest_objs.c b/tests/hwloc/hwloc_get_closest_objs.c similarity index 100% rename from tests/hwloc_get_closest_objs.c rename to tests/hwloc/hwloc_get_closest_objs.c diff --git a/tests/hwloc_get_largest_objs_inside_cpuset.c b/tests/hwloc/hwloc_get_largest_objs_inside_cpuset.c similarity index 100% rename from tests/hwloc_get_largest_objs_inside_cpuset.c rename to tests/hwloc/hwloc_get_largest_objs_inside_cpuset.c diff --git a/tests/hwloc_get_last_cpu_location.c b/tests/hwloc/hwloc_get_last_cpu_location.c similarity index 100% rename from tests/hwloc_get_last_cpu_location.c rename to tests/hwloc/hwloc_get_last_cpu_location.c diff --git a/tests/hwloc_get_next_obj_covering_cpuset.c b/tests/hwloc/hwloc_get_next_obj_covering_cpuset.c similarity index 100% rename from tests/hwloc_get_next_obj_covering_cpuset.c rename to tests/hwloc/hwloc_get_next_obj_covering_cpuset.c diff --git a/tests/hwloc_get_obj_below_array_by_type.c b/tests/hwloc/hwloc_get_obj_below_array_by_type.c similarity index 100% rename from tests/hwloc_get_obj_below_array_by_type.c rename to tests/hwloc/hwloc_get_obj_below_array_by_type.c diff --git a/tests/hwloc_get_obj_covering_cpuset.c b/tests/hwloc/hwloc_get_obj_covering_cpuset.c similarity index 100% rename from tests/hwloc_get_obj_covering_cpuset.c rename to tests/hwloc/hwloc_get_obj_covering_cpuset.c diff --git a/tests/hwloc_get_obj_inside_cpuset.c b/tests/hwloc/hwloc_get_obj_inside_cpuset.c similarity index 100% rename from tests/hwloc_get_obj_inside_cpuset.c rename to tests/hwloc/hwloc_get_obj_inside_cpuset.c diff --git a/tests/hwloc_get_shared_cache_covering_obj.c b/tests/hwloc/hwloc_get_shared_cache_covering_obj.c similarity index 100% rename from tests/hwloc_get_shared_cache_covering_obj.c rename to tests/hwloc/hwloc_get_shared_cache_covering_obj.c diff --git a/tests/hwloc_groups.c b/tests/hwloc/hwloc_groups.c similarity index 100% rename from tests/hwloc_groups.c rename to tests/hwloc/hwloc_groups.c diff --git a/tests/hwloc_groups2.c b/tests/hwloc/hwloc_groups2.c similarity index 100% rename from tests/hwloc_groups2.c rename to tests/hwloc/hwloc_groups2.c diff --git a/tests/hwloc_insert_misc.c b/tests/hwloc/hwloc_insert_misc.c similarity index 100% rename from tests/hwloc_insert_misc.c rename to tests/hwloc/hwloc_insert_misc.c diff --git a/tests/hwloc_iodevs.c b/tests/hwloc/hwloc_iodevs.c similarity index 100% rename from tests/hwloc_iodevs.c rename to tests/hwloc/hwloc_iodevs.c diff --git a/tests/hwloc_is_thissystem.c b/tests/hwloc/hwloc_is_thissystem.c similarity index 100% rename from tests/hwloc_is_thissystem.c rename to tests/hwloc/hwloc_is_thissystem.c diff --git a/tests/hwloc_list_components.c b/tests/hwloc/hwloc_list_components.c similarity index 100% rename from tests/hwloc_list_components.c rename to tests/hwloc/hwloc_list_components.c diff --git a/tests/hwloc_obj_infos.c b/tests/hwloc/hwloc_obj_infos.c similarity index 100% rename from tests/hwloc_obj_infos.c rename to tests/hwloc/hwloc_obj_infos.c diff --git a/tests/hwloc_object_userdata.c b/tests/hwloc/hwloc_object_userdata.c similarity index 100% rename from tests/hwloc_object_userdata.c rename to tests/hwloc/hwloc_object_userdata.c diff --git a/tests/hwloc_pci_backend.c b/tests/hwloc/hwloc_pci_backend.c similarity index 100% rename from tests/hwloc_pci_backend.c rename to tests/hwloc/hwloc_pci_backend.c diff --git a/tests/hwloc_synthetic.c b/tests/hwloc/hwloc_synthetic.c similarity index 100% rename from tests/hwloc_synthetic.c rename to tests/hwloc/hwloc_synthetic.c diff --git a/tests/hwloc_topology_diff.c b/tests/hwloc/hwloc_topology_diff.c similarity index 100% rename from tests/hwloc_topology_diff.c rename to tests/hwloc/hwloc_topology_diff.c diff --git a/tests/hwloc_topology_dup.c b/tests/hwloc/hwloc_topology_dup.c similarity index 100% rename from tests/hwloc_topology_dup.c rename to tests/hwloc/hwloc_topology_dup.c diff --git a/tests/hwloc_topology_restrict.c b/tests/hwloc/hwloc_topology_restrict.c similarity index 100% rename from tests/hwloc_topology_restrict.c rename to tests/hwloc/hwloc_topology_restrict.c diff --git a/tests/hwloc_type_depth.c b/tests/hwloc/hwloc_type_depth.c similarity index 100% rename from tests/hwloc_type_depth.c rename to tests/hwloc/hwloc_type_depth.c diff --git a/tests/intel-mic.c b/tests/hwloc/intel-mic.c similarity index 100% rename from tests/intel-mic.c rename to tests/hwloc/intel-mic.c diff --git a/tests/linux-libnuma.c b/tests/hwloc/linux-libnuma.c similarity index 100% rename from tests/linux-libnuma.c rename to tests/hwloc/linux-libnuma.c diff --git a/tests/linux/128ia64-17n4s2c.output b/tests/hwloc/linux/128ia64-17n4s2c.output similarity index 100% rename from tests/linux/128ia64-17n4s2c.output rename to tests/hwloc/linux/128ia64-17n4s2c.output diff --git a/tests/linux/128ia64-17n4s2c.tar.bz2 b/tests/hwloc/linux/128ia64-17n4s2c.tar.bz2 similarity index 100% rename from tests/linux/128ia64-17n4s2c.tar.bz2 rename to tests/hwloc/linux/128ia64-17n4s2c.tar.bz2 diff --git a/tests/linux/16amd64-4n4c-cgroup-distance-merge.options b/tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.options similarity index 100% rename from tests/linux/16amd64-4n4c-cgroup-distance-merge.options rename to tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.options diff --git a/tests/linux/16amd64-4n4c-cgroup-distance-merge.output b/tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.output similarity index 100% rename from tests/linux/16amd64-4n4c-cgroup-distance-merge.output rename to tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.output diff --git a/tests/linux/16amd64-4n4c-cgroup-distance-merge.tar.bz2 b/tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.tar.bz2 similarity index 100% rename from tests/linux/16amd64-4n4c-cgroup-distance-merge.tar.bz2 rename to tests/hwloc/linux/16amd64-4n4c-cgroup-distance-merge.tar.bz2 diff --git a/tests/linux/16amd64-8n2c-cpusets.output b/tests/hwloc/linux/16amd64-8n2c-cpusets.output similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets.output rename to tests/hwloc/linux/16amd64-8n2c-cpusets.output diff --git a/tests/linux/16amd64-8n2c-cpusets.tar.bz2 b/tests/hwloc/linux/16amd64-8n2c-cpusets.tar.bz2 similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets.tar.bz2 rename to tests/hwloc/linux/16amd64-8n2c-cpusets.tar.bz2 diff --git a/tests/linux/16amd64-8n2c-cpusets.xml.options b/tests/hwloc/linux/16amd64-8n2c-cpusets.xml.options similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets.xml.options rename to tests/hwloc/linux/16amd64-8n2c-cpusets.xml.options diff --git a/tests/linux/16amd64-8n2c-cpusets.xml.output b/tests/hwloc/linux/16amd64-8n2c-cpusets.xml.output similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets.xml.output rename to tests/hwloc/linux/16amd64-8n2c-cpusets.xml.output diff --git a/tests/linux/16amd64-8n2c-cpusets.xml.source b/tests/hwloc/linux/16amd64-8n2c-cpusets.xml.source similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets.xml.source rename to tests/hwloc/linux/16amd64-8n2c-cpusets.xml.source diff --git a/tests/linux/16amd64-8n2c-cpusets_noadmin.options b/tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.options similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets_noadmin.options rename to tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.options diff --git a/tests/linux/16amd64-8n2c-cpusets_noadmin.output b/tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.output similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets_noadmin.output rename to tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.output diff --git a/tests/linux/16amd64-8n2c-cpusets_noadmin.source b/tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.source similarity index 100% rename from tests/linux/16amd64-8n2c-cpusets_noadmin.source rename to tests/hwloc/linux/16amd64-8n2c-cpusets_noadmin.source diff --git a/tests/linux/16amd64-8n2c.output b/tests/hwloc/linux/16amd64-8n2c.output similarity index 100% rename from tests/linux/16amd64-8n2c.output rename to tests/hwloc/linux/16amd64-8n2c.output diff --git a/tests/linux/16amd64-8n2c.tar.bz2 b/tests/hwloc/linux/16amd64-8n2c.tar.bz2 similarity index 100% rename from tests/linux/16amd64-8n2c.tar.bz2 rename to tests/hwloc/linux/16amd64-8n2c.tar.bz2 diff --git a/tests/linux/16em64t-2m4c2t.output b/tests/hwloc/linux/16em64t-2m4c2t.output similarity index 100% rename from tests/linux/16em64t-2m4c2t.output rename to tests/hwloc/linux/16em64t-2m4c2t.output diff --git a/tests/linux/16em64t-2m4c2t.tar.bz2 b/tests/hwloc/linux/16em64t-2m4c2t.tar.bz2 similarity index 100% rename from tests/linux/16em64t-2m4c2t.tar.bz2 rename to tests/hwloc/linux/16em64t-2m4c2t.tar.bz2 diff --git a/tests/linux/16em64t-4s2c2t-offlines.output b/tests/hwloc/linux/16em64t-4s2c2t-offlines.output similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines.output rename to tests/hwloc/linux/16em64t-4s2c2t-offlines.output diff --git a/tests/linux/16em64t-4s2c2t-offlines.tar.bz2 b/tests/hwloc/linux/16em64t-4s2c2t-offlines.tar.bz2 similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines.tar.bz2 rename to tests/hwloc/linux/16em64t-4s2c2t-offlines.tar.bz2 diff --git a/tests/linux/16em64t-4s2c2t-offlines.xml.options b/tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.options similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines.xml.options rename to tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.options diff --git a/tests/linux/16em64t-4s2c2t-offlines.xml.output b/tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.output similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines.xml.output rename to tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.output diff --git a/tests/linux/16em64t-4s2c2t-offlines.xml.source b/tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.source similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines.xml.source rename to tests/hwloc/linux/16em64t-4s2c2t-offlines.xml.source diff --git a/tests/linux/16em64t-4s2c2t-offlines_noadmin.options b/tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.options similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines_noadmin.options rename to tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.options diff --git a/tests/linux/16em64t-4s2c2t-offlines_noadmin.output b/tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.output similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines_noadmin.output rename to tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.output diff --git a/tests/linux/16em64t-4s2c2t-offlines_noadmin.source b/tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.source similarity index 100% rename from tests/linux/16em64t-4s2c2t-offlines_noadmin.source rename to tests/hwloc/linux/16em64t-4s2c2t-offlines_noadmin.source diff --git a/tests/linux/16em64t-4s2c2t.output b/tests/hwloc/linux/16em64t-4s2c2t.output similarity index 100% rename from tests/linux/16em64t-4s2c2t.output rename to tests/hwloc/linux/16em64t-4s2c2t.output diff --git a/tests/linux/16em64t-4s2c2t.tar.bz2 b/tests/hwloc/linux/16em64t-4s2c2t.tar.bz2 similarity index 100% rename from tests/linux/16em64t-4s2c2t.tar.bz2 rename to tests/hwloc/linux/16em64t-4s2c2t.tar.bz2 diff --git a/tests/linux/16em64t-4s2c2t.xml.options b/tests/hwloc/linux/16em64t-4s2c2t.xml.options similarity index 100% rename from tests/linux/16em64t-4s2c2t.xml.options rename to tests/hwloc/linux/16em64t-4s2c2t.xml.options diff --git a/tests/linux/16em64t-4s2c2t.xml.output b/tests/hwloc/linux/16em64t-4s2c2t.xml.output similarity index 100% rename from tests/linux/16em64t-4s2c2t.xml.output rename to tests/hwloc/linux/16em64t-4s2c2t.xml.output diff --git a/tests/linux/16em64t-4s2c2t.xml.source b/tests/hwloc/linux/16em64t-4s2c2t.xml.source similarity index 100% rename from tests/linux/16em64t-4s2c2t.xml.source rename to tests/hwloc/linux/16em64t-4s2c2t.xml.source diff --git a/tests/linux/16em64t-4s2c2t_merge.options b/tests/hwloc/linux/16em64t-4s2c2t_merge.options similarity index 100% rename from tests/linux/16em64t-4s2c2t_merge.options rename to tests/hwloc/linux/16em64t-4s2c2t_merge.options diff --git a/tests/linux/16em64t-4s2c2t_merge.output b/tests/hwloc/linux/16em64t-4s2c2t_merge.output similarity index 100% rename from tests/linux/16em64t-4s2c2t_merge.output rename to tests/hwloc/linux/16em64t-4s2c2t_merge.output diff --git a/tests/linux/16em64t-4s2c2t_merge.source b/tests/hwloc/linux/16em64t-4s2c2t_merge.source similarity index 100% rename from tests/linux/16em64t-4s2c2t_merge.source rename to tests/hwloc/linux/16em64t-4s2c2t_merge.source diff --git a/tests/linux/16em64t-4s2c2t_ncaches.options b/tests/hwloc/linux/16em64t-4s2c2t_ncaches.options similarity index 100% rename from tests/linux/16em64t-4s2c2t_ncaches.options rename to tests/hwloc/linux/16em64t-4s2c2t_ncaches.options diff --git a/tests/linux/16em64t-4s2c2t_ncaches.output b/tests/hwloc/linux/16em64t-4s2c2t_ncaches.output similarity index 100% rename from tests/linux/16em64t-4s2c2t_ncaches.output rename to tests/hwloc/linux/16em64t-4s2c2t_ncaches.output diff --git a/tests/linux/16em64t-4s2c2t_ncaches.source b/tests/hwloc/linux/16em64t-4s2c2t_ncaches.source similarity index 100% rename from tests/linux/16em64t-4s2c2t_ncaches.source rename to tests/hwloc/linux/16em64t-4s2c2t_ncaches.source diff --git a/tests/linux/16em64t-4s2ca2c-cpusetreorder.output b/tests/hwloc/linux/16em64t-4s2ca2c-cpusetreorder.output similarity index 100% rename from tests/linux/16em64t-4s2ca2c-cpusetreorder.output rename to tests/hwloc/linux/16em64t-4s2ca2c-cpusetreorder.output diff --git a/tests/linux/16em64t-4s2ca2c-cpusetreorder.tar.bz2 b/tests/hwloc/linux/16em64t-4s2ca2c-cpusetreorder.tar.bz2 similarity index 100% rename from tests/linux/16em64t-4s2ca2c-cpusetreorder.tar.bz2 rename to tests/hwloc/linux/16em64t-4s2ca2c-cpusetreorder.tar.bz2 diff --git a/tests/linux/16ia64-8n2s.output b/tests/hwloc/linux/16ia64-8n2s.output similarity index 100% rename from tests/linux/16ia64-8n2s.output rename to tests/hwloc/linux/16ia64-8n2s.output diff --git a/tests/linux/16ia64-8n2s.tar.bz2 b/tests/hwloc/linux/16ia64-8n2s.tar.bz2 similarity index 100% rename from tests/linux/16ia64-8n2s.tar.bz2 rename to tests/hwloc/linux/16ia64-8n2s.tar.bz2 diff --git a/tests/linux/1alpha.output b/tests/hwloc/linux/1alpha.output similarity index 100% rename from tests/linux/1alpha.output rename to tests/hwloc/linux/1alpha.output diff --git a/tests/linux/1alpha.tar.bz2 b/tests/hwloc/linux/1alpha.tar.bz2 similarity index 100% rename from tests/linux/1alpha.tar.bz2 rename to tests/hwloc/linux/1alpha.tar.bz2 diff --git a/tests/linux/20s390-2g6s4c.output b/tests/hwloc/linux/20s390-2g6s4c.output similarity index 100% rename from tests/linux/20s390-2g6s4c.output rename to tests/hwloc/linux/20s390-2g6s4c.output diff --git a/tests/linux/20s390-2g6s4c.tar.bz2 b/tests/hwloc/linux/20s390-2g6s4c.tar.bz2 similarity index 100% rename from tests/linux/20s390-2g6s4c.tar.bz2 rename to tests/hwloc/linux/20s390-2g6s4c.tar.bz2 diff --git a/tests/linux/24em64t-2n6c2t+2mic.olddriver.options b/tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.options similarity index 100% rename from tests/linux/24em64t-2n6c2t+2mic.olddriver.options rename to tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.options diff --git a/tests/linux/24em64t-2n6c2t+2mic.olddriver.output b/tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.output similarity index 100% rename from tests/linux/24em64t-2n6c2t+2mic.olddriver.output rename to tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.output diff --git a/tests/linux/24em64t-2n6c2t+2mic.olddriver.tar.bz2 b/tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.tar.bz2 similarity index 100% rename from tests/linux/24em64t-2n6c2t+2mic.olddriver.tar.bz2 rename to tests/hwloc/linux/24em64t-2n6c2t+2mic.olddriver.tar.bz2 diff --git a/tests/linux/256ia64-64n2s2c.output b/tests/hwloc/linux/256ia64-64n2s2c.output similarity index 100% rename from tests/linux/256ia64-64n2s2c.output rename to tests/hwloc/linux/256ia64-64n2s2c.output diff --git a/tests/linux/256ia64-64n2s2c.tar.bz2 b/tests/hwloc/linux/256ia64-64n2s2c.tar.bz2 similarity index 100% rename from tests/linux/256ia64-64n2s2c.tar.bz2 rename to tests/hwloc/linux/256ia64-64n2s2c.tar.bz2 diff --git a/tests/linux/256ppc-8n8s4t-nocache.exclude b/tests/hwloc/linux/256ppc-8n8s4t-nocache.exclude similarity index 100% rename from tests/linux/256ppc-8n8s4t-nocache.exclude rename to tests/hwloc/linux/256ppc-8n8s4t-nocache.exclude diff --git a/tests/linux/256ppc-8n8s4t-nocache.output b/tests/hwloc/linux/256ppc-8n8s4t-nocache.output similarity index 100% rename from tests/linux/256ppc-8n8s4t-nocache.output rename to tests/hwloc/linux/256ppc-8n8s4t-nocache.output diff --git a/tests/linux/256ppc-8n8s4t-nocache.source b/tests/hwloc/linux/256ppc-8n8s4t-nocache.source similarity index 100% rename from tests/linux/256ppc-8n8s4t-nocache.source rename to tests/hwloc/linux/256ppc-8n8s4t-nocache.source diff --git a/tests/linux/256ppc-8n8s4t-nosys.exclude b/tests/hwloc/linux/256ppc-8n8s4t-nosys.exclude similarity index 100% rename from tests/linux/256ppc-8n8s4t-nosys.exclude rename to tests/hwloc/linux/256ppc-8n8s4t-nosys.exclude diff --git a/tests/linux/256ppc-8n8s4t-nosys.output b/tests/hwloc/linux/256ppc-8n8s4t-nosys.output similarity index 100% rename from tests/linux/256ppc-8n8s4t-nosys.output rename to tests/hwloc/linux/256ppc-8n8s4t-nosys.output diff --git a/tests/linux/256ppc-8n8s4t-nosys.source b/tests/hwloc/linux/256ppc-8n8s4t-nosys.source similarity index 100% rename from tests/linux/256ppc-8n8s4t-nosys.source rename to tests/hwloc/linux/256ppc-8n8s4t-nosys.source diff --git a/tests/linux/256ppc-8n8s4t.output b/tests/hwloc/linux/256ppc-8n8s4t.output similarity index 100% rename from tests/linux/256ppc-8n8s4t.output rename to tests/hwloc/linux/256ppc-8n8s4t.output diff --git a/tests/linux/256ppc-8n8s4t.tar.bz2 b/tests/hwloc/linux/256ppc-8n8s4t.tar.bz2 similarity index 100% rename from tests/linux/256ppc-8n8s4t.tar.bz2 rename to tests/hwloc/linux/256ppc-8n8s4t.tar.bz2 diff --git a/tests/linux/28em64t-2s2n7c-buggycoresiblings.output b/tests/hwloc/linux/28em64t-2s2n7c-buggycoresiblings.output similarity index 100% rename from tests/linux/28em64t-2s2n7c-buggycoresiblings.output rename to tests/hwloc/linux/28em64t-2s2n7c-buggycoresiblings.output diff --git a/tests/linux/28em64t-2s2n7c-buggycoresiblings.tar.bz2 b/tests/hwloc/linux/28em64t-2s2n7c-buggycoresiblings.tar.bz2 similarity index 100% rename from tests/linux/28em64t-2s2n7c-buggycoresiblings.tar.bz2 rename to tests/hwloc/linux/28em64t-2s2n7c-buggycoresiblings.tar.bz2 diff --git a/tests/linux/2amd64-2n.output b/tests/hwloc/linux/2amd64-2n.output similarity index 100% rename from tests/linux/2amd64-2n.output rename to tests/hwloc/linux/2amd64-2n.output diff --git a/tests/linux/2amd64-2n.tar.bz2 b/tests/hwloc/linux/2amd64-2n.tar.bz2 similarity index 100% rename from tests/linux/2amd64-2n.tar.bz2 rename to tests/hwloc/linux/2amd64-2n.tar.bz2 diff --git a/tests/linux/2arm-2c.output b/tests/hwloc/linux/2arm-2c.output similarity index 100% rename from tests/linux/2arm-2c.output rename to tests/hwloc/linux/2arm-2c.output diff --git a/tests/linux/2arm-2c.tar.bz2 b/tests/hwloc/linux/2arm-2c.tar.bz2 similarity index 100% rename from tests/linux/2arm-2c.tar.bz2 rename to tests/hwloc/linux/2arm-2c.tar.bz2 diff --git a/tests/linux/2i386-2c-nohugepage.tar.bz2 b/tests/hwloc/linux/2i386-2c-nohugepage.tar.bz2 similarity index 100% rename from tests/linux/2i386-2c-nohugepage.tar.bz2 rename to tests/hwloc/linux/2i386-2c-nohugepage.tar.bz2 diff --git a/tests/linux/2i386-2c-nohugepage.xml.options b/tests/hwloc/linux/2i386-2c-nohugepage.xml.options similarity index 100% rename from tests/linux/2i386-2c-nohugepage.xml.options rename to tests/hwloc/linux/2i386-2c-nohugepage.xml.options diff --git a/tests/linux/2i386-2c-nohugepage.xml.output b/tests/hwloc/linux/2i386-2c-nohugepage.xml.output similarity index 100% rename from tests/linux/2i386-2c-nohugepage.xml.output rename to tests/hwloc/linux/2i386-2c-nohugepage.xml.output diff --git a/tests/linux/2i386-2c-nohugepage.xml.source b/tests/hwloc/linux/2i386-2c-nohugepage.xml.source similarity index 100% rename from tests/linux/2i386-2c-nohugepage.xml.source rename to tests/hwloc/linux/2i386-2c-nohugepage.xml.source diff --git a/tests/linux/2i386-2t-hugepagesizecount.tar.bz2 b/tests/hwloc/linux/2i386-2t-hugepagesizecount.tar.bz2 similarity index 100% rename from tests/linux/2i386-2t-hugepagesizecount.tar.bz2 rename to tests/hwloc/linux/2i386-2t-hugepagesizecount.tar.bz2 diff --git a/tests/linux/2i386-2t-hugepagesizecount.xml.env b/tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.env similarity index 100% rename from tests/linux/2i386-2t-hugepagesizecount.xml.env rename to tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.env diff --git a/tests/linux/2i386-2t-hugepagesizecount.xml.options b/tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.options similarity index 100% rename from tests/linux/2i386-2t-hugepagesizecount.xml.options rename to tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.options diff --git a/tests/linux/2i386-2t-hugepagesizecount.xml.output b/tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.output similarity index 100% rename from tests/linux/2i386-2t-hugepagesizecount.xml.output rename to tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.output diff --git a/tests/linux/2i386-2t-hugepagesizecount.xml.source b/tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.source similarity index 100% rename from tests/linux/2i386-2t-hugepagesizecount.xml.source rename to tests/hwloc/linux/2i386-2t-hugepagesizecount.xml.source diff --git a/tests/linux/2ps3-2t.output b/tests/hwloc/linux/2ps3-2t.output similarity index 100% rename from tests/linux/2ps3-2t.output rename to tests/hwloc/linux/2ps3-2t.output diff --git a/tests/linux/2ps3-2t.tar.bz2 b/tests/hwloc/linux/2ps3-2t.tar.bz2 similarity index 100% rename from tests/linux/2ps3-2t.tar.bz2 rename to tests/hwloc/linux/2ps3-2t.tar.bz2 diff --git a/tests/linux/2s390-2c.output b/tests/hwloc/linux/2s390-2c.output similarity index 100% rename from tests/linux/2s390-2c.output rename to tests/hwloc/linux/2s390-2c.output diff --git a/tests/linux/2s390-2c.tar.bz2 b/tests/hwloc/linux/2s390-2c.tar.bz2 similarity index 100% rename from tests/linux/2s390-2c.tar.bz2 rename to tests/hwloc/linux/2s390-2c.tar.bz2 diff --git a/tests/linux/32amd64-4s2n4c-cgroup.env b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.env similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.env rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.env diff --git a/tests/linux/32amd64-4s2n4c-cgroup.output b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.output similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.output rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.output diff --git a/tests/linux/32amd64-4s2n4c-cgroup.tar.bz2 b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.tar.bz2 similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.tar.bz2 rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.tar.bz2 diff --git a/tests/linux/32amd64-4s2n4c-cgroup.xml.env b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.env similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.xml.env rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.env diff --git a/tests/linux/32amd64-4s2n4c-cgroup.xml.options b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.options similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.xml.options rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.options diff --git a/tests/linux/32amd64-4s2n4c-cgroup.xml.output b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.output similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.xml.output rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.output diff --git a/tests/linux/32amd64-4s2n4c-cgroup.xml.source b/tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.source similarity index 100% rename from tests/linux/32amd64-4s2n4c-cgroup.xml.source rename to tests/hwloc/linux/32amd64-4s2n4c-cgroup.xml.source diff --git a/tests/linux/32em64t-2n8c+1mic.options b/tests/hwloc/linux/32em64t-2n8c+1mic.options similarity index 100% rename from tests/linux/32em64t-2n8c+1mic.options rename to tests/hwloc/linux/32em64t-2n8c+1mic.options diff --git a/tests/linux/32em64t-2n8c+1mic.output b/tests/hwloc/linux/32em64t-2n8c+1mic.output similarity index 100% rename from tests/linux/32em64t-2n8c+1mic.output rename to tests/hwloc/linux/32em64t-2n8c+1mic.output diff --git a/tests/linux/32em64t-2n8c+1mic.tar.bz2 b/tests/hwloc/linux/32em64t-2n8c+1mic.tar.bz2 similarity index 100% rename from tests/linux/32em64t-2n8c+1mic.tar.bz2 rename to tests/hwloc/linux/32em64t-2n8c+1mic.tar.bz2 diff --git a/tests/linux/32ppc-4n4c2c.output b/tests/hwloc/linux/32ppc-4n4c2c.output similarity index 100% rename from tests/linux/32ppc-4n4c2c.output rename to tests/hwloc/linux/32ppc-4n4c2c.output diff --git a/tests/linux/32ppc-4n4c2c.tar.bz2 b/tests/hwloc/linux/32ppc-4n4c2c.tar.bz2 similarity index 100% rename from tests/linux/32ppc-4n4c2c.tar.bz2 rename to tests/hwloc/linux/32ppc-4n4c2c.tar.bz2 diff --git a/tests/linux/40intel64-2g2n4c+pci.env b/tests/hwloc/linux/40intel64-2g2n4c+pci.env similarity index 100% rename from tests/linux/40intel64-2g2n4c+pci.env rename to tests/hwloc/linux/40intel64-2g2n4c+pci.env diff --git a/tests/linux/40intel64-2g2n4c+pci.options b/tests/hwloc/linux/40intel64-2g2n4c+pci.options similarity index 100% rename from tests/linux/40intel64-2g2n4c+pci.options rename to tests/hwloc/linux/40intel64-2g2n4c+pci.options diff --git a/tests/linux/40intel64-2g2n4c+pci.output b/tests/hwloc/linux/40intel64-2g2n4c+pci.output similarity index 100% rename from tests/linux/40intel64-2g2n4c+pci.output rename to tests/hwloc/linux/40intel64-2g2n4c+pci.output diff --git a/tests/linux/40intel64-2g2n4c+pci.tar.bz2 b/tests/hwloc/linux/40intel64-2g2n4c+pci.tar.bz2 similarity index 100% rename from tests/linux/40intel64-2g2n4c+pci.tar.bz2 rename to tests/hwloc/linux/40intel64-2g2n4c+pci.tar.bz2 diff --git a/tests/linux/40intel64-4n10c+pci-conflicts.env b/tests/hwloc/linux/40intel64-4n10c+pci-conflicts.env similarity index 100% rename from tests/linux/40intel64-4n10c+pci-conflicts.env rename to tests/hwloc/linux/40intel64-4n10c+pci-conflicts.env diff --git a/tests/linux/40intel64-4n10c+pci-conflicts.output b/tests/hwloc/linux/40intel64-4n10c+pci-conflicts.output similarity index 100% rename from tests/linux/40intel64-4n10c+pci-conflicts.output rename to tests/hwloc/linux/40intel64-4n10c+pci-conflicts.output diff --git a/tests/linux/40intel64-4n10c+pci-conflicts.tar.bz2 b/tests/hwloc/linux/40intel64-4n10c+pci-conflicts.tar.bz2 similarity index 100% rename from tests/linux/40intel64-4n10c+pci-conflicts.tar.bz2 rename to tests/hwloc/linux/40intel64-4n10c+pci-conflicts.tar.bz2 diff --git a/tests/linux/48amd64-4d2n6c-sparse.output b/tests/hwloc/linux/48amd64-4d2n6c-sparse.output similarity index 100% rename from tests/linux/48amd64-4d2n6c-sparse.output rename to tests/hwloc/linux/48amd64-4d2n6c-sparse.output diff --git a/tests/linux/48amd64-4d2n6c-sparse.tar.bz2 b/tests/hwloc/linux/48amd64-4d2n6c-sparse.tar.bz2 similarity index 100% rename from tests/linux/48amd64-4d2n6c-sparse.tar.bz2 rename to tests/hwloc/linux/48amd64-4d2n6c-sparse.tar.bz2 diff --git a/tests/linux/4em64t-2c2t-ignore-reorder.options b/tests/hwloc/linux/4em64t-2c2t-ignore-reorder.options similarity index 100% rename from tests/linux/4em64t-2c2t-ignore-reorder.options rename to tests/hwloc/linux/4em64t-2c2t-ignore-reorder.options diff --git a/tests/linux/4em64t-2c2t-ignore-reorder.output b/tests/hwloc/linux/4em64t-2c2t-ignore-reorder.output similarity index 100% rename from tests/linux/4em64t-2c2t-ignore-reorder.output rename to tests/hwloc/linux/4em64t-2c2t-ignore-reorder.output diff --git a/tests/linux/4em64t-2c2t-ignore-reorder.tar.bz2 b/tests/hwloc/linux/4em64t-2c2t-ignore-reorder.tar.bz2 similarity index 100% rename from tests/linux/4em64t-2c2t-ignore-reorder.tar.bz2 rename to tests/hwloc/linux/4em64t-2c2t-ignore-reorder.tar.bz2 diff --git a/tests/linux/4ia64-4s.output b/tests/hwloc/linux/4ia64-4s.output similarity index 100% rename from tests/linux/4ia64-4s.output rename to tests/hwloc/linux/4ia64-4s.output diff --git a/tests/linux/4ia64-4s.tar.bz2 b/tests/hwloc/linux/4ia64-4s.tar.bz2 similarity index 100% rename from tests/linux/4ia64-4s.tar.bz2 rename to tests/hwloc/linux/4ia64-4s.tar.bz2 diff --git a/tests/linux/4ppc-4c.output b/tests/hwloc/linux/4ppc-4c.output similarity index 100% rename from tests/linux/4ppc-4c.output rename to tests/hwloc/linux/4ppc-4c.output diff --git a/tests/linux/4ppc-4c.tar.bz2 b/tests/hwloc/linux/4ppc-4c.tar.bz2 similarity index 100% rename from tests/linux/4ppc-4c.tar.bz2 rename to tests/hwloc/linux/4ppc-4c.tar.bz2 diff --git a/tests/linux/4qs22-2s2t.output b/tests/hwloc/linux/4qs22-2s2t.output similarity index 100% rename from tests/linux/4qs22-2s2t.output rename to tests/hwloc/linux/4qs22-2s2t.output diff --git a/tests/linux/4qs22-2s2t.tar.bz2 b/tests/hwloc/linux/4qs22-2s2t.tar.bz2 similarity index 100% rename from tests/linux/4qs22-2s2t.tar.bz2 rename to tests/hwloc/linux/4qs22-2s2t.tar.bz2 diff --git a/tests/linux/64amd64-4s2n4ca2co.output b/tests/hwloc/linux/64amd64-4s2n4ca2co.output similarity index 100% rename from tests/linux/64amd64-4s2n4ca2co.output rename to tests/hwloc/linux/64amd64-4s2n4ca2co.output diff --git a/tests/linux/64amd64-4s2n4ca2co.tar.bz2 b/tests/hwloc/linux/64amd64-4s2n4ca2co.tar.bz2 similarity index 100% rename from tests/linux/64amd64-4s2n4ca2co.tar.bz2 rename to tests/hwloc/linux/64amd64-4s2n4ca2co.tar.bz2 diff --git a/tests/linux/64fake-4n2s2ca2c2t.output b/tests/hwloc/linux/64fake-4n2s2ca2c2t.output similarity index 100% rename from tests/linux/64fake-4n2s2ca2c2t.output rename to tests/hwloc/linux/64fake-4n2s2ca2c2t.output diff --git a/tests/linux/64fake-4n2s2ca2c2t.tar.bz2 b/tests/hwloc/linux/64fake-4n2s2ca2c2t.tar.bz2 similarity index 100% rename from tests/linux/64fake-4n2s2ca2c2t.tar.bz2 rename to tests/hwloc/linux/64fake-4n2s2ca2c2t.tar.bz2 diff --git a/tests/linux/8amd64-4n2c.output b/tests/hwloc/linux/8amd64-4n2c.output similarity index 100% rename from tests/linux/8amd64-4n2c.output rename to tests/hwloc/linux/8amd64-4n2c.output diff --git a/tests/linux/8amd64-4n2c.tar.bz2 b/tests/hwloc/linux/8amd64-4n2c.tar.bz2 similarity index 100% rename from tests/linux/8amd64-4n2c.tar.bz2 rename to tests/hwloc/linux/8amd64-4n2c.tar.bz2 diff --git a/tests/linux/8em64t-2s2ca2c-buggynuma.output b/tests/hwloc/linux/8em64t-2s2ca2c-buggynuma.output similarity index 100% rename from tests/linux/8em64t-2s2ca2c-buggynuma.output rename to tests/hwloc/linux/8em64t-2s2ca2c-buggynuma.output diff --git a/tests/linux/8em64t-2s2ca2c-buggynuma.tar.bz2 b/tests/hwloc/linux/8em64t-2s2ca2c-buggynuma.tar.bz2 similarity index 100% rename from tests/linux/8em64t-2s2ca2c-buggynuma.tar.bz2 rename to tests/hwloc/linux/8em64t-2s2ca2c-buggynuma.tar.bz2 diff --git a/tests/linux/8em64t-2s2ca2c.output b/tests/hwloc/linux/8em64t-2s2ca2c.output similarity index 100% rename from tests/linux/8em64t-2s2ca2c.output rename to tests/hwloc/linux/8em64t-2s2ca2c.output diff --git a/tests/linux/8em64t-2s2ca2c.tar.bz2 b/tests/hwloc/linux/8em64t-2s2ca2c.tar.bz2 similarity index 100% rename from tests/linux/8em64t-2s2ca2c.tar.bz2 rename to tests/hwloc/linux/8em64t-2s2ca2c.tar.bz2 diff --git a/tests/linux/8em64t-2s4c-heterogeneous.output b/tests/hwloc/linux/8em64t-2s4c-heterogeneous.output similarity index 100% rename from tests/linux/8em64t-2s4c-heterogeneous.output rename to tests/hwloc/linux/8em64t-2s4c-heterogeneous.output diff --git a/tests/linux/8em64t-2s4c-heterogeneous.tar.bz2 b/tests/hwloc/linux/8em64t-2s4c-heterogeneous.tar.bz2 similarity index 100% rename from tests/linux/8em64t-2s4c-heterogeneous.tar.bz2 rename to tests/hwloc/linux/8em64t-2s4c-heterogeneous.tar.bz2 diff --git a/tests/linux/8em64t-4c2t.output b/tests/hwloc/linux/8em64t-4c2t.output similarity index 100% rename from tests/linux/8em64t-4c2t.output rename to tests/hwloc/linux/8em64t-4c2t.output diff --git a/tests/linux/8em64t-4c2t.tar.bz2 b/tests/hwloc/linux/8em64t-4c2t.tar.bz2 similarity index 100% rename from tests/linux/8em64t-4c2t.tar.bz2 rename to tests/hwloc/linux/8em64t-4c2t.tar.bz2 diff --git a/tests/linux/8ia64-2n2s2c.output b/tests/hwloc/linux/8ia64-2n2s2c.output similarity index 100% rename from tests/linux/8ia64-2n2s2c.output rename to tests/hwloc/linux/8ia64-2n2s2c.output diff --git a/tests/linux/8ia64-2n2s2c.tar.bz2 b/tests/hwloc/linux/8ia64-2n2s2c.tar.bz2 similarity index 100% rename from tests/linux/8ia64-2n2s2c.tar.bz2 rename to tests/hwloc/linux/8ia64-2n2s2c.tar.bz2 diff --git a/tests/linux/8ia64-2s2c2t.output b/tests/hwloc/linux/8ia64-2s2c2t.output similarity index 100% rename from tests/linux/8ia64-2s2c2t.output rename to tests/hwloc/linux/8ia64-2s2c2t.output diff --git a/tests/linux/8ia64-2s2c2t.tar.bz2 b/tests/hwloc/linux/8ia64-2s2c2t.tar.bz2 similarity index 100% rename from tests/linux/8ia64-2s2c2t.tar.bz2 rename to tests/hwloc/linux/8ia64-2s2c2t.tar.bz2 diff --git a/tests/linux/8ia64-4s2c.output b/tests/hwloc/linux/8ia64-4s2c.output similarity index 100% rename from tests/linux/8ia64-4s2c.output rename to tests/hwloc/linux/8ia64-4s2c.output diff --git a/tests/linux/8ia64-4s2c.tar.bz2 b/tests/hwloc/linux/8ia64-4s2c.tar.bz2 similarity index 100% rename from tests/linux/8ia64-4s2c.tar.bz2 rename to tests/hwloc/linux/8ia64-4s2c.tar.bz2 diff --git a/tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.env b/tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.env similarity index 100% rename from tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.env rename to tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.env diff --git a/tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.output b/tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.output similarity index 100% rename from tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.output rename to tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.output diff --git a/tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.source b/tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.source similarity index 100% rename from tests/linux/96em64t-4n4d3ca2co-forcecpuinfo.source rename to tests/hwloc/linux/96em64t-4n4d3ca2co-forcecpuinfo.source diff --git a/tests/linux/96em64t-4n4d3ca2co.output b/tests/hwloc/linux/96em64t-4n4d3ca2co.output similarity index 100% rename from tests/linux/96em64t-4n4d3ca2co.output rename to tests/hwloc/linux/96em64t-4n4d3ca2co.output diff --git a/tests/linux/96em64t-4n4d3ca2co.tar.bz2 b/tests/hwloc/linux/96em64t-4n4d3ca2co.tar.bz2 similarity index 100% rename from tests/linux/96em64t-4n4d3ca2co.tar.bz2 rename to tests/hwloc/linux/96em64t-4n4d3ca2co.tar.bz2 diff --git a/tests/linux/Makefile.am b/tests/hwloc/linux/Makefile.am similarity index 100% rename from tests/linux/Makefile.am rename to tests/hwloc/linux/Makefile.am diff --git a/tests/linux/README b/tests/hwloc/linux/README similarity index 100% rename from tests/linux/README rename to tests/hwloc/linux/README diff --git a/tests/linux/gather/Makefile.am b/tests/hwloc/linux/gather/Makefile.am similarity index 100% rename from tests/linux/gather/Makefile.am rename to tests/hwloc/linux/gather/Makefile.am diff --git a/tests/linux/gather/test-gather-topology.sh.in b/tests/hwloc/linux/gather/test-gather-topology.sh.in old mode 100755 new mode 100644 similarity index 92% rename from tests/linux/gather/test-gather-topology.sh.in rename to tests/hwloc/linux/gather/test-gather-topology.sh.in index a51deb0125..bd3a506288 --- a/tests/linux/gather/test-gather-topology.sh.in +++ b/tests/hwloc/linux/gather/test-gather-topology.sh.in @@ -3,14 +3,14 @@ # # Copyright © 2012-2014 Inria. All rights reserved. -# Copyright © 2010 Cisco Systems, Inc. All rights reserved. +# Copyright © 2010-2014 Cisco Systems, Inc. All rights reserved. # Copyright © 2011 Université Bordeaux 1 # See COPYING in top-level directory. # HWLOC_top_builddir="@HWLOC_top_builddir@" lstopo="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics" -gather="$HWLOC_top_builddir/tests/linux/hwloc-gather-topology" +gather="$HWLOC_top_builddir/tests/hwloc/linux/hwloc-gather-topology" # make sure we use default numeric formats LANG=C @@ -25,7 +25,7 @@ case `uname -a` in *) echo "Not running on linux; skipped" exit 77 ;; -esac +esac error() { diff --git a/tests/linux/hwloc-gather-topology.in b/tests/hwloc/linux/hwloc-gather-topology.in old mode 100755 new mode 100644 similarity index 98% rename from tests/linux/hwloc-gather-topology.in rename to tests/hwloc/linux/hwloc-gather-topology.in index affc294c3e..f84f9b89fe --- a/tests/linux/hwloc-gather-topology.in +++ b/tests/hwloc/linux/hwloc-gather-topology.in @@ -5,6 +5,7 @@ # Copyright © 2009 CNRS # Copyright © 2009-2014 Inria. All rights reserved. # Copyright © 2009-2012 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # diff --git a/tests/linux/test-topology.sh.in b/tests/hwloc/linux/test-topology.sh.in similarity index 90% rename from tests/linux/test-topology.sh.in rename to tests/hwloc/linux/test-topology.sh.in index 3361c26578..3271ff88ab 100644 --- a/tests/linux/test-topology.sh.in +++ b/tests/hwloc/linux/test-topology.sh.in @@ -5,7 +5,7 @@ # Copyright © 2009 CNRS # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009-2011 Université Bordeaux 1 -# Copyright © 2009 Cisco Systems, Inc. All rights reserved. +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # @@ -16,7 +16,7 @@ HWLOC_top_srcdir="@HWLOC_top_srcdir@" HWLOC_top_builddir="@HWLOC_top_builddir@" lstopo="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH actual_output="$1" @@ -101,7 +101,7 @@ actual_options="$topology".options # if there's a .source file, use the tarball name it contains instead of $topology if [ -f "$topology".source ] ; then - actual_source="$HWLOC_top_srcdir"/tests/linux/`cat "$topology".source` + actual_source="$HWLOC_top_srcdir"/tests/hwloc/linux/`cat "$topology".source` else actual_source="$topology".tar.bz2 fi @@ -112,7 +112,7 @@ if [ -f "$topology".env ] ; then fi # use an absolute path for tar options because tar is invoked from the temp directory -actual_exclude="$HWLOC_top_srcdir/tests/linux/`basename $topology`".exclude +actual_exclude="$HWLOC_top_srcdir/tests/hwloc/linux/`basename $topology`".exclude [ -f "$actual_exclude" ] && tar_options="--exclude-from=$actual_exclude" result=1 diff --git a/tests/myriexpress.c b/tests/hwloc/myriexpress.c similarity index 100% rename from tests/myriexpress.c rename to tests/hwloc/myriexpress.c diff --git a/tests/nvml.c b/tests/hwloc/nvml.c similarity index 100% rename from tests/nvml.c rename to tests/hwloc/nvml.c diff --git a/tests/opencl.c b/tests/hwloc/opencl.c similarity index 100% rename from tests/opencl.c rename to tests/hwloc/opencl.c diff --git a/tests/openfabrics-verbs.c b/tests/hwloc/openfabrics-verbs.c similarity index 100% rename from tests/openfabrics-verbs.c rename to tests/hwloc/openfabrics-verbs.c diff --git a/tests/hwloc/ports/Makefile.am b/tests/hwloc/ports/Makefile.am new file mode 100644 index 0000000000..45a89e7af0 --- /dev/null +++ b/tests/hwloc/ports/Makefile.am @@ -0,0 +1,165 @@ +# Copyright © 2009-2012 Inria. All rights reserved. +# Copyright © 2009, 2011-2012 Université Bordeaux 1 +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. + +AM_CFLAGS = $(HWLOC_CFLAGS) +AM_CPPFLAGS = $(HWLOC_CPPFLAGS) +AM_LDFLAGS = $(HWLOC_LDFLAGS) + +SRC = $(HWLOC_top_srcdir)/hwloc + +if HWLOC_HAVE_LINUX +check_LTLIBRARIES = \ + libhwloc-port-aix.la \ + libhwloc-port-bgq.la \ + libhwloc-port-darwin.la \ + libhwloc-port-freebsd.la \ + libhwloc-port-hpux.la \ + libhwloc-port-netbsd.la \ + libhwloc-port-osf.la \ + libhwloc-port-solaris.la \ + libhwloc-port-windows.la \ + libhwloc-port-opencl.la \ + libhwloc-port-cuda.la \ + libhwloc-port-nvml.la \ + libhwloc-port-gl.la +endif HWLOC_HAVE_LINUX + +# Note that AC_CONFIG_LINKS sets up the sym links for the files in +# this directory (back to the $top_srcdir/src directory). So if you +# need more sym-linked files in here, go edit configure.ac. Note that +# we have to use sym links in here rather than just directly +# referencing the files via $HWLOC_top_srcdir/src/foo.c because of +# dependencies issues when using the Automake option "subdir-objects". +# We nodist these because they're created by configure. + +common_CPPFLAGS = \ + $(HWLOC_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/include \ + -DHWLOC_COMPILE_PORTS \ + -DHWLOC_INSIDE_LIBHWLOC + +nodist_libhwloc_port_aix_la_SOURCES = topology-aix.c +libhwloc_port_aix_la_SOURCES = \ + include/aix/procinfo.h \ + include/aix/sys/processor.h \ + include/aix/sys/rset.h \ + include/aix/sys/systemcfg.h \ + include/aix/sys/thread.h +libhwloc_port_aix_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/aix \ + -DHWLOC_AIX_SYS \ + -DHWLOC_HAVE_PTHREAD_GETTHRDS_NP \ + -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 + +nodist_libhwloc_port_bgq_la_SOURCES = topology-bgq.c +libhwloc_port_bgq_la_SOURCES = \ + include/bgq/spi/include/kernel/location.h \ + include/bgq/spi/include/kernel/process.h +libhwloc_port_bgq_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/bgq \ + -DHWLOC_BGQ_SYS + +nodist_libhwloc_port_darwin_la_SOURCES = topology-darwin.c +libhwloc_port_darwin_la_SOURCES = \ + include/darwin/sys/sysctl.h +libhwloc_port_darwin_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/darwin \ + -DHWLOC_DARWIN_SYS \ + -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 + +nodist_libhwloc_port_freebsd_la_SOURCES = topology-freebsd.c +libhwloc_port_freebsd_la_SOURCES = \ + include/freebsd/pthread.h \ + include/freebsd/pthread_np.h \ + include/freebsd/sys/cpuset.h \ + include/freebsd/sys/sysctl.h +libhwloc_port_freebsd_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/freebsd \ + -DHWLOC_FREEBSD_SYS \ + -DHAVE_PTHREAD_NP_H \ + -DHAVE_SYS_CPUSET_H \ + -DHAVE_SYS_SYSCTL_H \ + -DHAVE_SYSCTL \ + -DHAVE_CPUSET_SETAFFINITY \ + -Dhwloc_thread_t=pthread_t \ + -DHAVE_DECL_PTHREAD_SETAFFINITY_NP=1 \ + -DHAVE_DECL_PTHREAD_GETAFFINITY_NP=1 \ + -DHAVE_CPUSET_SETID + +nodist_libhwloc_port_hpux_la_SOURCES = topology-hpux.c +libhwloc_port_hpux_la_SOURCES = \ + include/hpux/sys/mpctl.h +libhwloc_port_hpux_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/hpux \ + -DHWLOC_HPUX_SYS + +nodist_libhwloc_port_netbsd_la_SOURCES = topology-netbsd.c +libhwloc_port_netbsd_la_SOURCES = \ + include/netbsd/pthread.h \ + include/netbsd/sched.h +libhwloc_port_netbsd_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/netbsd \ + -DHWLOC_NETBSD_SYS + +nodist_libhwloc_port_osf_la_SOURCES = topology-osf.c +libhwloc_port_osf_la_SOURCES = \ + include/osf/cpuset.h \ + include/osf/numa.h \ + include/osf/radset.h +libhwloc_port_osf_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/osf \ + -DHWLOC_OSF_SYS \ + -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 + +nodist_libhwloc_port_solaris_la_SOURCES = topology-solaris.c topology-solaris-chiptype.c +libhwloc_port_solaris_la_SOURCES = \ + include/solaris/kstat.h \ + include/solaris/picl.h \ + include/solaris/sys/lgrp_user.h \ + include/solaris/sys/processor.h \ + include/solaris/sys/procset.h \ + include/solaris/sys/systeminfo.h +libhwloc_port_solaris_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/solaris \ + -DHWLOC_SOLARIS_SYS \ + -DHAVE_LIBLGRP \ + -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 \ + -DHAVE_LGRP_LATENCY_COOKIE \ + -DHAVE_LIBKSTAT \ + -DHAVE_PICL_H + +nodist_libhwloc_port_windows_la_SOURCES = topology-windows.c +libhwloc_port_windows_la_SOURCES = \ + include/windows/windows.h +libhwloc_port_windows_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/windows \ + -DHWLOC_WIN_SYS \ + -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 + +nodist_libhwloc_port_opencl_la_SOURCES = topology-opencl.c +libhwloc_port_opencl_la_SOURCES = \ + include/opencl/CL/cl_ext.h +libhwloc_port_opencl_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/opencl + +nodist_libhwloc_port_cuda_la_SOURCES = topology-cuda.c +libhwloc_port_cuda_la_SOURCES = \ + include/cuda/cuda_runtime_api.h +libhwloc_port_cuda_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/cuda + +nodist_libhwloc_port_nvml_la_SOURCES = topology-nvml.c +libhwloc_port_nvml_la_SOURCES = \ + include/nvml/nvml.h +libhwloc_port_nvml_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/nvml + +nodist_libhwloc_port_gl_la_SOURCES = topology-gl.c +libhwloc_port_gl_la_SOURCES = \ + include/gl/X11/Xlib.h \ + include/gl/NVCtrl/NVCtrl.h \ + include/gl/NVCtrl/NVCtrlLib.h +libhwloc_port_gl_la_CPPFLAGS = $(common_CPPFLAGS) \ + -I$(HWLOC_top_srcdir)/tests/hwloc/ports/include/gl diff --git a/tests/ports/include/aix/procinfo.h b/tests/hwloc/ports/include/aix/procinfo.h similarity index 100% rename from tests/ports/include/aix/procinfo.h rename to tests/hwloc/ports/include/aix/procinfo.h diff --git a/tests/ports/include/aix/sys/processor.h b/tests/hwloc/ports/include/aix/sys/processor.h similarity index 100% rename from tests/ports/include/aix/sys/processor.h rename to tests/hwloc/ports/include/aix/sys/processor.h diff --git a/tests/ports/include/aix/sys/rset.h b/tests/hwloc/ports/include/aix/sys/rset.h similarity index 100% rename from tests/ports/include/aix/sys/rset.h rename to tests/hwloc/ports/include/aix/sys/rset.h diff --git a/tests/ports/include/aix/sys/systemcfg.h b/tests/hwloc/ports/include/aix/sys/systemcfg.h similarity index 100% rename from tests/ports/include/aix/sys/systemcfg.h rename to tests/hwloc/ports/include/aix/sys/systemcfg.h diff --git a/tests/ports/include/aix/sys/thread.h b/tests/hwloc/ports/include/aix/sys/thread.h similarity index 100% rename from tests/ports/include/aix/sys/thread.h rename to tests/hwloc/ports/include/aix/sys/thread.h diff --git a/tests/ports/include/bgq/spi/include/kernel/location.h b/tests/hwloc/ports/include/bgq/spi/include/kernel/location.h similarity index 100% rename from tests/ports/include/bgq/spi/include/kernel/location.h rename to tests/hwloc/ports/include/bgq/spi/include/kernel/location.h diff --git a/tests/ports/include/bgq/spi/include/kernel/process.h b/tests/hwloc/ports/include/bgq/spi/include/kernel/process.h similarity index 100% rename from tests/ports/include/bgq/spi/include/kernel/process.h rename to tests/hwloc/ports/include/bgq/spi/include/kernel/process.h diff --git a/tests/ports/include/cuda/cuda_runtime_api.h b/tests/hwloc/ports/include/cuda/cuda_runtime_api.h similarity index 100% rename from tests/ports/include/cuda/cuda_runtime_api.h rename to tests/hwloc/ports/include/cuda/cuda_runtime_api.h diff --git a/tests/ports/include/darwin/sys/sysctl.h b/tests/hwloc/ports/include/darwin/sys/sysctl.h similarity index 100% rename from tests/ports/include/darwin/sys/sysctl.h rename to tests/hwloc/ports/include/darwin/sys/sysctl.h diff --git a/tests/ports/include/freebsd/pthread.h b/tests/hwloc/ports/include/freebsd/pthread.h similarity index 100% rename from tests/ports/include/freebsd/pthread.h rename to tests/hwloc/ports/include/freebsd/pthread.h diff --git a/tests/ports/include/freebsd/pthread_np.h b/tests/hwloc/ports/include/freebsd/pthread_np.h similarity index 100% rename from tests/ports/include/freebsd/pthread_np.h rename to tests/hwloc/ports/include/freebsd/pthread_np.h diff --git a/tests/ports/include/freebsd/sys/cpuset.h b/tests/hwloc/ports/include/freebsd/sys/cpuset.h similarity index 100% rename from tests/ports/include/freebsd/sys/cpuset.h rename to tests/hwloc/ports/include/freebsd/sys/cpuset.h diff --git a/tests/ports/include/freebsd/sys/sysctl.h b/tests/hwloc/ports/include/freebsd/sys/sysctl.h similarity index 100% rename from tests/ports/include/freebsd/sys/sysctl.h rename to tests/hwloc/ports/include/freebsd/sys/sysctl.h diff --git a/tests/ports/include/gl/NVCtrl/NVCtrl.h b/tests/hwloc/ports/include/gl/NVCtrl/NVCtrl.h similarity index 100% rename from tests/ports/include/gl/NVCtrl/NVCtrl.h rename to tests/hwloc/ports/include/gl/NVCtrl/NVCtrl.h diff --git a/tests/ports/include/gl/NVCtrl/NVCtrlLib.h b/tests/hwloc/ports/include/gl/NVCtrl/NVCtrlLib.h similarity index 100% rename from tests/ports/include/gl/NVCtrl/NVCtrlLib.h rename to tests/hwloc/ports/include/gl/NVCtrl/NVCtrlLib.h diff --git a/tests/ports/include/gl/X11/Xlib.h b/tests/hwloc/ports/include/gl/X11/Xlib.h similarity index 100% rename from tests/ports/include/gl/X11/Xlib.h rename to tests/hwloc/ports/include/gl/X11/Xlib.h diff --git a/tests/ports/include/hpux/sys/mpctl.h b/tests/hwloc/ports/include/hpux/sys/mpctl.h similarity index 100% rename from tests/ports/include/hpux/sys/mpctl.h rename to tests/hwloc/ports/include/hpux/sys/mpctl.h diff --git a/tests/ports/include/netbsd/pthread.h b/tests/hwloc/ports/include/netbsd/pthread.h similarity index 100% rename from tests/ports/include/netbsd/pthread.h rename to tests/hwloc/ports/include/netbsd/pthread.h diff --git a/tests/ports/include/netbsd/sched.h b/tests/hwloc/ports/include/netbsd/sched.h similarity index 100% rename from tests/ports/include/netbsd/sched.h rename to tests/hwloc/ports/include/netbsd/sched.h diff --git a/tests/ports/include/nvml/nvml.h b/tests/hwloc/ports/include/nvml/nvml.h similarity index 100% rename from tests/ports/include/nvml/nvml.h rename to tests/hwloc/ports/include/nvml/nvml.h diff --git a/tests/ports/include/opencl/CL/cl_ext.h b/tests/hwloc/ports/include/opencl/CL/cl_ext.h similarity index 100% rename from tests/ports/include/opencl/CL/cl_ext.h rename to tests/hwloc/ports/include/opencl/CL/cl_ext.h diff --git a/tests/ports/include/osf/cpuset.h b/tests/hwloc/ports/include/osf/cpuset.h similarity index 100% rename from tests/ports/include/osf/cpuset.h rename to tests/hwloc/ports/include/osf/cpuset.h diff --git a/tests/ports/include/osf/numa.h b/tests/hwloc/ports/include/osf/numa.h similarity index 100% rename from tests/ports/include/osf/numa.h rename to tests/hwloc/ports/include/osf/numa.h diff --git a/tests/ports/include/osf/radset.h b/tests/hwloc/ports/include/osf/radset.h similarity index 100% rename from tests/ports/include/osf/radset.h rename to tests/hwloc/ports/include/osf/radset.h diff --git a/tests/ports/include/solaris/kstat.h b/tests/hwloc/ports/include/solaris/kstat.h similarity index 100% rename from tests/ports/include/solaris/kstat.h rename to tests/hwloc/ports/include/solaris/kstat.h diff --git a/tests/ports/include/solaris/picl.h b/tests/hwloc/ports/include/solaris/picl.h similarity index 100% rename from tests/ports/include/solaris/picl.h rename to tests/hwloc/ports/include/solaris/picl.h diff --git a/tests/ports/include/solaris/sys/lgrp_user.h b/tests/hwloc/ports/include/solaris/sys/lgrp_user.h similarity index 100% rename from tests/ports/include/solaris/sys/lgrp_user.h rename to tests/hwloc/ports/include/solaris/sys/lgrp_user.h diff --git a/tests/ports/include/solaris/sys/processor.h b/tests/hwloc/ports/include/solaris/sys/processor.h similarity index 100% rename from tests/ports/include/solaris/sys/processor.h rename to tests/hwloc/ports/include/solaris/sys/processor.h diff --git a/tests/ports/include/solaris/sys/procset.h b/tests/hwloc/ports/include/solaris/sys/procset.h similarity index 100% rename from tests/ports/include/solaris/sys/procset.h rename to tests/hwloc/ports/include/solaris/sys/procset.h diff --git a/tests/ports/include/solaris/sys/systeminfo.h b/tests/hwloc/ports/include/solaris/sys/systeminfo.h similarity index 100% rename from tests/ports/include/solaris/sys/systeminfo.h rename to tests/hwloc/ports/include/solaris/sys/systeminfo.h diff --git a/tests/ports/include/windows/windows.h b/tests/hwloc/ports/include/windows/windows.h similarity index 100% rename from tests/ports/include/windows/windows.h rename to tests/hwloc/ports/include/windows/windows.h diff --git a/tests/rename/Makefile.am b/tests/hwloc/rename/Makefile.am similarity index 100% rename from tests/rename/Makefile.am rename to tests/hwloc/rename/Makefile.am diff --git a/tests/rename/main.c b/tests/hwloc/rename/main.c similarity index 100% rename from tests/rename/main.c rename to tests/hwloc/rename/main.c diff --git a/tests/wrapper.sh.in b/tests/hwloc/wrapper.sh.in similarity index 100% rename from tests/wrapper.sh.in rename to tests/hwloc/wrapper.sh.in diff --git a/tests/xml/16amd64-8n2c-cpusets.xml b/tests/hwloc/xml/16amd64-8n2c-cpusets.xml similarity index 100% rename from tests/xml/16amd64-8n2c-cpusets.xml rename to tests/hwloc/xml/16amd64-8n2c-cpusets.xml diff --git a/tests/xml/16em64t-4s2c2t-offlines.xml b/tests/hwloc/xml/16em64t-4s2c2t-offlines.xml similarity index 100% rename from tests/xml/16em64t-4s2c2t-offlines.xml rename to tests/hwloc/xml/16em64t-4s2c2t-offlines.xml diff --git a/tests/xml/16em64t-4s2c2t.xml b/tests/hwloc/xml/16em64t-4s2c2t.xml similarity index 100% rename from tests/xml/16em64t-4s2c2t.xml rename to tests/hwloc/xml/16em64t-4s2c2t.xml diff --git a/tests/xml/192em64t-12gr2n8c2t-distancegroups.env b/tests/hwloc/xml/192em64t-12gr2n8c2t-distancegroups.env similarity index 100% rename from tests/xml/192em64t-12gr2n8c2t-distancegroups.env rename to tests/hwloc/xml/192em64t-12gr2n8c2t-distancegroups.env diff --git a/tests/xml/192em64t-12gr2n8c2t-distancegroups.xml b/tests/hwloc/xml/192em64t-12gr2n8c2t-distancegroups.xml similarity index 100% rename from tests/xml/192em64t-12gr2n8c2t-distancegroups.xml rename to tests/hwloc/xml/192em64t-12gr2n8c2t-distancegroups.xml diff --git a/tests/xml/192em64t-24n8c2t-distancegroups.env b/tests/hwloc/xml/192em64t-24n8c2t-distancegroups.env similarity index 100% rename from tests/xml/192em64t-24n8c2t-distancegroups.env rename to tests/hwloc/xml/192em64t-24n8c2t-distancegroups.env diff --git a/tests/xml/192em64t-24n8c2t-distancegroups.source b/tests/hwloc/xml/192em64t-24n8c2t-distancegroups.source similarity index 100% rename from tests/xml/192em64t-24n8c2t-distancegroups.source rename to tests/hwloc/xml/192em64t-24n8c2t-distancegroups.source diff --git a/tests/xml/192em64t-24n8c2t-distancegroups.xml b/tests/hwloc/xml/192em64t-24n8c2t-distancegroups.xml similarity index 100% rename from tests/xml/192em64t-24n8c2t-distancegroups.xml rename to tests/hwloc/xml/192em64t-24n8c2t-distancegroups.xml diff --git a/tests/xml/192em64t-24n8c2t-nodistancegroups.env b/tests/hwloc/xml/192em64t-24n8c2t-nodistancegroups.env similarity index 100% rename from tests/xml/192em64t-24n8c2t-nodistancegroups.env rename to tests/hwloc/xml/192em64t-24n8c2t-nodistancegroups.env diff --git a/tests/xml/192em64t-24n8c2t-nodistancegroups.xml b/tests/hwloc/xml/192em64t-24n8c2t-nodistancegroups.xml similarity index 100% rename from tests/xml/192em64t-24n8c2t-nodistancegroups.xml rename to tests/hwloc/xml/192em64t-24n8c2t-nodistancegroups.xml diff --git a/tests/xml/24em64t-2n6c2t-pci.xml b/tests/hwloc/xml/24em64t-2n6c2t-pci.xml similarity index 100% rename from tests/xml/24em64t-2n6c2t-pci.xml rename to tests/hwloc/xml/24em64t-2n6c2t-pci.xml diff --git a/tests/xml/32em64t-2n8c2t-pci-noio.options b/tests/hwloc/xml/32em64t-2n8c2t-pci-noio.options similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-noio.options rename to tests/hwloc/xml/32em64t-2n8c2t-pci-noio.options diff --git a/tests/xml/32em64t-2n8c2t-pci-noio.source b/tests/hwloc/xml/32em64t-2n8c2t-pci-noio.source similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-noio.source rename to tests/hwloc/xml/32em64t-2n8c2t-pci-noio.source diff --git a/tests/xml/32em64t-2n8c2t-pci-noio.xml b/tests/hwloc/xml/32em64t-2n8c2t-pci-noio.xml similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-noio.xml rename to tests/hwloc/xml/32em64t-2n8c2t-pci-noio.xml diff --git a/tests/xml/32em64t-2n8c2t-pci-normalio.source b/tests/hwloc/xml/32em64t-2n8c2t-pci-normalio.source similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-normalio.source rename to tests/hwloc/xml/32em64t-2n8c2t-pci-normalio.source diff --git a/tests/xml/32em64t-2n8c2t-pci-normalio.xml b/tests/hwloc/xml/32em64t-2n8c2t-pci-normalio.xml similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-normalio.xml rename to tests/hwloc/xml/32em64t-2n8c2t-pci-normalio.xml diff --git a/tests/xml/32em64t-2n8c2t-pci-wholeio.options b/tests/hwloc/xml/32em64t-2n8c2t-pci-wholeio.options similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-wholeio.options rename to tests/hwloc/xml/32em64t-2n8c2t-pci-wholeio.options diff --git a/tests/xml/32em64t-2n8c2t-pci-wholeio.xml b/tests/hwloc/xml/32em64t-2n8c2t-pci-wholeio.xml similarity index 100% rename from tests/xml/32em64t-2n8c2t-pci-wholeio.xml rename to tests/hwloc/xml/32em64t-2n8c2t-pci-wholeio.xml diff --git a/tests/xml/8em64t-2mi2ma2c.xml b/tests/hwloc/xml/8em64t-2mi2ma2c.xml similarity index 100% rename from tests/xml/8em64t-2mi2ma2c.xml rename to tests/hwloc/xml/8em64t-2mi2ma2c.xml diff --git a/tests/xml/96em64t-4n4d3ca2co-pci.xml b/tests/hwloc/xml/96em64t-4n4d3ca2co-pci.xml similarity index 100% rename from tests/xml/96em64t-4n4d3ca2co-pci.xml rename to tests/hwloc/xml/96em64t-4n4d3ca2co-pci.xml diff --git a/tests/hwloc/xml/Makefile.am b/tests/hwloc/xml/Makefile.am new file mode 100644 index 0000000000..a04db8036f --- /dev/null +++ b/tests/hwloc/xml/Makefile.am @@ -0,0 +1,51 @@ +# Copyright © 2009-2014 Inria. All rights reserved. +# Copyright © 2009-2010 Université Bordeaux 1 +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. + +AM_CFLAGS = $(HWLOC_CFLAGS) +AM_CPPFLAGS = $(HWLOC_CPPFLAGS) +AM_LDFLAGS = $(HWLOC_LDFLAGS) + +# Add your XML input files here. +xml_inputs = \ + 16amd64-8n2c-cpusets.xml \ + 16em64t-4s2c2t.xml \ + 16em64t-4s2c2t-offlines.xml \ + 24em64t-2n6c2t-pci.xml \ + 8em64t-2mi2ma2c.xml \ + 32em64t-2n8c2t-pci-noio.xml \ + 32em64t-2n8c2t-pci-normalio.xml \ + 32em64t-2n8c2t-pci-wholeio.xml \ + 96em64t-4n4d3ca2co-pci.xml \ + 192em64t-12gr2n8c2t-distancegroups.xml \ + 192em64t-24n8c2t-nodistancegroups.xml \ + 192em64t-24n8c2t-distancegroups.xml + +# Each output `xyz.source' may have a corresponding `xyz.source' +# file modifying its source file +xml_source = \ + 32em64t-2n8c2t-pci-noio.source \ + 32em64t-2n8c2t-pci-normalio.source \ + 192em64t-24n8c2t-distancegroups.source + +# Each output `xyz.xml' may have a corresponding `xyz.options' +# file modifying the behavior of lstopo +xml_options = \ + 32em64t-2n8c2t-pci-noio.options \ + 32em64t-2n8c2t-pci-wholeio.options + +# Each output `xyz.xml' may have a corresponding `xyz.env' +# modifying the environment of lstopo +xml_envs = \ + 192em64t-12gr2n8c2t-distancegroups.env \ + 192em64t-24n8c2t-nodistancegroups.env \ + 192em64t-24n8c2t-distancegroups.env + +# Only run the tests if we're building standalone, because the tests +# call hwloc executables. +TESTS = $(xml_inputs) + +EXTRA_DIST = $(xml_inputs) $(xml_source) $(xml_options) $(xml_envs) + +LOG_COMPILER = $(HWLOC_top_builddir)/tests/hwloc/xml/test-topology.sh diff --git a/tests/xml/test-topology.sh.in b/tests/hwloc/xml/test-topology.sh.in old mode 100755 new mode 100644 similarity index 90% rename from tests/xml/test-topology.sh.in rename to tests/hwloc/xml/test-topology.sh.in index c01afed114..a25b378f0d --- a/tests/xml/test-topology.sh.in +++ b/tests/hwloc/xml/test-topology.sh.in @@ -5,7 +5,7 @@ # Copyright © 2009 CNRS # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009-2012 Université Bordeaux 1 -# Copyright © 2010 Cisco Systems, Inc. All rights reserved. +# Copyright © 2010-2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # @@ -14,9 +14,9 @@ HWLOC_top_builddir="@HWLOC_top_builddir@" HWLOC_top_srcdir="@HWLOC_top_srcdir@" -lstopo="@HWLOC_top_builddir@/utils/lstopo/lstopo-no-graphics" +lstopo="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH if test x@HWLOC_XML_LOCALIZED@ = x1; then @@ -82,7 +82,7 @@ do_run() if [ -n "@XMLLINT@" ] then - cp -f "$HWLOC_top_srcdir"/src/hwloc.dtd "$tmp/" + cp -f "$HWLOC_top_srcdir"/hwloc/hwloc.dtd "$tmp/" ( cd $tmp ; @XMLLINT@ --valid lstopo_xml.output.xml ) > /dev/null fi diff --git a/tests/xmlbuffer.c b/tests/hwloc/xmlbuffer.c similarity index 100% rename from tests/xmlbuffer.c rename to tests/hwloc/xmlbuffer.c diff --git a/tests/ports/Makefile.am b/tests/ports/Makefile.am deleted file mode 100644 index 7bbdbfe006..0000000000 --- a/tests/ports/Makefile.am +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright © 2009-2012 Inria. All rights reserved. -# Copyright © 2009, 2011-2012 Université Bordeaux 1 -# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. -# See COPYING in top-level directory. - -AM_CFLAGS = $(HWLOC_CFLAGS) -AM_CPPFLAGS = $(HWLOC_CPPFLAGS) -AM_LDFLAGS = $(HWLOC_LDFLAGS) - -SRC = $(HWLOC_top_srcdir)/src - -if HWLOC_HAVE_LINUX -check_LTLIBRARIES = \ - libhwloc-port-aix.la \ - libhwloc-port-bgq.la \ - libhwloc-port-darwin.la \ - libhwloc-port-freebsd.la \ - libhwloc-port-hpux.la \ - libhwloc-port-netbsd.la \ - libhwloc-port-osf.la \ - libhwloc-port-solaris.la \ - libhwloc-port-windows.la \ - libhwloc-port-opencl.la \ - libhwloc-port-cuda.la \ - libhwloc-port-nvml.la \ - libhwloc-port-gl.la -endif HWLOC_HAVE_LINUX - -# Note that AC_CONFIG_LINKS sets up the sym links for the files in -# this directory (back to the $top_srcdir/src directory). So if you -# need more sym-linked files in here, go edit configure.ac. Note that -# we have to use sym links in here rather than just directly -# referencing the files via $HWLOC_top_srcdir/src/foo.c because of -# dependencies issues when using the Automake option "subdir-objects". -# We nodist these because they're created by configure. - -common_CPPFLAGS = \ - $(HWLOC_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/include \ - -DHWLOC_COMPILE_PORTS \ - -DHWLOC_INSIDE_LIBHWLOC - -nodist_libhwloc_port_aix_la_SOURCES = topology-aix.c -libhwloc_port_aix_la_SOURCES = \ - include/aix/procinfo.h \ - include/aix/sys/processor.h \ - include/aix/sys/rset.h \ - include/aix/sys/systemcfg.h \ - include/aix/sys/thread.h -libhwloc_port_aix_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/aix \ - -DHWLOC_AIX_SYS \ - -DHWLOC_HAVE_PTHREAD_GETTHRDS_NP \ - -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 - -nodist_libhwloc_port_bgq_la_SOURCES = topology-bgq.c -libhwloc_port_bgq_la_SOURCES = \ - include/bgq/spi/include/kernel/location.h \ - include/bgq/spi/include/kernel/process.h -libhwloc_port_bgq_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/bgq \ - -DHWLOC_BGQ_SYS - -nodist_libhwloc_port_darwin_la_SOURCES = topology-darwin.c -libhwloc_port_darwin_la_SOURCES = \ - include/darwin/sys/sysctl.h -libhwloc_port_darwin_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/darwin \ - -DHWLOC_DARWIN_SYS \ - -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 - -nodist_libhwloc_port_freebsd_la_SOURCES = topology-freebsd.c -libhwloc_port_freebsd_la_SOURCES = \ - include/freebsd/pthread.h \ - include/freebsd/pthread_np.h \ - include/freebsd/sys/cpuset.h \ - include/freebsd/sys/sysctl.h -libhwloc_port_freebsd_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/freebsd \ - -DHWLOC_FREEBSD_SYS \ - -DHAVE_PTHREAD_NP_H \ - -DHAVE_SYS_CPUSET_H \ - -DHAVE_SYS_SYSCTL_H \ - -DHAVE_SYSCTL \ - -DHAVE_CPUSET_SETAFFINITY \ - -Dhwloc_thread_t=pthread_t \ - -DHAVE_DECL_PTHREAD_SETAFFINITY_NP=1 \ - -DHAVE_DECL_PTHREAD_GETAFFINITY_NP=1 \ - -DHAVE_CPUSET_SETID - -nodist_libhwloc_port_hpux_la_SOURCES = topology-hpux.c -libhwloc_port_hpux_la_SOURCES = \ - include/hpux/sys/mpctl.h -libhwloc_port_hpux_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/hpux \ - -DHWLOC_HPUX_SYS - -nodist_libhwloc_port_netbsd_la_SOURCES = topology-netbsd.c -libhwloc_port_netbsd_la_SOURCES = \ - include/netbsd/pthread.h \ - include/netbsd/sched.h -libhwloc_port_netbsd_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/netbsd \ - -DHWLOC_NETBSD_SYS - -nodist_libhwloc_port_osf_la_SOURCES = topology-osf.c -libhwloc_port_osf_la_SOURCES = \ - include/osf/cpuset.h \ - include/osf/numa.h \ - include/osf/radset.h -libhwloc_port_osf_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/osf \ - -DHWLOC_OSF_SYS \ - -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 - -nodist_libhwloc_port_solaris_la_SOURCES = topology-solaris.c topology-solaris-chiptype.c -libhwloc_port_solaris_la_SOURCES = \ - include/solaris/kstat.h \ - include/solaris/picl.h \ - include/solaris/sys/lgrp_user.h \ - include/solaris/sys/processor.h \ - include/solaris/sys/procset.h \ - include/solaris/sys/systeminfo.h -libhwloc_port_solaris_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/solaris \ - -DHWLOC_SOLARIS_SYS \ - -DHAVE_LIBLGRP \ - -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 \ - -DHAVE_LGRP_LATENCY_COOKIE \ - -DHAVE_LIBKSTAT \ - -DHAVE_PICL_H - -nodist_libhwloc_port_windows_la_SOURCES = topology-windows.c -libhwloc_port_windows_la_SOURCES = \ - include/windows/windows.h -libhwloc_port_windows_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/windows \ - -DHWLOC_WIN_SYS \ - -DHAVE__SC_LARGE_PAGESIZE -D_SC_LARGE_PAGESIZE=33 - -nodist_libhwloc_port_opencl_la_SOURCES = topology-opencl.c -libhwloc_port_opencl_la_SOURCES = \ - include/opencl/CL/cl_ext.h -libhwloc_port_opencl_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/opencl - -nodist_libhwloc_port_cuda_la_SOURCES = topology-cuda.c -libhwloc_port_cuda_la_SOURCES = \ - include/cuda/cuda_runtime_api.h -libhwloc_port_cuda_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/cuda - -nodist_libhwloc_port_nvml_la_SOURCES = topology-nvml.c -libhwloc_port_nvml_la_SOURCES = \ - include/nvml/nvml.h -libhwloc_port_nvml_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/nvml - -nodist_libhwloc_port_gl_la_SOURCES = topology-gl.c -libhwloc_port_gl_la_SOURCES = \ - include/gl/X11/Xlib.h \ - include/gl/NVCtrl/NVCtrl.h \ - include/gl/NVCtrl/NVCtrlLib.h -libhwloc_port_gl_la_CPPFLAGS = $(common_CPPFLAGS) \ - -I$(HWLOC_top_srcdir)/tests/ports/include/gl diff --git a/tests/xml/Makefile.am b/tests/xml/Makefile.am deleted file mode 100644 index edc2cabb19..0000000000 --- a/tests/xml/Makefile.am +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright © 2009-2014 Inria. All rights reserved. -# Copyright © 2009-2010 Université Bordeaux 1 -# Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. -# See COPYING in top-level directory. - -AM_CFLAGS = $(HWLOC_CFLAGS) -AM_CPPFLAGS = $(HWLOC_CPPFLAGS) -AM_LDFLAGS = $(HWLOC_LDFLAGS) - -# Add your XML input files here. -xml_inputs = \ - 16amd64-8n2c-cpusets.xml \ - 16em64t-4s2c2t.xml \ - 16em64t-4s2c2t-offlines.xml \ - 24em64t-2n6c2t-pci.xml \ - 8em64t-2mi2ma2c.xml \ - 32em64t-2n8c2t-pci-noio.xml \ - 32em64t-2n8c2t-pci-normalio.xml \ - 32em64t-2n8c2t-pci-wholeio.xml \ - 96em64t-4n4d3ca2co-pci.xml \ - 192em64t-12gr2n8c2t-distancegroups.xml \ - 192em64t-24n8c2t-nodistancegroups.xml \ - 192em64t-24n8c2t-distancegroups.xml - -# Each output `xyz.source' may have a corresponding `xyz.source' -# file modifying its source file -xml_source = \ - 32em64t-2n8c2t-pci-noio.source \ - 32em64t-2n8c2t-pci-normalio.source \ - 192em64t-24n8c2t-distancegroups.source - -# Each output `xyz.xml' may have a corresponding `xyz.options' -# file modifying the behavior of lstopo -xml_options = \ - 32em64t-2n8c2t-pci-noio.options \ - 32em64t-2n8c2t-pci-wholeio.options - -# Each output `xyz.xml' may have a corresponding `xyz.env' -# modifying the environment of lstopo -xml_envs = \ - 192em64t-12gr2n8c2t-distancegroups.env \ - 192em64t-24n8c2t-nodistancegroups.env \ - 192em64t-24n8c2t-distancegroups.env - -# Only run the tests if we're building standalone, because the tests -# call hwloc executables. -TESTS = $(xml_inputs) - -EXTRA_DIST = $(xml_inputs) $(xml_source) $(xml_options) $(xml_envs) - -LOG_COMPILER = $(HWLOC_top_builddir)/tests/xml/test-topology.sh diff --git a/utils/.gitignore b/utils/.gitignore deleted file mode 100644 index 3980c76e90..0000000000 --- a/utils/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/topo-ls diff --git a/utils/hwloc/Makefile.am b/utils/hwloc/Makefile.am index 7ca8027d09..9cb498e424 100644 --- a/utils/hwloc/Makefile.am +++ b/utils/hwloc/Makefile.am @@ -10,7 +10,7 @@ AM_CFLAGS = $(HWLOC_CFLAGS) AM_CPPFLAGS = $(HWLOC_CPPFLAGS) AM_LDFLAGS = $(HWLOC_LDFLAGS) -LDADD = $(HWLOC_top_builddir)/src/libhwloc.la +LDADD = $(HWLOC_top_builddir)/hwloc/libhwloc.la EXTRA_DIST = \ test-hwloc-annotate.input test-hwloc-annotate.output \ diff --git a/utils/hwloc/hwloc-compress-dir.in b/utils/hwloc/hwloc-compress-dir.in old mode 100755 new mode 100644 diff --git a/utils/hwloc/test-fake-plugin.sh.in b/utils/hwloc/test-fake-plugin.sh.in index 9b9aeb499e..36e9113412 100644 --- a/utils/hwloc/test-fake-plugin.sh.in +++ b/utils/hwloc/test-fake-plugin.sh.in @@ -4,13 +4,15 @@ # # Copyright © 2009-2014 Inria. All rights reserved. # Copyright © 2009, 2011 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # HWLOC_top_builddir="@HWLOC_top_builddir@" -lstopo="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics" +builddir="$HWLOC_top_builddir/utils/lstopo" +lstopo="$builddir/lstopo-no-graphics" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH HWLOC_DEBUG_FAKE_COMPONENT=1 diff --git a/utils/hwloc/test-hwloc-annotate.sh.in b/utils/hwloc/test-hwloc-annotate.sh.in index cb311251b0..6cc66b32df 100644 --- a/utils/hwloc/test-hwloc-annotate.sh.in +++ b/utils/hwloc/test-hwloc-annotate.sh.in @@ -3,14 +3,17 @@ # # Copyright © 2009-2013 Inria. All rights reserved. +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -annotate="$HWLOC_top_builddir/utils/hwloc/hwloc-annotate" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +annotate="$builddir/hwloc-annotate" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH if test x@HWLOC_XML_LOCALIZED@ = x1; then @@ -34,7 +37,7 @@ file="$tmp/test-hwloc-annotate.output" set -e -$annotate $HWLOC_top_srcdir/utils/hwloc/test-hwloc-annotate.input $file all info Foo Bar +$annotate $srcdir/test-hwloc-annotate.input $file all info Foo Bar $annotate --ci $file $file Core:all info Foo2 Bar2 $annotate --ci $file $file L2Cache:0 none $annotate --ri $file $file socket:all info Foo @@ -42,5 +45,5 @@ $annotate $file $file socket:0 info Foo2 Bar $annotate $file $file socket:0 info Foo2 Bar2 $annotate --ri $file $file socket:0 info Foo2 Bar3 -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-annotate.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-annotate.output "$file" rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-assembler.sh.in b/utils/hwloc/test-hwloc-assembler.sh.in old mode 100755 new mode 100644 index a32f330051..8c8984dc4e --- a/utils/hwloc/test-hwloc-assembler.sh.in +++ b/utils/hwloc/test-hwloc-assembler.sh.in @@ -4,14 +4,17 @@ # # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009, 2011 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -assembler="$HWLOC_top_builddir/utils/hwloc/hwloc-assembler" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +assembler="$builddir/hwloc-assembler" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH if test x@HWLOC_XML_LOCALIZED@ = x1; then @@ -36,8 +39,8 @@ file="$tmp/test-hwloc-assembler.output" set -e $assembler $file \ - --name input1 $HWLOC_top_srcdir/utils/hwloc/test-hwloc-assembler.input1 \ - --name input2 $HWLOC_top_srcdir/utils/hwloc/test-hwloc-assembler.input2 \ - --name input1again $HWLOC_top_srcdir/utils/hwloc/test-hwloc-assembler.input1 -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-assembler.output "$file" + --name input1 $srcdir/test-hwloc-assembler.input1 \ + --name input2 $srcdir/test-hwloc-assembler.input2 \ + --name input1again $srcdir/test-hwloc-assembler.input1 +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-assembler.output "$file" rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-calc.sh.in b/utils/hwloc/test-hwloc-calc.sh.in old mode 100755 new mode 100644 index 38611aa206..ad366f591d --- a/utils/hwloc/test-hwloc-calc.sh.in +++ b/utils/hwloc/test-hwloc-calc.sh.in @@ -5,14 +5,18 @@ # Copyright © 2009 CNRS # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009, 2011 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -calc="$HWLOC_top_builddir/utils/hwloc/hwloc-calc" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +calc="$builddir/hwloc-calc" +xmldir="$HWLOC_top_srcdir/tests/hwloc/xml" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwlo export HWLOC_PLUGINS_PATH : ${TMPDIR=/tmp} @@ -72,14 +76,14 @@ set -e $calc --if synthetic --input "group:2 group:2 cache:2 cache:2 pu:1" Group2:1 Group1:0 $calc --if synthetic --input "group:2 group:2 cache:2 cache:2 pu:1" l2:0-2 L1cache:13:3 echo - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml os=eth6 os=eth4 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml os=sdc os=sr0 ~os=sda - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci:1000:0062:3:2 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci:14e4:1639:1 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci:14e4:1639:2-5 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 pci=0000:02:00.1 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 xpci=0000:02:00.0 - $calc --if xml --input $HWLOC_top_srcdir/tests/xml/96em64t-4n4d3ca2co-pci.xml pci=0000:02:00.0 xpci=0000:02:00.1 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml os=eth6 os=eth4 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml os=sdc os=sr0 ~os=sda + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci:1000:0062:3:2 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci:14e4:1639:1 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci:14e4:1639:2-5 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 pci=0000:02:00.1 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:62:00.1 xpci=0000:02:00.0 + $calc --if xml --input $xmldir/96em64t-4n4d3ca2co-pci.xml pci=0000:02:00.0 xpci=0000:02:00.1 echo cat << EOF | $calc --if synthetic --input "node:4 core:4 pu:4" pu:0 @@ -91,5 +95,5 @@ node:0 node:3 root EOF ) > "$file" -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-calc.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-calc.output "$file" rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-compress-dir.sh.in b/utils/hwloc/test-hwloc-compress-dir.sh.in old mode 100755 new mode 100644 index cf5e0ce6f2..dbb59d204a --- a/utils/hwloc/test-hwloc-compress-dir.sh.in +++ b/utils/hwloc/test-hwloc-compress-dir.sh.in @@ -3,14 +3,17 @@ # # Copyright © 2013 Inria. All rights reserved. +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -compress="$HWLOC_top_builddir/utils/hwloc/hwloc-compress-dir" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +compress="$builddir/hwloc-compress-dir" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH if test x@HWLOC_XML_LOCALIZED@ = x1; then @@ -33,8 +36,8 @@ fi set -e -(cd "$tmp" && gunzip -c $HWLOC_top_srcdir/utils/hwloc/test-hwloc-compress-dir.input.tar.gz | tar xf -) -(cd "$tmp" && gunzip -c $HWLOC_top_srcdir/utils/hwloc/test-hwloc-compress-dir.output.tar.gz | tar xf -) +(cd "$tmp" && gunzip -c $srcdir/test-hwloc-compress-dir.input.tar.gz | tar xf -) +(cd "$tmp" && gunzip -c $srcdir/test-hwloc-compress-dir.output.tar.gz | tar xf -) (cd "$tmp" && mkdir test-hwloc-compress-dir.newoutput) (cd "$tmp" && mkdir test-hwloc-compress-dir.newoutput2) diff --git a/utils/hwloc/test-hwloc-diffpatch.sh.in b/utils/hwloc/test-hwloc-diffpatch.sh.in index c8fce2d0e2..8ef6a0e5b6 100644 --- a/utils/hwloc/test-hwloc-diffpatch.sh.in +++ b/utils/hwloc/test-hwloc-diffpatch.sh.in @@ -3,15 +3,18 @@ # # Copyright © 2009-2013 Inria. All rights reserved. +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -diff="$HWLOC_top_builddir/utils/hwloc/hwloc-diff" -patch="$HWLOC_top_builddir/utils/hwloc/hwloc-patch" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +diff="$builddir/hwloc-diff" +patch="$builddir/hwloc-patch" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH if test x@HWLOC_XML_LOCALIZED@ = x1; then @@ -39,14 +42,15 @@ output2="test-hwloc-diffpatch.output2" set -e -$diff $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input1 $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input2 > $diffoutput -cp $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input1 . -#cat $diffoutput | $patch $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input1 - $output1 +$diff $srcdir/test-hwloc-diffpatch.input1 \ + $srcdir/test-hwloc-diffpatch.input2 > $diffoutput +cp $srcdir/test-hwloc-diffpatch.input1 . +#cat $diffoutput | $patch $srcdir/test-hwloc-diffpatch.input1 - $output1 cat $diffoutput | $patch refname - $output1 -$patch -R $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input2 $diffoutput $output2 +$patch -R $srcdir/test-hwloc-diffpatch.input2 $diffoutput $output2 -diff -u $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input1 "$output2" -diff -u $HWLOC_top_srcdir/utils/hwloc/test-hwloc-diffpatch.input2 "$output1" +diff -u $srcdir/test-hwloc-diffpatch.input1 "$output2" +diff -u $srcdir/test-hwloc-diffpatch.input2 "$output1" cd .. rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-distances.sh.in b/utils/hwloc/test-hwloc-distances.sh.in index 1adb9df835..f895a9076c 100644 --- a/utils/hwloc/test-hwloc-distances.sh.in +++ b/utils/hwloc/test-hwloc-distances.sh.in @@ -3,14 +3,17 @@ # # Copyright © 2012-2013 Inria. All rights reserved. +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -distances="$HWLOC_top_builddir/utils/hwloc/hwloc-distances" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +distances="$builddir/hwloc-distances" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH # make sure we use default numeric formats @@ -62,5 +65,5 @@ set -e HWLOC_NUMANode_DISTANCES=none echo ) > "$file" -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-distances.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-distances.output "$file" rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-distrib.sh.in b/utils/hwloc/test-hwloc-distrib.sh.in old mode 100755 new mode 100644 index 029eef084f..d10eec63a4 --- a/utils/hwloc/test-hwloc-distrib.sh.in +++ b/utils/hwloc/test-hwloc-distrib.sh.in @@ -5,14 +5,17 @@ # Copyright © 2009 CNRS # Copyright © 2009-2014 Inria. All rights reserved. # Copyright © 2009 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -distrib="$HWLOC_top_builddir/utils/hwloc/hwloc-distrib" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +distrib="$builddir/hwloc-distrib" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH : ${TMPDIR=/tmp} @@ -55,5 +58,5 @@ set -e echo $distrib --if synthetic --input "4 4 4 4" 19 ) > "$file" -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-distrib.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-distrib.output "$file" rm -rf "$tmp" diff --git a/utils/hwloc/test-hwloc-info.sh.in b/utils/hwloc/test-hwloc-info.sh.in old mode 100755 new mode 100644 index 12211b1198..fd4b298c2a --- a/utils/hwloc/test-hwloc-info.sh.in +++ b/utils/hwloc/test-hwloc-info.sh.in @@ -5,14 +5,17 @@ # Copyright © 2009 CNRS # Copyright © 2009-2013 Inria. All rights reserved. # Copyright © 2009 Université Bordeaux 1 +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -info="$HWLOC_top_builddir/utils/hwloc/hwloc-info" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/hwloc" +builddir="$HWLOC_top_builddir/utils/hwloc" +info="$builddir/hwloc-info" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH : ${TMPDIR=/tmp} @@ -41,5 +44,5 @@ set -e echo $info --if synthetic --input "node:2 core:2 ca:2 ca:2 pu:2" --ancestor l1 -s pu:7-10 ) > "$file" -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/hwloc/test-hwloc-info.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-info.output "$file" rm -rf "$tmp" diff --git a/utils/lstopo/Makefile.am b/utils/lstopo/Makefile.am index 3d76d81c98..1814c74ded 100644 --- a/utils/lstopo/Makefile.am +++ b/utils/lstopo/Makefile.am @@ -11,7 +11,7 @@ AM_CFLAGS = $(HWLOC_CFLAGS) AM_CPPFLAGS = $(HWLOC_CPPFLAGS) -I$(top_srcdir)/utils/hwloc AM_LDFLAGS = $(HWLOC_LDFLAGS) -LDADD = $(HWLOC_top_builddir)/src/libhwloc.la +LDADD = $(HWLOC_top_builddir)/hwloc/libhwloc.la bin_PROGRAMS = \ lstopo-no-graphics diff --git a/utils/lstopo/test-hwloc-ls.sh.in b/utils/lstopo/test-hwloc-ls.sh.in old mode 100755 new mode 100644 index 63000b75f0..8cf0225696 --- a/utils/lstopo/test-hwloc-ls.sh.in +++ b/utils/lstopo/test-hwloc-ls.sh.in @@ -8,11 +8,13 @@ # See COPYING in top-level directory. # -HWLOC_top_builddir="@HWLOC_top_builddir@" -ls="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics" HWLOC_top_srcdir="@HWLOC_top_srcdir@" +HWLOC_top_builddir="@HWLOC_top_builddir@" +srcdir="$HWLOC_top_srcdir/utils/lstopo" +builddir="$HWLOC_top_builddir/utils/lstopo" +ls="$builddir/lstopo-no-graphics" -HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/src +HWLOC_PLUGINS_PATH=${HWLOC_top_builddir}/hwloc export HWLOC_PLUGINS_PATH : ${TMPDIR=/tmp} @@ -51,5 +53,5 @@ $ls HWLOC_NO_LIBXML_EXPORT=1 $ls $tmp/test.xml $ls --input "ma:1 no:2 so:1 ca:2 2" $tmp/test.synthetic ) > "$file" -diff @HWLOC_DIFF_U@ $HWLOC_top_srcdir/utils/lstopo/test-hwloc-ls.output "$file" +diff @HWLOC_DIFF_U@ $srcdir/test-hwloc-ls.output "$file" rm -rf "$tmp" From c04fe4daf286d8c057421e9dac8bd6ea340e4cf7 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 23 Sep 2014 11:16:42 +0200 Subject: [PATCH 02/10] Add netloc Library source files go under netloc/* on the side of hwloc/ Headers, tests, utils are added near hwloc ones. doc/main.doxy is added, which includes the former hwloc.doxy and the new netloc.doxy To be better integrated later. --- .gitignore | 67 + AUTHORS | 32 +- Makefile.am | 13 +- VERSION | 1 + config/hwloc.m4 | 5 + config/hwloc_internal.m4 | 18 +- config/netloc-jansson.m4 | 131 ++ config/netloc.m4 | 118 ++ configure.ac | 92 +- contrib/update-my-copyright.pl | 2 +- doc/Makefile.am | 10 +- doc/README-netloc.infiniband | 84 + doc/README-netloc.openflow | 169 ++ doc/doxygen-config.cfg.in | 9 +- doc/images/netloc-design-small.png | Bin 0 -> 91512 bytes doc/main.doxy | 7 + doc/netloc.doxy | 1192 ++++++++++++ include/Makefile.am | 20 +- include/netloc.h | 911 +++++++++ include/netloc/dc.h | 306 +++ include/netloc/map.h | 540 ++++++ include/netloc/rename.h | 14 + include/netloc/rename_map.h | 14 + include/private/map.h | 110 ++ include/private/netloc.h | 561 ++++++ netloc.pc.in | 11 + netloc/Makefile.am | 63 + netloc/README | 61 + netloc/api.c | 182 ++ netloc/data_collect.c | 768 ++++++++ netloc/data_types.c | 1107 +++++++++++ netloc/export.c | 353 ++++ netloc/jansson/CHANGES | 583 ++++++ netloc/jansson/CMakeLists.txt | 509 +++++ netloc/jansson/LICENSE | 19 + netloc/jansson/Makefile.am | 21 + netloc/jansson/README.rst | 63 + netloc/jansson/config.h.in | 139 ++ netloc/jansson/configure.ac | 103 + netloc/jansson/jansson.pc.in | 10 + netloc/jansson/src/Makefile.am | 29 + netloc/jansson/src/dump.c | 456 +++++ netloc/jansson/src/error.c | 63 + netloc/jansson/src/hashtable.c | 345 ++++ netloc/jansson/src/hashtable.h | 181 ++ netloc/jansson/src/hashtable_seed.c | 278 +++ netloc/jansson/src/jansson.def | 63 + netloc/jansson/src/jansson.h | 282 +++ netloc/jansson/src/jansson_config.h.in | 39 + netloc/jansson/src/jansson_private.h | 93 + netloc/jansson/src/load.c | 1077 +++++++++++ netloc/jansson/src/lookup3.h | 366 ++++ netloc/jansson/src/memory.c | 56 + netloc/jansson/src/pack_unpack.c | 762 ++++++++ netloc/jansson/src/strbuffer.c | 116 ++ netloc/jansson/src/strbuffer.h | 33 + netloc/jansson/src/strconv.c | 134 ++ netloc/jansson/src/utf.c | 190 ++ netloc/jansson/src/utf.h | 27 + netloc/jansson/src/value.c | 966 ++++++++++ netloc/lookup_table.c | 538 ++++++ netloc/map.c | 1705 +++++++++++++++++ netloc/metadata.c | 359 ++++ netloc/pathfinder.c | 562 ++++++ netloc/support.c | 345 ++++ netloc/support.h | 133 ++ netloc/topology.c | 99 + tests/Makefile.am | 3 + tests/netloc/Makefile.am | 34 + tests/netloc/README | 18 + tests/netloc/data/create-synthetic-hwloc.pl | 95 + tests/netloc/data/hwloc/node01.xml | 76 + tests/netloc/data/hwloc/node02.xml | 76 + tests/netloc/data/hwloc/node03.xml | 76 + tests/netloc/data/hwloc/node04.xml | 76 + tests/netloc/data/hwloc/node05.xml | 76 + tests/netloc/data/hwloc/node06.xml | 76 + tests/netloc/data/hwloc/node07.xml | 76 + tests/netloc/data/hwloc/node08.xml | 76 + .../data/netloc/ETH-unknown-log-paths.ndat | 1 + .../netloc/data/netloc/ETH-unknown-nodes.ndat | 1 + .../data/netloc/ETH-unknown-phy-paths.ndat | 1 + .../IB-fe80:0000:0000:0000-log-paths.ndat | 1 + .../netloc/IB-fe80:0000:0000:0000-nodes.ndat | 1 + .../IB-fe80:0000:0000:0000-phy-paths.ndat | 1 + tests/netloc/data/node-template.xml | 76 + tests/netloc/embedded/Makefile.am | 21 + tests/netloc/embedded/README.txt | 36 + tests/netloc/embedded/autogen.sh | 2 + tests/netloc/embedded/configure.ac | 45 + tests/netloc/embedded/do_test.c | 68 + tests/netloc/embedded/main.c | 21 + tests/netloc/embedded/run-embedded-tests.sh | 133 ++ tests/netloc/hwloc_compress.c | 90 + tests/netloc/map_paths.c | 168 ++ tests/netloc/netloc_all.c | 148 ++ tests/netloc/netloc_hello.c | 84 + tests/netloc/netloc_nodes.c | 107 ++ tests/netloc/run-all.pl | 59 + tests/netloc/test_API.c | 525 +++++ tests/netloc/test_ETH_API.c | 522 +++++ tests/netloc/test_ETH_verbose.c | 126 ++ tests/netloc/test_conv.c | 86 + tests/netloc/test_find_neighbors.c | 136 ++ tests/netloc/test_map.c | 153 ++ tests/netloc/test_map_hwloc.c | 69 + tests/netloc/test_metadata.c | 450 +++++ utils/Makefile.am | 10 + utils/lsmap/Makefile.am | 19 + utils/lsmap/lsmap.c | 213 ++ utils/lsnettopo/Makefile.am | 21 + utils/lsnettopo/README | 55 + utils/lsnettopo/lsnettopo.c | 401 ++++ utils/lsnettopo/viz-networkx.py | 104 + utils/netloc_gather_ib/Makefile.am | 33 + utils/netloc_gather_ib/README | 10 + .../netloc_ib_extract_dats.pl | 88 + .../netloc_gather_ib/netloc_ib_gather_raw.pl | 416 ++++ utils/netloc_reader_ib/Makefile.am | 53 + utils/netloc_reader_ib/Perl_IB_support.pm.in | 135 ++ utils/netloc_reader_ib/README | 45 + utils/netloc_reader_ib/netloc_reader_ib.c | 1328 +++++++++++++ .../netloc_reader_ib_backend_general.pl | 248 +++ .../netloc_reader_ib_backend_log_prep.pl | 157 ++ utils/netloc_reader_ib/perl_json_support.h | 38 + utils/netloc_reader_of/Makefile.am | 53 + utils/netloc_reader_of/Perl_OF_support.pm.in | 134 ++ utils/netloc_reader_of/README | 65 + utils/netloc_reader_of/netloc_reader_of.c | 1024 ++++++++++ .../netloc_reader_of_floodlight.pl | 270 +++ .../netloc_reader_of_opendaylight.pl | 312 +++ utils/netloc_reader_of/perl_json_support.h | 38 + utils/netloc_reader_static/Makefile.am | 22 + utils/netloc_reader_static/README | 65 + .../netloc_reader_static/example-2-nodes.json | 45 + .../netloc_reader_static.c | 1132 +++++++++++ .../netloc_reader_static_schema.json | 150 ++ .../netloc_reader_static_validate.pl | 42 + 138 files changed, 28291 insertions(+), 39 deletions(-) create mode 100644 config/netloc-jansson.m4 create mode 100644 config/netloc.m4 create mode 100644 doc/README-netloc.infiniband create mode 100644 doc/README-netloc.openflow create mode 100644 doc/images/netloc-design-small.png create mode 100644 doc/main.doxy create mode 100644 doc/netloc.doxy create mode 100644 include/netloc.h create mode 100644 include/netloc/dc.h create mode 100644 include/netloc/map.h create mode 100644 include/netloc/rename.h create mode 100644 include/netloc/rename_map.h create mode 100644 include/private/map.h create mode 100644 include/private/netloc.h create mode 100644 netloc.pc.in create mode 100644 netloc/Makefile.am create mode 100644 netloc/README create mode 100644 netloc/api.c create mode 100644 netloc/data_collect.c create mode 100644 netloc/data_types.c create mode 100644 netloc/export.c create mode 100644 netloc/jansson/CHANGES create mode 100644 netloc/jansson/CMakeLists.txt create mode 100644 netloc/jansson/LICENSE create mode 100644 netloc/jansson/Makefile.am create mode 100644 netloc/jansson/README.rst create mode 100644 netloc/jansson/config.h.in create mode 100644 netloc/jansson/configure.ac create mode 100644 netloc/jansson/jansson.pc.in create mode 100644 netloc/jansson/src/Makefile.am create mode 100644 netloc/jansson/src/dump.c create mode 100644 netloc/jansson/src/error.c create mode 100644 netloc/jansson/src/hashtable.c create mode 100644 netloc/jansson/src/hashtable.h create mode 100644 netloc/jansson/src/hashtable_seed.c create mode 100644 netloc/jansson/src/jansson.def create mode 100644 netloc/jansson/src/jansson.h create mode 100644 netloc/jansson/src/jansson_config.h.in create mode 100644 netloc/jansson/src/jansson_private.h create mode 100644 netloc/jansson/src/load.c create mode 100644 netloc/jansson/src/lookup3.h create mode 100644 netloc/jansson/src/memory.c create mode 100644 netloc/jansson/src/pack_unpack.c create mode 100644 netloc/jansson/src/strbuffer.c create mode 100644 netloc/jansson/src/strbuffer.h create mode 100644 netloc/jansson/src/strconv.c create mode 100644 netloc/jansson/src/utf.c create mode 100644 netloc/jansson/src/utf.h create mode 100644 netloc/jansson/src/value.c create mode 100644 netloc/lookup_table.c create mode 100644 netloc/map.c create mode 100644 netloc/metadata.c create mode 100644 netloc/pathfinder.c create mode 100644 netloc/support.c create mode 100644 netloc/support.h create mode 100644 netloc/topology.c create mode 100644 tests/netloc/Makefile.am create mode 100644 tests/netloc/README create mode 100755 tests/netloc/data/create-synthetic-hwloc.pl create mode 100644 tests/netloc/data/hwloc/node01.xml create mode 100644 tests/netloc/data/hwloc/node02.xml create mode 100644 tests/netloc/data/hwloc/node03.xml create mode 100644 tests/netloc/data/hwloc/node04.xml create mode 100644 tests/netloc/data/hwloc/node05.xml create mode 100644 tests/netloc/data/hwloc/node06.xml create mode 100644 tests/netloc/data/hwloc/node07.xml create mode 100644 tests/netloc/data/hwloc/node08.xml create mode 100644 tests/netloc/data/netloc/ETH-unknown-log-paths.ndat create mode 100644 tests/netloc/data/netloc/ETH-unknown-nodes.ndat create mode 100644 tests/netloc/data/netloc/ETH-unknown-phy-paths.ndat create mode 100644 tests/netloc/data/netloc/IB-fe80:0000:0000:0000-log-paths.ndat create mode 100644 tests/netloc/data/netloc/IB-fe80:0000:0000:0000-nodes.ndat create mode 100644 tests/netloc/data/netloc/IB-fe80:0000:0000:0000-phy-paths.ndat create mode 100644 tests/netloc/data/node-template.xml create mode 100644 tests/netloc/embedded/Makefile.am create mode 100644 tests/netloc/embedded/README.txt create mode 100755 tests/netloc/embedded/autogen.sh create mode 100644 tests/netloc/embedded/configure.ac create mode 100644 tests/netloc/embedded/do_test.c create mode 100644 tests/netloc/embedded/main.c create mode 100644 tests/netloc/embedded/run-embedded-tests.sh create mode 100644 tests/netloc/hwloc_compress.c create mode 100644 tests/netloc/map_paths.c create mode 100644 tests/netloc/netloc_all.c create mode 100644 tests/netloc/netloc_hello.c create mode 100644 tests/netloc/netloc_nodes.c create mode 100755 tests/netloc/run-all.pl create mode 100644 tests/netloc/test_API.c create mode 100644 tests/netloc/test_ETH_API.c create mode 100644 tests/netloc/test_ETH_verbose.c create mode 100644 tests/netloc/test_conv.c create mode 100644 tests/netloc/test_find_neighbors.c create mode 100644 tests/netloc/test_map.c create mode 100644 tests/netloc/test_map_hwloc.c create mode 100644 tests/netloc/test_metadata.c create mode 100644 utils/lsmap/Makefile.am create mode 100644 utils/lsmap/lsmap.c create mode 100644 utils/lsnettopo/Makefile.am create mode 100644 utils/lsnettopo/README create mode 100644 utils/lsnettopo/lsnettopo.c create mode 100755 utils/lsnettopo/viz-networkx.py create mode 100644 utils/netloc_gather_ib/Makefile.am create mode 100644 utils/netloc_gather_ib/README create mode 100755 utils/netloc_gather_ib/netloc_ib_extract_dats.pl create mode 100755 utils/netloc_gather_ib/netloc_ib_gather_raw.pl create mode 100644 utils/netloc_reader_ib/Makefile.am create mode 100644 utils/netloc_reader_ib/Perl_IB_support.pm.in create mode 100644 utils/netloc_reader_ib/README create mode 100644 utils/netloc_reader_ib/netloc_reader_ib.c create mode 100644 utils/netloc_reader_ib/netloc_reader_ib_backend_general.pl create mode 100644 utils/netloc_reader_ib/netloc_reader_ib_backend_log_prep.pl create mode 100644 utils/netloc_reader_ib/perl_json_support.h create mode 100644 utils/netloc_reader_of/Makefile.am create mode 100644 utils/netloc_reader_of/Perl_OF_support.pm.in create mode 100644 utils/netloc_reader_of/README create mode 100644 utils/netloc_reader_of/netloc_reader_of.c create mode 100644 utils/netloc_reader_of/netloc_reader_of_floodlight.pl create mode 100644 utils/netloc_reader_of/netloc_reader_of_opendaylight.pl create mode 100644 utils/netloc_reader_of/perl_json_support.h create mode 100644 utils/netloc_reader_static/Makefile.am create mode 100644 utils/netloc_reader_static/README create mode 100644 utils/netloc_reader_static/example-2-nodes.json create mode 100644 utils/netloc_reader_static/netloc_reader_static.c create mode 100644 utils/netloc_reader_static/netloc_reader_static_schema.json create mode 100755 utils/netloc_reader_static/netloc_reader_static_validate.pl diff --git a/.gitignore b/.gitignore index 2b2d3656ff..9bd350d8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,11 @@ Makefile .libs test-suite.log *~ +*.lo +*.la +*.o +*.log +*.trs /config/ar-lib /config/argz.m4 @@ -173,3 +178,65 @@ test-suite.log /utils/lstopo/test-hwloc-ls.sh /utils/lstopo/test-*.sh.log /utils/lstopo/test-*.sh.trs + +/netloc.pc + +/utils/lsmap/lsmap +/utils/lsnettopo/lsnettopo +/utils/netloc_gather_ib/netloc_ib_extract_dats +/utils/netloc_gather_ib/netloc_ib_gather_raw +/utils/netloc_reader_ib/netloc_reader_ib +/utils/netloc_reader_ib/netloc_reader_ib_backend_general +/utils/netloc_reader_ib/netloc_reader_ib_backend_log_prep +/utils/netloc_reader_ib/Perl_IB_support.pm +/utils/netloc_reader_of/netloc_reader_of +/utils/netloc_reader_of/netloc_reader_of_floodlight +/utils/netloc_reader_of/netloc_reader_of_opendaylight +/utils/netloc_reader_of/Perl_OF_support.pm +/utils/netloc_reader_static/netloc_reader_static + +/netloc/jansson/stamp-h? +/netloc/jansson/config.h +/netloc/jansson/src/jansson_config.h + +/tests/netloc/hwloc_compress +/tests/netloc/map_paths +/tests/netloc/netloc_all +/tests/netloc/netloc_hello +/tests/netloc/netloc_nodes +/tests/netloc/test_API +/tests/netloc/test_ETH_API +/tests/netloc/test_ETH_verbose +/tests/netloc/test_conv +/tests/netloc/test_find_neighbors +/tests/netloc/test_map +/tests/netloc/test_map_hwloc +/tests/netloc/test_metadata + +/tests/netloc/embedded/aclocal.m4 +/tests/netloc/embedded/autom4te.cache +/tests/netloc/embedded/check.out +/tests/netloc/embedded/clean.out +/tests/netloc/embedded/config.out +/tests/netloc/embedded/config.status +/tests/netloc/embedded/config +/tests/netloc/embedded/config/ar-lib +/tests/netloc/embedded/config/compile +/tests/netloc/embedded/config/config.guess +/tests/netloc/embedded/config/config.sub +/tests/netloc/embedded/config/depcomp +/tests/netloc/embedded/config/install-sh +/tests/netloc/embedded/config/libtool.m4 +/tests/netloc/embedded/config/ltmain.sh +/tests/netloc/embedded/config/ltoptions.m4 +/tests/netloc/embedded/config/ltsugar.m4 +/tests/netloc/embedded/config/ltversion.m4 +/tests/netloc/embedded/config/lt~obsolete.m4 +/tests/netloc/embedded/config/missing +/tests/netloc/embedded/config/test-driver +/tests/netloc/embedded/configure +/tests/netloc/embedded/distclean.out +/tests/netloc/embedded/libtool +/tests/netloc/embedded/main +/tests/netloc/embedded/make.out +/tests/netloc/embedded/netloc-tree diff --git a/AUTHORS b/AUTHORS index 837b27f2ca..9408531a5a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,8 +1,24 @@ -Cédric Augonnet -Jérôme Clet-Ortega -Ludovic Courtès -Brice Goglin -Nathalie Furmento -Samuel Thibault -Jeff Squyres -Alexey Kardashevskiy +netloc Authors +============== + +The following cumulative list contains the names of all individuals who +have committed code to the netloc repository. + +Name Affiliation(s) +--------------------------- -------------------- +Cédric Augonnet Inria +Nicholas Buroker UWL +Jérôme Clet-Ortega Inria +Ludovic Courtès Inria +Nathalie Furmento Inria +Brice Goglin Inria +Joshua Hursey UWL +Alexey Kardashevskiy IBM +Douglas MacFarland UWL +Jeff Squyres Cisco +Samuel Thibault Inria + +Affiliaion abbreviations: +------------------------- +Cisco = Cisco Systems, Inc. +UWL = University of Wisconsin-La Crosse diff --git a/Makefile.am b/Makefile.am index 1fd76032d5..3eddb9effa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,10 @@ EXTRA_DIST = \ SUBDIRS = include hwloc +if BUILD_NETLOC +SUBDIRS += netloc +endif + if HWLOC_BUILD_STANDALONE SUBDIRS += utils tests # We need doc/ if HWLOC_BUILD_DOXYGEN, or during make install if HWLOC_INSTALL_DOXYGEN. @@ -34,8 +38,13 @@ if HWLOC_BUILD_STANDALONE if !HWLOC_HAVE_WINDOWS pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = hwloc.pc -endif -endif +if BUILD_NETLOC +# JMS Need to compare hwloc.pc and netloc.pc -- I think netloc.pc is +# missing some things. +pkgconfig_DATA += netloc.pc +endif BUILD_NETLOC +endif !HWLOC_HAVE_WINDOWS +endif HWLOC_BUILD_STANDALONE # Only install the valgrind suppressions file if we're building in # standalone mode diff --git a/VERSION b/VERSION index 3f94570b9a..7a63850ba6 100644 --- a/VERSION +++ b/VERSION @@ -40,3 +40,4 @@ date="Unreleased developer copy" # format. libhwloc_so_version=0:0:0 +libnetloc_so_version=0:0:0 diff --git a/config/hwloc.m4 b/config/hwloc.m4 index 3292941381..1d14e57649 100644 --- a/config/hwloc.m4 +++ b/config/hwloc.m4 @@ -1178,6 +1178,11 @@ AC_DEFUN([HWLOC_DO_AM_CONDITIONALS],[ AM_CONDITIONAL([HWLOC_HAVE_CXX], [test "x$hwloc_have_cxx" = "xyes"]) ]) hwloc_did_am_conditionals=yes + + # For backwards compatibility (i.e., packages that only call + # HWLOC_DO_AM_CONDITIONS, not NETLOC DO_AM_CONDITIONALS), we also have to + # do the netloc AM conditionals here + NETLOC_DO_AM_CONDITIONALS ])dnl #----------------------------------------------------------------------- diff --git a/config/hwloc_internal.m4 b/config/hwloc_internal.m4 index 2feadc81d7..caf80be3a0 100644 --- a/config/hwloc_internal.m4 +++ b/config/hwloc_internal.m4 @@ -322,7 +322,16 @@ EOF hwloc_config_prefix[utils/Makefile] hwloc_config_prefix[utils/hwloc/Makefile] hwloc_config_prefix[utils/lstopo/Makefile] - hwloc_config_prefix[hwloc.pc]) + hwloc_config_prefix[hwloc.pc] + + hwloc_config_prefix[utils/lsmap/Makefile] + hwloc_config_prefix[utils/lsnettopo/Makefile] + hwloc_config_prefix[utils/netloc_gather_ib/Makefile] + hwloc_config_prefix[utils/netloc_reader_ib/Makefile] + hwloc_config_prefix[utils/netloc_reader_of/Makefile] + hwloc_config_prefix[utils/netloc_reader_static/Makefile] + hwloc_config_prefix[netloc.pc] + ) ])dnl #----------------------------------------------------------------------- @@ -332,7 +341,7 @@ AC_DEFUN([HWLOC_SETUP_TESTS],[ cat <0 and <3), # but it is necessary in AM 1.12.x. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +LT_INIT([dlopen win32-dll]) +LT_LANG([C]) +LT_LANG([C++]) + +#################################################################### +# Setup C, C++ compilers +#################################################################### + +CFLAGS_save=$CFLAGS +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CC_C99 +CFLAGS=$CFLAGS_save + AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) AS_IF([test -z "$CC_FOR_BUILD"],[ AC_SUBST([CC_FOR_BUILD], [$CC]) @@ -150,15 +163,59 @@ AS_IF([test "$enable_embedded_mode" != "yes"], # Setup for the hwloc API #################################################################### +AC_SUBST([libhwloc_so_version]) + # Setup the hwloc core HWLOC_SETUP_CORE([], [], [AC_MSG_ERROR([Cannot build hwloc core])], [1]) +#################################################################### +# Setup the netloc API +#################################################################### + +AC_SUBST([libnetloc_so_version]) + +AC_ARG_ENABLE([netloc], + [AC_HELP_STRING([--enable-netloc], + [The Netloc functionality is enabled by default, but will be silently skipped it if cannot be built (e.g., not supported on your platform). Using --enable-netloc will cause configure to abort if Netloc cannot be build. Using --disable-netloc will cause configure to skip attempting to build netloc at all.]) + ]) + +AS_IF([test "$enable_netloc" != "no"], + [NETLOC_SETUP_CORE([], [], + [AS_IF([test "$enable_netloc" = "yes"], + [AC_MSG_ERROR([Cannot build netloc core])]) + ], + [1]) + ]) + +#################################################################### +# Setup the rest of the infrastructure +#################################################################### + # Setup hwloc's docs, utils, and tests AS_IF([test "$hwloc_mode" = "standalone"], [HWLOC_SETUP_DOCS HWLOC_SETUP_UTILS HWLOC_SETUP_TESTS]) +# +# SED_I +# Linux and OS X take different sed arguments. +# +AC_PROG_SED +AC_MSG_CHECKING([if the sed -i option requires an argument]) + rm -f conftest + cat > conftest < /dev/null +AS_IF([test -f conftest-e], + [SED_I="$SED -i ''" + AC_MSG_RESULT([yes])], + [SED_I="$SED -i" + AC_MSG_RESULT([no])]) +rm -f conftest conftest-e +AC_SUBST([SED_I]) + cat < Preferences + "Network" -> Add vboxnet (with DNS) + - Setup the mininet VM + Setting -> Network -> Adapter 2 (Enable as Host-only Adapter) + - Start mininet VM + - sudo pico /etc/network/interfaces + Copy the "eth0" entry to an "eth1" + Save and exit + - Boot the eth1 interface + sudo ifup eth1 + +(2) Download and install Floodlight in Eclipse + http://docs.projectfloodlight.org/display/floodlightcontroller/Installation+Guide + +(3) Launch mininet VM + - username/password: mininet/mininet + - Make sure eth1 is listed in 'ifconfig' + +(4) Start floodlight controller + - Eclipse -> Run + +(5) Start a Virtual network in the mininet VM + - IP of the floodlight controller is the gateway provided by + $ route -n + - Start up a simple tree topology: + $ sudo mn --mac --controller=remote,ip=10.0.2.2,port=6633 --topo tree,depth=3,fanout=2 + - Have all nodes communicate with one another + $ pingall + +(6) Use the netloc reader for OpenFlow to query the controller. + $ netloc_reader_of --controller floodlight -o netloc/ + +(7) Verify the output + $ lsnettopo netloc/ +Network: ETH-unknown + Type : Ethernet + Subnet : unknown + Hosts : 8 + Switches: 7 + + + +----- ***** ----- ***** ----- ***** ----- ***** ----- ***** ----- ***** +***** ----- ***** ----- ***** ----- ***** ----- ***** ----- ***** ----- +----- ***** ----- ***** ----- ***** ----- ***** ----- ***** ----- ***** +Appendix B: + Emulating an OpenFlow network with mininet and OpenDaylight +-------------------------------------------------- +(1) Download and install mininet in VirtualBox + See Appendix A.1 + +(2) Download and install OpenDaylight + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Installation + Unzip the target.zip file, then unzip file ending with: osgipackage.zip + $ unzip target.zip + $ cd target + $ unzip distribution.opendaylight-osgipackage.zip + $ cd opendaylight/ + + You may need to set the JAVA_HOME environment variable: + $ export JAVA_HOME=`/usr/libexec/java_home -v 1.7` + +(3) Startup the controller + $ ./run.sh + +(4) Configure the controller (this shows a basic setup) + - Open an Internet browser and go to + http://127.0.0.1/8080 + - login using + username: admin + password: admin + - In the bottom right frame labeled 'Subnet Gateway Configuration' + - Click the button 'Add Gateway IP Address' + - Give it the name 'subnet1' and add the IP and subnet of '10.0.0.254/8' + +(5) Setup mininet + See Appendix A.5 + Note that when you do a pingall the first node will timeout on all hosts. + When you run it again, then all hosts will be connected. + The controller website will also display all nodes and switches. + + Some additional details at the link below: + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Installation + +(6) Use the netloc reader for OpenFlow to query the controller. + $ netloc_reader_of --controller opendaylight -o netloc/ + -- or if you have changed the username/password + $ netloc_reader_of --controller opendaylight -o netloc/ -u -p + +(7) Verify the output + $ lsnettopo netloc/ +Network: ETH-unknown + Type : Ethernet + Subnet : unknown + Hosts : 8 + Switches: 7 diff --git a/doc/doxygen-config.cfg.in b/doc/doxygen-config.cfg.in index e8ac777e24..e174f46cef 100644 --- a/doc/doxygen-config.cfg.in +++ b/doc/doxygen-config.cfg.in @@ -7,6 +7,7 @@ PROJECT_NUMBER = @PACKAGE_VERSION@ INPUT = \ + @top_srcdir@/doc/main.doxy \ @top_srcdir@/doc/hwloc.doxy \ @top_srcdir@/include/hwloc.h \ @top_srcdir@/include/hwloc/helper.h \ @@ -23,9 +24,13 @@ INPUT = \ @top_srcdir@/include/hwloc/gl.h \ @top_srcdir@/include/hwloc/intel-mic.h \ @top_srcdir@/include/hwloc/openfabrics-verbs.h \ - @top_srcdir@/include/hwloc/myriexpress.h + @top_srcdir@/include/hwloc/myriexpress.h \ + @top_srcdir@/doc/netloc.doxy \ + @top_srcdir@/include/netloc.h \ + @top_srcdir@/include/netloc_dc.h \ + @top_srcdir@/include/netloc_map.h -EXAMPLE_PATH = @top_srcdir@/doc +EXAMPLE_PATH = @top_srcdir@/doc @top_srcdir@/tests/netloc IMAGE_PATH = @top_srcdir@/doc/images images diff --git a/doc/images/netloc-design-small.png b/doc/images/netloc-design-small.png new file mode 100644 index 0000000000000000000000000000000000000000..230815648f10b2f3b7f897b9dd9c0a8d007325c5 GIT binary patch literal 91512 zcmV)EK)}C=P)4Tx02mo#U|=$Eba8TJ5@2A+%_}Jia(7aQh>TKTzreu3z|A1cV9a2hm|R@o z7!csY00epYd8r^86@0tKzz7n#tP3&=RgNH!E4iSk1gPo{5F4eW7AG?>Fd6{a+2th# zKyk)7K(VEd*RP=h4G?I6!1+NyNQ|AG9kR2t@yREj zVEy{_SiE>K1`Qf?&KX{If+YmW*47qVw{Atpjvev%0|3D%z7yAc%?1tDl>%aqt(&gMx)g;)u9wRY`VRh8Rszg-b4A!OpD zAy)_!sOr=3(*S`62%H-P^f4@By-AZMxa+RF@Z*m^;>eLBieQ~fZkLr{=@l(4Ek$Bt zBKr65kI>Li-CGee`8ZqZYfbn!e$j}#4PizFh(+4J`0z6`@5|FK(x!{wo+|@kYWCfg zQKO4j3+Xdmnrhm#smeGdCB@2Joo&Bf5d=$WFBKLFY%-ZtWB#g0sTyZ#ulBAH7v29t zpEcoD^Zi2dJ$)cu+&Z6a-AE>{7-FTtgf-_ttf^tO`l}!{Yp4|@Ya2ylOmEdUe6QK2 zi`8G&vaYZfy?qW24vNz<7!2oJL)&vs@h2vz+1Y<$F;_&^(s|ndi&q`9xe8oqg|Sj2 z`ld=FDvZVpE}(8bO{Pj13>AvYy5P*uAp;=|#tH+BCQV&%4oNS1RBQj$$=T{JEUq|f zKU@0SR(mR3*9n)3ScQs;3RG5I5o=(oMt|0iv|ZFd0;_X%R}{gjHC3H!ORkdmB1*}; zns#(A<}O%-)SMDkbDdbrlWV?;<5chRttGO?tLd-5OQ4}R12ew-7;AQ>sJQEAe~IZ| z{{Tw~r{$^VtMcGL(eu*%B@<(L2~v)yAiubrEWOGW$p_Zr$^U$b%z|>|L8Fu!X|=j* zG3B>rSoOOeUb9U7T@TZrdVR7|_T!CrKSyd_HO%xh)~BARo~JcVjr!IT?aW@5elV65 zVZ(~WSh#F8a!V>yd=+G_z}~Iv@YB4-NXso${was{V&S}bSg>FL=FFah^_zDfzto@x zYeD7-{JLxEG3)2mP}7a2tTR{U>J8C}`uVir$|6|j(}Jrh4UteLm8$Y0 z{PNw~7&T%T7OvcCZGn;&WJacFtaqyZ)CaBpUHhqJQB_%n)yrogC9_C**pc|S<0?aABj`TS?W!4j3wW^g@Xk)2=Mk$QDjWl%u~HHq&^db zUmIXRW?B-KuiS;vqX%RCx^=j&e^-QhJ1P(q6x&1@kCs+c!US}Fi{m!k0xT%mJNvSu^SFM204)*{;P2%srJ^7=6WRIY@Nl)k;e!WI zZtI2Cty`*aAx&jPIoQ8%A2P``xqAAt?4}6u^Hyo)M-du6^HL9D`cKF3!t|%%!D3Bh z_v}bPi}EwEch6qr78?;A7mv7@aM;(Od6JKK6=tVl*RDMv~qMpY@b%Jv(&d)$9}lG%{2VFVLO_K_ag~waCITj0F$~9`7^&Q9LfI8 z%aD~Y4lg|OJo2_K$L@p2tfd~?z8Vu^qA=;M`!M_G#dvO5Cp_}%M@TO+k|34fyH8(5 zL|8Yx`1-q8H1AuqZrT#xFWIcp%NQ{l4IIoGFR<~)5AeTFzC)RWRup007jGlBS!>Mx zWf?wu`&m3YZ7zz-DzRtvOvGP%AJ%T%h_Bv#8Q0%*A9ki>Gff$GuKE=lHYH-s;+c5r z$(M29=n14IZ$Yzr-$!Ft z?tBE_{x}EEOzeVtUi%!`B_AH=;+zkyY2S2OK!e7$fvjH>z+A5{+8&!KIb z5Y#FG&7x%$nTCiYR;QA7;JK+oao@kDW6At)kPtfpvwqn~GAmKE)HlhaiJ=5x^|k1 z?r7PH=G+qG*TaE!yISc0djZwDeb{ks_tesXBY3=e1+8Y|TdGmyiWx z1ik*Mk_|s-;IJ+c5(whS%xo&jz@o3-!RXs&qE)*t7}CKTE2-D$(lmbOyB;3yE-(~k zM4{}kaM!|RUEGTlg5~E>|`qZJfh&`qH&^?rFr=7{g+_V=1wes;3jyv zI^f1p-(%`qpP^0bcr7etQp$76NEP!geZy-0O){csUp_ zf5zwdemn4ZWB{s4^T{=9qPJd&VE+jGyyHh?7MH@;%}dc;y+8l3Vt<1O4Fu~FcXIOn zt@yE|9lmZBMlPTd9R?4>{m(DPZR3WZX|N|M4My}Gd^7s?=?n)uTZF}R#KZr+9UG1w zL#eSH%;l9BJ8&49h6SjackVY5INqV8@RZ*!rk3ngO+eF zBoMYFuKA~q0-f*1fWDpK;$RP#m=?JH{#WqnvYjZb7y}y;ixHD1qD$L$aN_oiM$ygj z^iUwXs0azsK^RYyoG(8A8Wlr&A|f&xu`v-k!=aTW)WKYel7e)YU7A?KN{UWV1e*)L zKEtqM^LkX8ZBde2gx$YPN7{+U6v2|k3sJn8O$Hp;v=g_Fd;*O_MAQX3bsK~!qxz%5 zLRfT8MkW=_$pV2eIr_K7n-B3TEi8tMPcS<7=#O{jErhwL88O3$qDf>Zin8*p>1^#B zv7EZM|GJiQvMHjtUx}|5tVEk|52Wui!N$(H7OnL3b`d!m#RiR#onCr%J^qew4Fv0w z^tuocK|KSu{I(G(YZl;>kD@W($qt#B9PnG_Ve9UDNw7L_kdVV5r{kb85~_B70Rbq? zG@+6wlpN$X{ZJB9+@-@p@CkgD$GO*r9G)}6-^j~ ^s@z3HUK=S2?mNF3I4+ndl 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 bJ7)g_)16Bh+>K3`00000NkvXXu0mjfp2~4> literal 0 HcmV?d00001 diff --git a/doc/main.doxy b/doc/main.doxy new file mode 100644 index 0000000000..c32e6ffc65 --- /dev/null +++ b/doc/main.doxy @@ -0,0 +1,7 @@ +/* + * Just for the moment, include the two .doxy files. + * Need to do better integration of these two files. + */ + +\include hwloc.doxy +\include netloc.doxy diff --git a/doc/netloc.doxy b/doc/netloc.doxy new file mode 100644 index 0000000000..85aa23a89b --- /dev/null +++ b/doc/netloc.doxy @@ -0,0 +1,1192 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2014 Cisco Systems, Inc. All rights reserved. + * + * Copyright © 2014 Inria. All rights reserved. + * See COPYING in top-level directory. + * + * $HEADER$ + */ +/*! \mainpage Network Locality + +

Portable abstraction of network topologies for high-performance computing

+ +
+ + + +\htmlonly +
+\endhtmlonly +\section Introduction + +The Portable Network Locality (netloc) software package provides network +topology discovery tools, and an abstract representation of those networks +topologies for a range of network types and configurations. It is provided as a +companion to the Portable Hardware Locality (hwloc) package. These two software +packages work together to provide a comprehensive view of the HPC system +topology, spanning from the processor cores in one server to the cores in +another - including the complex network(s) in between. + +Towards this end, netloc is divided into three components: +
    +
  • Network topology discovery tools for each network type and discovery + technique (called readers) +
  • Merging hwloc server topology information with that network topology +information to produce a unified map of an entire computing system (even if +that system includes multiple networks of different types, and servers that are +on at least one of those networks). +
  • A portable C API for higher-level software to query, traverse, and + manipulate the abstract representation of the network topology and unified map +(represented as a graph) +
+ +\image html netloc-design-small.png +\image latex netloc-design-small.png "" width=9cm + +The network topology graph not only provides information about the physical +nodes and edges in the network topology, but also information about the paths +between nodes (both physical and logical, where available). Since the type of +analysis (e.g., graph partitioning) required of this graph is often +application-specific, netloc limits the amount of analysis it performs and +leaves further analysis to higher level applications and libraries built upon +this service. Additionally, the \ref tools_lsnettopo tool can display and export +this network topology information in a variety of formats (e.g., GraphML and +GEXF file formats) providing developers with an additional mechanism to access +the data for further analysis. + +Similar to hwloc, netloc primarily aims at helping applications with gathering +information about modern computing and networking hardware so as to exploit it +accordingly and efficiently. + +\subsection supportednetworks Supported Networks + +The following networks are currently supported: + +
    +
  • InfiniBand (See \ref tools_reader_ib). +
  • OpenFlow-managed Ethernet newtworks (See \ref tools_reader_of). +Below are the supported OpenFlow controllers: + +
  • Static (User Defined) (See \ref tools_reader_static). +
+ + + +\htmlonly +
+\endhtmlonly +\section installation Installation + +The typical installation follows the following pattern: + +\verbatim +shell$ ./configure [options...] +shell$ make +shell$ make install +\endverbatim + + +\subsection configuration Configure Parameters + +There are a few configuration options available. See ./configure --help for +a complete list. + +\verbatim + --prefix= + Install netloc into the base directory specified. + + --with-jansson= + Installation directory of the Jansson JSON parsing library. + http://www.digip.org/jansson/ + + --with-hwloc= + Installation directory of the hwloc library. + http://www.open-mpi.org/projects/hwloc/ +\endverbatim + +A small number of API unit tests and testing data have been made available +as part of this distribution. To compile these tests use the following +command: + +\verbatim +shell$ make check +shell$ cd tests +# Run all of the programs compiled in this directory +\endverbatim + + + +\htmlonly +
+\endhtmlonly +\section interface Programming Interface + +The netloc model separates network topology discovery mechanism from the +mechanism for querying that network topology data via the netloc API. The +reason for this separation is due to the need, for some networks, to run the +discovery mechanism in a privileged mode. + +Follow the link(s) below that best suit your intended use of netloc: +
    +
  • \ref termsanddefs (A good place to start) +
  • \ref apiuser : For developers integrating netloc topology data into + their application(s). +
  • \ref apicli : For information on how to discover network topology data + for your network. +
  • \ref apireader : For developers interested in supporting a new type of + network or extend support for existing networks in netloc. +
+ + + +\htmlonly +
+\endhtmlonly +\section bugs Questions and Bugs + +Questions should be sent to the netloc users and/or developers mailing list +(http://www.open-mpi.org/community/lists/netloc.php). + +Bug reports should be reported in the tracker +(https://git.open-mpi.org/trac/netloc/). + + + + +\page apiuser End-User API + +There are a series of steps that a user must move through to gain access to the +network topology information. +
    +
  1. Run a netloc Reader tool to generate the \c .ndat file containing the + network information (\ref apicli). You will need to know the directory in + which the \c .ndat files are contained. +
  2. Access \ref apiusermetadata
    + This provides a lightweight discovery mechanism for choosing the network(s) + about which to gather more detailed information. +
  3. Access the \ref apiusertopo
    + This opaque handle provides access to the detailed topology information. +
  4. Use the \ref apiuserquery
    + This interfaces allow you to access various components of the network + topology including nodes, edges, and paths. +
+ + +\htmlonly +
+\endhtmlonly +\section apiusermetadata Network Metadata + +The following interfaces allow the application to find available network +information and choose the subset of those networks for further investigation. +they +
    +
  • \ref netloc_find_network : Find a specific network +
  • \ref netloc_foreach_network : Iterate through all available networks. +
+ +\code + char **search_uris = NULL; + int num_uris = 1, ret; + netloc_network_t *tmp_network = NULL; + + // Specify where to search for network data + search_uris = (char**)malloc(sizeof(char*) * num_uris ); + search_uris[0] = strdup("file://data/"); + + // Find a specific InfiniBand network + tmp_network = netloc_dt_network_t_construct(); + tmp_network->network_type = NETLOC_NETWORK_TYPE_INFINIBAND; + tmp_network->subnet_id = strdup("fe80:0000:0000:0000"); + + // Search for the specific network + ret = netloc_find_network(search_uris[0], tmp_network); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: network not found!\n"); + netloc_dt_network_t_destruct(tmp_network); + return NETLOC_ERROR; + } + + printf("\tFound Network: %s\n", netloc_pretty_print_network_t(tmp_network)); + + // Cleanup (Do this only once finished querying the network) + netloc_dt_network_t_destruct(tmp_network); + tmp_network = NULL; +\endcode + + +\htmlonly +
+\endhtmlonly +\section apiusertopo Network Topology Handle + +The following interfaces attach a topology handle to a specific network +discovered during the metadata discovery process (\ref apiusermetadata). +they +
    +
  • \ref netloc_attach : Attach to a specific network. +
  • \ref netloc_detach : Detach from the network. +
  • \ref netloc_access_network_ref : Access the network handle associated + with this topology. +
+ +(Note the code below is continued from the \ref apiusermetadata section.) +\code + netloc_topology_t topology; + + // Attach to the network + ret = netloc_attach(&topology, *tmp_network); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: netloc_attach returned an error (%d)\n", ret); + return ret; + } + + // Query the network topology (see next section, below) + // ... + + // Detach from the network + ret = netloc_detach(topology); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: netloc_detach returned an error (%d)\n", ret); + return ret; + } +\endcode + + +\htmlonly +
+\endhtmlonly +\section apiuserquery Network Topology Query Interfaces + +The following interfaces query the network topology using the netloc topology +handle. +they +
    +
  • \ref netloc_get_all_nodes : Access all of the nodes in the network topology. +
  • \ref netloc_get_all_switch_nodes : Access only those nodes identified as + switches. +
  • \ref netloc_get_all_host_nodes : Access only those nodes identified as + hosts. +
  • \ref netloc_get_all_edges : Access all of the edges in the topology. +
  • \ref netloc_get_node_by_physical_id : Find a node by their physical + identifier. +
  • \ref netloc_get_path : Access the physical or logical path between two + nodes. +
+ +A few of these interfaces return a lookup table of information for collections +of similar data types. The following functionality allows the user to tranverse +this collection. +
    +
  • \ref netloc_dt_lookup_table_iterator_t_construct : Create an iterator for + a lookup table. +
  • \ref netloc_dt_lookup_table_iterator_t_destruct : Destroy a previously + created iterator. +
  • \ref netloc_lookup_table_destroy : Destroy a lookup table returned by the + query API. +
  • \ref netloc_lookup_table_size : Access the used size of the lookup table + (number of entries). +
  • \ref netloc_lookup_table_access : Access a specific entry in the table. +
  • \ref netloc_lookup_table_iterator_next_key : Get the next key and advance + the iterator. +
  • \ref netloc_lookup_table_iterator_next_entry : Get the next entry and + advance the iterator. +
  • \ref netloc_lookup_table_iterator_at_end : Check if the iterator is at + the end of the collection. +
  • \ref netloc_lookup_table_iterator_reset : Reset the iterator to the + beginning of the collection. +
+ +(Note the code below assumes a topology handle is attached, per \ref apiusertopo section.) +\code + netloc_topology_t topology; + // Assume that the 'topology' handle is attached to a network. + + netloc_dt_lookup_table_t nodes = NULL; + netloc_dt_lookup_table_iterator_t hti = NULL; + const char * key = NULL; + netloc_node_t *node = NULL; + + // Access all of the nodes in the topology + ret = netloc_get_all_nodes(topology, &nodes); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: get_all_nodes returned %d\n", ret); + return ret; + } + + // Display all of the nodes found + hti = netloc_dt_lookup_table_iterator_t_construct( nodes ); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + // Access the data by key (could also access by entry in the example) + key = netloc_lookup_table_iterator_next_key(hti); + if( NULL == key ) { + break; + } + + node = (netloc_node_t*)netloc_lookup_table_access(nodes, key); + if( NETLOC_NODE_TYPE_INVALID == node->node_type ) { + fprintf(stderr, "Error: Returned unexpected node: %s\n", netloc_pretty_print_node_t(node)); + return NETLOC_ERROR; + } + + printf("Found: %s\n", netloc_pretty_print_node_t(node)); + } + + /* Cleanup */ + netloc_dt_lookup_table_iterator_t_destruct(hti); + netloc_lookup_table_destroy(nodes); + free(nodes); + nodes = NULL; +\endcode + + + +\htmlonly +
+\endhtmlonly +\section apiuserexample Example Programs + +The following small C example (named ``netloc_hello.c'') accesses a specific +network and searches for a specific node by its physical identifier (e.g., MAC +address, GUID). + +\include "netloc_hello.c" + + +The following C example (named ``netloc_nodes.c'') is an accumulation of +the inline examples above to display all of the nodes in a single network. + +\include "netloc_nodes.c" + + +The following small C example (named ``netloc_all.c'') prints all of the +nodes in all of the network topologies discovered. + +\include "netloc_all.c" + + + + + +\page apicli Command Line Tools and Network Readers + + + +\htmlonly +
+\endhtmlonly +\section tools_lsnettopo lsnettopo + +The \c lsnettopo command provides a description of the network information discovered. +This command will list the network topology summary information for all +networks in the specified directory. The network topology information is +displayed to the console or can be exported in a variety of formats (e.g., +GraphML and GEXF file formats) providing developers with an additional +mechanism to access the data for further analysis. + +\verbatim +shell$ lsnettopo data/ +Network: ETH-unknown + Type : Ethernet + Subnet : unknown + Hosts : 8 + Switches: 7 +--------------------------------------------------- +shell$ +shell$ lsnettopo data/ --export gexf +Network: ETH-unknown + Filename: ETH-unknown.gexf +shell$ +shell$ lsnettopo data/ -f +Network: ETH-unknown + Type : Ethernet + Subnet : unknown + Hosts : 8 + Switches: 7 +--------------------------------------------------- + +Information by Host +--------------------- +00:00:00:00:00:02 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:03 (Switch) on port 2 +00:00:00:00:00:07 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:07 (Switch) on port 1 +00:00:00:00:00:03 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:04 (Switch) on port 1 +00:00:00:00:00:06 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:06 (Switch) on port 2 +00:00:00:00:00:08 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:07 (Switch) on port 2 +00:00:00:00:00:05 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:06 (Switch) on port 1 +00:00:00:00:00:01 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:03 (Switch) on port 1 +00:00:00:00:00:04 ( Host) on port -1 [-> 1/1 <-] 00:00:00:00:00:00:00:04 (Switch) on port 2 + +Information by Switch +--------------------- +00:00:00:00:00:00:00:06 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:05 (Switch) on port 1 +00:00:00:00:00:00:00:06 (Switch) on port 2 [-> 1/1 <-] 00:00:00:00:00:06 ( Host) on port -1 +00:00:00:00:00:00:00:06 (Switch) on port 1 [-> 1/1 <-] 00:00:00:00:00:05 ( Host) on port -1 +00:00:00:00:00:00:00:03 (Switch) on port 2 [-> 1/1 <-] 00:00:00:00:00:02 ( Host) on port -1 +00:00:00:00:00:00:00:03 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:02 (Switch) on port 1 +00:00:00:00:00:00:00:03 (Switch) on port 1 [-> 1/1 <-] 00:00:00:00:00:01 ( Host) on port -1 +00:00:00:00:00:00:00:07 (Switch) on port 1 [-> 1/1 <-] 00:00:00:00:00:07 ( Host) on port -1 +00:00:00:00:00:00:00:07 (Switch) on port 2 [-> 1/1 <-] 00:00:00:00:00:08 ( Host) on port -1 +00:00:00:00:00:00:00:07 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:05 (Switch) on port 2 +00:00:00:00:00:00:00:02 (Switch) on port 2 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:04 (Switch) on port 3 +00:00:00:00:00:00:00:02 (Switch) on port 1 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:03 (Switch) on port 3 +00:00:00:00:00:00:00:02 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:01 (Switch) on port 1 +00:00:00:00:00:00:00:04 (Switch) on port 1 [-> 1/1 <-] 00:00:00:00:00:03 ( Host) on port -1 +00:00:00:00:00:00:00:04 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:02 (Switch) on port 2 +00:00:00:00:00:00:00:04 (Switch) on port 2 [-> 1/1 <-] 00:00:00:00:00:04 ( Host) on port -1 +00:00:00:00:00:00:00:05 (Switch) on port 3 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:01 (Switch) on port 2 +00:00:00:00:00:00:00:05 (Switch) on port 1 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:06 (Switch) on port 3 +00:00:00:00:00:00:00:05 (Switch) on port 2 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:07 (Switch) on port 3 +00:00:00:00:00:00:00:01 (Switch) on port 1 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:02 (Switch) on port 3 +00:00:00:00:00:00:00:01 (Switch) on port 2 [-> 10000000000/1 <-] 00:00:00:00:00:00:00:05 (Switch) on port 3 +------------------------------------------------------------------------------ +\endverbatim + +\subsection tools_lsnettopo_cli Command Line Interface + +There are a few command line options available. See lsnettopo --help +for a complete list. + +\verbatim + (Optional) + Path to directory where the netloc .dat files are placed. + Detected as the first unknown option on the command line + Default: ./ + +--full | -f (Optional) + Full output, in addition to the brief overview + Default: disabled + +--export | -e (Optional) + Export the data in the specified format type. + Supported Format Types + screen (Default) + Display to the terminal + GraphML + File extension .graphml + http://graphml.graphdrawing.org/ + GEXF + File extension .gexf + http://gexf.net/ + +--verbose | -v (Optional) + Verbose output. + +--help | -h (Optional) + Display a help message. +\endverbatim + + + +\htmlonly +
+\endhtmlonly +\section tools_reader_static Reader: Static (User Defined) + +The \c netloc_reader_static tool processes data from a user supplied input +file. This reader is useful for users on networks that do not (yet) have a +netloc reader or, due to restricted access, the user cannot run the necessary +reader. The format of the input file is specified below. + +
    +
  • \c netloc_reader_static : Static specification of the network topology information. +
+ +\verbatim +shell$ netloc_reader_static -i example-2-nodes.json -o netloc/ + Input file : example-2-nodes.json + Output Directory : ./ +Parsing the input file... + Processing: Network Information... + Processing: Node Information... + Processing: Edge Information... +Status: Computing Physical Paths +Status: Validating the output... + Number of hosts : 2 + Number of switches: 1 + Number of edges : 4 +shell$ +shell$ lsnettopo netloc/ +Network: ETH-unknown (version 1) + Type : Ethernet + Subnet : unknown + Hosts : 2 + Switches: 1 +--------------------------------------------------- +\endverbatim + +\subsection tools_reader_static_cli Command Line Interfaces (netloc_reader_static) + +There are a few command line options available. See netloc_reader_static --help +for a complete list. + +\verbatim +--input | -i + The JSON input file describing the network nodes and edges. + +--outdir | -o (Optional) + Path to directory where output .dat filess are placed by the tool. + Default: "./" + +--progress | -p + Show progress of processing node and edge information + Default: disabled + +--help | -h (Optional) + Display a help message. +\endverbatim + +\subsection tools_reader_static_json JSON Format + +Below is the JSON schema for the input file. + +\verbinclude "../tools/reader_static/netloc_reader_static_schema.json" + +Below is an example of the expected format of the JSON input file with two nodes and one swich. + +\verbinclude "../tools/reader_static/example-2-nodes.json" + + + + + +\htmlonly +
+\endhtmlonly +\section tools_reader_ib Reader: InfiniBand + +The following tools are available for discovering the network topology of an +InfiniBand network. +
    +
  • \c netloc_ib_gather_raw : Call the \c ibnetdiscover and \c ibroutes tools + to generate the necessary raw data files. +
  • \c netloc_ib_extract_dats : This command simplifies the use of the + \c netloc_reader_ib tool by processing all subnet data generated from the + \c netloc_ib_gather_raw tool.. +
  • \c netloc_reader_ib : Processes raw data from the \c ibnetdiscover and + \c ibroutes tools. The resulting \c .ndat files are used as abstract + representations of the network graph +
+ +\verbatim +Normal way to use this: +* Get some hwloc outputs from some nodes (at least enough nodes to make all subnets available) + and store them as .xml in a single directory + shell$ ssh node001 lstopo ~/mycluster-data/hwloc/node001.xml + +* Run netloc-ib-gather-raw.pl --hwloc-dir --raw-dir + - If you cannot run the entire script as root, add --sudo to run ib* programs as root. + - If some subnets are not accessible from the local node, they will be skipped. + Add --verbose to see where you could run the same command to discover other subnets. + - If one subnet doesn't work for some reason, use --force-subnet instead of --hwloc-dir. + +* Make sure netloc_ib_reader and friends are in PATH + +* Run netloc-ib-extract-dats.pl --raw-dir --out-dir +\endverbatim + + +Example using \c netloc_ib_gather_raw and \c netloc_ib_extract_dats: + +\verbatim +shell$ netloc_ib_gather_raw --hwloc-dir hwloc/ --raw-dir ib-raw/ +shell$ +shell$ netloc_ib_extract_dats --raw-dir ib-raw --out-dir netloc +---------------------------------------------------------------------- +Processing Subnet: 3333:3333:3333:3333 +---------------------------------------------------------------------- +--------------- General Network Information +---------------------------------------------------------------------- +Processing Subnet: 2222:2222:2222:2222 +---------------------------------------------------------------------- +--------------- General Network Information +shell$ +shell$ lsnettopo netloc/ +Network: IB-2222:2222:2222:2222 + Type : InfiniBand + Subnet : 2222:2222:2222:2222 + Hosts : 38 + Switches: 12 +--------------------------------------------------- + +Network: IB-3333:3333:3333:3333 + Type : InfiniBand + Subnet : 3333:3333:3333:3333 + Hosts : 27 + Switches: 18 +--------------------------------------------------- +\endverbatim + +Example using \c netloc_ib_gather_raw and \c netloc_reader_ib to only process +one of the subnets. + +\verbatim +shell$ netloc-ib-gather-raw.pl --hwloc-dir hwloc/ --raw-dir ib-raw/ +shell$ +shell$ netloc_reader_ib --subnet 2222:2222:2222:2222 \ + --outdir dat_files/ \ + --file ib-raw/ib-subnet-2222\:2222\:2222\:2222.txt \ + --routedir ib-raw/ibroutes-2222\:2222\:2222\:2222/ + Output Directory : dat_files/ + Subnet : 2222:2222:2222:2222 + ibnetdiscover File : ib-raw/ib-subnet-2222:2222:2222:2222.txt + ibroutes Directory : ib-raw/ibroutes-2222:2222:2222:2222/ +Status: Querying the ibnetdiscover data for subnet 2222:2222:2222:2222... +Status: Processing Node Information +Status: Computing Physical Paths +Status: Querying the ibroutes data for subnet 2222:2222:2222:2222... +Status: Processing Logical Paths +Status: Validating the output... + Number of hosts : 38 + Number of switches: 12 + Number of edges : 220 +shell$ +shell$ lsnettopo dat_files/ +Network: IB-2222:2222:2222:2222 + Type : InfiniBand + Subnet : 2222:2222:2222:2222 + Hosts : 38 + Switches: 12 +--------------------------------------------------- +\endverbatim + + +\subsection tools_gather_ib_cli Command Line Interfaces (netloc_ib_gather_raw) + +There are a few command line options available. See netloc_ib_gather_raw +for a complete list. + +\verbatim +Output directory for raw IB data must be specified with + --out-dir + +Input must be one of these + --hwloc-dir + Specifies that contains the hwloc XML exports of the some nodes, + The list of IB subnets should be guessed from there. + + --force-subnet [:]: to force the discovery + Force discovery on local board port , and optionally force the + subnet id instead of reading it from the first GID. + Examples: --force-subnet mlx4_0:1 + --force-subnet fe80:0000:0000:0000:mlx4_0:1 + +Other options + --sudo + Pass sudo to internal ibnetdiscover and ibroute invocations. + Useful when the entire script cannot run as root. + + --ibnetdiscover --ibroute + Specify exact location of programs. Default is /usr/bin/ + + --ignore-errors + Ignore errors from ibnetdiscover and ibroute, assume their outputs are ok + + --verbose + Add verbose messages + + --dry-run + Do not actually run programs +\endverbatim + + +\subsection tools_extract_ib_cli Command Line Interfaces (netloc_ib_extract_dats) + +There are a few command line options available. See netloc_ib_extract_dats --help +for a complete list. + +\verbatim + --raw-dir (Optional) + Input directory with raw IB data must be specified with + Default is ./ib-raw + + --out-dir (Optional) + Output directory for netloc data can be specified with + Default is ./netloc + + --verbose | -v (Optional) + Verbose and progress information + + --help | -h (Optional) + Display a help message. +\endverbatim + + +\subsection tools_reader_ib_cli Command Line Interfaces (netloc_reader_ib) + +There are a few command line options available. See netloc_reader_ib --help +for a complete list. + +\verbatim +--file + The file containing the ibnetdiscover data + +--routedir (Optional) + Path to the file containing ibroutes data. + Information for each host should be stored in a separate file. + Default: Exclude logical routing information + +--subnet + The subset id of the network + +--outdir (Optional) + Path to directory where output .dat files are placed. + Default: ./ + +--progress | -p (Optional) + Display a progress percentage while processing the network files. + +--help | -h (Optional) + Display a help message. +\endverbatim + + + + +\htmlonly +
+\endhtmlonly +\section tools_reader_of Reader: OpenFlow-managed Ethernet + +The \c netloc_reader_of tool processes data from a supported OpenFlow +controller to discover information about an Ethernet network. The controller +must be running and reachable from the machine running this tool. + +
    +
  • \c netloc_reader_of : Contact the OpenFlow controller and extract the + network topology information. +
+ +\verbatim +shell$ netloc_reader_of --controller opendaylight -o netloc/ +shell$ +shell$ lsnettopo netloc/ +Network: ETH-unknown + Type : Ethernet + Subnet : unknown + Hosts : 8 + Switches: 7 +--------------------------------------------------- +\endverbatim + +\subsection tools_reader_of_cli Command Line Interfaces (netloc_reader_of) + +There are a few command line options available. See netloc_reader_of --help +for a complete list. + +\verbatim +--controller | -c + Name of the controller to use to access the OpenFlow network + information. See below for options. + Supported Controllers + opendaylight: + Attach to the OpenDaylight controller for network information. + + floodlight: + Attach to the Floodlight controller for network information. + + xnc: + Attach to the Cisco XNC controller for network information. + +--subnet | -s (Optional) + The subnet id of the network + Default: "unknown" + +--outdir | -o (Optional) + Path to directory where output .dat filess are placed by the tool. + Default: "./" + +--addr | -a (Optional) + IP address and port of the controller + Default: 127.0.0.1:8080 + +--username | -u (Optional) + Username for authorization to the controller + Default: + +--password | -p (Optional) + Password for authorization to the controller + Default: + +--help | -h (Optional) + Display a help message. +\endverbatim + + + + + +\page apireader Reader (Data Collection) API + +There are a series of steps that a developer will need to go through to create +a new netloc reader. The basic steps are below. +
    +
  1. Access the node and edge information from your network. The remainder of + this section assumes that you have this information and are trying to convert + it into netloc .ndat files. +
  2. \ref apireader_phase1 :
    + Setup the network information on the \ref netloc_network_t handle. +
  3. \ref apireader_phase2 :
    + Setup a data collection handle (\ref netloc_data_collection_handle_t) + associated with that network along with the output directory for the .ndat + files. +
  4. \ref apireader_phase3 :
    + Create a \ref netloc_node_t object for each addressable network endpoint + (e.g., MAC Address, GUID) in the system. +
  5. \ref apireader_phase4 :
    + Add the \ref netloc_node_t object to the collection. +
  6. \ref apireader_phase5 :
    + Create a \ref netloc_edge_t object for each unidirectional edge between + \ref netloc_node_t objects. +
  7. \ref apireader_phase6 :
    + Add the \ref netloc_edge_t object to the source \ref netloc_node_t + object. +
  8. \ref apireader_phase7 :
    + Compute the shortest physical paths between all nodes. +
  9. \ref apireader_phase8 :
    + Append logical paths between all nodes. +
  10. \ref apireader_phase9 :
    + Close the data collection handle to write the data to the .ndat files in + the specified output directory. +
+ + +\htmlonly +
+\endhtmlonly +\section apireader_phase1 Setup Network Information + +The following interfaces are useful in setting up the network information. +Note that the network information pertains to a single network type and subnet. +they +
    +
  • \ref netloc_network_t : Network handle. +
  • \ref netloc_dt_network_t_construct : Constructor for the network handle. +
  • \ref netloc_dt_network_t_destruct : Destructor for the network handle. +
+ +\code + netloc_network_t *network = NULL; + + network = netloc_dt_network_t_construct(); + + network->network_type = NETLOC_NETWORK_TYPE_ETHERNET; + network->subnet_id = strdup("unknown"); + network->version = strdup("1"); + network->description = strdup("This is an example"); + network->data_uri = strdup("file://."); +\endcode + + +\htmlonly +
+\endhtmlonly +\section apireader_phase2 Setup Data Collection Handle + +The following interfaces are useful in setting up the data collection handle +and associating it with the network information. +they +
    +
  • \ref netloc_data_collection_handle_t : Data Collection handle. +
  • \ref netloc_dc_create : Creates the handle and associates it with the + specified network. +
+ +\code + netloc_data_collection_handle_t *dc_handle = NULL; + + dc_handle = netloc_dc_create(network, outdir); + + // After which the network can be destructed + netloc_dt_network_t_destruct(network); + network = NULL; +\endcode + + +\htmlonly +
+\endhtmlonly +\section apireader_phase3 Create netloc Nodes + +The following interfaces are useful in creating a \ref netloc_node_t for each +addressable network endpoing (e.g., MAC address, GUID). +they +
    +
  • \ref netloc_node_t : Node type. +
  • \ref netloc_dt_node_t_construct : Constructor for the node type. +
  • \ref netloc_dt_node_t_destruct : Destructor for the node type. +
  • \ref netloc_encode_node_type : Encode the node type (e.g., Switch, Host) +
+ +\code + netloc_node_t *node = NULL; + + node = netloc_dt_node_t_construct(); + + // fill in the necessary fields. For example, + node->network_type = dc_handle->network->network_type; + node->subnet_id = strdup(dc_handle->network->subnet_id); + node->node_type = netloc_encode_node_type("CA") + node->logical_id = strdup("10.0.0.2"); + node->physical_id = strdup("00:00:00:00:00:02"); + node->description = strdup("eth0 on node02") +\endcode + + +\htmlonly +
+\endhtmlonly +\section apireader_phase4 Add the Node to the collection + +The following interfaces are useful in adding the \ref netloc_node_t object to +the data collection. +they +
    +
  • \ref netloc_dc_append_node : Append the neloc node to the collection. +
+ +\code + netloc_dc_append_node(dc_handle, node); + + // You can destroy the node, since it is copied internally + netloc_dt_node_t_destruct(node); +\endcode + + +\htmlonly +
+\endhtmlonly +\section apireader_phase5 Create edges between the nodes + +The following interfaces are useful in creating \ref netloc_edge_t objects +representing the links between nodes. +they +
    +
  • \ref netloc_edge_t : Netloc edge type. +
  • \ref netloc_dt_edge_t_construct : Edge constructor. +
+ +\code + netloc_edge_t *edge = NULL; + + edge = netloc_dt_edge_t_construct(); + + // fill in the necessary fields. For example, + edge->src_node_id = strdup(node->physical_id); + edge->src_node_type = NETLOC_NODE_TYPE_HOST; + edge->src_port_id = strdup("-1"); + + edge->dest_node_id = strdup(dst_node->physical_id); + edge->dest_node_type = NETLOC_NODE_TYPE_SWITCH; + edge->dest_port_id = strdup("5"); + + edge->speed = strdup("100000"); + edge->width = strdup("1"); + edge->description = strdup("node02 to switch"); +\endcode + + + +\htmlonly +
+\endhtmlonly +\section apireader_phase6 Add the edges to the collection + +The following interfaces are useful in adding the \ref netloc_edge_t objects to +the data collection. Note that the edge is always associated with the source +node. +
    +
  • \ref netloc_dc_get_node_by_physical_id : Access a reference to the stored + \ref netloc_node_t object with the specified physical identifier. +
  • \ref netloc_dc_append_edge_to_node : Add the edge to the node in the data + collection. +
+ +\code + // You need the node reference of the source node to attach the edge. + // We always attach the edge to the source node which can always be + // accessed by its physical ID + node = netloc_dc_get_node_by_physical_id(dc_handle, "00:00:00:00:00:02"); + + // Now add the edge to the node on the handle + netloc_dc_append_edge_to_node(dc_handle, node, edge); + + // You can destroy the edge, since it is copied internally + netloc_dt_edge_t_destruct(edge); +\endcode + + + +\htmlonly +
+\endhtmlonly +\section apireader_phase7 (Optional) Physical Paths + +The following interfaces are useful in constructing the physical path +information between nodes. Note that all of the nodes and edges must be +attached to the data collection handle before this will work. +
    +
  • \ref netloc_dc_compute_path_between_nodes : Compute the physical paths + between the two nodes specified. + Final parameter is "false" indicating a physical path computation. +
  • \ref netloc_dc_append_path : Append a path between two nodes to the data + collection. + Final parameter is "false" indicating a physical path addition. +
+ +\code + netloc_node_t *cur_src_node = NULL; + netloc_node_t *cur_dst_node = NULL; + int num_edges = 0; + netloc_edge_t **edges = NULL; + + // Access the node objects + cur_src_node = netloc_dc_get_node_by_physical_id(dc_handle, "00:00:00:00:00:01"); + cur_dst_node = netloc_dc_get_node_by_physical_id(dc_handle, "00:00:00:00:00:02"); + + // Use the netloc library to compute the physical paths between nodes + netloc_dc_compute_path_between_nodes(dc_handle, + cur_src_node, + cur_dst_node, + &num_edges, + &edges, + false); + + // Store the path on the data collection handle + netloc_dc_append_path(dc_handle, + cur_src_node->physical_id, + cur_dst_node->physical_id, + num_edges, + edges, + false); + + // Cleanup + num_edges = 0; + free(edges); + edges = NULL; +\endcode + + +\htmlonly +
+\endhtmlonly +\section apireader_phase8 (Optional) Logical Paths + +The following interfaces are useful in constructing the logical path +information between nodes. + +\todo JJH Logical paths have not been well tested. + +
    +
  • \ref netloc_dc_compute_path_between_nodes : Compute the physical paths + between the two nodes specified. + Final parameter is "ture" indicating a logical path computation. +
  • \ref netloc_dc_append_path : Append a path between two nodes to the data + collection. + Final parameter is "true" indicating a logical path addition. +
+ +\code + // TODO +\endcode + + + +\htmlonly +
+\endhtmlonly +\section apireader_phase9 Close the data collection + +The following interfaces are useful in closing the data collection. This will +write the data to the .ndat files in the directory specified on the data +collection handle. +
    +
  • \ref netloc_dc_close : Close the data collection and write out the netloc + .ndat files. +
+ +\code + // Close the data collection + netloc_dc_close(dc_handle); + + // Cleanup the handle when we are finished with it. + netloc_dt_data_collection_handle_t_destruct(dc_handle); + dc_handle = NULL; +\endcode + + + + + +\page termsanddefs Terms and Definitions + +
+ +
netloc network handle (\ref netloc_network_t)
+
+ Represents a lightweight handle to a single network subnet at a single point + in time. It is from this handle that the user can access metadata about the + network and create a netloc topology handle (\ref netloc_topology_t). + + This handle can be thought of as a tuple of information: network type, + network subnet, and version/timestamp. +
+ +
netloc topology handle (\ref netloc_topology_t)
+
+ An opaque data structure containing detailed network topology information. + This handle is used by all of the network topology query APIs. +
+ +
netloc node (\ref netloc_node_t)
+
+ Represents the concept of a node (a.k.a., vertex, endpoint) within a network + graph. This could be a server NIC or a network switch. + + If a server has more than one NIC then there are multiple netloc nodes for + this server, one for each NIC. This is because some networks cannot + distinguish node boundaries. In order to group multiple netloc nodes together + into a logical server the netloc topology data will need to to be mapped with + the hwloc data using the map API. +
+ +
netloc edge (\ref netloc_edge_t)
+
+ Represents the concept of a directed edge withing a network graph. + These are the physical connections between two netloc nodes (\ref + netloc_node_t). +
+ +
Physical Path (\ref netloc_node_t::physical_paths)
+
+ Represents the shortest physical path from one netloc node to another. + This path does not take into account higher level routing rules that might be + in place in the network. The path is represented as a series of 'hops' + through the network where each 'hop' is a \ref netloc_edge_t object (from + which you can access the source and destination \ref netloc_node_t). + + Path information is only calculated between servers, not between switches in + the network. +
+ +
Logical Path (\ref netloc_node_t::logical_paths)
+
+ Represents the logical path from one netloc node to another. This path takes + into account the higher level routing rules that are in place in the + network. Some network configurations do not provide this information, so it + is possible that the logical path(s) for a given \ref netloc_node_t is empty. + + Currently only one logical path between any two netloc nodes is + captured. Path information is only calculated between servers, not between + switches in the network. +
+ +
+ + +*/ diff --git a/include/Makefile.am b/include/Makefile.am index 08a26130ca..fcb58c0cc4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ # Copyright © 2009-2014 Inria. All rights reserved. # Copyright © 2009-2010 Université Bordeaux 1 -# Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. # Copyright © 2011 Oracle and/or its affiliates. All rights reserved. # See COPYING in top-level directory. @@ -9,6 +9,11 @@ if HWLOC_BUILD_STANDALONE include_HEADERS = hwloc.h + +if BUILD_NETLOC +include_HEADERS += netloc.h +endif + include_hwlocdir = $(includedir)/hwloc include_hwloc_HEADERS = \ hwloc/bitmap.h \ @@ -29,13 +34,24 @@ include_hwloc_HEADERS = \ include_hwloc_autogendir = $(includedir)/hwloc/autogen nodist_include_hwloc_autogen_HEADERS = hwloc/autogen/config.h +if BUILD_NETLOC +include_netlocdir = $(includedir)/netloc +include_netloc_HEADERS = \ + netloc/dc.h \ + netloc/map.h \ + netloc/rename.h \ + netloc/rename_map.h +endif + noinst_HEADERS = \ private/private.h \ private/debug.h \ private/misc.h \ private/xml.h \ private/components.h \ - private/cpuid-x86.h + private/cpuid-x86.h \ + private/netloc.h \ + private/map.h if HWLOC_HAVE_LINUX include_hwloc_HEADERS += \ diff --git a/include/netloc.h b/include/netloc.h new file mode 100644 index 0000000000..445caf7eb1 --- /dev/null +++ b/include/netloc.h @@ -0,0 +1,911 @@ +/* + * Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#ifndef _NETLOC_H_ +#define _NETLOC_H_ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // for asprintf +#endif + +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * "Import" a few things from hwloc + */ +#define __netloc_attribute_unused __hwloc_attribute_unused +#define __netloc_attribute_malloc __hwloc_attribute_malloc +#define __netloc_attribute_const __hwloc_attribute_const +#define __netloc_attribute_pure __hwloc_attribute_pure +#define __netloc_attribute_deprecated __hwloc_attribute_deprecated +#define __netloc_attribute_may_alias __hwloc_attribute_may_alias +#define NETLOC_DECLSPEC HWLOC_DECLSPEC + + +/** \defgroup netloc_api Netloc API + * @{ + */ + +/********************************************************************** + * Enumerated types + **********************************************************************/ + +/** + * Definitions for Comparators + * \sa These are the return values from the following functions: + * netloc_dt_network_t_compare, netloc_dt_edge_t_compare, netloc_dt_node_t_compare + */ +typedef enum { + NETLOC_CMP_SAME = 0, /**< Compared as the Same */ + NETLOC_CMP_SIMILAR = -1, /**< Compared as Similar, but not the Same */ + NETLOC_CMP_DIFF = -2 /**< Compared as Different */ +} netloc_compare_type_t; + +/** + * Enumerated type for the various types of supported networks + */ +typedef enum { + NETLOC_NETWORK_TYPE_ETHERNET = 1, /**< Ethernet network */ + NETLOC_NETWORK_TYPE_INFINIBAND = 2, /**< InfiniBand network */ + NETLOC_NETWORK_TYPE_INVALID = 3 /**< Invalid network */ +} netloc_network_type_t; + +/** + * Encode the network type + * + * \note Only used by netloc readers to encode the network type + * + * \param str_val String value to parse + * + * \returns A valid member of the \ref netloc_network_type_t type + */ +static inline netloc_network_type_t netloc_encode_network_type(const char * str_val) { + if( NULL == str_val ) { + return NETLOC_NETWORK_TYPE_INVALID; + } + else if( 0 == strncmp(str_val, "ETH", strlen(str_val)) ) { + return NETLOC_NETWORK_TYPE_ETHERNET; + } + else if( 0 == strncmp(str_val, "IB", strlen(str_val)) ) { + return NETLOC_NETWORK_TYPE_INFINIBAND; + } + else { + return NETLOC_NETWORK_TYPE_INVALID; + } +} + +/** + * Decode the network type + * + * \param net_type A valid member of the \ref netloc_network_type_t type + * + * \returns NULL if the type is invalid + * \returns A string for that \ref netloc_network_type_t type + */ +static inline const char * netloc_decode_network_type(netloc_network_type_t net_type) { + if( NETLOC_NETWORK_TYPE_ETHERNET == net_type ) { + return "ETH"; + } + else if( NETLOC_NETWORK_TYPE_INFINIBAND == net_type ) { + return "IB"; + } + else { + return NULL; + } +} + +/** + * Decode the network type into a human readable string + * + * \param net_type A valid member of the \ref netloc_network_type_t type + * + * \returns A string for that \ref netloc_network_type_t type + */ +static inline const char * netloc_decode_network_type_readable(netloc_network_type_t net_type) { + if( NETLOC_NETWORK_TYPE_ETHERNET == net_type ) { + return "Ethernet"; + } + else if( NETLOC_NETWORK_TYPE_INFINIBAND == net_type ) { + return "InfiniBand"; + } + else { + return "Invalid"; + } +} + + +/** + * Enumerated type for the various types of nodes + */ +typedef enum { + NETLOC_NODE_TYPE_SWITCH = 1, /**< Switch node */ + NETLOC_NODE_TYPE_HOST = 2, /**< Host (a.k.a., network addressable endpoint - e.g., MAC Address) node */ + NETLOC_NODE_TYPE_INVALID = 3 /**< Invalid node */ +} netloc_node_type_t; + +/** + * Encode the node type + * + * \note Only used by netloc readers to encode the network type + * + * \param str_val String value to parse + * + * \returns A valid member of the \ref netloc_node_type_t type + */ +static inline netloc_node_type_t netloc_encode_node_type(const char * str_val) { + if( NULL == str_val ) { + return NETLOC_NODE_TYPE_INVALID; + } + else if( 0 == strncmp(str_val, "CA", strlen(str_val)) ) { + return NETLOC_NODE_TYPE_HOST; + } + else if( 0 == strncmp(str_val, "SW", strlen(str_val)) ) { + return NETLOC_NODE_TYPE_SWITCH; + } + else { + return NETLOC_NODE_TYPE_INVALID; + } +} + +/** + * Decode the node type + * + * \param node_type A valid member of the \ref netloc_node_type_t type + * + * \returns NULL if the type is invalid + * \returns A string for that \ref netloc_node_type_t type + */ +static inline const char * netloc_decode_node_type(netloc_node_type_t node_type) { + if( NETLOC_NODE_TYPE_SWITCH == node_type ) { + return "SW"; + } + else if( NETLOC_NODE_TYPE_HOST == node_type ) { + return "CA"; + } + else { + return NULL; + } +} + +/** + * Decode the node type into a human readable string + * + * \param node_type A valid member of the \ref netloc_node_type_t type + * + * \returns NULL if the type is invalid + * \returns A string for that \ref netloc_node_type_t type + */ +static inline char * netloc_decode_node_type_readable(netloc_node_type_t node_type) { + if( NETLOC_NODE_TYPE_SWITCH == node_type ) { + return "Switch"; + } + else if( NETLOC_NODE_TYPE_HOST == node_type ) { + return "Host"; + } + else { + return "Invalid"; + } +} + +/** + * Return codes + */ +enum { + NETLOC_SUCCESS = 0, /**< Success */ + NETLOC_ERROR = -1, /**< Error: General condition */ + NETLOC_ERROR_NOTDIR = -2, /**< Error: URI is not a directory */ + NETLOC_ERROR_NOENT = -3, /**< Error: URI is invalid, no such entry */ + NETLOC_ERROR_EMPTY = -4, /**< Error: No networks found */ + NETLOC_ERROR_MULTIPLE = -5, /**< Error: Multiple matching networks found */ + NETLOC_ERROR_NOT_IMPL = -6, /**< Error: Interface not implemented */ + NETLOC_ERROR_EXISTS = -7, /**< Error: If the entry already exists when trying to add to a lookup table */ + NETLOC_ERROR_NOT_FOUND = -8, /**< Error: No path found */ + NETLOC_ERROR_MAX = -9 /**< Error: Enum upper bound marker. No errors less than this number Will not be returned externally. */ +}; + +/********************************************************************** + * Structures + **********************************************************************/ + +/** + * \struct netloc_topology_t + * \brief Netloc Topology Context + * + * An opaque data structure used to reference a network topology. + * + * \note Must be initialized with \ref netloc_attach() + */ +struct netloc_topology; +/** \cond IGNORE */ +typedef struct netloc_topology * netloc_topology_t; +/** \endcond */ + +/** + * \struct netloc_dt_lookup_table_t + * \brief Lookup Table Type + * + * An opaque data structure to represent a collection of data items + */ +struct netloc_dt_lookup_table; +/** \cond IGNORE */ +typedef struct netloc_dt_lookup_table * netloc_dt_lookup_table_t; +/** \endcond */ + +/** + * \struct netloc_dt_lookup_table_iterator_t + * \brief Lookup Table Iterator + * + * An opaque data structure representing the next location in the lookup table + */ +struct netloc_dt_lookup_table_iterator; +/** \cond IGNORE */ +typedef struct netloc_dt_lookup_table_iterator * netloc_dt_lookup_table_iterator_t; +/** \endcond */ + + +/** + * \brief Netloc Network Type + * + * Represents a single network type and subnet. + */ +struct netloc_network_t { + /** Type of network */ + netloc_network_type_t network_type; + + /** Subnet ID */ + char * subnet_id; + + /** Data URI */ + char * data_uri; + + /** Node URI */ + char * node_uri; + + /** Physical Path URI */ + char * phy_path_uri; + + /** Path URI */ + char * path_uri; + + /** Description information from discovery (if any) */ + char * description; + + /** Metadata about network information */ + char * version; + + /** + * Application-given private data pointer. + * Initialized to NULL, and not used by the netloc library. + */ + void * userdata; +}; +typedef struct netloc_network_t netloc_network_t; + + +/* Predefine the netloc_node_t structure so we can use it in the netloc_edge_t */ +struct netloc_node_t; +typedef struct netloc_node_t netloc_node_t; + + +/** + * \brief Netloc Edge Type + * + * Represents the concept of a directed edge within a network graph. + * + * \note We do not point to the netloc_node_t structure directly to + * simplify the representation, and allow the information to more easily + * be entered into the data store without circular references. + * \todo JJH Is the note above still true? + */ +struct netloc_edge_t { + /** Unique Edge ID */ + int edge_uid; + + /** Source: Pointer to neloc_node_t */ + netloc_node_t *src_node; + /** Source: Physical ID from netloc_node_t */ + char * src_node_id; + /** Source: Node type from netloc_node_t */ + netloc_node_type_t src_node_type; + /** Source: Port number */ + char * src_port_id; + + /** Dest: Pointer to neloc_node_t */ + netloc_node_t *dest_node; + /** Dest: Physical ID from netloc_node_t */ + char * dest_node_id; + /** Dest: Node type from netloc_node_t */ + netloc_node_type_t dest_node_type; + /** Dest: Port number */ + char * dest_port_id; + + /** Metadata: Speed */ + char * speed; + /** Metadata: Width */ + char * width; + + /** Description information from discovery (if any) */ + char * description; + + /** + * Application-given private data pointer. + * Initialized to NULL, and not used by the netloc library. + */ + void * userdata; +}; +typedef struct netloc_edge_t netloc_edge_t; + +/** + * \brief Netloc Node Type + * + * Represents the concept of a node (a.k.a., vertex, endpoint) within a network + * graph. This could be a server or a network switch. The \ref node_type parameter + * will distinguish the exact type of node this represents in the graph. + */ +struct netloc_node_t { + /** Type of the network connection */ + netloc_network_type_t network_type; + + /** Type of the node */ + netloc_node_type_t node_type; + + /** Physical ID of the node (must be unique) */ + char * physical_id; + unsigned long physical_id_int; + + /** Logical ID of the node (if any) */ + char * logical_id; + + /** Internal unique ID: 0 - N */ + int __uid__; + + /** Subnet ID */ + char * subnet_id; + + /** Description information from discovery (if any) */ + char * description; + + /** + * Application-given private data pointer. + * Initialized to NULL, and not used by the netloc library. + */ + void * userdata; + + /** Number of Outgoing edges from this node */ + int num_edges; + /** Outgoing edges from this node */ + netloc_edge_t **edges; + + /** Number of edge IDs (Internal use only) */ + int num_edge_ids; + /** Edge IDs (Internal use only) */ + int *edge_ids; + + /** Number of physical paths computed from this node */ + int num_phy_paths; + /** Lookup table for physical paths from this node */ + netloc_dt_lookup_table_t physical_paths; + + /** Number of logical paths computed from this node */ + int num_log_paths; + /** Lookup table for logical paths from this node */ + netloc_dt_lookup_table_t logical_paths; +}; + + +/********************************************************************** + * Datatype Support Functions + **********************************************************************/ +/** + * Constructor for \ref netloc_network_t + * + * User is responsible for calling the destructor on the handle. + * + * \returns A newly allocated pointer to the network information. + */ +NETLOC_DECLSPEC netloc_network_t * netloc_dt_network_t_construct(void); + +/** + * Destructor for \ref netloc_network_t + * + * \param network A valid network handle + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_network_t_destruct(netloc_network_t *network); + +/** + * Copy Constructor for \ref netloc_network_t + * + * Allocates memory. User is responsible for calling + * \ref netloc_dt_network_t_destruct on the returned pointer. + * Does a shallow copy of the pointers to data. + * + * \param network A pointer to the network to duplicate + * + * \returns A newly allocated copy of the network. + */ +NETLOC_DECLSPEC netloc_network_t * netloc_dt_network_t_dup(netloc_network_t *network); + +/** + * Copy Function for \ref netloc_network_t + * + * Does not allocate memory for 'to'. Does a shallow copy of the pointers to data. + * + * \param from A pointer to the network to duplicate + * \param to A pointer to the network to duplicate into + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_network_t_copy(netloc_network_t *from, netloc_network_t *to); + +/** + * Compare function for \ref netloc_network_t + * + * \param a A pointer to one network object for comparison + * \param b A pointer to the other network object for comparison + * + * \returns \ref NETLOC_CMP_SAME if the same + * \returns \ref NETLOC_CMP_SIMILAR if only the metadata (e.g., version) is different + * \returns \ref NETLOC_CMP_DIFF if different + */ +NETLOC_DECLSPEC int netloc_dt_network_t_compare(netloc_network_t *a, netloc_network_t *b); + + +/** + * Compare function for \ref netloc_edge_t + * + * \param a A pointer to one edge object for comparison + * \param b A pointer to the other edge object for comparison + * + * \returns \ref NETLOC_CMP_SAME if the same + * \returns \ref NETLOC_CMP_DIFF if different + */ +NETLOC_DECLSPEC int netloc_dt_edge_t_compare(netloc_edge_t *a, netloc_edge_t *b); + + +/** + * Compare function for netloc_node_t + * + * \param a A pointer to one network object for comparison + * \param b A pointer to the other network object for comparison + * + * \returns \ref NETLOC_CMP_SAME if the same + * \returns \ref NETLOC_CMP_DIFF if different + */ +NETLOC_DECLSPEC int netloc_dt_node_t_compare(netloc_node_t *a, netloc_node_t *b); + + +/********************************************************************** + * Datatype Support Functions for Lookup Tables + **********************************************************************/ + +/** + * Constructor for a lookup table iterator + * + * User is responsible for calling the \ref netloc_dt_lookup_table_iterator_t_destruct on the handle. + * + * \param table The table to reference in this iterator + * + * \returns A newly allocated pointer to the lookup table iterator. + */ +NETLOC_DECLSPEC netloc_dt_lookup_table_iterator_t netloc_dt_lookup_table_iterator_t_construct(netloc_dt_lookup_table_t table); + +/** + * Destructor for a lookup table iterator + * + * \param hti A valid lookup table iterator handle + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_lookup_table_iterator_t_destruct(netloc_dt_lookup_table_iterator_t hti); + + +/********************************************************************** + * Lookup table API Functions + **********************************************************************/ + +/** + * Destroy a lookup table. + * + * \note The user is responsible for calling this function if they are ever returned + * a \ref netloc_dt_lookup_table_t from a function such as \ref netloc_get_all_nodes. + * + * \param table The lookup table to destroy + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_destroy(netloc_dt_lookup_table_t table); + + +/** + * Access the -used- size of the lookup table + * + * \param table A valid pointer to a lookup table + * + * \returns The used size of the lookup table + */ +NETLOC_DECLSPEC int netloc_lookup_table_size(netloc_dt_lookup_table_t table); + + +/** + * Access an entry in the lookup table + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * + * \returns NULL if nothing found + * \returns The pointer associated with this key + */ +NETLOC_DECLSPEC void * netloc_lookup_table_access(netloc_dt_lookup_table_t ht, const char *key); + + +/** + * Get the next key and advance the iterator + * + * The user should -not- call free() on the string returned. + * + * \param hti A valid pointer to a lookup table iterator + * + * \returns NULL if error or at end + * \returns A newly allocated string copy of the key. + */ +NETLOC_DECLSPEC const char * netloc_lookup_table_iterator_next_key(netloc_dt_lookup_table_iterator_t hti); + +/** + * Get the next entry and advance the iterator + * + * Similar to \ref netloc_lookup_table_iterator_next_key except the caller is + * given the next value directly. So they do not need to call the + * \ref netloc_lookup_table_access function to access the value. + * + * \param hti A valid pointer to a lookup table iterator + * + * \returns NULL if error or at end + * \returns The pointer associated with this key + */ +NETLOC_DECLSPEC void * netloc_lookup_table_iterator_next_entry(netloc_dt_lookup_table_iterator_t hti); + +/** + * Check if we are at the end of the iterator + * + * \param hti A valid pointer to a lookup table iterator + * + * \returns true if at the end of the data, false otherwise + */ +NETLOC_DECLSPEC bool netloc_lookup_table_iterator_at_end(netloc_dt_lookup_table_iterator_t hti); + +/** + * Reset the iterator back to the start + * + * \param hti A valid pointer to a lookup table iterator + * + */ +NETLOC_DECLSPEC void netloc_lookup_table_iterator_reset(netloc_dt_lookup_table_iterator_t hti); + + + +/********************************************************************** + * Network Metadata API Functions + **********************************************************************/ +/** + * Pretty print the network (Debugging Support) + * + * The user is responsible for calling free() on the string returned. + * + * \param network A valid pointer to a network + * + * \returns A newly allocated string representation of the network. + */ +NETLOC_DECLSPEC char * netloc_pretty_print_network_t(netloc_network_t* network); + +/** + * Pretty print the edge (Debugging Support) + * + * The user is responsible for calling free() on the string returned. + * + * \param edge A valid pointer to an edge + * + * \returns A newly allocated string representation of the edge. + */ +NETLOC_DECLSPEC char * netloc_pretty_print_edge_t(netloc_edge_t* edge); + +/** + * Pretty print the node (Debugging Support) + * + * The user is responsible for calling free() on the string returned. + * + * \param node A valid pointer to a node + * + * \returns A newly allocated string representation of the node. + */ +NETLOC_DECLSPEC char * netloc_pretty_print_node_t(netloc_node_t* node); + +/** + * Find a specific network at the URI specified. + * + * \param network_topo_uri URI to search for the specified network. + * \param network Netloc network handle (IN/OUT) + * A network handle with the data structure fields set to + * specify the search. For example, the user can set 'IB' + * and nothing else, if they do not know the subnet or any + * of the other necessary information. If the method + * returns success then the network handle will be filled + * out with the rest of the information found. If the method + * returns some error then the network handle is not modified. + * + * \returns NETLOC_SUCCESS if exactly one network matches the specification, + * and updates the network handle. + * \returns NETLOC_ERROR_MULTIPLE if more than one network matches the spec. + * \returns NETLOC_ERROR_EMPTY if no networks match the specification. + * \returns NETLOC_ERROR_NOENT if the directory does not exist. + * \returns NETLOC_ERROR_NOTDIR if the data_dir is not a directory. + * \returns NETLOC_ERROR if something else is wrong. + */ +NETLOC_DECLSPEC int netloc_find_network(const char * network_topo_uri, + netloc_network_t* network); + +/** + * Find all available networks in the specified URIs + * + * User is responsible for calling the destructor for each element of the networks array + * paramater, then free() on the entire array. + * + * \param search_uris Array of URIs. file:// syntax is the only supported mechanism + * at the moment. Array is searched for .dat files. All uris will + * be searched. If NULL is supplied then the default search path + * will be used (currently the CWD). + * \param num_uris Size of the search_uris array. + * \param (*func) A callback function triggered for each network found the user + * is provided an opportunity to decide if it should be included + * in the "networks" array or not. "net" is a handle to the + * network information (includes uri where it was found). + * If the callback returns non-zero then the entry is added to + * the networks array. If the callback returns 0 then the entry + * is not added to the networks array. If NULL is supplied as + * an argument for this function pointer then all networks are + * included in the array. + * \param funcdata User specified data pointer to be passed to the callback function. + * \param num_networks Size of the networks array. + * \param networks An array of networks discovered. + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_foreach_network(const char * const * search_uris, + int num_uris, + int (*func)(const netloc_network_t *network, void *funcdata), + void *funcdata, + int *num_networks, + netloc_network_t ***networks); + + +/********************************************************************** + * Topology API Functions + **********************************************************************/ +/** + * Attach to the specified network, and allocate a topology handle. + * + * User is responsible for calling \ref netloc_detach on the topology handle. + * The network parameter information is deep copied into the topology handle, so the + * user may destruct the network handle after calling this function and/or reuse + * the network handle. + * + * \param topology A pointer to a netloc_topology_t handle. + * \param network The \ref netloc_network_t handle from a prior call to either: + * - \ref netloc_find_network() + * - \ref netloc_foreach_network() + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_attach(netloc_topology_t * topology, netloc_network_t network); + +/** + * Detach from a topology handle + * + * \param topology A valid pointer to a \ref netloc_topology_t handle created + * from a prior call to \ref netloc_attach. + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_detach(netloc_topology_t topology); + +/** + * Refresh the data associated with the topology. + * + * \warning This interface is not currently implemented. + * + * \param topology A valid pointer to a \ref netloc_topology_t handle created + * from a prior call to \ref netloc_attach. + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_refresh(netloc_topology_t topology); + + +/********************************************************************** + * Query API Functions + **********************************************************************/ +/** + * Access a reference to the \ref netloc_network_t associated with the \ref netloc_topology_t + * + * The user should -not- call \ref netloc_dt_network_t_destruct on the reference returned. + * + * \param topology A valid pointer to a topology handle + * + * \returns A reference to the \ref netloc_network_t associtated with the topology + * \returns NULL on error. + */ +NETLOC_DECLSPEC netloc_network_t* netloc_access_network_ref(netloc_topology_t topology); + +/** + * Get all nodes in the network topology + * + * The user is responsible for calling the lookup table destructor on the nodes + * table (\ref netloc_lookup_table_destroy). + * The user should -not- call the netloc_node_t's destructor on the elements in + * the lookup table. That interface (netloc_dt_node_t_destruct) is not publicly exposed. + * + * \param topology A valid pointer to a topology handle + * \param nodes A lookup table of the nodes requested + * Keys in the table are the \ref netloc_node_t::physical_id's of the \ref netloc_node_t objects + * The values are pointers to \ref netloc_node_t objects + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_get_all_nodes(netloc_topology_t topology, netloc_dt_lookup_table_t *nodes); + +/** + * Get only switch nodes in the network topology + * + * The user is responsible for calling the lookup table destructor on the nodes + * table (\ref netloc_lookup_table_destroy). + * The user should -not- call the netloc_node_t's destructor on the elements in + * the lookup table. That interface (netloc_dt_node_t_destruct) is not publicly exposed. + * + * \param topology A valid pointer to a topology handle + * \param nodes A lookup table of the nodes requested + * Keys in the table are the \ref netloc_node_t::physical_id's of the \ref netloc_node_t objects + * The values are pointers to \ref netloc_node_t objects + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_get_all_switch_nodes(netloc_topology_t topology, netloc_dt_lookup_table_t *nodes); + +/** + * Get only host nodes in the network topology + * + * The user is responsible for calling the lookup table destructor on the nodes + * table (\ref netloc_lookup_table_destroy). + * The user should -not- call the netloc_node_t's destructor on the elements in + * the lookup table. That interface (netloc_dt_node_t_destruct) is not publicly exposed. + * + * \param topology A valid pointer to a topology handle + * \param nodes A lookup table of the nodes requested + * Keys in the table are the \ref netloc_node_t::physical_id's of the \ref netloc_node_t objects + * The values are pointers to \ref netloc_node_t objects + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_get_all_host_nodes(netloc_topology_t topology, netloc_dt_lookup_table_t *nodes); + +/** + * Get all of the edges from the specified node in the network topology. + * There should be one edge for every active port on this node. + * + * The user should not free the array, neither its elements. + * + * \param topology A valid pointer to a topology handle + * \param node A valid pointer to a \ref netloc_node_t from which to get the edges. + * \param num_edges The number of edges in the edges array. + * \param edges An array of \ref netloc_edge_t objects + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_get_all_edges(netloc_topology_t topology, + netloc_node_t *node, + int *num_edges, + netloc_edge_t ***edges); + +/** + * Access the \ref netloc_node_t pointer given a physical identifier (e.g., MAC address, GUID) + * + * The user should -not- call the destructor on the returned value. + * + * \param topology A valid pointer to a topology handle + * \param phy_id The physical identifier to search for (e.g., MAC address, GUID) + * + * \returns A pointer to the \ref netloc_node_t with the specified physical identifier + * \returns NULL if the phy_id is not found. + */ +NETLOC_DECLSPEC netloc_node_t * netloc_get_node_by_physical_id(netloc_topology_t topology, const char * phy_id); + +/** + * Get the "path" from the source to the destination as an ordered array of \ref netloc_edge_t objects + * + * The user is responsible for calling free() on the allocated array, but -not- the elements in the array. + * + * \warning A large API change is in the works for v1.0 that will change how we represent path data. + * + * \param topology A valid pointer to a topology handle + * \param src_node A valid pointer to the source node + * \param dst_node A valid pointer to the destination node + * \param num_edges The number of edges in the path array. + * \param path An ordered array of \ref netloc_edge_t objects from the source to the destination + * \param is_logical If the path should represent the logical or the physical path information. + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_get_path(const netloc_topology_t topology, + netloc_node_t *src_node, + netloc_node_t *dst_node, + int *num_edges, + netloc_edge_t ***path, + bool is_logical); + + +/********************************************************************** + * Export API Functions + **********************************************************************/ +/** + * Exports the network topology to a GraphML formatted file. + * + * \param topology A valid pointer to a topology handle + * \param filename The filename to write the data to + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_topology_export_graphml(netloc_topology_t topology, const char * filename); + +/** + * Exports the network topology to a GEXF formatted file. + * + * \param topology A valid pointer to a topology handle + * \param filename The filename to write the data to + * + * \returns NETLOC_SUCCESS on success + * \returns NETLOC_ERROR upon an error. + */ +NETLOC_DECLSPEC int netloc_topology_export_gexf(netloc_topology_t topology, const char * filename); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/** @} */ + +#endif // _NETLOC_H_ diff --git a/include/netloc/dc.h b/include/netloc/dc.h new file mode 100644 index 0000000000..43d5bdcd1c --- /dev/null +++ b/include/netloc/dc.h @@ -0,0 +1,306 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + * + */ + +#ifndef _NETLOC_DC_H_ +#define _NETLOC_DC_H_ + +#include +#include + +#define _GNU_SOURCE // for asprintf +#include +#include +#include +#include + +#include + +#include + +/** \defgroup netloc_dc_api Data Collection API + * This interface extends the "north bound" (user facing) interface with + * functionlaity to support backed (or "south bound") readers. + * + * Readers should use this API to store netloc structures. The intention + * of this interface is to abstract away the data storage mechanism from + * the readers. + * @{ + */ + +/********************************************************************** + * Enumerated types + **********************************************************************/ + +/********************************************************************** + * Structures + **********************************************************************/ +/** + * \brief Data Collection Handle + * + * THe data collection handle off of which the topology data is stored. + */ +struct netloc_data_collection_handle_t { + /** Point to the network */ + netloc_network_t *network; + + /** Status of the handle : If it is open */ + bool is_open; + /** Status of the handle : If it is read only */ + bool is_read_only; + + /** Unique ID String */ + char * unique_id_str; + + /** Data URI */ + char * data_uri; + + /** Filename: Nodes */ + char * filename_nodes; + + /** Filename: Physical Paths */ + char * filename_physical_paths; + + /** Filename: Logical Paths */ + char * filename_logical_paths; + + /** Lookup table for all node information */ + netloc_dt_lookup_table_t node_list; + + /** Lookup table for all edge information */ + netloc_dt_lookup_table_t edges; + + /** JSON Object for nodes */ + json_t *node_data; + /** (Internal Use only) Accumulation object used to store JSON data while + * the node lists are being built in \ref netloc_dc_append_node */ + json_t *node_data_acc; + + /** JSON Object for paths */ + json_t *path_data; + /** (Internal Use only) Accumulation object */ + json_t *path_data_acc; + + /** JSON Object for paths */ + json_t *phy_path_data; + /** (Internal Use only) Accumulation object */ + json_t *phy_path_data_acc; +}; +typedef struct netloc_data_collection_handle_t netloc_data_collection_handle_t; + + +/********************************************************************** + * Datatype Support Functions + **********************************************************************/ +/** + * Constructor for \ref netloc_data_collection_handle_t + * + * User is responsible for calling the destructor on the handle. + * + * \returns A newly constructed collection handle + */ +NETLOC_DECLSPEC netloc_data_collection_handle_t * netloc_dt_data_collection_handle_t_construct(); + +/** + * Destructor for \ref netloc_data_collection_handle_t + * + * \param handle A pointer to a \ref netloc_data_collection_handle_t previously constructed + * by \ref netloc_dt_data_collection_handle_t_construct. + */ +NETLOC_DECLSPEC int netloc_dt_data_collection_handle_t_destruct(netloc_data_collection_handle_t *handle); + + +/********************************************************************** + * Data Collection API Functions + **********************************************************************/ +/** + * Create a new data collection for this network. + * + * The user is responsible for calling the \ref netloc_dt_data_collection_handle_t_destruct function + * on the pointer returned once finished with the handle. + * + * This function duplicates the \ref netloc_network_t pointer passed to it, so the user is free to call the + * the \ref netloc_dt_network_t_destruct function on the pointer when finished with it. + * + * \param network Network information (must be complete, from a prior call to \ref netloc_find_network) + * \param dir Directory to store the .ndat files (Allowed to be NULL if current working directory) + * + * \returns NULL on error + * \returns A valid data collection handle on success + */ +NETLOC_DECLSPEC netloc_data_collection_handle_t * netloc_dc_create(netloc_network_t *network, char * dir); + +/** + * Close a data collection handle + * This may write out data if the handle was created in \ref netloc_dc_create. + * + * The user is responsible for calling \ref netloc_dt_data_collection_handle_t_destruct on + * the handle when finished with it. The close function does not destruct the handle. + * + * \param handle A valid pointer to a data collection handle + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_close(netloc_data_collection_handle_t *handle); + +/** + * Get the network information from the handle. + * + * \param handle A valid pointer to a data collection handle + * + * \returns NULL if no network information found + * \returns Pointer to a \ref netloc_network_t (caller is responsibe for deallocating this object) + */ +NETLOC_DECLSPEC netloc_network_t * netloc_dc_handle_get_network(netloc_data_collection_handle_t *handle); + +/** + * Get the unique_id_str for the specified handle + * + * \param handle A valid pointer to a data collection handle + * + * \returns NULL if handle is invalid, or has no unique_id_str + * \returns Unique ID string for this handle (caller is responsible for deallocating the string) + */ +NETLOC_DECLSPEC char * netloc_dc_handle_get_unique_id_str(netloc_data_collection_handle_t *handle); + +/** + * Get the unique_id_str for the specified filename (so we might open it) + * + * \param filename Filename with network information + * + * \returns NULL if handle is invalid, or has no unique_id_str + * \returns Unique ID string for this handle (caller is responsible for deallocating the string) + */ +NETLOC_DECLSPEC char * netloc_dc_handle_get_unique_id_str_filename(char *filename); + +/** + * Append \ref netloc_node_t information to the data collection + * + * \param handle A valid pointer to a data collection handle + * \param node A pointer to the \ref netloc_node_t to append + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_append_node(netloc_data_collection_handle_t *handle, netloc_node_t *node); + +/** + * Append \ref netloc_edge_t information to the \ref netloc_node_t structure + * + * This function makes a copy of the edge information before storing it on the node. So + * the user may reuse the edge, and is responsible for calling the edge destructor when + * finished with it (\ref netloc_dt_edge_t_destruct). + * + * \todo JJH It would be easy to allow the node parameter to be NULL and infer to node from the edge. + * \todo JJH Add a check to make sure we only add edges to the source node. + * + * \param handle A valid pointer to a data collection handle + * \param node A valid pointer to a \ref netloc_node_t to append the edge to + * \param edge A valid pointer to the edge information to attach + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_append_edge_to_node(netloc_data_collection_handle_t *handle, netloc_node_t *node, netloc_edge_t *edge); + +/** + * Append \ref netloc_edge_t information to the internal \ref netloc_node_t + * structure by using the physical ID of the node. + * + * Logically, this is similar to doing the following. + * \code + netloc_dc_append_edge_to_node(handle, netloc_dc_get_node_by_physical_id(handle, phy_id), edge); + \endcode + * + * This function makes a copy of the edge information before storing it on the node. So + * the user may reuse the edge, and is responsible for calling the edge destructor when + * finished with it (\ref netloc_dt_edge_t_destruct). + * + * \param handle A valid pointer to a data collection handle + * \param phy_id The physical_id to search for + * \param edge A valid pointer to the edge information to attach + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_append_edge_to_node_by_id(netloc_data_collection_handle_t *handle, char * phy_id, netloc_edge_t *edge); + +/** + * Access a stored node by the physcial identifier (e.g., MAC address, GUID) + * + * The user should -not- call the destructor on the returned value. + * + * \param handle A valid pointer to a data collection handle + * \param phy_id The physical_id to search for + * + * \returns A pointer to the \ref netloc_node_t with the specified physical_id + * \returns NULL if the phy_id is not found. + */ +NETLOC_DECLSPEC netloc_node_t * netloc_dc_get_node_by_physical_id(netloc_data_collection_handle_t *handle, char * phy_id); + +/** + * Append a path between two \ref netloc_node_t objects + * Each edge in this list will be appened to the data collection, if it is not already there. + * + * \param handle A valid pointer to a data collection handle + * \param src_node_id Physical node id of the source + * \param dest_node_id Physical node id of the destination + * \param num_edges Number of edges in the edges array + * \param edges Ordered array of edges from the source to the destination + * \param is_logical If the path is a logical or physical path + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_append_path(netloc_data_collection_handle_t *handle, + const char * src_node_id, + const char * dest_node_id, + int num_edges, netloc_edge_t **edges, + bool is_logical); + +/** + * Compute the path between two nodes + * + * \warning Logical paths is known not to be fully implemented/tested. + * + * \param handle A valid point to a data collection handle + * \param src_node A reference to the source node to compute the path from + * \param dest_node A reference to the destination node to compute the path to + * \param num_edges The number of edges in the edges array + * \param edges An ordered list of edges from the source node to the destination node. + * \param is_logical If the path is a logical or physical path + * + * \returns NETLOC_SUCCESS upon success + * \returns NETLOC_ERROR_NOT_IMPL if is_logical is true + * \returns NETLOC_ERROR otherwise + */ +NETLOC_DECLSPEC int netloc_dc_compute_path_between_nodes(netloc_data_collection_handle_t *handle, + netloc_node_t *src_node, + netloc_node_t *dest_node, + int *num_edges, + netloc_edge_t ***edges, + bool is_logical); + + +/** + * Pretty print the data collection to stdout (Debugging Support) + * + * \param handle A valid pointer to a data collection handle + * + */ +NETLOC_DECLSPEC void netloc_dc_pretty_print(netloc_data_collection_handle_t *handle); + +/** @} */ + +#endif // _NETLOC_DC_H_ diff --git a/include/netloc/map.h b/include/netloc/map.h new file mode 100644 index 0000000000..7a8167d704 --- /dev/null +++ b/include/netloc/map.h @@ -0,0 +1,540 @@ +/* + * Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. + * Copyright © 2013-2014 Inria. All rights reserved. + * + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#ifndef _NETLOC_MAP_H_ +#define _NETLOC_MAP_H_ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + + + +/** \defgroup netloc_map_api_main Netloc Map API - Main objects. + * @{ + */ + +/** A netloc map handle. + * A map contains servers interconnected by networks. + */ +typedef void * netloc_map_t; + +/** A netloc map server handle. */ +typedef void * netloc_map_server_t; +/** A netloc map port handle. + * Servers are interconnected by their ports. + */ +typedef void * netloc_map_port_t; + +/** @} */ + + + +/** \defgroup netloc_map_api_map Netloc Map API - Building maps. + * @{ + */ + +/** + * Create a map + * + * \param map The map object to create. + * + * Once created, the map object needs to be attached to hwloc and netloc data directories. + * + * \returns 0 on success + * \returns -1 on error + */ +NETLOC_DECLSPEC int netloc_map_create(netloc_map_t *map); + +/** + * Loading the hwloc data from a directory into a map. + * + * \param map The map object to attach the data to. + * \param data_dir the data directory to read the hwloc information from. + * + * Actual failures to read the data will cause an error during netloc_map_build(). + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_load_hwloc_data(netloc_map_t map, const char *data_dir); + +/** + * Loading the netloc data from a directory into a map. + * + * \param map The map object to attach the data to. + * \param data_dir the data directory to read the netloc information from. + * + * Actual failures to read the data will cause an error during netloc_map_build(). + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_load_netloc_data(netloc_map_t map, const char *data_dir); + +/** + * Flags to be passed as a OR'ed set to the netloc_map_build() function + */ +enum netloc_map_build_flags_e { + NETLOC_MAP_BUILD_FLAG_COMPRESS_HWLOC = (1<<0) /**< Enable hwloc topology compression if supported. \hideinitializer */ +}; + +/** + * Build a map that was previously created and where hwloc and netloc data were loaded. + * + * Requires the netloc_map_load_hwloc_data() and netloc_map_load_netloc_data() + * functions have been called on the map object. + * + * \param map A netloc map. + * \param flags Any OR'ed set of ::netloc_map_build_flags_e. + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_build(netloc_map_t map, unsigned long flags); + +/** + * Destroy a map. + * + * \param map A netloc map. + * + * This function must be called even if netloc_map_build() failed. + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_destroy(netloc_map_t map); + +/** @} */ + + + +/** \defgroup netloc_map_api_servers_ports Netloc Map API - Manipulating servers and ports + * @{ + */ + +/** + * Returns map ports that are close to a hwloc topology and object. + * + * \param map A netloc map. + * + * \param htopo A hwloc topology that was previously returned by netloc. + * + * \param hobj A optional hwloc object inside the hwloc topology. + * If \p hobj is \c NULL, all ports of that map server match. + * If \p hobj is a I/O device, the matching ports that are returned are connected to that device. + * Otherwise, the matching ports are connected to a I/O device close to \p hobj. + * + * \param ports The array where the corresponding map ports will be stored. + * The caller must be preallocate a number of slots that is given in \p *nrp on input. + * + * \param nrp A pointer to the number of ports. + * On input, specifies how many ports can be stored in the \p ports array. + * On output, specifies how many were actually stored. + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_hwloc2port(netloc_map_t map, + hwloc_topology_t htopo, hwloc_obj_t hobj, + netloc_map_port_t *ports, unsigned *nrp); + +/** + * Return the map port corresponding to a network edge and/or node. + * + * \param map A netloc map. + * \param ntopo A network topology. + * \param nnode A network node where to look for ports. Cannot be \c NULL if nedge is \c NULL. + * \param nedge A network edge where to look for ports. Cannot be \c NULL if nnode is \c NULL. + * \param port The corresponding port returned on success. + * + * \note On input, one (and only one) of nedge and nnode may be NULL. If both are non-NULL, they should match. + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_netloc2port(netloc_map_t map, + netloc_topology_t ntopo, netloc_node_t *nnode, netloc_edge_t *nedge, + netloc_map_port_t *port); + +/** + * Return the network node and edge from a port. + * + * \param port A port to look for edge and node. + * \param ntopo A netloc topology returned on success. + * \param nnode The corresponding network node returned on success, if not \c NULL. + * \param nedge The corresponding network edge returned on success, if not \c NULL. + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_port2netloc(netloc_map_port_t port, + netloc_topology_t *ntopo, netloc_node_t **nnode, netloc_edge_t **nedge); + +/** + * Return the hwloc topology and object from a port. + * + * \param port A port to look for hwloc topology and object. + * \param htopop The corresponding hwloc topology is returned on success. + * \param hobjp The corresponding hwloc object is returned on success, if not \c NULL. + * + * A reference will be taken on the returned hwloc topology, it should be released later with netloc_map_put_hwloc(). + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_port2hwloc(netloc_map_port_t port, + hwloc_topology_t *htopop, hwloc_obj_t *hobjp); + +/** + * Return the hwloc topology from a map server. + * + * \param server A map server. + * \param topology The corresponding hwloc topology is returned on success. + * + * A reference will be taken on the returned hwloc topology, it should be released later with netloc_map_put_hwloc(). + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_server2hwloc(netloc_map_server_t server, hwloc_topology_t *topology); + +/** + * Return a map server from a hwloc topology. + * + * \param map A netloc map. + * + * \param topology A hwloc topology. + * It must have been previously obtained from this netloc map. + * It cannot be another topology loaded by another piece of software. + * + * \param server The corresponding map server returned on success. + * + * \note Server should not be freed by the caller. + * + * \note Another way to find a server is to extract the hostname from a hwloc topology + * with hwloc_obj_get_info_by_name(hwloc_get_root_obj(topology), "HostName") and + * pass it to netloc_map_name2server(). + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_hwloc2server(netloc_map_t map, hwloc_topology_t topology, netloc_map_server_t *server); + +/** + * Release a hwloc topology pointer that we got above. + * + * \param map A netloc map. + * + * \param topology A hwloc topology previously obtained with netloc_map_port2hwloc() + * or netloc_map_server2hwloc(). + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_put_hwloc(netloc_map_t map, hwloc_topology_t topology); + +/* FIXME: uniformize the following get() calls: + * - get_subnets: the caller should free the array, not its contents (no internal array exists). + * - get_servers: the caller should alloc/free the array, not its contents (no internal array exists). + * this one may be huge, but it's only useful for debugging. + * - get_ports: the caller should not alloc/free anything (we return a copy of the internal array). + */ + +/** + * Get an array of subnets existing in a netloc map. + * + * \param map A netloc map. + * \param nr The number of network topologies returned in \p *topos on success. + * \param topos The array of network topologies returned on success. + * + * \note the caller should free the array, not its contents. + * + * \returns 0 on success + * \return -1 on error + */ +NETLOC_DECLSPEC int netloc_map_get_subnets(netloc_map_t map, unsigned *nr, netloc_topology_t **topos); + +/** + * Get the number of servers. + * + * \param map A netloc map. + * + * \returns The number of servers in the map. + */ +NETLOC_DECLSPEC int netloc_map_get_nbservers(netloc_map_t map); + +/** + * Fill the input array with a range of servers. + * + * \param map A netloc map. + * \param first The index of the first server to return. + * \param nr The number of servers to return. + * \param servers A preallocated array that is filled with servers on success. + * + * \note Servers must be allocated (and freed) by the caller. + * + * \note This function is not performance-optimized, it may be slow when first is high. + * + * \returns 0 on success + * \return -1 on error, for instance if \p first and/or \p nr is too high. + */ +NETLOC_DECLSPEC int netloc_map_get_servers(netloc_map_t map, + unsigned first, unsigned nr, + netloc_map_server_t servers[]); + +/** + * Return the map ports from the server. + * + * \param server A map server. + * \param nr The number of ports returned in \p ports on success. + * \param ports The array of map server ports returned on success. + * + * \note The caller should not free the array. + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_get_server_ports(netloc_map_server_t server, + unsigned *nr, netloc_map_port_t **ports); + +/** + * Return the map server from a port. + * + * \param port A map server port. + * \param server The corresponding map server returned on success. + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_port2server(netloc_map_port_t port, + netloc_map_server_t *server); + +/** + * Return the map of a server + * + * \param server A server object + * \param map The corresponding map which the server is part of. + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_server2map(netloc_map_server_t server, netloc_map_t *map); + +/** + * Return the name of a server. + * + * \param server A server object. + * \param name The name associated with that server. + * + * \returns 0 on success + * \returns -1 on error + */ +NETLOC_DECLSPEC int netloc_map_server2name(netloc_map_server_t server, const char **name); + +/** + * Return the map server object from a name. + * + * \param map A netloc map. + * \param name The name of the server. + * \param server The corresponding server object returned on success. + * + * \returns 0 on success + * \returns -1 on error + */ +NETLOC_DECLSPEC int netloc_map_name2server(netloc_map_t map, + const char *name, netloc_map_server_t *server); + +/** @} */ + + + +/** \defgroup netloc_map_api_paths Netloc Map API - Finding paths within a map + * @{ + */ + +/** A netloc map edge. */ +struct netloc_map_edge_s { + /** A netloc map edge type. */ + enum netloc_map_edge_type_e { + NETLOC_MAP_EDGE_TYPE_NETLOC, /**< The edge is a regular network edge. */ + NETLOC_MAP_EDGE_TYPE_HWLOC_PARENT, /**< The edge is a hwloc edge from child to parent. */ + NETLOC_MAP_EDGE_TYPE_HWLOC_HORIZONTAL, /**< The edhe is a horizontal hwloc edge. */ + NETLOC_MAP_EDGE_TYPE_HWLOC_CHILD, /**< The edge is a hwloc edge from parent to child. */ + NETLOC_MAP_EDGE_TYPE_HWLOC_PCI /**< The edge is a hwloc edge between a PCI and a regular object. */ + } type; + union { + struct { + /** A regular network edge. */ + netloc_edge_t *edge; + /** The netloc topology corresponding to the edge. */ + netloc_topology_t topology; + } netloc; + struct { + /** The source object of a hwloc edge. */ + hwloc_obj_t src_obj; + /** The target object of a hwloc edge. */ + hwloc_obj_t dest_obj; + /* The weigth of the hwloc edge. + * + * 1 if there's a direct connection between them. + * Otherwise the amount of edges between them on the shortest path across the hwloc tree. + * Usually latency increases with this weigth while bandwidth decreases. + * For PCI, the weight usually includes an edge from a NUMA node to a hostbridge, + * some edges between PCI bridges/devices, and an edge from a PCI device to a OS device. + */ + unsigned weight; + } hwloc; + }; +}; + +/** Flags to be given as a OR'ed set to netloc_map_paths_build(). + * + * \note By default only horizontal hwloc edges are reported, for instance cross-NUMA links. + */ +enum netloc_map_paths_flag_e { + NETLOC_MAP_PATHS_FLAG_IO = (1UL << 0), /**< Want edges between I/O objects such as PCI NICs and normal hwloc objects */ + NETLOC_MAP_PATHS_FLAG_VERTICAL = (1UL << 1) /**< Want edges between normal hwloc object child and parent, for instance from a core to a NUMA node */ +}; + +/** A netloc map path handle. */ +typedef void * netloc_map_paths_t; + +/** + * Build the list of netloc map paths between two hwloc objects in two hwloc topologies. + * + * \param map A netloc map. + * \param srctopo The hwloc topology of the source server. + * \param srcobj The source hwloc object within the source topology. + * \param dsttopo The hwloc topology of the destination server. + * \param dstobj The destination hwloc object within the destination topology. + * \param flags A OR'ed set of ::netloc_map_paths_flag_e. + * \param paths The paths handle returned on success. It must be freed with netloc_map_paths_destroy() after use. + * \param nr The number of paths contained in the \p paths handle that is returned on success. + * + * \returns 0 on success + * \returns -1 on error + */ +/* FIXME: add an optional subnet */ +/* FIXME: make srcobj/dstobj optional. paths would only contain network edges. */ +NETLOC_DECLSPEC int netloc_map_paths_build(netloc_map_t map, + hwloc_topology_t srctopo, hwloc_obj_t srcobj, + hwloc_topology_t dsttopo, hwloc_obj_t dstobj, + unsigned long flags, + netloc_map_paths_t *paths, unsigned *nr); + +/** + * Get a single path from a previously built netloc map paths handle. + * + * \param paths A paths handle previously returned by netloc_map_paths_build(). + * + * \param idx The index of the path to return. + * + * \param edges The array of map edges returned on success. + * It must not be modified or freed by the caller. + * It is only valid until netloc_map_paths_destroy() is called. + + * \param nr_edges The number of edges returned in the \p edges array on success. + * + * \returns 0 on success + * \returns -1 on error + */ +/* FIXME: also return a subnet pointer. + * would be NULL if we ever have path across multiple subnets with gateways */ +NETLOC_DECLSPEC int netloc_map_paths_get(netloc_map_paths_t paths, unsigned idx, + struct netloc_map_edge_s **edges, unsigned *nr_edges); + +/* FIXME: get the distance (minimal path length, using PCI/NUMA/Eth/IB values */ + +/** + * Destroy a previously built netloc map paths handle. + * + * \param paths A paths handle previously returned by netloc_map_paths_build(). + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_paths_destroy(netloc_map_paths_t paths); + +/** @} */ + + + +/** \defgroup netloc_map_api_misc Netloc Map API - Misc + * @{ + */ + +/** + * Find the neighbors of the specified node out to a given depth in the network. + * + * \todo Brice FIXME: get neighbor nodes at a given distance, within any or a single subnet + * \todo Brice FIXME: get neighbor nodes with enough cores, within any or a single subnet + * \todo Brice This interface is temporary, for debugging + * + * \param map A map object. + * \param hostname The hostname of the node to start from. + * \param depth The depth into the network to search. + * + * \returns 0 on success + * \returns -1 on error + */ +NETLOC_DECLSPEC int netloc_map_find_neighbors(netloc_map_t map, + const char *hostname, unsigned depth); + +/** + * Display the map to stdout (for debugging purposes only). + * + * \param map A map object. + * + * \returns 0 on success + */ +NETLOC_DECLSPEC int netloc_map_dump(netloc_map_t map); + +#ifdef __cplusplus +} +#endif + +/** @} */ + + + +/* + * Ideas + * + * do users come with a predefined list of nodes (1), or are we going to tell them which nodes to use (2) ? + * + * If (1), one may want + * * all distances/routes between all pairs of nodes within my set + * - with an algorithm that is faster than computing for each pair independently + * * there could be a call computing everything and then a handle to retrieve the distance/route + * of a given pair? + * + * If (2), one may want + * * a set of nodes that are very close to each other + * - with or without a source node for this small neighborhood? + * + * For all of them, we may want variants with nodes only, and with cores + * * give me 8 nodes or give enough nodes for 56 cores + * + * Distances can be expressed as + * 3) a number of network hops, with optional link attributes + * 4) a number of intra-node links + * On current architecture, only the number of inter-NUMA links matters. + * If the network ever goes to QPI without PCI, we may have to specify whether + * there are PCI bridges on the path. So keep the model flexible to add new types of links. + * If PCIe ever becomes a networks, we may to specify whether there is + * + * (4) may be negligible against (3), so it's not clear whether we'll want a + * full distance description (such as 1x NUMA + 1x PCI bridge + 2x network links. + * (4) will be useful once you chose the nodes, and now need some cores on these, + * which means we need a distance from cores to a subnet? + */ + +#endif /* _NETLOC_MAP_H_ */ diff --git a/include/netloc/rename.h b/include/netloc/rename.h new file mode 100644 index 0000000000..cd4b6329c9 --- /dev/null +++ b/include/netloc/rename.h @@ -0,0 +1,14 @@ +// +// Copyright © 2013 Cisco Systems, Inc. All rights reserved. +// +// See COPYING in top-level directory. +// + +#ifndef NETLOC_RENAME_H +#define NETLOC_RENAME_H + +#include + +// JMS To be filled in after rapid prototyping... + +#endif /* NETLOC_RENAME_H */ diff --git a/include/netloc/rename_map.h b/include/netloc/rename_map.h new file mode 100644 index 0000000000..30e6a0e541 --- /dev/null +++ b/include/netloc/rename_map.h @@ -0,0 +1,14 @@ +/* + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * + * See COPYING in top-level directory. + */ + +#ifndef NETLOC_MAP_RENAME_H +#define NETLOC_MAP_RENAME_H + +#include + +/* JMS To be filled in after rapid prototyping... */ + +#endif /* NETLOC_MAP_RENAME_H */ diff --git a/include/private/map.h b/include/private/map.h new file mode 100644 index 0000000000..77c18a5210 --- /dev/null +++ b/include/private/map.h @@ -0,0 +1,110 @@ +/* + * Copyright © 2013 Inria. All rights reserved. + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#ifndef _PRIVATE_NETLOC_MAP_H_ +#define _PRIVATE_NETLOC_MAP_H_ + +#include +#include + + +struct netloc_map__subnet; +struct netloc_map__server; + +struct netloc_map__port { + struct netloc_map__subnet * subnet; + struct netloc_map__server * server; + + netloc_edge_t * edge; + + unsigned hwloc_obj_depth; + unsigned hwloc_obj_index; + hwloc_obj_t hwloc_obj; /* cached from depth/index above, + * only non-NULL if the topology hasn't been compressed in the meantime. + */ + + struct netloc_map__port *prev, *next; + + char id[0]; +}; + +struct netloc_map__subnet { + netloc_topology_t topology; + netloc_network_type_t type; + + int port_by_id_ready; + struct netloc_dt_lookup_table port_by_id; + + struct netloc_map__subnet *prev, *next; + + struct netloc_map__port *port_first, *port_last; + unsigned ports_nr; + + char id[0]; +}; + +struct netloc_map__server { + hwloc_topology_t topology; /* NULL if compressed */ +#if HWLOC_API_VERSION >= 0x00010800 + hwloc_topology_diff_t topology_diff; + struct netloc_map__server *topology_diff_refserver; +#endif + + int usecount; /* references from the application, + * or from topology diff for other servers. + * no compression when > 0 + */ + + unsigned nr_ports; + unsigned nr_ports_allocated; + struct netloc_map__port ** ports; + + struct netloc_map__server *prev, *next; + struct netloc_map *map; + + char name[0]; +}; + +enum netloc_map_verbose_flags_e { + NETLOC_MAP_VERBOSE_FLAG_COMPRESS = (1<<0) +}; + +struct netloc_map { + unsigned long flags; + unsigned long verbose_flags; + + unsigned server_ports_nr; /* needed during build, to create large-enough hash tables */ + + char *hwloc_xml_path; + struct netloc_dt_lookup_table server_by_name; + struct netloc_map__server *server_first, *server_last; + unsigned servers_nr; + + char *netloc_data_path; + struct netloc_dt_lookup_table subnet_by_id[NETLOC_NETWORK_TYPE_INVALID]; /* enough room for existing types */ + struct netloc_map__subnet *subnet_first, *subnet_last; + unsigned subnets_nr; + + int merged; +}; + +struct netloc_map__paths { + struct netloc_map *map; + unsigned long flags; + unsigned nr_paths; + struct netloc_map__path { + /* FIXME: cache the subnet */ + unsigned nr_edges; + struct netloc_map_edge_s *edges; + } * paths; +}; + +#endif /* _PRIVATE_NETLOC_MAP_H_ */ diff --git a/include/private/netloc.h b/include/private/netloc.h new file mode 100644 index 0000000000..8d7ab8b514 --- /dev/null +++ b/include/private/netloc.h @@ -0,0 +1,561 @@ +/* + * Copyright © 2014 Cisco Systems, Inc. All rights reserved. + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#ifndef _NETLOC_PRIVATE_H_ +#define _NETLOC_PRIVATE_H_ + +#include +#include + + + +#define NETLOC_EDGE_UID_START 0 +#define NETLOC_EDGE_UID_NULL -1 +#define NETLOC_EDGE_UID_INVALID -2 + + +/********************************************************************** + * Lookup table functionality + **********************************************************************/ +/** + * Lookup table entry + */ +struct netloc_lookup_table_entry_t { + /** Key */ + const char *key; + /** Value pointer */ + void *value; + /** Lookup key */ + unsigned long __key__; +}; +typedef struct netloc_lookup_table_entry_t netloc_lookup_table_entry_t; + +/** + * Lookup table + */ +struct netloc_dt_lookup_table { + /** Table entries array */ + netloc_lookup_table_entry_t **ht_entries; + /** Number of entries in the lookup table */ + size_t ht_size; + /** Number of filled entried in the lookup table */ + size_t ht_used_size; + /** Flags */ + unsigned long flags; +}; + + +/** + * Lookup table iterator + */ +struct netloc_dt_lookup_table_iterator { + /** A pointer to the lookup table */ + struct netloc_dt_lookup_table *htp; + /** The current location in the table */ + size_t loc; + /** Flag if we reached the end */ + bool at_end; +}; + + +/********************************************************************** + * Topology object + **********************************************************************/ +/** + * Topology state used by the API functions. + */ +struct netloc_topology { + /** Copy of the network structure */ + netloc_network_t *network; + + /** Lazy load the node list */ + bool nodes_loaded; + + /** Node List */ + int num_nodes; + netloc_node_t **nodes; + + /** Lookup table for all edge information */ + struct netloc_dt_lookup_table *edges; +}; + + +/********************************************************************** + * Datatype support functionality + **********************************************************************/ +/** + * Constructor for netloc_edge_t + * + * User is responsible for calling the destructor on the handle. + * + * Returns + * A newly allocated pointer to the edge information. + */ +NETLOC_DECLSPEC netloc_edge_t * netloc_dt_edge_t_construct(void); + +/** + * Destructor for netloc_edge_t + * + * \param edge A valid edge handle + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_edge_t_destruct(netloc_edge_t *edge); + +/** + * Copy Constructor for netloc_edge_t + * + * Allocates memory. User is responsible for calling _destruct on the returned pointer. + * Does a shallow copy of the pointers to data. + * + * \param edge A pointer to the edge to duplicate + * + * Returns + * A newly allocated copy of the edge. + */ +NETLOC_DECLSPEC netloc_edge_t * netloc_dt_edge_t_dup(netloc_edge_t *edge); + +/** + * Copy Function for netloc_edge_t + * + * Does not allocate memory for 'to'. Does a shallow copy of the pointers to data. + * + * \param from A pointer to the edge to duplicate + * \param to A pointer to the edge to duplicate into + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_edge_t_copy(netloc_edge_t *from, netloc_edge_t *to); + +/*************************************************/ + +/** + * Constructor for netloc_node_t + * + * User is responsible for calling the destructor on the handle. + * + * Returns + * A newly allocated pointer to the network information. + */ +NETLOC_DECLSPEC netloc_node_t * netloc_dt_node_t_construct(void); + +/** + * Destructor for netloc_node_t + * + * \param node A valid node handle + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_node_t_destruct(netloc_node_t *node); + +/** + * Copy Constructor for netloc_node_t + * + * Allocates memory. User is responsible for calling _destruct on the returned pointer. + * Does a shallow copy of the pointers to data. + * + * \param node A pointer to the node to duplicate + * + * Returns + * A newly allocated copy of the node. + */ +NETLOC_DECLSPEC netloc_node_t * netloc_dt_node_t_dup(netloc_node_t *node); + +/** + * Copy Function for netloc_node_t + * + * Does not allocate memory for 'to'. Does a shallow copy of the pointers to data. + * + * \param from A pointer to the node to duplicate + * \param to A pointer to the node to duplicate into + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_node_t_copy(netloc_node_t *from, netloc_node_t *to); + + +/*************************************************/ + +/** + * Convert a string MAC address (':' separated) into a whole number value + * + * \param mac String MAC address + * + * Returns + * whole number encoding of that value + */ +NETLOC_DECLSPEC unsigned long netloc_dt_convert_mac_str_to_int(const char * mac); + +/** + * Convert a value encoding a MAC address into a string representation (':' separated) + * + * Caller is responsible for free'ing the pointer returned. + * + * \param value encoded value MAC address + * + * Returns + * NULL on error + * otherwise string representation. + */ +NETLOC_DECLSPEC char * netloc_dt_convert_mac_int_to_str(const unsigned long value); + +/** + * Convert a string GUID address (':' separated) into a whole number value + * + * \param guid String GUID address + * + * Returns + * whole number encoding of that value + */ +NETLOC_DECLSPEC unsigned long netloc_dt_convert_guid_str_to_int(const char * guid); + +/** + * Convert a value encoding a GUID address into a string representation (':' separated) + * + * Caller is responsible for free'ing the pointer returned. + * + * \param value encoded value GUID address + * + * Returns + * NULL on error + * otherwise string representation. + */ +NETLOC_DECLSPEC char * netloc_dt_convert_guid_int_to_str(const unsigned long value); + + +/********************************************************************** + * Datatype Support Functions for Lookup Tables + **********************************************************************/ +/** + * Copy a lookup table and all entries + * + * Note that the pointers are copied for each entry. The user is responsible for reference counting. + * + * \param from A pointer to the lookup table to duplicate + * \param to A pointer to the lookup table to duplicate into + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_dt_lookup_table_t_copy(netloc_dt_lookup_table_t from, netloc_dt_lookup_table_t to); + + +/********************************************************************** + * Lookup table API Functions + **********************************************************************/ +enum netloc_lookup_table_init_flag_e { + /* Don't duplicate keys inside the table, assume the given string + * will remain valid and unchanged during the entire table life. + */ + NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY = (1UL<<0) +}; + +/** + * Initialize the lookup table + * + * The lookup table must have been memset'ed to 0 before calling this function. + * + * \param table The lookup table to initialize + * \param size Initial table size (will automaticly expand as necessary) + * \param flags Flags to tune the table, OR'ed set of netloc_lookup_table_init_flag_e. + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_init(netloc_dt_lookup_table_t table, size_t size, unsigned long flags); + +/** + * Access the -allocated- size of the lookup table + * + * \param table A valid pointer to a lookup table + * + * Returns + * The allocated size of the lookup table + */ +NETLOC_DECLSPEC int netloc_lookup_table_size_alloc(netloc_dt_lookup_table_t table); + +/** + * Append an entry to the lookup table + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param value The pointer to associate with this key + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error +*/ +NETLOC_DECLSPEC int netloc_lookup_table_append(netloc_dt_lookup_table_t ht, const char *key, void *value); + +/** + * Append an entry to the lookup table while specifying the integer key to use + * (instead of calculating it) + * + * Warning: This interface is only used internally at the moment. + * Warning: In order for this interface to work, you must use all of the + * *_with_int() methods when interacting with this loopup table. + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param key_int The unique integer key used to find the data + * \param value The pointer to associate with this key + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_append_with_int(netloc_dt_lookup_table_t ht, const char *key, unsigned long key_int, void *value); + +/** + * Access an entry to the lookup table while specifying the integer key to use + * (instead of calculating it) + * + * \warning This interface is only used internally at the moment. + * In order for this interface to work, you must use all of the + * *_with_int() methods when interacting with this loopup table. + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param key_int The unique integer key used to find the data + * + * Returns + * NULL if nothing found + * The pointer stored from a prior call to netloc_lookup_table_append + */ +NETLOC_DECLSPEC void * netloc_lookup_table_access_with_int(netloc_dt_lookup_table_t ht, const char *key, unsigned long key_int); + + +/** + * Replace an entry in the lookup table with the provided value + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param value The pointer to associate with this key + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_replace(netloc_dt_lookup_table_t ht, const char *key, void *value); + +/** + * Replace an entry in the lookup table with the provided value + * while specifying the integer key to use (instead of calculating it) + * + * Warning: This interface is only used internally at the moment. + * Warning: In order for this interface to work, you must use all of the + * *_with_int() methods when interacting with this loopup table. + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param key_int The unique integer key used to find the data + * \param value The pointer to associate with this key + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_replace_with_int(netloc_dt_lookup_table_t ht, const char *key, unsigned long key_int, void *value); + + +/** + * Remove an entry from the lookup table. + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_remove(netloc_dt_lookup_table_t ht, const char *key); + +/** + * Remove an entry from the lookup table. + * while specifying the integer key to use (instead of calculating it) + * + * Warning: This interface is only used internally at the moment. + * Warning: In order for this interface to work, you must use all of the + * *_with_int() methods when interacting with this loopup table. + * + * \param ht A valid pointer to a lookup table + * \param key The key used to find the data + * \param key_int The unique integer key used to find the data + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +NETLOC_DECLSPEC int netloc_lookup_table_remove_with_int(netloc_dt_lookup_table_t ht, const char *key, unsigned long key_int); + +/** + * Pretty print the lookup table to stdout (Debugging Support) + * + * \param ht A valid pointer to a lookup table + */ +NETLOC_DECLSPEC void netloc_lookup_table_pretty_print(netloc_dt_lookup_table_t ht); + +/** + * Get the next key and advance the iterator + * + * \param hti A valid pointer to a lookup table iterator + * + * Returns + * internal lookup key, 0 if error + */ +NETLOC_DECLSPEC unsigned long netloc_lookup_table_iterator_next_key_int(netloc_dt_lookup_table_iterator_t hti); + + +/********************************************************************** + * JSON Encode/Decode functionality + **********************************************************************/ +/** + * JSON Encode the data + * + * \param network A pointer to the network to process + * + * Returns + * A valid json object representing the network information + */ +NETLOC_DECLSPEC json_t* netloc_dt_network_t_json_encode(netloc_network_t *network); + +/** + * JSON Decode the data + * + * User is responsible for calling _destruct on the returned pointer. + * + * \param json_nw A point to a valid json object representing the network information + * + * Returns + * A newly allocated network type filled in with the stored information + */ +NETLOC_DECLSPEC netloc_network_t* netloc_dt_network_t_json_decode(json_t *json_nw); + +/*************************************************/ + +/** + * JSON Encode the data + * + * \param edge A pointer to the edge to process + * + * Returns + * A valid json object representing the edge information + */ +NETLOC_DECLSPEC json_t* netloc_dt_edge_t_json_encode(netloc_edge_t *edge); + +/** + * JSON Decode the data + * + * User is responsible for calling _destruct on the returned pointer. + * + * \param json_edge A point to a valid json object representing the edge information + * + * Returns + * A newly allocated edge type filled in with the stored information + */ +NETLOC_DECLSPEC netloc_edge_t* netloc_dt_edge_t_json_decode(json_t *json_edge); + +/*************************************************/ + +/** + * JSON Encode the data + * + * This will -not- encode the path information + * + * \param node A pointer to the node to process + * + * Returns + * A valid json object representing the node information + */ +NETLOC_DECLSPEC json_t* netloc_dt_node_t_json_encode(netloc_node_t *node); + +/** + * JSON Decode the data + * + * This will -not- decode the path information + * User is responsible for calling _destruct on the returned pointer. + * + * \param json_node A point to a valid json object representing the node information + * + * Returns + * A newly allocated node type filled in with the stored information + */ +NETLOC_DECLSPEC netloc_node_t* netloc_dt_node_t_json_decode(netloc_dt_lookup_table_t edge_table, json_t *json_node); + +/** + * JSON Encode the paths in the data structure + * + * This -only- encodes the path information specified. + * + * \param node A pointer to the node to process + * \param paths A pointer to the paths data to process + * + * Returns + * A valid json object representing the paths information for this node + */ +NETLOC_DECLSPEC json_t* netloc_dt_node_t_json_encode_paths(netloc_node_t *node, netloc_dt_lookup_table_t paths); + +/** + * JSON Decode the paths in the data structure + * + * This will -only- decode the path information + * User is responsible for calling _destruct on the returned pointer. + * + * \param json_all_paths A point to a valid json object representing the path information for a node + * + * Returns + * A newly allocated lookup table for the path information stored in the json object + */ +NETLOC_DECLSPEC netloc_dt_lookup_table_t netloc_dt_node_t_json_decode_paths(netloc_dt_lookup_table_t edge_table, json_t *json_all_paths); + +/*************************************************/ + +/** + * JSON Encode the data + * + * \param table A pointer to a lookup table + * \param (*func) A function to encode the individual values + * + * Returns + * A valid json object representing the lookup table information + */ +NETLOC_DECLSPEC json_t* netloc_dt_lookup_table_t_json_encode(netloc_dt_lookup_table_t table, + json_t* (*func)(const char * key, void *value)); + +/** + * JSON Decode the data + * + * User is responsible for calling _destruct on the returned pointer. + * + * \param json_lt A pointer to a valid json object representing the lookup table information + * \param (*func) A function to decode the individual values + * + * Returns + * A newly allocated lookup table type filled in with the stored information + */ +NETLOC_DECLSPEC netloc_dt_lookup_table_t netloc_dt_lookup_table_t_json_decode(json_t *json_lt, + void * (*func)(const char *key, json_t* json_obj)); + +/*************************************************/ + +#endif // _NETLOC_PRIVATE_H_ diff --git a/netloc.pc.in b/netloc.pc.in new file mode 100644 index 0000000000..a714c9d23d --- /dev/null +++ b/netloc.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: netloc +Description: Network locality detection and management library +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lnetloc -lhwloc +Libs.private: @LIBS@ diff --git a/netloc/Makefile.am b/netloc/Makefile.am new file mode 100644 index 0000000000..1fcf05189a --- /dev/null +++ b/netloc/Makefile.am @@ -0,0 +1,63 @@ +# Copyright © 2014 Cisco Systems, Inc. All rights reserved. +# Copyright © 2014 University of Wisconsin-La Crosse. +# All rights reserved. +# +# See COPYING in top-level directory. +# +# $HEADER$ +# + +DIST_SUBDIRS = jansson + +if BUILD_NETLOC +SUBDIRS = jansson + +AM_CPPFLAGS = \ + $(JANSSON_CPPFLAGS) \ + $(NETLOC_CPPFLAGS) \ + $(HWLOC_CPPFLAGS) + +# If we're in standalone mode, build the installable library. +# Otherwise, build the embedded library. + +if HWLOC_BUILD_STANDALONE +lib_LTLIBRARIES = libnetloc.la +else +noinst_LTLIBRARIES = libnetloc_embedded.la +endif + +sources = \ + support.h \ + topology.c \ + metadata.c \ + api.c \ + support.c \ + data_types.c \ + data_collect.c \ + pathfinder.c \ + lookup_table.c \ + export.c \ + map.c + +ldflags = $(JANSSON_LDFLAGS) + +# Installable library + +libnetloc_la_SOURCES = $(sources) +libnetloc_la_LDFLAGS = $(ldflags) -version-info $(libnetloc_so_version) +libnetloc_la_LIBADD = \ + $(top_builddir)/hwloc/libhwloc.la \ + $(JANSSON_LIBS) + +# Embedded library (note the lack of a .so version number -- that +# intentionally only appears in the installable library). Also note +# the lack of _LDFLAGS -- all libs are added by the upper layer (via +# HWLOC_EMBEDDED_LIBS). + +libnetloc_embedded_la_SOURCES = $(sources) +libnetloc_embedded_la_LDFLAGS = $(ldflags) +libnetloc_embedded_la_LIBADD = \ + $(HWLOC_top_builddir)/hwloc/libhwloc_embedded.la \ + $(JANSSON_LIBS) + +endif BUILD_NETLOC diff --git a/netloc/README b/netloc/README new file mode 100644 index 0000000000..9c99192ebf --- /dev/null +++ b/netloc/README @@ -0,0 +1,61 @@ +# Copyright © 2013 University of Wisconsin-La Crosse. +# All rights reserved. +# +# See COPYING in top-level directory. +# +# $HEADER$ +# + +Some notes on the data format: + +------------------------------------------------------------------------ +** node-style database format + + High level format: + A hash where "physical id => netloc_node" such that, for each + key-value pair (k,v), k == v.get_physical_id(). + + The database contains JSON structured as: + + { Keys = Physical id of the netloc_node the value represents + Values = + { Keys = keywords defined in netloc/src/support.h for netloc_node + Values = JSON string (all but CONNECTIONS) + = + { Keys = Physical id of netloc_node this netloc_node has the edge to + Values = + [ + Values = + { Keys = keywords defined in netloc/src/support.h for netloc_edge + Values = JSON string + } + ] + } + } + } + +------------------------------------------------------------------------ + +** paths-style database format + + High level format: + A hash where "(physical id, physical id) => vector" + such that, for each key-key-value triple (k1,k2,v), + k1 == v.front().get_node_from().get_phy_id() and + k2 == v.back().get_node_to().get_phy_id(). + + The database contains JSON structured as: + + { Keys = Physical ids of souce node + Values = + { Keys = Physical ids of destination node + Values = + [ + Values = + { Keys = keywords defined in netloc/src/support.h for netloc_edge + Values = JSON string + } + ] + } + } +------------------------------------------------------------------------ diff --git a/netloc/api.c b/netloc/api.c new file mode 100644 index 0000000000..d380fd563f --- /dev/null +++ b/netloc/api.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include "support.h" + +/** + * Find all of the nodes that match the netloc_node_type_t + * + * \param topology A valid pointer to a topology handle + * \param nodes A lookup table of nodes that match + * \param nt The netloc_node_type_t to compare against (NULL if anything can match) + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR otherwise + */ +static int find_matching_nodes(struct netloc_topology * topology, struct netloc_dt_lookup_table ** nodes, netloc_node_type_t *nt); + + +/*********************************************************************/ + +netloc_network_t* netloc_access_network_ref(struct netloc_topology * topology) +{ + if( NULL == topology ) { + return NULL; + } + return topology->network; +} + +int netloc_get_all_nodes(struct netloc_topology * topology, struct netloc_dt_lookup_table ** nodes) +{ + return find_matching_nodes(topology, nodes, NULL); +} + +int netloc_get_all_switch_nodes(struct netloc_topology * topology, struct netloc_dt_lookup_table ** switches) +{ + netloc_node_type_t nt = NETLOC_NODE_TYPE_SWITCH; + return find_matching_nodes(topology, switches, &nt); +} + +int netloc_get_all_host_nodes(struct netloc_topology * topology, struct netloc_dt_lookup_table ** hosts) +{ + netloc_node_type_t nt = NETLOC_NODE_TYPE_HOST; + return find_matching_nodes(topology, hosts, &nt); +} + +netloc_node_t * netloc_get_node_by_physical_id(struct netloc_topology * topology, const char * phy_id) +{ + int i, ret; + + if( NULL == phy_id ) { + return NULL; + } + + /* + * Lazy load the node information + */ + if( !topology->nodes_loaded ) { + ret = support_load_json(topology); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the topology\n"); + return NULL; + } + } + + for(i = 0; i < topology->num_nodes; ++i) { + if( 0 == strncmp(topology->nodes[i]->physical_id, phy_id, strlen(topology->nodes[i]->physical_id)) ) { + return topology->nodes[i]; + } + } + + return NULL; +} + +int netloc_get_all_edges(struct netloc_topology * topology, netloc_node_t *node, int *num_edges, netloc_edge_t ***edges) +{ + int ret; + + /* + * Lazy load the node information + */ + if( !topology->nodes_loaded ) { + ret = support_load_json(topology); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the topology\n"); + return ret; + } + } + + // Note that we are just adjusting pointers, -not- copying data + (*num_edges) = node->num_edges; + (*edges) = node->edges; + + return NETLOC_SUCCESS; +} + +int netloc_get_path(const netloc_topology_t topology, + netloc_node_t *src_node, + netloc_node_t *dest_node, + int *num_edges, + netloc_edge_t ***path, + bool is_logical) +{ + int ret; + + /* + * Lazy load the node information + */ + if( !topology->nodes_loaded ) { + ret = support_load_json(topology); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the topology\n"); + return ret; + } + } + + (*num_edges) = 0; + if( is_logical ) { + (*path) = (netloc_edge_t**)netloc_lookup_table_access(src_node->logical_paths, dest_node->physical_id); + } else { + (*path) = (netloc_edge_t**)netloc_lookup_table_access(src_node->physical_paths, dest_node->physical_id); + } + if( NULL == (*path) ) { + return NETLOC_ERROR_NOT_FOUND; + } + + /* Count the edges */ + for((*num_edges) = 0; NULL != (*path)[(*num_edges)]; (*num_edges) += 1) { + ; + } + + return NETLOC_SUCCESS; +} + + +/********************************************************************* + * Support Functions + *********************************************************************/ +static int find_matching_nodes(struct netloc_topology * topology, struct netloc_dt_lookup_table ** nodes, netloc_node_type_t *nt) +{ + int ret; + int i; + + (*nodes) = NULL; + + /* + * Lazy load the node information + */ + if( !topology->nodes_loaded ) { + ret = support_load_json(topology); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the topology\n"); + return ret; + } + } + + /* + * Search the nodes to find all of the nodes, and add them to the hash + */ + for(i = 0; i < topology->num_nodes; ++i) { + if( NULL == nt || (*nt) == topology->nodes[i]->node_type ) { + if( NULL == (*nodes) ) { + (*nodes) = calloc(1, sizeof(**nodes)); + netloc_lookup_table_init((*nodes), 0, 0); + } + + netloc_lookup_table_append( (*nodes), topology->nodes[i]->physical_id, topology->nodes[i]); + } + } + + return NETLOC_SUCCESS; +} diff --git a/netloc/data_collect.c b/netloc/data_collect.c new file mode 100644 index 0000000000..29a9e33417 --- /dev/null +++ b/netloc/data_collect.c @@ -0,0 +1,768 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include +#include + +#include + +#include "support.h" + +/** + * Encode an edge + */ +json_t* dc_encode_edge(const char * key, void *value); + +/** + * Display a netloc_node_t + */ +static void display_node(netloc_node_t *node, char * prefix); + +/** + * Display a netloc_edge_t + */ +static void display_edge(netloc_edge_t *edge, char * prefix); + +/** + * Display a path + */ +static void display_path(const char * src, const char * dest, int num_edges, netloc_edge_t **edges, char * prefix); + +netloc_data_collection_handle_t * netloc_dt_data_collection_handle_t_construct() +{ + netloc_data_collection_handle_t *handle = NULL; + + handle = (netloc_data_collection_handle_t*)malloc(sizeof(netloc_data_collection_handle_t)); + if( NULL == handle ) { + return NULL; + } + + handle->network = NULL; + handle->is_open = false; + handle->is_read_only = false; + handle->unique_id_str = NULL; + handle->data_uri = NULL; + handle->filename_nodes = NULL; + handle->filename_physical_paths = NULL; + handle->filename_logical_paths = NULL; + + handle->node_list = NULL; + + handle->edges = NULL; + + handle->node_data = NULL; + handle->node_data_acc = NULL; + handle->path_data = NULL; + handle->path_data_acc = NULL; + + return handle; +} + +int netloc_dt_data_collection_handle_t_destruct(netloc_data_collection_handle_t *handle) +{ + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_node_t *cur_node = NULL; + netloc_edge_t *cur_edge = NULL; + + if( NULL != handle->network ) { + netloc_dt_network_t_destruct(handle->network); + handle->network = NULL; + } + + handle->is_open = false; + handle->is_read_only = false; + + if( NULL != handle->unique_id_str ) { + free(handle->unique_id_str); + handle->unique_id_str = NULL; + } + + if( NULL != handle->data_uri ) { + free(handle->data_uri); + handle->data_uri = NULL; + } + + if( NULL != handle->filename_nodes ) { + free(handle->filename_nodes); + handle->filename_nodes = NULL; + } + + if( NULL != handle->filename_physical_paths ) { + free(handle->filename_physical_paths); + handle->filename_physical_paths = NULL; + } + + if( NULL != handle->filename_logical_paths ) { + free(handle->filename_logical_paths); + handle->filename_logical_paths = NULL; + } + + if( NULL != handle->node_list ) { + // Make sure to free all of the nodes pointed to in the lookup table + hti = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_node ) { + break; + } + netloc_dt_node_t_destruct(cur_node); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + + netloc_lookup_table_destroy(handle->node_list); + free(handle->node_list); + handle->node_list = NULL; + } + + if( NULL != handle->edges ) { + // Make sure to free all of the edges pointed to in the lookup table + hti = netloc_dt_lookup_table_iterator_t_construct(handle->edges); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_edge = (netloc_edge_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_edge ) { + break; + } + netloc_dt_edge_t_destruct(cur_edge); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + + netloc_lookup_table_destroy(handle->edges); + free(handle->edges); + handle->edges = NULL; + } + + if( NULL != handle->node_data ) { + json_decref(handle->node_data); + handle->node_data = NULL; + // Implied decref of handle->node_data_acc + } + + if( NULL != handle->path_data ) { + json_decref(handle->path_data); + handle->path_data = NULL; + // Implied decref of handle->path_data_acc + } + + free( handle ); + + return NETLOC_SUCCESS; +} + + +netloc_data_collection_handle_t * netloc_dc_create(netloc_network_t *network, char * dir) +{ + netloc_data_collection_handle_t *handle = NULL; + + /* + * Sanity Checks + */ + if( NULL == network ) { + fprintf(stderr, "Error: Null network provided\n"); + return NULL; + } + + if( NETLOC_NETWORK_TYPE_INVALID == network->network_type ) { + fprintf(stderr, "Error: Invalid network type provided\n"); + return NULL; + } + + if( NULL == network->subnet_id ) { + fprintf(stderr, "Error: Null subnet provided\n"); + return NULL; + } + + /* + * Setup the handle to the data files + */ + handle = netloc_dt_data_collection_handle_t_construct(); + + handle->network = netloc_dt_network_t_dup(network); + + asprintf(&handle->unique_id_str, "%s-%s", + netloc_decode_network_type(network->network_type), + network->subnet_id); + + /* + * Setup the data filenames + */ + if( NULL == dir ) { + dir = strdup(""); + } + asprintf(&handle->filename_nodes, "%s/%s-nodes.ndat", dir, handle->unique_id_str); + asprintf(&handle->filename_physical_paths, "%s/%s-phy-paths.ndat", dir, handle->unique_id_str); + asprintf(&handle->filename_logical_paths, "%s/%s-log-paths.ndat", dir, handle->unique_id_str); + asprintf(&handle->data_uri, "file://%s", dir); + + handle->is_open = true; + handle->is_read_only = false; + + /* + * Set metadata and network data in the JSON files + */ + handle->node_data = json_object(); + json_object_set_new(handle->node_data, JSON_NODE_FILE_NETWORK_INFO, netloc_dt_network_t_json_encode(handle->network)); + handle->node_data_acc = json_object(); + + handle->path_data = json_object(); + json_object_set_new(handle->path_data, JSON_NODE_FILE_NETWORK_INFO, netloc_dt_network_t_json_encode(handle->network)); + handle->path_data_acc = json_object(); + + handle->phy_path_data = json_object(); + json_object_set_new(handle->phy_path_data, JSON_NODE_FILE_NETWORK_INFO, netloc_dt_network_t_json_encode(handle->network)); + handle->phy_path_data_acc = json_object(); + + return handle; +} + +int netloc_dc_close(netloc_data_collection_handle_t *handle) +{ + int ret; + + /* + * Sanity Checks + */ + if( NULL == handle ) { + fprintf(stderr, "Error: Null handle provided\n"); + return NETLOC_ERROR; + } + + /* + * If read only, then just close the fd + */ + if( handle->is_read_only ) { + handle->is_open = false; + return NETLOC_SUCCESS; + } + + + /******************** Node and Edge Data **************************/ + + json_object_set_new(handle->node_data, JSON_NODE_FILE_NODE_INFO, handle->node_data_acc); + + /* + * Add the edge lookup table to the node data + */ + json_object_set_new(handle->node_data, JSON_NODE_FILE_EDGE_INFO, netloc_dt_lookup_table_t_json_encode(handle->edges, &dc_encode_edge)); + //netloc_lookup_table_pretty_print(handle->edges); + + /* + * If creating a new file, then write out the data (Node) + */ + ret = json_dump_file(handle->node_data, handle->filename_nodes, JSON_COMPACT); + if( 0 != ret ) { + fprintf(stderr, "Error: Failed to write out node JSON file!\n"); + return NETLOC_ERROR; + } + + json_decref(handle->node_data); + handle->node_data = NULL; + + + /******************** Physical Path Data **************************/ + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_node_t *cur_node = NULL; + + /* + * Add path entries to the JSON file (physical path) + */ + hti = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_node ) { + break; + } + + json_object_set_new(handle->phy_path_data_acc, + cur_node->physical_id, + netloc_dt_node_t_json_encode_paths(cur_node, cur_node->physical_paths)); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + json_object_set_new(handle->phy_path_data, JSON_NODE_FILE_PATH_INFO, handle->phy_path_data_acc); + + /* + * Write out path data + */ + ret = json_dump_file(handle->phy_path_data, handle->filename_physical_paths, JSON_COMPACT); + if( 0 != ret ) { + fprintf(stderr, "Error: Failed to write out physical path JSON file!\n"); + return NETLOC_ERROR; + } + + json_decref(handle->phy_path_data); + handle->phy_path_data = NULL; + + + /******************** Logical Path Data **************************/ + + /* + * Add path entries to the JSON file (logical path) + */ + hti = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_node ) { + break; + } + + json_object_set_new(handle->path_data_acc, + cur_node->physical_id, + netloc_dt_node_t_json_encode_paths(cur_node, cur_node->logical_paths)); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + json_object_set_new(handle->path_data, JSON_NODE_FILE_PATH_INFO, handle->path_data_acc); + + /* + * Write out path data + */ + ret = json_dump_file(handle->path_data, handle->filename_logical_paths, JSON_COMPACT); + if( 0 != ret ) { + fprintf(stderr, "Error: Failed to write out logical path JSON file!\n"); + return NETLOC_ERROR; + } + + json_decref(handle->path_data); + handle->path_data = NULL; + + /* + * Mark file as closed + */ + handle->is_open = false; + + return NETLOC_SUCCESS; +} + +netloc_network_t * netloc_dc_handle_get_network(netloc_data_collection_handle_t *handle) +{ + if( NULL == handle ) { + fprintf(stderr, "Error: Null handle provided\n"); + return NULL; + } + + return handle->network; +} + +char * netloc_dc_handle_get_unique_id_str(netloc_data_collection_handle_t *handle) +{ + if( NULL == handle ) { + fprintf(stderr, "Error: Null handle provided\n"); + return NULL; + } + + return handle->unique_id_str; +} + +char * netloc_dc_handle_get_unique_id_str_filename(char *filename) +{ + if( NULL == filename ) { + fprintf(stderr, "Error: Null filename provided\n"); + return NULL; + } + + // JJH TODO + + return NULL; +} + +int netloc_dc_append_node(netloc_data_collection_handle_t *handle, netloc_node_t *node) +{ + char *key = NULL; + netloc_node_t *cur_node = NULL; + unsigned long key_int; + + /* + * Setup the table for the first node + */ + if(NULL == handle->node_list) { + handle->node_list = calloc(1, sizeof(*handle->node_list)); + netloc_lookup_table_init(handle->node_list, 1, 0); + } + + /* + * Check to see if we have seen this node before + */ + SUPPORT_CONVERT_ADDR_TO_INT(node->physical_id, handle->network->network_type, key_int); + asprintf(&key, "%s", node->physical_id); + cur_node = netloc_lookup_table_access_with_int(handle->node_list, key, key_int); + + if( NULL != cur_node ) { + if( NETLOC_NODE_TYPE_INVALID == cur_node->node_type ) { + // JJH: We should be able to use 'replace' instead of 'remove' and 'append' + // Need to double check ordering. + netloc_lookup_table_remove_with_int(handle->node_list, key, key_int); + } else { + fprintf(stderr, "Warning: A version of this node has already been added to the data set!\n"); + fprintf(stderr, "Warning: Support for updating nodes is not yet available\n"); + // JJH: Delete the old cached version ? replace it? + //json_object_del(handle->node_data_acc, node->physical_id); + } + } + free(key); + key = NULL; + + /* + * Add the node to our list + */ + if( NULL == cur_node ) { + cur_node = netloc_dt_node_t_dup(node); + + cur_node->__uid__ = 0; + + cur_node->physical_id_int = key_int; + asprintf(&key, "%s", node->physical_id); + netloc_lookup_table_append_with_int(handle->node_list, key, key_int, cur_node); + + /* + * Encode the data: Physical ID is the key + */ + json_object_set_new(handle->node_data_acc, node->physical_id, netloc_dt_node_t_json_encode(node)); + } + else if( NETLOC_NODE_TYPE_INVALID == cur_node->node_type ) { + netloc_dt_node_t_copy(node, cur_node); + + cur_node->__uid__ = 0; + + cur_node->physical_id_int = key_int; + asprintf(&key, "%s", node->physical_id); + netloc_lookup_table_append_with_int(handle->node_list, key, key_int, cur_node); + + /* + * Encode the data: Physical ID is the key + */ + json_object_set_new(handle->node_data_acc, node->physical_id, netloc_dt_node_t_json_encode(node)); + } + else { + /* + * Replace the node? + * The code below will fix the cache (node_data_acc), but the handle->node_list needs to also be updated. + */ + //json_object_del(handle->node_data_acc, node->physical_id); + //json_object_set_new(handle->node_data_acc, node->physical_id, netloc_dt_node_t_json_encode(node)); + return NETLOC_ERROR_NOT_IMPL; + } + + return NETLOC_SUCCESS; +} + +int netloc_dc_append_edge_to_node(netloc_data_collection_handle_t *handle, netloc_node_t *node, netloc_edge_t *edge) +{ + char *key = NULL; + netloc_edge_t *found_edge = NULL; + netloc_node_t *found_node = NULL; + unsigned long key_int; + bool is_cached = false; + + /* + * Setup the table for the first edge + */ + if( NULL == handle->edges ) { + handle->edges = calloc(1, sizeof(*handle->edges)); + netloc_lookup_table_init(handle->edges, 1, 0); + } + + /* + * Setup the table for the first node + */ + if(NULL == handle->node_list) { + handle->node_list = calloc(1, sizeof(*handle->node_list)); + netloc_lookup_table_init(handle->node_list, 1, 0); + } + + /* + * Check to see if we have seen this edge before + */ + asprintf(&key, "%d", edge->edge_uid); + found_edge = (netloc_edge_t*)netloc_lookup_table_access(handle->edges, key); + free(key); + key = NULL; + // JJH: Should we be checking the contents of the edge, not just the key? + + /* + * If not add it to the edges lookup table + */ + if( NULL == found_edge ) { + found_edge = netloc_dt_edge_t_dup(edge); + + asprintf(&key, "%d", found_edge->edge_uid); + netloc_lookup_table_append(handle->edges, key, found_edge); + free(key); + key = NULL; + } + + /* + * Update the edge links + * if the node endpoint is not in the list, then add a stub + */ + if( NULL == edge->src_node_id ) { + return NETLOC_ERROR_NOT_FOUND; + } + SUPPORT_CONVERT_ADDR_TO_INT(edge->src_node_id, handle->network->network_type, key_int); + asprintf(&key, "%s", edge->src_node_id); + found_node = netloc_lookup_table_access_with_int(handle->node_list, key, key_int); + + if( NULL == found_node ) { + found_node = netloc_dt_node_t_construct(); + + found_node->physical_id = strdup(edge->src_node_id); + found_node->physical_id_int = key_int; + found_node->node_type = NETLOC_NODE_TYPE_INVALID; + + netloc_lookup_table_append_with_int(handle->node_list, key, key_int, found_node); + } else { + is_cached = true; + } + found_edge->src_node = found_node; + free(key); + key = NULL; + + if( NULL == edge->dest_node_id ) { + return NETLOC_ERROR_NOT_FOUND; + } + asprintf(&key, "%s", edge->dest_node_id); + SUPPORT_CONVERT_ADDR_TO_INT(edge->dest_node_id, handle->network->network_type, key_int); + found_node = netloc_lookup_table_access_with_int(handle->node_list, key, key_int); + + if( NULL == found_node ) { + found_node = netloc_dt_node_t_construct(); + + found_node->physical_id = strdup(edge->dest_node_id); + found_node->physical_id_int = key_int; + found_node->node_type = NETLOC_NODE_TYPE_INVALID; + + netloc_lookup_table_append_with_int(handle->node_list, key, key_int, found_node); + } + found_edge->dest_node = found_node; + free(key); + key = NULL; + + /* + * Add the edge index to the node passed to us + */ + node->num_edge_ids++; + node->edge_ids = (int*)realloc(node->edge_ids, sizeof(int) * node->num_edge_ids); + node->edge_ids[node->num_edge_ids -1] = found_edge->edge_uid; + + node->num_edges++; + node->edges = (netloc_edge_t**)realloc(node->edges, sizeof(netloc_edge_t*) * node->num_edges); + node->edges[node->num_edges -1] = found_edge; + + /* + * Update the cached version of this node + */ + if( is_cached ) { + json_object_del(handle->node_data_acc, node->physical_id); + json_object_set_new(handle->node_data_acc, node->physical_id, netloc_dt_node_t_json_encode(node)); + } + + return NETLOC_SUCCESS; +} + +int netloc_dc_append_path(netloc_data_collection_handle_t *handle, + const char * src_node_id, + const char * dest_node_id, + int num_edges, netloc_edge_t **edges, + bool is_logical) +{ + int i; + netloc_node_t *node = NULL; + int *edge_ids = NULL; + unsigned long key_int; + + /* + * Find the source Node + */ + SUPPORT_CONVERT_ADDR_TO_INT(src_node_id, handle->network->network_type, key_int); + node = netloc_lookup_table_access_with_int( handle->node_list, src_node_id, key_int ); + + if( NULL == node ) { + fprintf(stderr, "Error: node not found in the list (id = %s)\n", src_node_id); + return NETLOC_ERROR; + } + + /* + * Copy the edge id's + * Note: The 'path' storage is not a set of edge pointers, but edge ids. + * It is assumed that the user will push paths into the data collection, but + * not have to retrieve that path from the dc_handle. + */ + edge_ids = (int*)malloc(sizeof(int)* (num_edges+1)); + if( NULL == edge_ids ) { + return NETLOC_ERROR; + } + + for(i = 0; i < num_edges; ++i) { + if( NULL == edges[i] ) { + edge_ids[i] = NETLOC_EDGE_UID_INVALID; + } else { + edge_ids[i] = edges[i]->edge_uid; + } + } + // Null terminated array + edge_ids[num_edges] = NETLOC_EDGE_UID_NULL; + + + /* + * Add the entry to the hash + */ + if( is_logical ) { + if( NULL == node->logical_paths ) { + node->logical_paths = calloc(1, sizeof(*node->logical_paths)); + netloc_lookup_table_init(node->logical_paths, 1, 0); + node->num_log_paths = 0; + } + node->num_log_paths += 1; + netloc_lookup_table_append( node->logical_paths, dest_node_id, edge_ids); + } else { + if( NULL == node->physical_paths ) { + node->physical_paths = calloc(1, sizeof(*node->physical_paths)); + netloc_lookup_table_init(node->physical_paths, 1, 0); + node->num_log_paths = 0; + } + node->num_log_paths += 1; + netloc_lookup_table_append( node->physical_paths, dest_node_id, edge_ids); + } + + + return NETLOC_SUCCESS; +} + +int netloc_dc_append_edge_to_node_by_id(netloc_data_collection_handle_t *handle, char * phy_id, netloc_edge_t *edge) +{ + netloc_node_t *node = NULL; + + node = netloc_dc_get_node_by_physical_id(handle, phy_id); + if( NULL == node ) { + return NETLOC_ERROR_NOT_FOUND; + } + + return netloc_dc_append_edge_to_node(handle, node, edge); +} + + +netloc_node_t * netloc_dc_get_node_by_physical_id(netloc_data_collection_handle_t *handle, char * phy_id) +{ + unsigned long key_int; + + if( NULL == phy_id ) { + return NULL; + } + + SUPPORT_CONVERT_ADDR_TO_INT(phy_id, handle->network->network_type, key_int); + return netloc_lookup_table_access_with_int( handle->node_list, phy_id, key_int ); +} + + +void netloc_dc_pretty_print(netloc_data_collection_handle_t *handle) +{ + int p; + struct netloc_dt_lookup_table_iterator *hti = NULL; + const char * key = NULL; + netloc_edge_t **path = NULL; + int path_len; + struct netloc_dt_lookup_table_iterator *htin = NULL; + netloc_node_t *cur_node = NULL; + + htin = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); + while( !netloc_lookup_table_iterator_at_end(htin) ) { + cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(htin); + if( NULL == cur_node ) { + break; + } + display_node(cur_node, strdup("")); + + printf("Physical Paths\n"); + printf("--------------\n"); + // Display all of the paths from this node to other nodes (if any) + hti = netloc_dt_lookup_table_iterator_t_construct(cur_node->physical_paths); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + key = netloc_lookup_table_iterator_next_key(hti); + if( NULL == key ) { + break; + } + path = (netloc_edge_t**)netloc_lookup_table_access(cur_node->physical_paths, key); + path_len = 0; + for(p = 0; NULL != path[p]; ++p) { + ++path_len; + } + display_path(cur_node->physical_id, + key, path_len, path, strdup("\t")); + } + + printf("Logical Paths\n"); + printf("--------------\n"); + // Display all of the paths from this node to other nodes (if any) + hti = netloc_dt_lookup_table_iterator_t_construct(cur_node->logical_paths); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + key = netloc_lookup_table_iterator_next_key(hti); + if( NULL == key ) { + break; + } + path = (netloc_edge_t**)netloc_lookup_table_access(cur_node->logical_paths, key); + path_len = 0; + for(p = 0; NULL != path[p]; ++p) { + ++path_len; + } + display_path(cur_node->physical_id, + key, path_len, path, strdup("\t")); + } + } + netloc_dt_lookup_table_iterator_t_destruct(htin); +} + +/************************************************************* + * Support Functionality + *************************************************************/ +static void display_node(netloc_node_t *node, char * prefix) +{ + int i; + + printf("%s%s\n", + prefix, + netloc_pretty_print_node_t(node) ); + + for(i = 0; i < node->num_edges; ++i ) { + display_edge(node->edges[i], strdup("\t")); + } +} + +static void display_edge(netloc_edge_t *edge, char * prefix) +{ + printf("%s%s\n", + prefix, + netloc_pretty_print_edge_t(edge)); +} + +static void display_path(const char * src, const char * dest, int num_edges, netloc_edge_t **edges, char * prefix) +{ + int i; + + printf("%sPath (%s) \t (%s)\n", + prefix, + src, dest); + + for(i = 0; i < num_edges; ++i) { + if(i == 0 ) { + printf("\t\t[%s] <--> [%s]", + edges[i]->src_node_id, edges[i]->dest_node_id); + } else { + printf(" <--> [%s]", + edges[i]->dest_node_id); + } + } + printf("\n"); +} + +json_t* dc_encode_edge(const char * key, void *value) +{ + return netloc_dt_edge_t_json_encode((netloc_edge_t*)value); +} diff --git a/netloc/data_types.c b/netloc/data_types.c new file mode 100644 index 0000000000..64b9f2d181 --- /dev/null +++ b/netloc/data_types.c @@ -0,0 +1,1107 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include + +#define _GNU_SOURCE +#include +#include "support.h" + + +#define STRDUP_IF_NOT_NULL(str) (NULL == str ? NULL : strdup(str)) +#define STR_EMPTY_IF_NULL(str) (NULL == str ? "" : str) + +#define ASSIGN_NULL_IF_EMPTY(lhs, obj, key) { \ + const char * str_val = json_string_value( json_object_get( obj, key) ); \ + if( NULL != str_val && strlen(str_val) > 0 ) { \ + lhs = strdup( str_val ); \ + } else { \ + lhs = NULL; \ + } \ +} + +/*******************************************************************/ + +char * netloc_pretty_print_network_t(netloc_network_t* network) +{ + char * str = NULL; + const char * tmp_str = NULL; + + tmp_str = netloc_decode_network_type(network->network_type); + + if( NULL != network->version ) { + asprintf(&str, "%s-%s (version %s)", tmp_str, network->subnet_id, network->version); + } else { + asprintf(&str, "%s-%s", tmp_str, network->subnet_id); + } + + return str; +} + +netloc_network_t * netloc_dt_network_t_construct( ) +{ + netloc_network_t *network = NULL; + + network = (netloc_network_t*)malloc(sizeof(netloc_network_t)); + if( NULL == network ) { + return NULL; + } + + network->network_type = NETLOC_NETWORK_TYPE_INVALID; + network->subnet_id = NULL; + network->data_uri = NULL; + network->node_uri = NULL; + network->phy_path_uri = NULL; + network->path_uri = NULL; + network->description = NULL; + network->version = NULL; + network->userdata = NULL; + + return network; +} + +netloc_network_t * netloc_dt_network_t_dup(netloc_network_t *orig) +{ + netloc_network_t *network = NULL; + + if( NULL == orig ) { + return NULL; + } + + network = netloc_dt_network_t_construct(); + if( NULL == network ) { + return NULL; + } + + netloc_dt_network_t_copy(orig, network); + + return network; +} + +int netloc_dt_network_t_copy(netloc_network_t *from, netloc_network_t *to) +{ + + if( NULL == to || NULL == from ) { + return NETLOC_ERROR; + } + + to->network_type = from->network_type; + + if( NULL != to->subnet_id ) { + free(to->subnet_id); + } + to->subnet_id = STRDUP_IF_NOT_NULL(from->subnet_id); + + if( NULL != to->data_uri ) { + free(to->data_uri); + } + to->data_uri = STRDUP_IF_NOT_NULL(from->data_uri); + + if( NULL != to->node_uri ) { + free(to->node_uri); + } + to->node_uri = STRDUP_IF_NOT_NULL(from->node_uri); + + if( NULL != to->path_uri ) { + free(to->path_uri); + } + to->path_uri = STRDUP_IF_NOT_NULL(from->path_uri); + + if( NULL != to->phy_path_uri ) { + free(to->phy_path_uri); + } + to->phy_path_uri = STRDUP_IF_NOT_NULL(from->phy_path_uri); + + if( NULL != to->description ) { + free(to->description); + } + to->description = STRDUP_IF_NOT_NULL(from->description); + + if( NULL != to->version ) { + free(to->version); + } + to->version = STRDUP_IF_NOT_NULL(from->version); + + to->userdata = from->userdata; + + return NETLOC_SUCCESS; +} + +json_t* netloc_dt_network_t_json_encode(netloc_network_t *network) +{ + json_t *json_nw = NULL; + + json_nw = json_object(); + + json_object_set_new(json_nw, JSON_NODE_FILE_NETWORK_TYPE, json_integer(network->network_type)); + json_object_set_new(json_nw, JSON_NODE_FILE_SUBNET_ID, json_string( STR_EMPTY_IF_NULL(network->subnet_id) )); + + json_object_set_new(json_nw, JSON_NODE_FILE_DESCRIPTION, json_string( STR_EMPTY_IF_NULL(network->description) )); + json_object_set_new(json_nw, JSON_NODE_FILE_META_VERSION, json_string( STR_EMPTY_IF_NULL(network->version) )); + + return json_nw; +} + +netloc_network_t * netloc_dt_network_t_json_decode(json_t *json_nw) +{ + netloc_network_t *network = NULL; + + network = netloc_dt_network_t_construct(); + if( NULL == network ) { + return NULL; + } + + network->network_type = (netloc_network_type_t)json_integer_value( json_object_get( json_nw, JSON_NODE_FILE_NETWORK_TYPE) ); + + ASSIGN_NULL_IF_EMPTY( network->subnet_id, json_nw, JSON_NODE_FILE_SUBNET_ID ); + ASSIGN_NULL_IF_EMPTY( network->description, json_nw, JSON_NODE_FILE_DESCRIPTION ); + ASSIGN_NULL_IF_EMPTY( network->version, json_nw, JSON_NODE_FILE_META_VERSION ); + + return network; +} + +int netloc_dt_network_t_destruct(netloc_network_t * network) +{ + if( NULL != network->subnet_id ) { + free(network->subnet_id); + network->subnet_id = NULL; + } + + if( NULL != network->data_uri ) { + free(network->data_uri); + network->data_uri = NULL; + } + + if( NULL != network->node_uri ) { + free(network->node_uri); + network->node_uri = NULL; + } + + if( NULL != network->path_uri ) { + free(network->path_uri); + network->path_uri = NULL; + } + + if( NULL != network->phy_path_uri ) { + free(network->phy_path_uri); + network->phy_path_uri = NULL; + } + + if( NULL != network->description ) { + free(network->description); + network->description = NULL; + } + + if( NULL != network->version ) { + free(network->version); + network->version = NULL; + } + + if( NULL != network->userdata ) { + network->userdata = NULL; + } + + free(network); + network = NULL; + + return NETLOC_SUCCESS; +} + + +int netloc_dt_network_t_compare(netloc_network_t *a, netloc_network_t *b) +{ + /* Check: Network Type */ + if(a->network_type != b->network_type) { + return NETLOC_CMP_DIFF; + } + + /* Check: Subnet ID */ + if( (NULL == a->subnet_id && NULL != b->subnet_id) || + (NULL != a->subnet_id && NULL == b->subnet_id) ) { + return NETLOC_CMP_DIFF; + } + if( NULL != a->subnet_id && NULL != b->subnet_id ) { + if( 0 != strncmp(a->subnet_id, b->subnet_id, strlen(a->subnet_id)) ) { + return NETLOC_CMP_DIFF; + } + } + + /* Check: Metadata */ + if( (NULL == a->version && NULL != b->version) || + (NULL != a->version && NULL == b->version) ) { + return NETLOC_CMP_SIMILAR; + } + if( NULL != a->version && NULL != b->version ) { + if( 0 != strncmp(a->version, b->version, strlen(a->version)) ) { + return NETLOC_CMP_SIMILAR; + } + } + + return NETLOC_CMP_SAME; +} + + +/*******************************************************************/ + + +netloc_edge_t * netloc_dt_edge_t_construct() +{ + static int cur_uid = NETLOC_EDGE_UID_START; + + netloc_edge_t *edge = NULL; + + edge = (netloc_edge_t*)malloc(sizeof(netloc_edge_t)); + if( NULL == edge ) { + return NULL; + } + + edge->edge_uid = cur_uid; + cur_uid++; + + edge->src_node = NULL; + edge->src_node_id = NULL; + edge->src_node_type = NETLOC_NODE_TYPE_INVALID; + edge->src_port_id = NULL; + + edge->dest_node = NULL; + edge->dest_node_id = NULL; + edge->dest_node_type = NETLOC_NODE_TYPE_INVALID; + edge->dest_port_id = NULL; + + edge->speed = NULL; + edge->width = NULL; + + edge->description = NULL; + + edge->userdata = NULL; + + return edge; +} + +char * netloc_pretty_print_edge_t(netloc_edge_t* edge) +{ + char * str = NULL; + const char * tmp_src_str = NULL; + const char * tmp_dest_str = NULL; + + tmp_src_str = netloc_decode_node_type(edge->src_node_type); + tmp_dest_str = netloc_decode_node_type(edge->dest_node_type); + + asprintf(&str, "%3d (%s) [%23s] %2s [<- %s / %s ->] (%s) [%23s] %2s", + edge->edge_uid, + tmp_src_str, + edge->src_node_id, + edge->src_port_id, + edge->speed, + edge->width, + tmp_dest_str, + edge->dest_node_id, + edge->dest_port_id); + + return str; +} + +netloc_edge_t * netloc_dt_edge_t_dup(netloc_edge_t *orig) +{ + netloc_edge_t * edge = NULL; + + if( NULL == orig ) { + return NULL; + } + + edge = netloc_dt_edge_t_construct(); + if( NULL == edge ) { + return NULL; + } + + netloc_dt_edge_t_copy(orig, edge); + + return edge; +} + +int netloc_dt_edge_t_copy(netloc_edge_t *from, netloc_edge_t *to) +{ + if( NULL == to || NULL == from ) { + return NETLOC_ERROR; + } + + /* Note: Does not copy the edge UID */ + + to->src_node = from->src_node; + + if( NULL != to->src_node_id ) { + free(to->src_node_id); + } + to->src_node_id = STRDUP_IF_NOT_NULL(from->src_node_id); + + to->src_node_type = from->src_node_type; + + if( NULL != to->src_port_id ) { + free(to->src_port_id); + } + to->src_port_id = STRDUP_IF_NOT_NULL(from->src_port_id); + + + to->dest_node = from->dest_node; + + if( NULL != to->dest_node_id ) { + free(to->dest_node_id); + } + to->dest_node_id = STRDUP_IF_NOT_NULL(from->dest_node_id); + + to->dest_node_type = from->dest_node_type; + + if( NULL != to->dest_port_id ) { + free(to->dest_port_id ); + } + to->dest_port_id = STRDUP_IF_NOT_NULL(from->dest_port_id); + + + if( NULL != to->speed ) { + free(to->speed); + } + to->speed = STRDUP_IF_NOT_NULL(from->speed); + + if( NULL != to->width ) { + free(to->width); + } + to->width = STRDUP_IF_NOT_NULL(from->width); + + + if( NULL != to->description ) { + free(to->description); + } + to->description = STRDUP_IF_NOT_NULL(from->description); + + to->userdata = from->userdata; + + return NETLOC_SUCCESS; +} + +json_t* netloc_dt_edge_t_json_encode(netloc_edge_t *edge) +{ + json_t *json_edge = NULL; + + json_edge = json_object(); + + json_object_set_new(json_edge, JSON_NODE_FILE_EDGE_UID, json_integer(edge->edge_uid)); + + json_object_set_new(json_edge, JSON_NODE_FILE_SRC_ID, json_string( STR_EMPTY_IF_NULL(edge->src_node_id))); + json_object_set_new(json_edge, JSON_NODE_FILE_SRC_TYPE, json_integer(edge->src_node_type)); + json_object_set_new(json_edge, JSON_NODE_FILE_SRC_PORT, json_string( STR_EMPTY_IF_NULL(edge->src_port_id))); + + json_object_set_new(json_edge, JSON_NODE_FILE_DEST_ID, json_string( STR_EMPTY_IF_NULL(edge->dest_node_id))); + json_object_set_new(json_edge, JSON_NODE_FILE_DEST_TYPE, json_integer(edge->dest_node_type)); + json_object_set_new(json_edge, JSON_NODE_FILE_DEST_PORT, json_string( STR_EMPTY_IF_NULL(edge->dest_port_id))); + + json_object_set_new(json_edge, JSON_NODE_FILE_EDGE_SPEED, json_string( STR_EMPTY_IF_NULL(edge->speed))); + json_object_set_new(json_edge, JSON_NODE_FILE_EDGE_WIDTH, json_string( STR_EMPTY_IF_NULL(edge->width))); + + json_object_set_new(json_edge, JSON_NODE_FILE_DESCRIPTION, json_string( STR_EMPTY_IF_NULL(edge->description) )); + + return json_edge; +} + +netloc_edge_t* netloc_dt_edge_t_json_decode(json_t *json_edge) +{ + netloc_edge_t *edge = NULL; + + edge = netloc_dt_edge_t_construct(); + if( NULL == edge ) { + return NULL; + } + + edge->edge_uid = json_integer_value( json_object_get( json_edge, JSON_NODE_FILE_EDGE_UID)); + + ASSIGN_NULL_IF_EMPTY( edge->src_node_id, json_edge, JSON_NODE_FILE_SRC_ID); + edge->src_node_type = (netloc_node_type_t)json_integer_value( json_object_get( json_edge, JSON_NODE_FILE_SRC_TYPE)); + ASSIGN_NULL_IF_EMPTY( edge->src_port_id, json_edge, JSON_NODE_FILE_SRC_PORT); + + ASSIGN_NULL_IF_EMPTY( edge->dest_node_id, json_edge, JSON_NODE_FILE_DEST_ID); + edge->dest_node_type = (netloc_node_type_t)json_integer_value( json_object_get( json_edge, JSON_NODE_FILE_DEST_TYPE)); + ASSIGN_NULL_IF_EMPTY( edge->dest_port_id, json_edge, JSON_NODE_FILE_DEST_PORT); + + ASSIGN_NULL_IF_EMPTY( edge->speed, json_edge, JSON_NODE_FILE_EDGE_SPEED); + ASSIGN_NULL_IF_EMPTY( edge->width, json_edge, JSON_NODE_FILE_EDGE_WIDTH); + + ASSIGN_NULL_IF_EMPTY( edge->description, json_edge, JSON_NODE_FILE_DESCRIPTION ); + + return edge; +} + +int netloc_dt_edge_t_destruct(netloc_edge_t * edge) +{ + if( NULL == edge ) { + return NETLOC_SUCCESS; + } + + // Do not free - just nullify the reference + edge->src_node = NULL; + + if( NULL != edge->src_node_id ) { + free(edge->src_node_id); + edge->src_node_id = NULL; + } + + if( NULL != edge->src_port_id ) { + free(edge->src_port_id); + edge->src_port_id = NULL; + } + + // Do not free - just nullify the reference + edge->dest_node = NULL; + + if( NULL != edge->dest_node_id ) { + free(edge->dest_node_id); + edge->dest_node_id = NULL; + } + + if( NULL != edge->dest_port_id ) { + free(edge->dest_port_id); + edge->dest_port_id = NULL; + } + + if( NULL != edge->speed ) { + free(edge->speed); + edge->speed = NULL; + } + + if( NULL != edge->width ) { + free(edge->width); + edge->width = NULL; + } + + if( NULL != edge->description ) { + free(edge->description); + edge->description = NULL; + } + + if( NULL != edge->userdata ) { + edge->userdata = NULL; + } + + free(edge); + edge = NULL; + return NETLOC_SUCCESS; +} + +int netloc_dt_edge_t_compare(netloc_edge_t *a, netloc_edge_t *b) +{ + if( 0 != strncmp(a->src_node_id, b->src_node_id, strlen(a->src_node_id)) ) { + return NETLOC_CMP_DIFF; + } + + if( 0 != strncmp(a->src_port_id, b->src_port_id, strlen(a->src_port_id)) ) { + return NETLOC_CMP_DIFF; + } + + if( 0 != strncmp(a->dest_node_id, b->dest_node_id, strlen(a->dest_node_id)) ) { + return NETLOC_CMP_DIFF; + } + + if( 0 != strncmp(a->dest_port_id, b->dest_port_id, strlen(a->dest_port_id)) ) { + return NETLOC_CMP_DIFF; + } + + return NETLOC_CMP_SAME; +} + + +/*******************************************************************/ + + +netloc_node_t * netloc_dt_node_t_construct() +{ + netloc_node_t *node = NULL; + + node = (netloc_node_t*)malloc(sizeof(netloc_node_t)); + if( NULL == node ) { + return NULL; + } + + node->network_type = NETLOC_NETWORK_TYPE_INVALID; + node->node_type = NETLOC_NODE_TYPE_INVALID; + node->physical_id = NULL; + node->physical_id_int = 0; + node->logical_id = NULL; + node->subnet_id = NULL; + node->description = NULL; + node->userdata = NULL; + node->num_edges = 0; + node->edges = NULL; + + node->num_edge_ids = 0; + node->edge_ids = NULL; + + node->num_phy_paths = 0; + node->physical_paths = calloc(1, sizeof(*node->physical_paths)); + + node->num_log_paths = 0; + node->logical_paths = calloc(1, sizeof(*node->logical_paths)); + + return node; +} + +char * netloc_pretty_print_node_t(netloc_node_t* node) +{ + char * str = NULL; + const char * tmp_nw_type = NULL; + const char * tmp_node_type = NULL; + + tmp_nw_type = netloc_decode_network_type(node->network_type); + tmp_node_type = netloc_decode_node_type(node->node_type); + + asprintf(&str, "(%s-\t %s) [%23s][%lu]/[%15s] %s -- %s (%d/%d edges)", + tmp_nw_type, + tmp_node_type, + node->physical_id, + node->physical_id_int, + node->logical_id, + node->subnet_id, + node->description, + node->num_edges, + node->num_edge_ids); + + return str; +} + +netloc_node_t * netloc_dt_node_t_dup(netloc_node_t *orig) +{ + netloc_node_t * node = NULL; + + if( NULL == orig ) { + return NULL; + } + + node = netloc_dt_node_t_construct(); + if( NULL == node ) { + return NULL; + } + + netloc_dt_node_t_copy(orig, node); + + return node; +} + +int netloc_dt_node_t_copy(netloc_node_t *from, netloc_node_t *to) +{ + int i; + + to->network_type = from->network_type; + to->node_type = from->node_type; + + if( NULL != to->physical_id ) { + free(to->physical_id ); + } + to->physical_id = STRDUP_IF_NOT_NULL(from->physical_id); + + to->physical_id_int = from->physical_id_int; + + if( NULL != to->logical_id ) { + free(to->logical_id); + } + to->logical_id = STRDUP_IF_NOT_NULL(from->logical_id); + + if( NULL != to->subnet_id ) { + free(to->subnet_id); + } + to->subnet_id = STRDUP_IF_NOT_NULL(from->subnet_id); + + if( NULL != to->description ) { + free(to->description); + } + to->description = STRDUP_IF_NOT_NULL(from->description); + + to->userdata = from->userdata; + + + if( NULL != to->edges ) { + for(i = 0; i < to->num_edges; ++i) { + // Nothing to deallocate here, since we just have pointers + to->edges[i] = NULL; + } + free(to->edges); + } + to->num_edges = from->num_edges; + to->edges = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*)*to->num_edges); + for(i = 0; i < to->num_edges; ++i) { + // Copy the pointer to the edge + to->edges[i] = from->edges[i]; + } + + + if( NULL != to->edge_ids ) { + free(to->edge_ids); + } + to->num_edge_ids = from->num_edge_ids; + to->edge_ids = (int*)malloc(sizeof(int) * to->num_edge_ids); + for(i = 0; i < to->num_edge_ids; ++i) { + to->edge_ids[i] = from->edge_ids[i]; + } + + + if( NULL != to->physical_paths ) { + netloc_lookup_table_destroy(to->physical_paths); + free(to->physical_paths); + } + to->num_phy_paths = from->num_phy_paths; + to->physical_paths = calloc(1, sizeof(*to->physical_paths)); + // Note: This does -not- do a deep copy of the keys + netloc_dt_lookup_table_t_copy(from->physical_paths, to->physical_paths); + + + if( NULL != to->logical_paths ) { + netloc_lookup_table_destroy(to->logical_paths); + free(to->logical_paths); + } + to->num_log_paths = from->num_log_paths; + to->logical_paths = calloc(1, sizeof(*to->logical_paths)); + // Note: This does -not- do a deep copy of the keys + netloc_dt_lookup_table_t_copy(from->logical_paths, to->logical_paths); + + return NETLOC_SUCCESS; +} + +json_t* netloc_dt_node_t_json_encode(netloc_node_t *node) +{ + json_t *json_node = NULL; + json_t *json_edges = NULL; + int i; + + json_node = json_object(); + + json_object_set_new(json_node, JSON_NODE_FILE_NETWORK_TYPE, json_integer(node->network_type)); + json_object_set_new(json_node, JSON_NODE_FILE_NODE_TYPE, json_integer(node->node_type)); + + json_object_set_new(json_node, JSON_NODE_FILE_PHY_ID, json_string( STR_EMPTY_IF_NULL(node->physical_id) )); + json_object_set_new(json_node, JSON_NODE_FILE_LOG_ID, json_string( STR_EMPTY_IF_NULL(node->logical_id) )); + // JJH: Subnet ID is duplication from network data... + json_object_set_new(json_node, JSON_NODE_FILE_SUBNET_ID, json_string( STR_EMPTY_IF_NULL(node->subnet_id) )); + + json_object_set_new(json_node, JSON_NODE_FILE_DESCRIPTION, json_string( STR_EMPTY_IF_NULL(node->description) )); + + // Do not encode the edges, just the edge_id's + // We will re-point the edges when we read back in the data set + json_edges = json_array(); + for(i = 0; i < node->num_edge_ids; ++i) { + json_array_append_new(json_edges, json_integer(node->edge_ids[i])); + } + json_object_set_new(json_node, JSON_NODE_FILE_EDGE_ID_LIST, json_edges); + + /** Do not encode the Logical Paths here. **/ + + return json_node; +} + +netloc_node_t* netloc_dt_node_t_json_decode(struct netloc_dt_lookup_table *edge_table, json_t *json_node) +{ + netloc_node_t *node = NULL; + size_t i; + json_t *edge_list = NULL; + char * key = NULL; + + node = netloc_dt_node_t_construct(); + if( NULL == node ) { + return NULL; + } + + node->network_type = (netloc_network_type_t)json_integer_value( json_object_get( json_node, JSON_NODE_FILE_NETWORK_TYPE)); + node->node_type = (netloc_node_type_t)json_integer_value( json_object_get( json_node, JSON_NODE_FILE_NODE_TYPE)); + + ASSIGN_NULL_IF_EMPTY( node->physical_id, json_node, JSON_NODE_FILE_PHY_ID); + SUPPORT_CONVERT_ADDR_TO_INT(node->physical_id, node->network_type, node->physical_id_int); + + ASSIGN_NULL_IF_EMPTY( node->logical_id, json_node, JSON_NODE_FILE_LOG_ID); + ASSIGN_NULL_IF_EMPTY( node->subnet_id, json_node, JSON_NODE_FILE_SUBNET_ID); + + ASSIGN_NULL_IF_EMPTY( node->description, json_node, JSON_NODE_FILE_DESCRIPTION ); + + /* + * While reading in the edge_id list, create pointers to the data in the 'edges' array + * These pointers are for ease of use. The user could lookup the data from the + * lookup table each time they access an edge, but the direct pointer is better. + * We just need to be a bit more careful. + */ + edge_list = json_object_get(json_node, JSON_NODE_FILE_EDGE_ID_LIST); + node->num_edge_ids = json_array_size(edge_list); + node->edge_ids = (int*)malloc(sizeof(int) * node->num_edge_ids); + if( NULL == node->edge_ids ) { + return NULL; + } + + node->num_edges = node->num_edge_ids; + node->edges = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * node->num_edges); + if( NULL == node->edges ) { + return NULL; + } + + for(i = 0; i < node->num_edge_ids; ++i) { + node->edge_ids[i] = json_integer_value( json_array_get(edge_list, i)); + asprintf(&key, "%d", node->edge_ids[i]); + node->edges[i] = (netloc_edge_t*)netloc_lookup_table_access(edge_table, key); + if( NULL == node->edges[i] ) { + printf("Error: Failed to find edge UID %d for the following node\n",node->edge_ids[i]); + printf("Error: \t%s\n", netloc_pretty_print_node_t(node)); + return NULL; + } + + // Update the edge->src_node pointer to reference ourself + // Note: We cannot fill in the dest_node since that node may not exist yet. + // We can only do that after all nodes have been read. + node->edges[i]->src_node = node; + + free(key); + } + + /** Do not decode the Logical Paths here. **/ + + return node; +} + +// NOTE: This assumes that the "paths" is a NULL terminated array of +// edge_ids. Which it will be when called from the data +// collector. Otherwise, it will be netloc_edge_t pointers. +json_t* netloc_dt_node_t_json_encode_paths(netloc_node_t *node, struct netloc_dt_lookup_table *paths) +{ + struct netloc_dt_lookup_table_iterator *hti = NULL; + const char * key = NULL; + int *path = NULL; + + int i; + + json_t *json_all_paths = NULL; + json_t *json_edges = NULL; + + json_all_paths = json_object(); + + // All paths from this source + hti = netloc_dt_lookup_table_iterator_t_construct(paths); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + key = netloc_lookup_table_iterator_next_key(hti); + if( NULL == key ) { + break; + } + + // Path is a NULL terminated array of edge_ids to that destination. + path = (int*)netloc_lookup_table_access(paths, key); + json_edges = json_array(); + for(i = 0; NETLOC_EDGE_UID_NULL != path[i]; ++i) { + json_array_append_new(json_edges, json_integer(path[i])); + } + + // Add path to all paths + // Key = Destination + json_object_set_new(json_all_paths, key, json_edges); + } + + netloc_dt_lookup_table_iterator_t_destruct(hti); + + return json_all_paths; +} + +struct netloc_dt_lookup_table * netloc_dt_node_t_json_decode_paths(struct netloc_dt_lookup_table *edge_table, json_t *json_all_paths) +{ + struct netloc_dt_lookup_table * ht = NULL; + size_t size = 0; + + const char * key1 = NULL; + json_t * value1 = NULL; + + size_t i, j, num_edges = 0; + netloc_edge_t **edges = NULL; + int *edge_ids = NULL; + + char *edge_key = NULL; + + ht = calloc(1, sizeof(*ht)); + + size = json_object_size(json_all_paths); + + netloc_lookup_table_init(ht, size, 0); + + if( 0 == size ) { + return ht; + } + + json_object_foreach(json_all_paths, key1, value1) { + num_edges = json_array_size(value1); + + /* + * Only edge_id's are stored in the JSON file, so we need a temporary + * structure to hold those ids before we translate them to real edge + * pointers. + */ + edge_ids = (int*)malloc(sizeof(int) * (num_edges)); + if( NULL == edge_ids ) { + return NULL; + } + + for(i = 0; i < num_edges; ++i ) { + edge_ids[i] = json_integer_value( json_array_get(value1, i) ); + } + + /* + * Now that we have the edge ids, find the cooresponding pointer in the + * edge_table + */ + edges = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * (num_edges+1)); + if( NULL == edges ) { + free(edge_ids); + edge_ids = NULL; + return NULL; + } + + for(i = 0; i < num_edges; ++i ) { + asprintf(&edge_key, "%d", edge_ids[i]); + edges[i] = (netloc_edge_t*)netloc_lookup_table_access(edge_table, edge_key); + if( NULL == edges[i] ) { + printf("Error: Failed to find edge UID %d while decoding the path:\n", edge_ids[i]); + printf("Error: \t"); + for(j = 0; j < num_edges; ++j) { + printf("%3d,", edge_ids[j]); + } + printf("\n"); + + free(edge_ids); + edge_ids = NULL; + return NULL; + } + free(edge_key); + edge_key = NULL; + } + // Null terminated array + edges[num_edges] = NULL; + + /* + * Add the array of edge pointers to the table with the + * key = destination + */ + netloc_lookup_table_append(ht, key1, edges); + edges = NULL; // Do --not-- free the memory. + + if( NULL != edge_ids ) { + free(edge_ids); + edge_ids = NULL; + } + } + + if( NULL != edge_ids ) { + free(edge_ids); + edge_ids = NULL; + } + + if( NULL != edge_key ) { + free(edge_key); + edge_key = NULL; + } + + return ht; +} + + +int netloc_dt_node_t_destruct(netloc_node_t * node) +{ + int i; + void **path = NULL; + struct netloc_dt_lookup_table_iterator *hti = NULL; + + node->physical_id_int = 0; + + if( NULL != node->physical_id ) { + free(node->physical_id); + node->physical_id = NULL; + } + + if( NULL != node->logical_id ) { + free(node->logical_id); + node->logical_id = NULL; + } + + if( NULL != node->subnet_id ) { + free( node->subnet_id ); + node->subnet_id = NULL; + } + + if( NULL != node->description ) { + free(node->description); + node->description = NULL; + } + + if( NULL != node->userdata ) { + node->userdata = NULL; + } + + if( NULL != node->edges ) { + for(i = 0; i < node->num_edges; ++i ) { + // Do not deallocate the edges here, since we are just holding pointers + // into the lookup table. + node->edges[i] = NULL; + } + + free(node->edges); + node->edges = NULL; + node->num_edges = 0; + } + + if( NULL != node->edge_ids ) { + free(node->edge_ids); + node->edge_ids = NULL; + node->num_edge_ids = 0; + } + + if( NULL != node->physical_paths ) { + // Destruct all of the pointer arrays in the table + hti = netloc_dt_lookup_table_iterator_t_construct(node->physical_paths); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + path = (void*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == path ) { + break; + } + // Path is a NULL terminated array of edge_ids to that destination. + free(path); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + + netloc_lookup_table_destroy(node->physical_paths); + free(node->physical_paths); + node->physical_paths = NULL; + node->num_phy_paths = 0; + } + + if( NULL != node->logical_paths ) { + // Destruct all of the pointer arrays in the table + hti = netloc_dt_lookup_table_iterator_t_construct(node->logical_paths); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + path = (void*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == path ) { + break; + } + // Path is a NULL terminated array of edge_ids to that destination. + free(path); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + + netloc_lookup_table_destroy(node->logical_paths); + free(node->logical_paths); + node->logical_paths = NULL; + node->num_log_paths = 0; + } + + free(node); + node = NULL; + + return NETLOC_SUCCESS; +} + +int netloc_dt_node_t_compare(netloc_node_t *a, netloc_node_t *b) +{ + if( 0 != strncmp(a->physical_id, b->physical_id, strlen(a->physical_id)) ) { + return NETLOC_CMP_DIFF; + } + + return NETLOC_CMP_SAME; +} + +/**************************************************/ +unsigned long netloc_dt_convert_mac_str_to_int(const char * mac) +{ + unsigned long value; + unsigned char addr[6]; + + sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]); + + value = 0; + value = value | addr[0]; + value = value << 8; + value = value | addr[1]; + value = value << 8; + value = value | addr[2]; + value = value << 8; + value = value | addr[3]; + value = value << 8; + value = value | addr[4]; + value = value << 8; + value = value | addr[5]; + + return value; +} + +char * netloc_dt_convert_mac_int_to_str(const unsigned long value) +{ + unsigned char addr[6]; + unsigned long rem; + char * tmp_str = NULL; + + rem = value; + + addr[0] = rem >> 40; + rem = rem << 8; + addr[1] = rem >> 40; + rem = rem << 8; + addr[2] = rem >> 40; + rem = rem << 8; + addr[3] = rem >> 40; + rem = rem << 8; + addr[4] = rem >> 40; + rem = rem << 8; + addr[5] = rem >> 40; + + asprintf(&tmp_str, "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + return tmp_str; +} + +unsigned long netloc_dt_convert_guid_str_to_int(const char * guid) +{ + unsigned long value; + short unsigned int addr[4]; + + sscanf(guid, "%hX:%hX:%hX:%hX", + &addr[0], &addr[1], &addr[2], &addr[3]); + + value = 0; + value = value | addr[0]; + value = value << 16; + value = value | addr[1]; + value = value << 16; + value = value | addr[2]; + value = value << 16; + value = value | addr[3]; + + return value; +} + +char * netloc_dt_convert_guid_int_to_str(const unsigned long value) +{ + short unsigned int addr[4]; + unsigned long rem; + char * tmp_str = NULL; + + rem = value; + + addr[0] = rem >> 48; + rem = rem << 16; + addr[1] = rem >> 48; + rem = rem << 16; + addr[2] = rem >> 48; + rem = rem << 16; + addr[3] = rem >> 48; + + asprintf(&tmp_str, "%04hX:%04hX:%04hX:%04hX", + addr[0], addr[1], addr[2], addr[3]); + + return tmp_str; +} diff --git a/netloc/export.c b/netloc/export.c new file mode 100644 index 0000000000..df990f7478 --- /dev/null +++ b/netloc/export.c @@ -0,0 +1,353 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include + +#include "support.h" + +/** + * Export a netloc_edge_t in GraphML format + */ +static int netloc_topology_export_graphml_edge(const netloc_edge_t *edge, FILE *fh); + +/** + * Export a netloc_edge_t in GEXF format + */ +static int netloc_topology_export_gexf_edge(const netloc_edge_t *edge, FILE *fh); + + +/*****************************************************/ + +int netloc_topology_export_graphml(struct netloc_topology * topology, const char* filename) { + int ret, exit_status = NETLOC_SUCCESS; + + struct netloc_dt_lookup_table *nodes = NULL; + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_node_t *node = NULL; + + int i; + int num_edges; + netloc_edge_t **edges = NULL; + + FILE *fh = NULL; + + /* + * Open the file + */ + fh = fopen(filename, "w"); + if( NULL == fh ) { + fprintf(stderr, "Error: Failed to open the file <%s> for writing of network %s\n", + filename, + netloc_pretty_print_network_t(topology->network) ); + return NETLOC_ERROR; + } + + /* + * Add the header information + */ + fprintf(fh, "\n"); + fprintf(fh, "\n"); + + + /* + * Add some custom data keys + */ + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + fprintf(fh, "\t\n"); + + + /* + * Basic Graph information + */ + fprintf(fh, "\t\n"); + fprintf(fh, "\t\t%s\n", netloc_decode_network_type_readable(topology->network->network_type)); + fprintf(fh, "\t\t%s\n", topology->network->subnet_id); + fprintf(fh, "\t\t%s\n", topology->network->description); + + + /* + * Get hosts and switches + */ + ret = netloc_get_all_nodes(topology, &nodes); + if( NETLOC_SUCCESS != ret ) { + exit_status = ret; + goto cleanup; + } + + /* + * Host information + */ + hti = netloc_dt_lookup_table_iterator_t_construct( nodes ); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == node ) { + break; + } + + // Add a node for this host + fprintf(fh, "\t\t\n", node->physical_id); + fprintf(fh, "\t\t\t%s\n", netloc_decode_node_type_readable(node->node_type) ); + fprintf(fh, "\t\t\t%s\n", netloc_decode_network_type_readable(node->network_type) ); + fprintf(fh, "\t\t\t%s\n", node->subnet_id); + fprintf(fh, "\t\t\t%s\n", node->logical_id); + fprintf(fh, "\t\t\t%s\n", node->physical_id); + fprintf(fh, "\t\t\t%s\n", node->description); + fprintf(fh, "\t\t\n"); + + ret = netloc_get_all_edges(topology, node, &num_edges, &edges); + if( NETLOC_SUCCESS != ret ) { + exit_status = ret; + goto cleanup; + } + + // Add each edge from this host + for(i = 0; i < num_edges; ++i ) { + netloc_topology_export_graphml_edge(edges[i], fh); + } + } + + /* Cleanup */ + netloc_dt_lookup_table_iterator_t_destruct(hti); + netloc_lookup_table_destroy(nodes); + free(nodes); + + fprintf(fh, "\t\n"); + fprintf(fh, "\n"); + + cleanup: + if( NULL != fh ) { + fclose(fh); + fh = NULL; + } + + return exit_status; +} + +int netloc_topology_export_gexf(struct netloc_topology * topology, const char * filename) { + int ret, exit_status = NETLOC_SUCCESS; + + struct netloc_dt_lookup_table *nodes = NULL; + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_node_t *node = NULL; + + int i; + int num_edges; + netloc_edge_t **edges = NULL; + + FILE *fh = NULL; + + /* + * Open the file + */ + fh = fopen(filename, "w"); + if( NULL == fh ) { + fprintf(stderr, "Error: Failed to open the file <%s> for writing of network %s\n", + filename, + netloc_pretty_print_network_t(topology->network) ); + return NETLOC_ERROR; + } + + /* + * Add the header information + */ + fprintf(fh, "\n"); + fprintf(fh, "\n"); + + + /* + * Basic Graph information + */ + fprintf(fh, "\t\n"); + fprintf(fh, "\t\t\n"); + fprintf(fh, "\t\t\t%s %s %s\n", + netloc_decode_network_type_readable(topology->network->network_type), + topology->network->subnet_id, + topology->network->description); + fprintf(fh, "\t\t\n"); + + fprintf(fh, "\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\n"); + + fprintf(fh, "\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + fprintf(fh, "\t\t\n"); + + + /* + * Get hosts and switches + */ + ret = netloc_get_all_nodes(topology, &nodes); + if( NETLOC_SUCCESS != ret ) { + exit_status = ret; + goto cleanup; + } + + /* + * Host information + */ + fprintf(fh, "\t\t\n"); + hti = netloc_dt_lookup_table_iterator_t_construct( nodes ); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == node ) { + break; + } + + fprintf(fh, "\t\t\t\n", node->physical_id); + fprintf(fh, "\t\t\t\t\n"); + fprintf(fh, "\t\t\t\t\t\n", netloc_decode_node_type_readable(node->node_type)); + fprintf(fh, "\t\t\t\t\t\n", netloc_decode_network_type_readable(node->network_type) ); + fprintf(fh, "\t\t\t\t\t\n", node->subnet_id ); + fprintf(fh, "\t\t\t\t\t\n", node->logical_id ); + fprintf(fh, "\t\t\t\t\t\n", node->physical_id ); + fprintf(fh, "\t\t\t\t\t\n", node->description ); + fprintf(fh, "\t\t\t\t\n"); + fprintf(fh, "\t\t\t\n"); + } + + fprintf(fh, "\t\t\n"); + + /* + * All edges next + */ + fprintf(fh, "\t\t\n"); + hti = netloc_dt_lookup_table_iterator_t_construct( nodes ); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == node ) { + break; + } + + ret = netloc_get_all_edges(topology, node, &num_edges, &edges); + if( NETLOC_SUCCESS != ret ) { + exit_status = ret; + goto cleanup; + } + + // Add each edge from this host + for(i = 0; i < num_edges; ++i ) { + netloc_topology_export_gexf_edge(edges[i], fh); + } + } + + fprintf(fh, "\t\t\n"); + + fprintf(fh, "\t\n"); + fprintf(fh, "\n"); + + cleanup: + if( NULL != fh ) { + fclose(fh); + fh = NULL; + } + + return exit_status; +} + + +/******************************************************************* + * Support Functionality + *******************************************************************/ +static int netloc_topology_export_graphml_edge(const netloc_edge_t *edge, FILE *fh) { + const char * src_type = NULL; + const char * target_type = NULL; + + src_type = netloc_decode_node_type_readable( edge->src_node_type ); + target_type = netloc_decode_node_type_readable( edge->dest_node_type ); + + fprintf(fh, "\t\t\n", + edge->src_node_id, + edge->dest_node_id); + + fprintf(fh, "\t\t\t%s\n", src_type); + fprintf(fh, "\t\t\t%s\n", target_type); + + fprintf(fh, "\t\t\t%s\n", edge->src_port_id); + fprintf(fh, "\t\t\t%s\n", edge->dest_port_id); + + fprintf(fh, "\t\t\t%s\n", edge->speed); + fprintf(fh, "\t\t\t%s\n", edge->width); + + fprintf(fh, "\t\t\t%s\n", edge->description); + + fprintf(fh, "\t\t\n"); + + return NETLOC_SUCCESS; +} + +static int netloc_topology_export_gexf_edge(const netloc_edge_t *edge, FILE *fh) { + static int counter = 0; + const char * src_type = NULL; + const char * target_type = NULL; + + src_type = netloc_decode_node_type_readable( edge->src_node_type ); + target_type = netloc_decode_node_type_readable( edge->dest_node_type ); + + fprintf(fh, "\t\t\t\n", + counter, + edge->src_node_id, + edge->dest_node_id ); + + fprintf(fh, "\t\t\t\t\n"); + fprintf(fh, "\t\t\t\t\t\n", src_type); + fprintf(fh, "\t\t\t\t\t\n", target_type); + + fprintf(fh, "\t\t\t\t\t\n", edge->src_port_id ); + fprintf(fh, "\t\t\t\t\t\n", edge->dest_port_id ); + + fprintf(fh, "\t\t\t\t\t\n", edge->speed ); + fprintf(fh, "\t\t\t\t\t\n", edge->width ); + + fprintf(fh, "\t\t\t\t\t\n", edge->description ); + fprintf(fh, "\t\t\t\t\n"); + + fprintf(fh, "\t\t\t\n"); + + return NETLOC_SUCCESS; +} diff --git a/netloc/jansson/CHANGES b/netloc/jansson/CHANGES new file mode 100644 index 0000000000..99d1647d75 --- /dev/null +++ b/netloc/jansson/CHANGES @@ -0,0 +1,583 @@ +Version 2.6 +=========== + +Released 2014-02-11 + +* Security: + + - CVE-2013-6401: The hash function used by the hashtable + implementation has been changed, and is automatically seeded with + random data when the first JSON object is created. This prevents + an attacker from causing large JSON objects with specially crafted + keys perform poorly. + +* New features: + + - `json_object_seed()`: Set the seed value of the hash function. + +* Bug fixes: + + - Include CMake specific files in the release tarball. + +* Documentation: + + - Fix tutorial source to send a User-Agent header, which is now + required by the GitHub API. + + - Set all memory to zero in secure_free() example. + + +Version 2.5 +=========== + +Released 2013-09-19 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and + ``+#``. + + - Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers + as real in the decoder (#123). + + - Add `json_array_foreach()`, paralleling `json_object_foreach()` + (#118). + +* Bug fixes: + + - `json_dumps()` and friends: Don't crash if json is *NULL* and + ``JSON_ENCODE_ANY`` is set. + + - Fix a theoretical integer overflow in `jsonp_strdup()`. + + - Fix `l_isxdigit()` macro (#97). + + - Fix an off-by-one error in `json_array_remove()`. + +* Build: + + - Support CMake in addition to GNU Autotools (#106, #107, #112, + #115, #120, #127). + + - Support building for Android (#109). + + - Don't use ``-Werror`` by default. + + - Support building and testing with VPATH (#93). + + - Fix compilation when ``NDEBUG`` is defined (#128) + +* Tests: + + - Fix a refleak in ``test/bin/json_process.c``. + +* Documentation: + + - Clarify the return value of `json_load_callback_t`. + + - Document how to circumvent problems with separate heaps on Windows. + + - Fix memory leaks and warnings in ``github_commits.c``. + + - Use `json_decref()` properly in tutorial. + +* Other: + + - Make it possible to forward declare ``struct json_t``. + + +Version 2.4 +=========== + +Released 2012-09-23 + +* New features: + + - Add `json_boolean()` macro that returns the JSON true or false + value based on its argument (#86). + + - Add `json_load_callback()` that calls a callback function + repeatedly to read the JSON input (#57). + + - Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of + ``/`` with ``\/``. + +* Bug fixes: + + - Check for and reject NaN and Inf values for reals. Encoding these + values resulted in invalid JSON. + + - Fix `json_real_set()` to return -1 on error. + +* Build: + + - Jansson now builds on Windows with Visual Studio 2010, and + includes solution and project files in ``win32/vs2010/`` + directory. + + - Fix build warnings (#77, #78). + + - Add ``-no-undefined`` to LDFLAGS (#90). + +* Tests: + + - Fix the symbol exports test on Linux/PPC64 (#88). + +* Documentation: + + - Fix typos (#73, #84). + + +Version 2.3.1 +============= + +Released 2012-04-20 + +* Build issues: + + - Only use ``long long`` if ``strtoll()`` is also available. + +* Documentation: + + - Fix the names of library version constants in documentation. (#52) + + - Change the tutorial to use GitHub API v3. (#65) + +* Tests: + + - Make some tests locale independent. (#51) + + - Distribute the library exports test in the tarball. + + - Make test run on shells that don't support the ``export FOO=bar`` + syntax. + + +Version 2.3 +=========== + +Released 2012-01-27 + +* New features: + + - `json_unpack()` and friends: Add support for optional object keys + with the ``{s?o}`` syntax. + + - Add `json_object_update_existing()` and + `json_object_update_missing()`, for updating only existing keys or + only adding missing keys to an object. (#37) + + - Add `json_object_foreach()` for more convenient iteration over + objects. (#45, #46) + + - When decoding JSON, write the number of bytes that were read from + input to ``error.position`` also on success. This is handy with + ``JSON_DISABLE_EOF_CHECK``. + + - Add support for decoding any JSON value, not just arrays or + objects. The support is enabled with the new ``JSON_DECODE_ANY`` + flag. Patch by Andrea Marchesini. (#4) + +* Bug fixes + + - Avoid problems with object's serial number growing too big. (#40, + #41) + + - Decoding functions now return NULL if the first argument is NULL. + Patch by Andrea Marchesini. + + - Include ``jansson_config.h.win32`` in the distribution tarball. + + - Remove ``+`` and leading zeros from exponents in the encoder. + (#39) + + - Make Jansson build and work on MinGW. (#39, #38) + +* Documentation + + - Note that the same JSON values must not be encoded in parallel by + separate threads. (#42) + + - Document MinGW support. + + +Version 2.2.1 +============= + +Released 2011-10-06 + +* Bug fixes: + + - Fix real number encoding and decoding under non-C locales. (#32) + + - Fix identifier decoding under non-UTF-8 locales. (#35) + + - `json_load_file()`: Open the input file in binary mode for maximum + compatiblity. + +* Documentation: + + - Clarify the lifecycle of the result of the ``s`` fromat of + `json_unpack()`. (#31) + + - Add some portability info. (#36) + + - Little clarifications here and there. + +* Other: + + - Some style fixes, issues detected by static analyzers. + + +Version 2.2 +=========== + +Released 2011-09-03 + +* New features: + + - `json_dump_callback()`: Pass the encoder output to a callback + function in chunks. + +* Bug fixes: + + - `json_string_set()`: Check that target is a string and value is + not NULL. + +* Other: + + - Documentation typo fixes and clarifications. + + +Version 2.1 +=========== + +Released 2011-06-10 + +* New features: + + - `json_loadb()`: Decode a string with a given size, useful if the + string is not null terminated. + + - Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON + value. By default, only arrays and objects can be encoded. (#19) + + - Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding + error if any JSON object in the input contins duplicate keys. (#3) + + - Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a + valid JSON input. This allows other data after the JSON data. + +* Bug fixes: + + - Fix an additional memory leak when memory allocation fails in + `json_object_set()` and friends. + + - Clear errno before calling `strtod()` for better portability. (#27) + +* Building: + + - Avoid set-but-not-used warning/error in a test. (#20) + +* Other: + + - Minor clarifications to documentation. + + +Version 2.0.1 +============= + +Released 2011-03-31 + +* Bug fixes: + + - Replace a few `malloc()` and `free()` calls with their + counterparts that support custom memory management. + + - Fix object key hashing in json_unpack() strict checking mode. + + - Fix the parentheses in ``JANSSON_VERSION_HEX`` macro. + + - Fix `json_object_size()` return value. + + - Fix a few compilation issues. + +* Portability: + + - Enhance portability of `va_copy()`. + + - Test framework portability enhancements. + +* Documentation: + + - Distribute ``doc/upgrading.rst`` with the source tarball. + + - Build documentation in strict mode in ``make distcheck``. + + +Version 2.0 +=========== + +Released 2011-02-28 + +This release is backwards incompatible with the 1.x release series. +See the chapter "Upgrading from older versions" in documentation for +details. + +* Backwards incompatible changes: + + - Unify unsigned integer usage in the API: All occurences of + unsigned int and unsigned long have been replaced with size_t. + + - Change JSON integer's underlying type to the widest signed integer + type available, i.e. long long if it's supported, otherwise long. + Add a typedef json_int_t that defines the type. + + - Change the maximum indentation depth to 31 spaces in encoder. This + frees up bits from the flags parameter of encoding functions + `json_dumpf()`, `json_dumps()` and `json_dump_file()`. + + - For future needs, add a flags parameter to all decoding functions + `json_loadf()`, `json_loads()` and `json_load_file()`. + +* New features + + - `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON + values based on a format string. + + - `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple + value extraction and validation functionality based on a format + string. + + - Add column, position and source fields to the ``json_error_t`` + struct. + + - Enhance error reporting in the decoder. + + - ``JANSSON_VERSION`` et al.: Preprocessor constants that define the + library version. + + - `json_set_alloc_funcs()`: Set custom memory allocation functions. + +* Fix many portability issues, especially on Windows. + +* Configuration + + - Add file ``jansson_config.h`` that contains site specific + configuration. It's created automatically by the configure script, + or can be created by hand if the configure script cannot be used. + The file ``jansson_config.h.win32`` can be used without + modifications on Windows systems. + + - Add a section to documentation describing how to build Jansson on + Windows. + + - Documentation now requires Sphinx 1.0 or newer. + + +Version 1.3 +=========== + +Released 2010-06-13 + +* New functions: + + - `json_object_iter_set()`, `json_object_iter_set_new()`: Change + object contents while iterating over it. + + - `json_object_iter_at()`: Return an iterator that points to a + specific object item. + +* New encoding flags: + + - ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object + keys. + +* Bug fixes: + + - Fix an error that occured when an array or object was first + encoded as empty, then populated with some data, and then + re-encoded + + - Fix the situation like above, but when the first encoding resulted + in an error + +* Documentation: + + - Clarify the documentation on reference stealing, providing an + example usage pattern + + +Version 1.2.1 +============= + +Released 2010-04-03 + +* Bug fixes: + + - Fix reference counting on ``true``, ``false`` and ``null`` + - Estimate real number underflows in decoder with 0.0 instead of + issuing an error + +* Portability: + + - Make ``int32_t`` available on all systems + - Support compilers that don't have the ``inline`` keyword + - Require Autoconf 2.60 (for ``int32_t``) + +* Tests: + + - Print test names correctly when ``VERBOSE=1`` + - ``test/suites/api``: Fail when a test fails + - Enhance tests for iterators + - Enhance tests for decoding texts that contain null bytes + +* Documentation: + + - Don't remove ``changes.rst`` in ``make clean`` + - Add a chapter on RFC conformance + + +Version 1.2 +=========== + +Released 2010-01-21 + +* New functions: + + - `json_equal()`: Test whether two JSON values are equal + - `json_copy()` and `json_deep_copy()`: Make shallow and deep copies + of JSON values + - Add a version of all functions taking a string argument that + doesn't check for valid UTF-8: `json_string_nocheck()`, + `json_string_set_nocheck()`, `json_object_set_nocheck()`, + `json_object_set_new_nocheck()` + +* New encoding flags: + + - ``JSON_SORT_KEYS``: Sort objects by key + - ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters + - ``JSON_COMPACT``: Use a compact representation with all unneeded + whitespace stripped + +* Bug fixes: + + - Revise and unify whitespace usage in encoder: Add spaces between + array and object items, never append newline to output. + - Remove const qualifier from the ``json_t`` parameter in + `json_string_set()`, `json_integer_set()` and `json_real_set`. + - Use ``int32_t`` internally for representing Unicode code points + (int is not enough on all platforms) + +* Other changes: + + - Convert ``CHANGES`` (this file) to reStructured text and add it to + HTML documentation + - The test system has been refactored. Python is no longer required + to run the tests. + - Documentation can now be built by invoking ``make html`` + - Support for pkg-config + + +Version 1.1.3 +============= + +Released 2009-12-18 + +* Encode reals correctly, so that first encoding and then decoding a + real always produces the same value +* Don't export private symbols in ``libjansson.so`` + + +Version 1.1.2 +============= + +Released 2009-11-08 + +* Fix a bug where an error message was not produced if the input file + could not be opened in `json_load_file()` +* Fix an assertion failure in decoder caused by a minus sign without a + digit after it +* Remove an unneeded include of ``stdint.h`` in ``jansson.h`` + + +Version 1.1.1 +============= + +Released 2009-10-26 + +* All documentation files were not distributed with v1.1; build + documentation in make distcheck to prevent this in the future +* Fix v1.1 release date in ``CHANGES`` + + +Version 1.1 +=========== + +Released 2009-10-20 + +* API additions and improvements: + + - Extend array and object APIs + - Add functions to modify integer, real and string values + - Improve argument validation + - Use unsigned int instead of ``uint32_t`` for encoding flags + +* Enhance documentation + + - Add getting started guide and tutorial + - Fix some typos + - General clarifications and cleanup + +* Check for integer and real overflows and underflows in decoder +* Make singleton values thread-safe (``true``, ``false`` and ``null``) +* Enhance circular reference handling +* Don't define ``-std=c99`` in ``AM_CFLAGS`` +* Add C++ guards to ``jansson.h`` +* Minor performance and portability improvements +* Expand test coverage + + +Version 1.0.4 +============= + +Released 2009-10-11 + +* Relax Autoconf version requirement to 2.59 +* Make Jansson compile on platforms where plain ``char`` is unsigned +* Fix API tests for object + + +Version 1.0.3 +============= + +Released 2009-09-14 + +* Check for integer and real overflows and underflows in decoder +* Use the Python json module for tests, or simplejson if the json + module is not found +* Distribute changelog (this file) + + +Version 1.0.2 +============= + +Released 2009-09-08 + +* Handle EOF correctly in decoder + + +Version 1.0.1 +============= + +Released 2009-09-04 + +* Fixed broken `json_is_boolean()` + + +Version 1.0 +=========== + +Released 2009-08-25 + +* Initial release diff --git a/netloc/jansson/CMakeLists.txt b/netloc/jansson/CMakeLists.txt new file mode 100644 index 0000000000..0425971fe6 --- /dev/null +++ b/netloc/jansson/CMakeLists.txt @@ -0,0 +1,509 @@ +# Notes: +# +# Author: Paul Harris, June 2012 +# Additions: Joakim Soderberg, Febuary 2013 +# +# Supports: building static/shared, release/debug/etc, can also build html docs +# and some of the tests. +# Note that its designed for out-of-tree builds, so it will not pollute your +# source tree. +# +# TODO 1: Finish implementing tests. api tests are working, but the valgrind +# variants are not flagging problems. +# +# TODO 2: There is a check_exports script that would try and incorporate. +# +# TODO 3: Consolidate version numbers, currently the version number is written +# into: * cmake (here) * autotools (the configure) * source code header files. +# Should not be written directly into header files, autotools/cmake can do +# that job. +# +# Brief intro on how to use cmake: +# > mkdir build (somewhere - we do out-of-tree builds) +# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you +# can only choose one variant: release,debug,etc... and static or shared. +# >> example: +# >> cd build +# >> ccmake -i ../path_to_jansson_dir +# >> inside, configure your options. press C until there are no lines +# with * next to them. +# >> note, I like to configure the 'install' path to ../install, so I get +# self-contained clean installs I can point other projects to. +# >> press G to 'generate' the project files. +# >> make (to build the project) +# >> make install +# >> make test (to run the tests, if you enabled them) +# +# Brief description on how it works: +# There is a small heirachy of CMakeLists.txt files which define how the +# project is built. +# Header file detection etc is done, and the results are written into config.h +# and jansson_config.h, which are generated from the corresponding +# config.h.cmake and jansson_config.h.cmake template files. +# The generated header files end up in the build directory - not in +# the source directory. +# The rest is down to the usual make process. + + + +cmake_minimum_required (VERSION 2.8) +# required for exports? cmake_minimum_required (VERSION 2.8.6) +project (jansson C) + +# Options +OPTION (BUILD_SHARED_LIBS "Build shared libraries." OFF) +OPTION (USE_URANDOM "Use /dev/urandom to seed the hash function." ON) +OPTION (USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON) + +if (MSVC) + # This option must match the settings used in your program, in particular if you + # are linking statically + OPTION( STATIC_CRT "Link the static CRT libraries" OFF ) +endif () + +# Set some nicer output dirs. +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + +# Give the debug version a different postfix for windows, +# so both the debug and release version can be built in the +# same build-tree on Windows (MSVC). +if (WIN32) + SET (CMAKE_DEBUG_POSTFIX "_d") +else (WIN32) +endif (WIN32) + +# This is how I thought it should go +# set (JANSSON_VERSION "2.3.1") +# set (JANSSON_SOVERSION 2) + +set(JANSSON_DISPLAY_VERSION "2.6") + +# This is what is required to match the same numbers as automake's +set (JANSSON_VERSION "4.6.0") +set (JANSSON_SOVERSION 4) + +# for CheckFunctionKeywords +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +INCLUDE (CheckCSourceCompiles) +include (CheckFunctionExists) +include (CheckFunctionKeywords) +include (CheckIncludeFiles) +include (CheckTypeSize) + +if (MSVC) + # Turn off Microsofts "security" warnings. + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" ) + + if (STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "/MT") + set(CMAKE_C_FLAGS_DEBUG "/MTd") + endif() + +endif() + +if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_C_FLAGS "-fPIC") +endif() + +check_include_files (endian.h HAVE_ENDIAN_H) +check_include_files (fcntl.h HAVE_FCNTL_H) +check_include_files (sched.h HAVE_SCHED_H) +check_include_files (unistd.h HAVE_UNISTD_H) +check_include_files (sys/param.h HAVE_SYS_PARAM_H) +check_include_files (sys/stat.h HAVE_SYS_STAT_H) +check_include_files (sys/time.h HAVE_SYS_TIME_H) +check_include_files (sys/time.h HAVE_SYS_TYPES_H) + +check_function_exists (close HAVE_CLOSE) +check_function_exists (getpid HAVE_GETPID) +check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists (open HAVE_OPEN) +check_function_exists (read HAVE_READ) +check_function_exists (sched_yield HAVE_SCHED_YIELD) + +# Check for the int-type includes +check_include_files (stdint.h HAVE_STDINT_H) + +# Check our 64 bit integer sizes +check_type_size (__int64 __INT64) +check_type_size (int64_t INT64_T) +check_type_size ("long long" LONG_LONG_INT) + +# Check our 32 bit integer sizes +check_type_size (int32_t INT32_T) +check_type_size (__int32 __INT32) +check_type_size ("long" LONG_INT) +check_type_size ("int" INT) +if (HAVE_INT32_T) + set (JSON_INT32 int32_t) +elseif (HAVE___INT32) + set (JSON_INT32 __int32) +elseif (HAVE_LONG_INT AND (${LONG_INT} EQUAL 4)) + set (JSON_INT32 long) +elseif (HAVE_INT AND (${INT} EQUAL 4)) + set (JSON_INT32 int) +else () + message (FATAL_ERROR "Could not detect a valid 32-bit integer type") +endif () + +check_type_size (uint32_t UINT32_T) +check_type_size (__uint32 __UINT32) +check_type_size ("unsigned long" UNSIGNED_LONG_INT) +check_type_size ("unsigned int" UNSIGNED_INT) +if (HAVE_UINT32_T) + set (JSON_UINT32 uint32_t) +elseif (HAVE___UINT32) + set (JSON_UINT32 __uint32) +elseif (HAVE_UNSIGNED_LONG_INT AND (${UNSIGNED_LONG_INT} EQUAL 4)) + set (JSON_UINT32 "unsigned long") +elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 4)) + set (JSON_UINT32 "unsigned int") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type") +endif () + +# Check for ssize_t and SSIZE_T existance. +check_type_size(ssize_t SSIZE_T) +check_type_size(SSIZE_T UPPERCASE_SSIZE_T) +if(NOT HAVE_SSIZE_T) + if(HAVE_UPPERCASE_SSIZE_T) + set(JSON_SSIZE SSIZE_T) + else() + set(JSON_SSIZE int) + endif() +endif() +set(CMAKE_EXTRA_INCLUDE_FILES "") + +# Check for all the variants of strtoll +check_function_exists (strtoll HAVE_STRTOLL) +check_function_exists (strtoq HAVE_STRTOQ) +check_function_exists (_strtoi64 HAVE__STRTOI64) + +# Figure out what variant we should use +if (HAVE_STRTOLL) + set (JSON_STRTOINT strtoll) +elseif (HAVE_STRTOQ) + set (JSON_STRTOINT strtoq) +elseif (HAVE__STRTOI64) + set (JSON_STRTOINT _strtoi64) +else () + # fallback to strtol (32 bit) + # this will set all the required variables + set (JSON_STRTOINT strtol) + set (JSON_INT_T long) + set (JSON_INTEGER_FORMAT "\"ld\"") +endif () + +# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function. +# detect what to use for the 64 bit type. +# Note: I will prefer long long if I can get it, as that is what the automake system aimed for. +if (NOT DEFINED JSON_INT_T) + if (HAVE_LONG_LONG_INT AND (${LONG_LONG_INT} EQUAL 8)) + set (JSON_INT_T "long long") + elseif (HAVE_INT64_T) + set (JSON_INT_T int64_t) + elseif (HAVE___INT64) + set (JSON_INT_T __int64) + else () + message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent") + endif () + + # Apparently, Borland BCC and MSVC wants I64d, + # Borland BCC could also accept LD + # and gcc wants ldd, + # I am not sure what cygwin will want, so I will assume I64d + + if (WIN32) # matches both msvc and cygwin + set (JSON_INTEGER_FORMAT "\"I64d\"") + else () + set (JSON_INTEGER_FORMAT "\"lld\"") + endif () +endif () + + +# If locale.h and localeconv() are available, define to 1, otherwise to 0. +check_include_files (locale.h HAVE_LOCALE_H) +check_function_exists (localeconv HAVE_LOCALECONV) + +if (HAVE_LOCALECONV AND HAVE_LOCALE_H) + set (JSON_HAVE_LOCALECONV 1) +else () + set (JSON_HAVE_LOCALECONV 0) +endif () + +# check if we have setlocale +check_function_exists (setlocale HAVE_SETLOCALE) + +# Check what the inline keyword is. +# Note that the original JSON_INLINE was always set to just 'inline', so this goes further. +check_function_keywords("inline") +check_function_keywords("__inline") +check_function_keywords("__inline__") + +if (HAVE_INLINE) + set (JSON_INLINE inline) +elseif (HAVE___INLINE) + set (JSON_INLINE __inline) +elseif (HAVE___INLINE__) + set (JSON_INLINE __inline__) +else (HAVE_INLINE) + # no inline on this platform + set (JSON_INLINE) +endif (HAVE_INLINE) + +# Find our snprintf +check_function_exists (snprintf HAVE_SNPRINTF) +check_function_exists (_snprintf HAVE__SNPRINTF) + +if (HAVE_SNPRINTF) + set (JSON_SNPRINTF snprintf) +elseif (HAVE__SNPRINTF) + set (JSON_SNPRINTF _snprintf) +endif () + +check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); return 0; } " HAVE_SYNC_BUILTINS) +check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE); return 0; }" HAVE_ATOMIC_BUILTINS) + +# Create pkg-conf file. +# (We use the same files as ./configure does, so we +# have to defined the same variables used there). +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR lib) +endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) +set(VERSION ${JANSSON_DISPLAY_VERSION}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY) + +# configure the public config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/config.h) + +# and tell the source code to include it +add_definitions (-DHAVE_CONFIG_H) + +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) + +# Add the lib sources. +file (GLOB C_FILES src/*.c) + +if (BUILD_SHARED_LIBS) + + add_library (jansson SHARED ${C_FILES} src/jansson.def) + + set_target_properties (jansson PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) + +else () + + add_library (jansson ${C_FILES}) + +endif () + +# LIBRARY for linux +# RUNTIME for windows (when building shared) +install (TARGETS jansson + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION bin +) + +install (FILES + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION include) + +install (FILES + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# For building Documentation (uses Sphinx) +OPTION (BUILD_DOCS "Build documentation (uses python-sphinx)." ON) +if (BUILD_DOCS) + find_package(Sphinx) + + if (NOT SPHINX_FOUND) + message(WARNING "Sphinx not found. Cannot generate documentation! + Set -DBUILD_DOCS=0 to get rid of this message.") + else() + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Your Sphinx version is too old! + This project requires Sphinx v1.0 or above to produce + proper documentation (you have v${Sphinx_VERSION_STRING}). + You will get output but it will have errors.") + endif() + + # configured documentation tools and intermediate build results + set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") + + # Sphinx cache with pickled ReST documents + set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") + + # CMake could be used to build the conf.py file too, + # eg it could automatically write the version of the program or change the theme. + # if(NOT DEFINED SPHINX_THEME) + # set(SPHINX_THEME default) + # endif() + # + # if(NOT DEFINED SPHINX_THEME_DIR) + # set(SPHINX_THEME_DIR) + # endif() + # + # configure_file( + # "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + # "${BINARY_BUILD_DIR}/conf.py" + # @ONLY) + + # TODO: Add support for all sphinx builders: http://sphinx-doc.org/builders.html + + # Add documentation targets. + set(DOC_TARGETS html) + + OPTION(BUILD_MAN "Create a target for building man pages." ON) + + if (BUILD_MAN) + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.") + else() + list(APPEND DOC_TARGETS man) + endif() + endif() + + OPTION(BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF) + + if (BUILD_LATEX) + find_package(LATEX) + + if (NOT LATEX_COMPILER) + message("Couldn't find Latex, can't build latex docs using Sphinx") + else() + message("Latex found! If you have problems building, see Sphinx documentation for required Latex packages.") + list(APPEND DOC_TARGETS latex) + endif() + endif() + + # The doc target will build all documentation targets. + add_custom_target(doc) + + foreach (DOC_TARGET ${DOC_TARGETS}) + add_custom_target(${DOC_TARGET} + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b ${DOC_TARGET} + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${CMAKE_CURRENT_BINARY_DIR}/doc/${DOC_TARGET}" + COMMENT "Building ${DOC_TARGET} documentation with Sphinx") + + add_dependencies(doc ${DOC_TARGET}) + endforeach() + + message("Building documentation enabled for: ${DOC_TARGETS}") + endif() +endif () + + +OPTION (WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF) + +if (NOT WITHOUT_TESTS) + OPTION (TEST_WITH_VALGRIND "Enable valgrind tests." OFF) + + ENABLE_TESTING() + + if (TEST_WITH_VALGRIND) + # TODO: Add FindValgrind.cmake instead of having a hardcoded path. + + # enable valgrind + set(CMAKE_MEMORYCHECK_COMMAND valgrind) + set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS + "--leak-check=full --show-reachable=yes --track-origins=yes -q") + + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") + separate_arguments(MEMCHECK_COMMAND) + endif () + + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement -Werror) + endif () + + set(api_tests + test_array + test_copy + test_dump + test_dump_callback + test_equal + test_load + test_loadb + test_number + test_object + test_pack + test_simple + test_unpack) + + # Doing arithmetic on void pointers is not allowed by Microsofts compiler + # such as secure_malloc and secure_free is doing, so exclude it for now. + if (NOT MSVC) + list(APPEND api_tests test_memory_funcs) + endif() + + # Helper macro for building and linking a test program. + macro(build_testprog name dir) + add_executable(${name} ${dir}/${name}.c) + add_dependencies(${name} jansson) + target_link_libraries(${name} jansson) + endmacro(build_testprog) + + # Create executables and tests/valgrind tests for API tests. + foreach (test ${api_tests}) + build_testprog(${test} ${PROJECT_SOURCE_DIR}/test/suites/api) + add_test(${test} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test}) + + if (TEST_WITH_VALGRIND) + add_test(memcheck_${test} ${MEMCHECK_COMMAND} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test}) + endif () + endforeach () + + # Test harness for the suites tests. + build_testprog(json_process ${PROJECT_SOURCE_DIR}/test/bin) + + set(SUITES encoding-flags valid invalid invalid-unicode) + foreach (SUITE ${SUITES}) + file(GLOB TESTDIRS ${jansson_SOURCE_DIR}/test/suites/${SUITE}/*) + foreach (TESTDIR ${TESTDIRS}) + if (IS_DIRECTORY ${TESTDIR}) + get_filename_component(TNAME ${TESTDIR} NAME) + add_test(${SUITE}__${TNAME} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process ${TESTDIR}) + if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip) + add_test(${SUITE}__${TNAME}__strip + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process --strip ${TESTDIR}) + endif () + endif () + endforeach () + endforeach () + + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS json_process ${api_tests}) +endif () diff --git a/netloc/jansson/LICENSE b/netloc/jansson/LICENSE new file mode 100644 index 0000000000..e4174d7c3a --- /dev/null +++ b/netloc/jansson/LICENSE @@ -0,0 +1,19 @@ +Copyright © 2009-2013 Petri Lehtinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/netloc/jansson/Makefile.am b/netloc/jansson/Makefile.am new file mode 100644 index 0000000000..97e3f0ac6e --- /dev/null +++ b/netloc/jansson/Makefile.am @@ -0,0 +1,21 @@ +# NETLOC: remove win32 and cmake from EXTRA_DIST +#EXTRA_DIST = CHANGES LICENSE README.rst win32 CMakeLists.txt cmake +EXTRA_DIST = CHANGES LICENSE README.rst CMakeLists.txt +# NETLOC: We don't care about building the doc or test subdirs +#SUBDIRS = doc src test +SUBDIRS = src + +# "make distcheck" builds the dvi target, so use it to check that the +# documentation is built correctly. +# NETLOC: change target to dvi-local (not dvi), per Automake warning +dvi-local: + $(MAKE) SPHINXOPTS_EXTRA=-W html + +# NETLOC: we don't need jansson.pc +#pkgconfigdir = $(libdir)/pkgconfig +#pkgconfig_DATA = jansson.pc + +if GCC +# These flags are gcc specific +export AM_CFLAGS = -Wall -Wextra -Wdeclaration-after-statement +endif diff --git a/netloc/jansson/README.rst b/netloc/jansson/README.rst new file mode 100644 index 0000000000..a01cbc02d0 --- /dev/null +++ b/netloc/jansson/README.rst @@ -0,0 +1,63 @@ +Jansson README +============== + +.. image:: https://travis-ci.org/akheron/jansson.png + :alt: Build status + :target: https://travis-ci.org/akheron/jansson + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Comprehensive documentation + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + + +Compilation and Installation +---------------------------- + +If you obtained a source tarball, just use the standard autotools +commands:: + + $ ./configure + $ make + $ make install + +To run the test suite, invoke:: + + $ make check + +If the source has been checked out from a Git repository, the +./configure script has to be generated first. The easiest way is to +use autoreconf:: + + $ autoreconf -i + + +Documentation +------------- + +Prebuilt HTML documentation is available at +http://www.digip.org/jansson/doc/. + +The documentation source is in the ``doc/`` subdirectory. To generate +HTML documentation, invoke:: + + $ make html + +Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ +1.0 or newer is required to generate the documentation. + + +.. _Jansson: http://www.digip.org/jansson/ +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Sphinx: http://sphinx.pocoo.org/ diff --git a/netloc/jansson/config.h.in b/netloc/jansson/config.h.in new file mode 100644 index 0000000000..68c5ae8e9e --- /dev/null +++ b/netloc/jansson/config.h.in @@ -0,0 +1,139 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if gcc's __atomic builtins are available */ +#undef HAVE_ATOMIC_BUILTINS + +/* Define to 1 if you have the `close' function. */ +#undef HAVE_CLOSE + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `getpid' function. */ +#undef HAVE_GETPID + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `localeconv' function. */ +#undef HAVE_LOCALECONV + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if the system has the type `long long int'. */ +#undef HAVE_LONG_LONG_INT + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `open' function. */ +#undef HAVE_OPEN + +/* Define to 1 if you have the `read' function. */ +#undef HAVE_READ + +/* Define to 1 if you have the header file. */ +#undef HAVE_SCHED_H + +/* Define to 1 if you have the `sched_yield' function. */ +#undef HAVE_SCHED_YIELD + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + +/* Define to 1 if gcc's __sync builtins are available */ +#undef HAVE_SYNC_BUILTINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if /dev/urandom should be used for seeding the hash function */ +#undef USE_URANDOM + +/* Define to 1 if CryptGenRandom should be used for seeding the hash function + */ +#undef USE_WINDOWS_CRYPTOAPI + +/* Version number of package */ +#undef VERSION + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t diff --git a/netloc/jansson/configure.ac b/netloc/jansson/configure.ac new file mode 100644 index 0000000000..e871f5f6bb --- /dev/null +++ b/netloc/jansson/configure.ac @@ -0,0 +1,103 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.6], [petri@digip.org]) + +AM_INIT_AUTOMAKE([1.10 foreign]) + +AC_CONFIG_SRCDIR([src/value.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll]) + +AC_MSG_CHECKING([for gcc __sync builtins]) +have_sync_builtins=no +AC_TRY_LINK( + [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1);], + [have_sync_builtins=yes], +) +if test "x$have_sync_builtins" = "xyes"; then + AC_DEFINE([HAVE_SYNC_BUILTINS], [1], + [Define to 1 if gcc's __sync builtins are available]) +fi +AC_MSG_RESULT([$have_sync_builtins]) + +AC_MSG_CHECKING([for gcc __atomic builtins]) +have_atomic_builtins=no +AC_TRY_LINK( + [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE);], + [have_atomic_builtins=yes], +) +if test "x$have_atomic_builtins" = "xyes"; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], + [Define to 1 if gcc's __atomic builtins are available]) +fi +AC_MSG_RESULT([$have_atomic_builtins]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +# Features +AC_ARG_ENABLE([urandom], + [AS_HELP_STRING([--disable-urandom], + [Don't use /dev/urandom to seed the hash function])], + [use_urandom=$enableval], [use_urandom=yes]) + +if test "x$use_urandom" = xyes; then +AC_DEFINE([USE_URANDOM], [1], + [Define to 1 if /dev/urandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([windows-cryptoapi], + [AS_HELP_STRING([--disable-windows-cryptoapi], + [Don't use CryptGenRandom to seed the hash function])], + [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) + +if test "x$use_windows_cryptoapi" = xyes; then +AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], + [Define to 1 if CryptGenRandom should be used for seeding the hash function]) +fi + +AC_CONFIG_FILES([ + jansson.pc + Makefile + doc/Makefile + src/Makefile + src/jansson_config.h + test/Makefile + test/bin/Makefile + test/suites/Makefile + test/suites/api/Makefile +]) +AC_OUTPUT diff --git a/netloc/jansson/jansson.pc.in b/netloc/jansson/jansson.pc.in new file mode 100644 index 0000000000..d9bf4dade6 --- /dev/null +++ b/netloc/jansson/jansson.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=${prefix}/include + +Name: Jansson +Description: Library for encoding, decoding and manipulating JSON data +Version: @VERSION@ +Libs: -L${libdir} -ljansson +Cflags: -I${includedir} diff --git a/netloc/jansson/src/Makefile.am b/netloc/jansson/src/Makefile.am new file mode 100644 index 0000000000..1e5a716e95 --- /dev/null +++ b/netloc/jansson/src/Makefile.am @@ -0,0 +1,29 @@ +EXTRA_DIST = jansson.def + +# NETLOC: do not install these headers +headers = jansson.h jansson_config.h + +# NETLOC: Turn this into a non-installable convenience LT library +noinst_LTLIBRARIES = libjansson.la +libjansson_la_SOURCES = \ + $(headers) \ + dump.c \ + error.c \ + hashtable.c \ + hashtable.h \ + hashtable_seed.c \ + jansson_private.h \ + load.c \ + lookup3.h \ + memory.c \ + pack_unpack.c \ + strbuffer.c \ + strbuffer.h \ + strconv.c \ + utf.c \ + utf.h \ + value.c +libjansson_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^json_' \ + -version-info 10:0:6 diff --git a/netloc/jansson/src/dump.c b/netloc/jansson/src/dump.c new file mode 100644 index 0000000000..9927b6c332 --- /dev/null +++ b/netloc/jansson/src/dump.c @@ -0,0 +1,456 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include "jansson.h" +#include "jansson_private.h" +#include "strbuffer.h" +#include "utf.h" + +#define MAX_INTEGER_STR_LENGTH 100 +#define MAX_REAL_STR_LENGTH 100 + +struct object_key { + size_t serial; + const char *key; +}; + +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) +{ + return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); +} + +static int dump_to_file(const char *buffer, size_t size, void *data) +{ + FILE *dest = (FILE *)data; + if(fwrite(buffer, size, 1, dest) != 1) + return -1; + return 0; +} + +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; + +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) +{ + if(JSON_INDENT(flags) > 0) + { + int i, ws_count = JSON_INDENT(flags); + + if(dump("\n", 1, data)) + return -1; + + for(i = 0; i < depth; i++) + { + if(dump(whitespace, ws_count, data)) + return -1; + } + } + else if(space && !(flags & JSON_COMPACT)) + { + return dump(" ", 1, data); + } + return 0; +} + +static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags) +{ + const char *pos, *end; + int32_t codepoint; + + if(dump("\"", 1, data)) + return -1; + + end = pos = str; + while(1) + { + const char *text; + char seq[13]; + int length; + + while(*end) + { + end = utf8_iterate(pos, &codepoint); + if(!end) + return -1; + + /* mandatory escape or control char */ + if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) + break; + + /* slash */ + if((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + + /* non-ASCII */ + if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) + break; + + pos = end; + } + + if(pos != str) { + if(dump(str, pos - str, data)) + return -1; + } + + if(end == pos) + break; + + /* handle \, /, ", and control codes */ + length = 2; + switch(codepoint) + { + case '\\': text = "\\\\"; break; + case '\"': text = "\\\""; break; + case '\b': text = "\\b"; break; + case '\f': text = "\\f"; break; + case '\n': text = "\\n"; break; + case '\r': text = "\\r"; break; + case '\t': text = "\\t"; break; + case '/': text = "\\/"; break; + default: + { + /* codepoint is in BMP */ + if(codepoint < 0x10000) + { + sprintf(seq, "\\u%04x", codepoint); + length = 6; + } + + /* not in BMP -> construct a UTF-16 surrogate pair */ + else + { + int32_t first, last; + + codepoint -= 0x10000; + first = 0xD800 | ((codepoint & 0xffc00) >> 10); + last = 0xDC00 | (codepoint & 0x003ff); + + sprintf(seq, "\\u%04x\\u%04x", first, last); + length = 12; + } + + text = seq; + break; + } + } + + if(dump(text, length, data)) + return -1; + + str = pos = end; + } + + return dump("\"", 1, data); +} + +static int object_key_compare_keys(const void *key1, const void *key2) +{ + return strcmp(((const struct object_key *)key1)->key, + ((const struct object_key *)key2)->key); +} + +static int object_key_compare_serials(const void *key1, const void *key2) +{ + size_t a = ((const struct object_key *)key1)->serial; + size_t b = ((const struct object_key *)key2)->serial; + + return a < b ? -1 : a == b ? 0 : 1; +} + +static int do_dump(const json_t *json, size_t flags, int depth, + json_dump_callback_t dump, void *data) +{ + if(!json) + return -1; + + switch(json_typeof(json)) { + case JSON_NULL: + return dump("null", 4, data); + + case JSON_TRUE: + return dump("true", 4, data); + + case JSON_FALSE: + return dump("false", 5, data); + + case JSON_INTEGER: + { + char buffer[MAX_INTEGER_STR_LENGTH]; + int size; + + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, + "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) + return -1; + + return dump(buffer, size, data); + } + + case JSON_REAL: + { + char buffer[MAX_REAL_STR_LENGTH]; + int size; + double value = json_real_value(json); + + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + if(size < 0) + return -1; + + return dump(buffer, size, data); + } + + case JSON_STRING: + return dump_string(json_string_value(json), dump, data, flags); + + case JSON_ARRAY: + { + int i; + int n; + json_array_t *array; + + /* detect circular references */ + array = json_to_array(json); + if(array->visited) + goto array_error; + array->visited = 1; + + n = json_array_size(json); + + if(dump("[", 1, data)) + goto array_error; + if(n == 0) { + array->visited = 0; + return dump("]", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + goto array_error; + + for(i = 0; i < n; ++i) { + if(do_dump(json_array_get(json, i), flags, depth + 1, + dump, data)) + goto array_error; + + if(i < n - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + goto array_error; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + goto array_error; + } + } + + array->visited = 0; + return dump("]", 1, data); + + array_error: + array->visited = 0; + return -1; + } + + case JSON_OBJECT: + { + json_object_t *object; + void *iter; + const char *separator; + int separator_length; + + if(flags & JSON_COMPACT) { + separator = ":"; + separator_length = 1; + } + else { + separator = ": "; + separator_length = 2; + } + + /* detect circular references */ + object = json_to_object(json); + if(object->visited) + goto object_error; + object->visited = 1; + + iter = json_object_iter((json_t *)json); + + if(dump("{", 1, data)) + goto object_error; + if(!iter) { + object->visited = 0; + return dump("}", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + goto object_error; + + if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) + { + struct object_key *keys; + size_t size, i; + int (*cmp_func)(const void *, const void *); + + size = json_object_size(json); + keys = jsonp_malloc(size * sizeof(struct object_key)); + if(!keys) + goto object_error; + + i = 0; + while(iter) + { + keys[i].serial = hashtable_iter_serial(iter); + keys[i].key = json_object_iter_key(iter); + iter = json_object_iter_next((json_t *)json, iter); + i++; + } + assert(i == size); + + if(flags & JSON_SORT_KEYS) + cmp_func = object_key_compare_keys; + else + cmp_func = object_key_compare_serials; + + qsort(keys, size, sizeof(struct object_key), cmp_func); + + for(i = 0; i < size; i++) + { + const char *key; + json_t *value; + + key = keys[i].key; + value = json_object_get(json, key); + assert(value); + + dump_string(key, dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(value, flags, depth + 1, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + + if(i < size - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + } + } + + jsonp_free(keys); + } + else + { + /* Don't sort keys */ + + while(iter) + { + void *next = json_object_iter_next((json_t *)json, iter); + + dump_string(json_object_iter_key(iter), dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(json_object_iter_value(iter), flags, depth + 1, + dump, data)) + goto object_error; + + if(next) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + goto object_error; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + goto object_error; + } + + iter = next; + } + } + + object->visited = 0; + return dump("}", 1, data); + + object_error: + object->visited = 0; + return -1; + } + + default: + /* not reached */ + return -1; + } +} + +char *json_dumps(const json_t *json, size_t flags) +{ + strbuffer_t strbuff; + char *result; + + if(strbuffer_init(&strbuff)) + return NULL; + + if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); + + strbuffer_close(&strbuff); + return result; +} + +int json_dumpf(const json_t *json, FILE *output, size_t flags) +{ + return json_dump_callback(json, dump_to_file, (void *)output, flags); +} + +int json_dump_file(const json_t *json, const char *path, size_t flags) +{ + int result; + + FILE *output = fopen(path, "w"); + if(!output) + return -1; + + result = json_dumpf(json, output, flags); + + fclose(output); + return result; +} + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) +{ + if(!(flags & JSON_ENCODE_ANY)) { + if(!json_is_array(json) && !json_is_object(json)) + return -1; + } + + return do_dump(json, flags, 0, callback, data); +} diff --git a/netloc/jansson/src/error.c b/netloc/jansson/src/error.c new file mode 100644 index 0000000000..a544a59fb1 --- /dev/null +++ b/netloc/jansson/src/error.c @@ -0,0 +1,63 @@ +#include +#include "jansson_private.h" + +void jsonp_error_init(json_error_t *error, const char *source) +{ + if(error) + { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if(source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) +{ + size_t length; + + if(!error || !source) + return; + + length = strlen(source); + if(length < JSON_ERROR_SOURCE_LENGTH) + strcpy(error->source, source); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + strcpy(error->source, "..."); + strcpy(error->source + 3, source + extra); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap) +{ + if(!error) + return; + + if(error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; +} diff --git a/netloc/jansson/src/hashtable.c b/netloc/jansson/src/hashtable.c new file mode 100644 index 0000000000..502c13f27e --- /dev/null +++ b/netloc/jansson/src/hashtable.c @@ -0,0 +1,345 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#if HAVE_STDINT_H +#include +#endif + +#include /* for JSON_INLINE */ +#include "jansson_private.h" /* for container_of() */ +#include "hashtable.h" + +typedef struct hashtable_list list_t; +typedef struct hashtable_pair pair_t; +typedef struct hashtable_bucket bucket_t; + +extern volatile uint32_t hashtable_seed; + +/* Implementation of the hash function */ +#include "lookup3.h" + +#define list_to_pair(list_) container_of(list_, pair_t, list) +#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed)) + +static JSON_INLINE void list_init(list_t *list) +{ + list->next = list; + list->prev = list; +} + +static JSON_INLINE void list_insert(list_t *list, list_t *node) +{ + node->next = list; + node->prev = list->prev; + list->prev->next = node; + list->prev = node; +} + +static JSON_INLINE void list_remove(list_t *list) +{ + list->prev->next = list->next; + list->next->prev = list->prev; +} + +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) +{ + return bucket->first == &hashtable->list && bucket->first == bucket->last; +} + +static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, + list_t *list) +{ + if(bucket_is_empty(hashtable, bucket)) + { + list_insert(&hashtable->list, list); + bucket->first = bucket->last = list; + } + else + { + list_insert(bucket->first, list); + bucket->first = list; + } +} + +static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, + const char *key, size_t hash) +{ + list_t *list; + pair_t *pair; + + if(bucket_is_empty(hashtable, bucket)) + return NULL; + + list = bucket->first; + while(1) + { + pair = list_to_pair(list); + if(pair->hash == hash && strcmp(pair->key, key) == 0) + return pair; + + if(list == bucket->last) + break; + + list = list->next; + } + + return NULL; +} + +/* returns 0 on success, -1 if key was not found */ +static int hashtable_do_del(hashtable_t *hashtable, + const char *key, size_t hash) +{ + pair_t *pair; + bucket_t *bucket; + size_t index; + + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return -1; + + if(&pair->list == bucket->first && &pair->list == bucket->last) + bucket->first = bucket->last = &hashtable->list; + + else if(&pair->list == bucket->first) + bucket->first = pair->list.next; + + else if(&pair->list == bucket->last) + bucket->last = pair->list.prev; + + list_remove(&pair->list); + json_decref(pair->value); + + jsonp_free(pair); + hashtable->size--; + + return 0; +} + +static void hashtable_do_clear(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + + for(list = hashtable->list.next; list != &hashtable->list; list = next) + { + next = list->next; + pair = list_to_pair(list); + json_decref(pair->value); + jsonp_free(pair); + } +} + +static int hashtable_do_rehash(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + size_t i, index, new_size; + + jsonp_free(hashtable->buckets); + + hashtable->order++; + new_size = hashsize(hashtable->order); + + hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if(!hashtable->buckets) + return -1; + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list = hashtable->list.next; + list_init(&hashtable->list); + + for(; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + index = pair->hash % new_size; + insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); + } + + return 0; +} + + +int hashtable_init(hashtable_t *hashtable) +{ + size_t i; + + hashtable->size = 0; + hashtable->order = 3; + hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); + if(!hashtable->buckets) + return -1; + + list_init(&hashtable->list); + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + return 0; +} + +void hashtable_close(hashtable_t *hashtable) +{ + hashtable_do_clear(hashtable); + jsonp_free(hashtable->buckets); +} + +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value) +{ + pair_t *pair; + bucket_t *bucket; + size_t hash, index; + + /* rehash if the load ratio exceeds 1 */ + if(hashtable->size >= hashsize(hashtable->order)) + if(hashtable_do_rehash(hashtable)) + return -1; + + hash = hash_str(key); + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + pair = hashtable_find_pair(hashtable, bucket, key, hash); + + if(pair) + { + json_decref(pair->value); + pair->value = value; + } + else + { + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1); + if(!pair) + return -1; + + pair->hash = hash; + pair->serial = serial; + strcpy(pair->key, key); + pair->value = value; + list_init(&pair->list); + + insert_to_bucket(hashtable, bucket, &pair->list); + + hashtable->size++; + } + return 0; +} + +void *hashtable_get(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return NULL; + + return pair->value; +} + +int hashtable_del(hashtable_t *hashtable, const char *key) +{ + size_t hash = hash_str(key); + return hashtable_do_del(hashtable, key, hash); +} + +void hashtable_clear(hashtable_t *hashtable) +{ + size_t i; + + hashtable_do_clear(hashtable); + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list_init(&hashtable->list); + hashtable->size = 0; +} + +void *hashtable_iter(hashtable_t *hashtable) +{ + return hashtable_iter_next(hashtable, &hashtable->list); +} + +void *hashtable_iter_at(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return NULL; + + return &pair->list; +} + +void *hashtable_iter_next(hashtable_t *hashtable, void *iter) +{ + list_t *list = (list_t *)iter; + if(list->next == &hashtable->list) + return NULL; + return list->next; +} + +void *hashtable_iter_key(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->key; +} + +size_t hashtable_iter_serial(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->serial; +} + +void *hashtable_iter_value(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->value; +} + +void hashtable_iter_set(void *iter, json_t *value) +{ + pair_t *pair = list_to_pair((list_t *)iter); + + json_decref(pair->value); + pair->value = value; +} diff --git a/netloc/jansson/src/hashtable.h b/netloc/jansson/src/hashtable.h new file mode 100644 index 0000000000..c854e503c6 --- /dev/null +++ b/netloc/jansson/src/hashtable.h @@ -0,0 +1,181 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef HASHTABLE_H +#define HASHTABLE_H + +struct hashtable_list { + struct hashtable_list *prev; + struct hashtable_list *next; +}; + +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ +struct hashtable_pair { + size_t hash; + struct hashtable_list list; + json_t *value; + size_t serial; + char key[1]; +}; + +struct hashtable_bucket { + struct hashtable_list *first; + struct hashtable_list *last; +}; + +typedef struct hashtable { + size_t size; + struct hashtable_bucket *buckets; + size_t order; /* hashtable has pow(2, order) buckets */ + struct hashtable_list list; +} hashtable_t; + + +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->list)) + + +/** + * hashtable_init - Initialize a hashtable object + * + * @hashtable: The (statically allocated) hashtable object + * + * Initializes a statically allocated hashtable object. The object + * should be cleared with hashtable_close when it's no longer used. + * + * Returns 0 on success, -1 on error (out of memory). + */ +int hashtable_init(hashtable_t *hashtable); + +/** + * hashtable_close - Release all resources used by a hashtable object + * + * @hashtable: The hashtable + * + * Destroys a statically allocated hashtable object. + */ +void hashtable_close(hashtable_t *hashtable); + +/** + * hashtable_set - Add/modify value in hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @serial: For addition order of keys + * @value: The value + * + * If a value with the given key already exists, its value is replaced + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. + * + * Returns 0 on success, -1 on failure (out of memory). + */ +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value); + +/** + * hashtable_get - Get a value associated with a key + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns value if it is found, or NULL otherwise. + */ +void *hashtable_get(hashtable_t *hashtable, const char *key); + +/** + * hashtable_del - Remove a value from the hashtable + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns 0 on success, or -1 if the key was not found. + */ +int hashtable_del(hashtable_t *hashtable, const char *key); + +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + +/** + * hashtable_iter - Iterate over hashtable + * + * @hashtable: The hashtable object + * + * Returns an opaque iterator to the first element in the hashtable. + * The iterator should be passed to hashtable_iter_* functions. + * The hashtable items are not iterated over in any particular order. + * + * There's no need to free the iterator in any way. The iterator is + * valid as long as the item that is referenced by the iterator is not + * deleted. Other values may be added or deleted. In particular, + * hashtable_iter_next() may be called on an iterator, and after that + * the key/value pair pointed by the old iterator may be deleted. + */ +void *hashtable_iter(hashtable_t *hashtable); + +/** + * hashtable_iter_at - Return an iterator at a specific key + * + * @hashtable: The hashtable object + * @key: The key that the iterator should point to + * + * Like hashtable_iter() but returns an iterator pointing to a + * specific key. + */ +void *hashtable_iter_at(hashtable_t *hashtable, const char *key); + +/** + * hashtable_iter_next - Advance an iterator + * + * @hashtable: The hashtable object + * @iter: The iterator + * + * Returns a new iterator pointing to the next element in the + * hashtable or NULL if the whole hastable has been iterated over. + */ +void *hashtable_iter_next(hashtable_t *hashtable, void *iter); + +/** + * hashtable_iter_key - Retrieve the key pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_key(void *iter); + +/** + * hashtable_iter_serial - Retrieve the serial number pointed to by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_serial(void *iter); + +/** + * hashtable_iter_value - Retrieve the value pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_value(void *iter); + +/** + * hashtable_iter_set - Set the value pointed by an iterator + * + * @iter: The iterator + * @value: The value to set + */ +void hashtable_iter_set(void *iter, json_t *value); + +#endif diff --git a/netloc/jansson/src/hashtable_seed.c b/netloc/jansson/src/hashtable_seed.c new file mode 100644 index 0000000000..cb5f3106e7 --- /dev/null +++ b/netloc/jansson/src/hashtable_seed.c @@ -0,0 +1,278 @@ +/* Generate sizeof(uint32_t) bytes of as random data as possible to seed + the hash function. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if defined(_WIN32) +/* For _getpid() */ +#include +#endif + +#include "jansson.h" + + +static uint32_t buf_to_uint32(char *data) { + size_t i; + uint32_t result = 0; + + for (i = 0; i < sizeof(uint32_t); i++) + result = (result << 8) | (unsigned char)data[i]; + + return result; +} + + + +/* /dev/urandom */ +#if !defined(_WIN32) && defined(USE_URANDOM) +static int seed_from_urandom(uint32_t *seed) { + /* Use unbuffered I/O if we have open(), close() and read(). Otherwise + fall back to fopen() */ + + char data[sizeof(uint32_t)]; + int ok; + +#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ) + int urandom; + urandom = open("/dev/urandom", O_RDONLY); + if (urandom == -1) + return 1; + + ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t); + close(urandom); +#else + FILE *urandom; + + urandom = fopen("/dev/urandom", "rb"); + if (!urandom) + return 1; + + ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t); + fclose(urandom); +#endif + + if (!ok) + return 1; + + *seed = buf_to_uint32(data); + return 0; +} +#endif + +/* Windows Crypto API */ +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) +#include +#include + +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +static int seed_from_windows_cryptoapi(uint32_t *seed) +{ + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + CRYPTGENRANDOM pCryptGenRandom = NULL; + CRYPTRELEASECONTEXT pCryptReleaseContext = NULL; + HCRYPTPROV hCryptProv = 0; + BYTE data[sizeof(uint32_t)]; + int ok; + + hAdvAPI32 = GetModuleHandle("advapi32.dll"); + if(hAdvAPI32 == NULL) + return 1; + + pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); + if (!pCryptAcquireContext) + return 1; + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom"); + if (!pCryptGenRandom) + return 1; + + pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext"); + if (!pCryptReleaseContext) + return 1; + + if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return 1; + + ok = CryptGenRandom(hCryptProv, sizeof(uint32_t), data); + pCryptReleaseContext(hCryptProv, 0); + + if (!ok) + return 1; + + *seed = buf_to_uint32((char *)data); + return 0; +} +#endif + +/* gettimeofday() and getpid() */ +static int seed_from_timestamp_and_pid(uint32_t *seed) { +#ifdef HAVE_GETTIMEOFDAY + /* XOR of seconds and microseconds */ + struct timeval tv; + gettimeofday(&tv, NULL); + *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec; +#else + /* Seconds only */ + *seed = (uint32_t)time(NULL); +#endif + + /* XOR with PID for more randomness */ +#if defined(_WIN32) + *seed ^= (uint32_t)_getpid(); +#elif defined(HAVE_GETPID) + *seed ^= (uint32_t)getpid(); +#endif + + return 0; +} + +static uint32_t generate_seed() { + uint32_t seed; + int done = 0; + +#if !defined(_WIN32) && defined(USE_URANDOM) + if (!done && seed_from_urandom(&seed) == 0) + done = 1; +#endif + +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) + if (!done && seed_from_windows_cryptoapi(&seed) == 0) + done = 1; +#endif + + if (!done) { + /* Fall back to timestamp and PID if no better randomness is + available */ + seed_from_timestamp_and_pid(&seed); + } + + /* Make sure the seed is never zero */ + if (seed == 0) + seed = 1; + + return seed; +} + + +volatile uint32_t hashtable_seed = 0; + +#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +static volatile char seed_initialized = 0; + +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE); + } else { + /* Wait for another thread to do the seeding */ + do { +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0); + } + } +} +#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) { + /* Explicit synchronization fences are not supported by the + __sync builtins, so every thread getting here has to + generate the seed value. + */ + new_seed = generate_seed(); + } + + do { + if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) { + /* We were the first to seed */ + break; + } else { + /* Wait for another thread to do the seeding */ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } + } while(hashtable_seed == 0); + } +} +#elif defined(_WIN32) +static long seed_initialized = 0; +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (InterlockedIncrement(&seed_initialized) == 1) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } else { + /* Wait for another thread to do the seeding */ + do { + SwitchToThread(); + } while (hashtable_seed == 0); + } + } +} +#else +/* Fall back to a thread-unsafe version */ +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } +} +#endif diff --git a/netloc/jansson/src/jansson.def b/netloc/jansson/src/jansson.def new file mode 100644 index 0000000000..af1c980557 --- /dev/null +++ b/netloc/jansson/src/jansson.def @@ -0,0 +1,63 @@ +EXPORTS + json_delete + json_true + json_false + json_null + json_string + json_string_nocheck + json_string_value + json_string_set + json_string_set_nocheck + json_integer + json_integer_value + json_integer_set + json_real + json_real_value + json_real_set + json_number_value + json_array + json_array_size + json_array_get + json_array_set_new + json_array_append_new + json_array_insert_new + json_array_remove + json_array_clear + json_array_extend + json_object + json_object_size + json_object_get + json_object_set_new + json_object_set_new_nocheck + json_object_del + json_object_clear + json_object_update + json_object_update_existing + json_object_update_missing + json_object_iter + json_object_iter_at + json_object_iter_next + json_object_iter_key + json_object_iter_value + json_object_iter_set_new + json_object_key_to_iter + json_object_seed + json_dumps + json_dumpf + json_dump_file + json_dump_callback + json_loads + json_loadb + json_loadf + json_load_file + json_load_callback + json_equal + json_copy + json_deep_copy + json_pack + json_pack_ex + json_vpack_ex + json_unpack + json_unpack_ex + json_vunpack_ex + json_set_alloc_funcs diff --git a/netloc/jansson/src/jansson.h b/netloc/jansson/src/jansson.h new file mode 100644 index 0000000000..b9f3ff4425 --- /dev/null +++ b/netloc/jansson/src/jansson.h @@ -0,0 +1,282 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include +#include /* for size_t */ +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 6 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.6" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct json_t { + json_type type; + size_t refcount; +} json_t; + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) (json && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) (json && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) (json && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) (json && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) (json && json_typeof(json) == JSON_FALSE) +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) (json && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_string_nocheck(const char *value); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +static JSON_INLINE +json_t *json_incref(json_t *json) +{ + if(json && json->refcount != (size_t)-1) + ++json->refcount; + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE +void json_decref(json_t *json) +{ + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) + json_delete(json); +} + + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + + +/* getters, setters, manipulation */ + +void json_object_seed(size_t seed); +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_del(json_t *object, const char *key); +int json_object_clear(json_t *object); +int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); +void *json_object_iter_next(json_t *object, void *iter); +const char *json_object_iter_key(void *iter); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + +static JSON_INLINE +int json_object_set(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_set_nocheck(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new_nocheck(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_iter_set(json_t *object, void *iter, json_t *value) +{ + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE +int json_array_set(json_t *array, size_t ind, json_t *value) +{ + return json_array_set_new(array, ind, json_incref(value)); +} + +static JSON_INLINE +int json_array_append(json_t *array, json_t *value) +{ + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE +int json_array_insert(json_t *array, size_t ind, json_t *value) +{ + return json_array_insert_new(array, ind, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_set_nocheck(json_t *string, const char *value); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + + +/* equality */ + +int json_equal(json_t *value1, json_t *value2); + + +/* copying */ + +json_t *json_copy(json_t *value); +json_t *json_deep_copy(const json_t *value); + + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); + + +/* encoding */ + +#define JSON_INDENT(n) (n & 0x1F) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/netloc/jansson/src/jansson_config.h.in b/netloc/jansson/src/jansson_config.h.in new file mode 100644 index 0000000000..bf2ebbf8e4 --- /dev/null +++ b/netloc/jansson/src/jansson_config.h.in @@ -0,0 +1,39 @@ +/* + * Copyright © 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @json_inline@ +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @json_have_localeconv@ + +#endif diff --git a/netloc/jansson/src/jansson_private.h b/netloc/jansson/src/jansson_private.h new file mode 100644 index 0000000000..a24d89f919 --- /dev/null +++ b/netloc/jansson/src/jansson_private.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_PRIVATE_H +#define JANSSON_PRIVATE_H + +#include +#include "jansson.h" +#include "hashtable.h" +#include "strbuffer.h" + +#define container_of(ptr_, type_, member_) \ + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif + +typedef struct { + json_t json; + hashtable_t hashtable; + size_t serial; + int visited; +} json_object_t; + +typedef struct { + json_t json; + size_t size; + size_t entries; + json_t **table; + int visited; +} json_array_t; + +typedef struct { + json_t json; + char *value; +} json_string_t; + +typedef struct { + json_t json; + double value; +} json_real_t; + +typedef struct { + json_t json; + json_int_t value; +} json_integer_t; + +#define json_to_object(json_) container_of(json_, json_object_t, json) +#define json_to_array(json_) container_of(json_, json_array_t, json) +#define json_to_string(json_) container_of(json_, json_string_t, json) +#define json_to_real(json_) container_of(json_, json_real_t, json) +#define json_to_integer(json_) container_of(json_, json_integer_t, json) + +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value); + +/* Wrappers for custom memory functions */ +void* jsonp_malloc(size_t size); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length); +char *jsonp_strdup(const char *str); + +/* Windows compatibility */ +#ifdef _WIN32 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +#endif diff --git a/netloc/jansson/src/load.c b/netloc/jansson/src/load.c new file mode 100644 index 0000000000..207daff9cc --- /dev/null +++ b/netloc/jansson/src/load.c @@ -0,0 +1,1077 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "jansson.h" +#include "jansson_private.h" +#include "strbuffer.h" +#include "utf.h" + +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + +#define TOKEN_INVALID -1 +#define TOKEN_EOF 0 +#define TOKEN_STRING 256 +#define TOKEN_INTEGER 257 +#define TOKEN_REAL 258 +#define TOKEN_TRUE 259 +#define TOKEN_FALSE 260 +#define TOKEN_NULL 261 + +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ +typedef int (*get_func)(void *data); + +typedef struct { + get_func get; + void *data; + char buffer[5]; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; +} stream_t; + +typedef struct { + stream_t stream; + strbuffer_t saved_text; + int token; + union { + char *string; + json_int_t integer; + double real; + } value; +} lex_t; + +#define stream_to_lex(stream) container_of(stream, lex_t, stream) + + +/*** error reporting ***/ + +static void error_set(json_error_t *error, const lex_t *lex, + const char *msg, ...) +{ + va_list ap; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; + + if(!error) + return; + + va_start(ap, msg); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + va_end(ap); + + if(lex) + { + const char *saved_text = strbuffer_value(&lex->saved_text); + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + + if(saved_text && saved_text[0]) + { + if(lex->saved_text.length <= 20) { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near '%s'", msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + else + { + if(lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } + else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near end of file", msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + } + + jsonp_error_set(error, line, col, pos, "%s", result); +} + + +/*** lexical analyzer ***/ + +static void +stream_init(stream_t *stream, get_func get, void *data) +{ + stream->get = get; + stream->data = data; + stream->buffer[0] = '\0'; + stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; +} + +static int stream_get(stream_t *stream, json_error_t *error) +{ + int c; + + if(stream->state != STREAM_STATE_OK) + return stream->state; + + if(!stream->buffer[stream->buffer_pos]) + { + c = stream->get(stream->data); + if(c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } + + stream->buffer[0] = c; + stream->buffer_pos = 0; + + if(0x80 <= c && c <= 0xFF) + { + /* multi-byte UTF-8 sequence */ + int i, count; + + count = utf8_check_first(c); + if(!count) + goto out; + + assert(count >= 2); + + for(i = 1; i < count; i++) + stream->buffer[i] = stream->get(stream->data); + + if(!utf8_check_full(stream->buffer, count, NULL)) + goto out; + + stream->buffer[count] = '\0'; + } + else + stream->buffer[1] = '\0'; + } + + c = stream->buffer[stream->buffer_pos++]; + + stream->position++; + if(c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } + else if(utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } + + return c; + +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; +} + +static void stream_unget(stream_t *stream, int c) +{ + if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if(c == '\n') { + stream->line--; + stream->column = stream->last_column; + } + else if(utf8_check_first(c)) + stream->column--; + + assert(stream->buffer_pos > 0); + stream->buffer_pos--; + assert(stream->buffer[stream->buffer_pos] == c); +} + + +static int lex_get(lex_t *lex, json_error_t *error) +{ + return stream_get(&lex->stream, error); +} + +static void lex_save(lex_t *lex, int c) +{ + strbuffer_append_byte(&lex->saved_text, c); +} + +static int lex_get_save(lex_t *lex, json_error_t *error) +{ + int c = stream_get(&lex->stream, error); + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); + return c; +} + +static void lex_unget(lex_t *lex, int c) +{ + stream_unget(&lex->stream, c); +} + +static void lex_unget_unsave(lex_t *lex, int c) +{ + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { + /* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ + #ifndef NDEBUG + char d; + #endif + stream_unget(&lex->stream, c); + #ifndef NDEBUG + d = + #endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } +} + +static void lex_save_cached(lex_t *lex) +{ + while(lex->stream.buffer[lex->stream.buffer_pos] != '\0') + { + lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); + lex->stream.buffer_pos++; + lex->stream.position++; + } +} + +/* assumes that str points to 'u' plus at least 4 valid hex digits */ +static int32_t decode_unicode_escape(const char *str) +{ + int i; + int32_t value = 0; + + assert(str[0] == 'u'); + + for(i = 1; i <= 4; i++) { + char c = str[i]; + value <<= 4; + if(l_isdigit(c)) + value += c - '0'; + else if(l_islower(c)) + value += c - 'a' + 10; + else if(l_isupper(c)) + value += c - 'A' + 10; + else + assert(0); + } + + return value; +} + +static void lex_scan_string(lex_t *lex, json_error_t *error) +{ + int c; + const char *p; + char *t; + int i; + + lex->value.string = NULL; + lex->token = TOKEN_INVALID; + + c = lex_get_save(lex, error); + + while(c != '"') { + if(c == STREAM_STATE_ERROR) + goto out; + + else if(c == STREAM_STATE_EOF) { + error_set(error, lex, "premature end of input"); + goto out; + } + + else if(0 <= c && c <= 0x1F) { + /* control character */ + lex_unget_unsave(lex, c); + if(c == '\n') + error_set(error, lex, "unexpected newline", c); + else + error_set(error, lex, "control character 0x%x", c); + goto out; + } + + else if(c == '\\') { + c = lex_get_save(lex, error); + if(c == 'u') { + c = lex_get_save(lex, error); + for(i = 0; i < 4; i++) { + if(!l_isxdigit(c)) { + error_set(error, lex, "invalid escape"); + goto out; + } + c = lex_get_save(lex, error); + } + } + else if(c == '"' || c == '\\' || c == '/' || c == 'b' || + c == 'f' || c == 'n' || c == 'r' || c == 't') + c = lex_get_save(lex, error); + else { + error_set(error, lex, "invalid escape"); + goto out; + } + } + else + c = lex_get_save(lex, error); + } + + /* the actual value is at most of the same length as the source + string, because: + - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte + - a single \uXXXX escape (length 6) is converted to at most 3 bytes + - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair + are converted to 4 bytes + */ + lex->value.string = jsonp_malloc(lex->saved_text.length + 1); + if(!lex->value.string) { + /* this is not very nice, since TOKEN_INVALID is returned */ + goto out; + } + + /* the target */ + t = lex->value.string; + + /* + 1 to skip the " */ + p = strbuffer_value(&lex->saved_text) + 1; + + while(*p != '"') { + if(*p == '\\') { + p++; + if(*p == 'u') { + char buffer[4]; + int length; + int32_t value; + + value = decode_unicode_escape(p); + p += 5; + + if(0xD800 <= value && value <= 0xDBFF) { + /* surrogate pair */ + if(*p == '\\' && *(p + 1) == 'u') { + int32_t value2 = decode_unicode_escape(++p); + p += 5; + + if(0xDC00 <= value2 && value2 <= 0xDFFF) { + /* valid second surrogate */ + value = + ((value - 0xD800) << 10) + + (value2 - 0xDC00) + + 0x10000; + } + else { + /* invalid second surrogate */ + error_set(error, lex, + "invalid Unicode '\\u%04X\\u%04X'", + value, value2); + goto out; + } + } + else { + /* no second surrogate */ + error_set(error, lex, "invalid Unicode '\\u%04X'", + value); + goto out; + } + } + else if(0xDC00 <= value && value <= 0xDFFF) { + error_set(error, lex, "invalid Unicode '\\u%04X'", value); + goto out; + } + else if(value == 0) + { + error_set(error, lex, "\\u0000 is not allowed"); + goto out; + } + + if(utf8_encode(value, buffer, &length)) + assert(0); + + memcpy(t, buffer, length); + t += length; + } + else { + switch(*p) { + case '"': case '\\': case '/': + *t = *p; break; + case 'b': *t = '\b'; break; + case 'f': *t = '\f'; break; + case 'n': *t = '\n'; break; + case 'r': *t = '\r'; break; + case 't': *t = '\t'; break; + default: assert(0); + } + t++; + p++; + } + } + else + *(t++) = *(p++); + } + *t = '\0'; + lex->token = TOKEN_STRING; + return; + +out: + jsonp_free(lex->value.string); +} + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) +{ + const char *saved_text; + char *end; + double value; + + lex->token = TOKEN_INVALID; + + if(c == '-') + c = lex_get_save(lex, error); + + if(c == '0') { + c = lex_get_save(lex, error); + if(l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + } + else if(l_isdigit(c)) { + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + else { + lex_unget_unsave(lex, c); + goto out; + } + + if(c != '.' && c != 'E' && c != 'e') { + json_int_t value; + + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + errno = 0; + value = json_strtoint(saved_text, &end, 10); + if(errno == ERANGE) { + if(value < 0) + error_set(error, lex, "too big negative integer"); + else + error_set(error, lex, "too big integer"); + goto out; + } + + assert(end == saved_text + lex->saved_text.length); + + lex->token = TOKEN_INTEGER; + lex->value.integer = value; + return 0; + } + + if(c == '.') { + c = lex_get(lex, error); + if(!l_isdigit(c)) { + lex_unget(lex, c); + goto out; + } + lex_save(lex, c); + + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + + if(c == 'E' || c == 'e') { + c = lex_get_save(lex, error); + if(c == '+' || c == '-') + c = lex_get_save(lex, error); + + if(!l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + + lex_unget_unsave(lex, c); + + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = value; + return 0; + +out: + return -1; +} + +static int lex_scan(lex_t *lex, json_error_t *error) +{ + int c; + + strbuffer_clear(&lex->saved_text); + + if(lex->token == TOKEN_STRING) { + jsonp_free(lex->value.string); + lex->value.string = NULL; + } + + c = lex_get(lex, error); + while(c == ' ' || c == '\t' || c == '\n' || c == '\r') + c = lex_get(lex, error); + + if(c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; + } + + if(c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; + goto out; + } + + lex_save(lex, c); + + if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') + lex->token = c; + + else if(c == '"') + lex_scan_string(lex, error); + + else if(l_isdigit(c) || c == '-') { + if(lex_scan_number(lex, c, error)) + goto out; + } + + else if(l_isalpha(c)) { + /* eat up the whole identifier for clearer error messages */ + const char *saved_text; + + c = lex_get_save(lex, error); + while(l_isalpha(c)) + c = lex_get_save(lex, error); + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + if(strcmp(saved_text, "true") == 0) + lex->token = TOKEN_TRUE; + else if(strcmp(saved_text, "false") == 0) + lex->token = TOKEN_FALSE; + else if(strcmp(saved_text, "null") == 0) + lex->token = TOKEN_NULL; + else + lex->token = TOKEN_INVALID; + } + + else { + /* save the rest of the input UTF-8 sequence to get an error + message of valid UTF-8 */ + lex_save_cached(lex); + lex->token = TOKEN_INVALID; + } + +out: + return lex->token; +} + +static char *lex_steal_string(lex_t *lex) +{ + char *result = NULL; + if(lex->token == TOKEN_STRING) + { + result = lex->value.string; + lex->value.string = NULL; + } + return result; +} + +static int lex_init(lex_t *lex, get_func get, void *data) +{ + stream_init(&lex->stream, get, data); + if(strbuffer_init(&lex->saved_text)) + return -1; + + lex->token = TOKEN_INVALID; + return 0; +} + +static void lex_close(lex_t *lex) +{ + if(lex->token == TOKEN_STRING) + jsonp_free(lex->value.string); + strbuffer_close(&lex->saved_text); +} + + +/*** parser ***/ + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); + +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *object = json_object(); + if(!object) + return NULL; + + lex_scan(lex, error); + if(lex->token == '}') + return object; + + while(1) { + char *key; + json_t *value; + + if(lex->token != TOKEN_STRING) { + error_set(error, lex, "string or '}' expected"); + goto error; + } + + key = lex_steal_string(lex); + if(!key) + return NULL; + + if(flags & JSON_REJECT_DUPLICATES) { + if(json_object_get(object, key)) { + jsonp_free(key); + error_set(error, lex, "duplicate object key"); + goto error; + } + } + + lex_scan(lex, error); + if(lex->token != ':') { + jsonp_free(key); + error_set(error, lex, "':' expected"); + goto error; + } + + lex_scan(lex, error); + value = parse_value(lex, flags, error); + if(!value) { + jsonp_free(key); + goto error; + } + + if(json_object_set_nocheck(object, key, value)) { + jsonp_free(key); + json_decref(value); + goto error; + } + + json_decref(value); + jsonp_free(key); + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != '}') { + error_set(error, lex, "'}' expected"); + goto error; + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *array = json_array(); + if(!array) + return NULL; + + lex_scan(lex, error); + if(lex->token == ']') + return array; + + while(lex->token) { + json_t *elem = parse_value(lex, flags, error); + if(!elem) + goto error; + + if(json_array_append(array, elem)) { + json_decref(elem); + goto error; + } + json_decref(elem); + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != ']') { + error_set(error, lex, "']' expected"); + goto error; + } + + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *json; + double value; + + switch(lex->token) { + case TOKEN_STRING: { + json = json_string_nocheck(lex->value.string); + break; + } + + case TOKEN_INTEGER: { + if (flags & JSON_DECODE_INT_AS_REAL) { + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + return NULL; + } + json = json_real(value); + } else { + json = json_integer(lex->value.integer); + } + break; + } + + case TOKEN_REAL: { + json = json_real(lex->value.real); + break; + } + + case TOKEN_TRUE: + json = json_true(); + break; + + case TOKEN_FALSE: + json = json_false(); + break; + + case TOKEN_NULL: + json = json_null(); + break; + + case '{': + json = parse_object(lex, flags, error); + break; + + case '[': + json = parse_array(lex, flags, error); + break; + + case TOKEN_INVALID: + error_set(error, lex, "invalid token"); + return NULL; + + default: + error_set(error, lex, "unexpected token"); + return NULL; + } + + if(!json) + return NULL; + + return json; +} + +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *result; + + lex_scan(lex, error); + if(!(flags & JSON_DECODE_ANY)) { + if(lex->token != '[' && lex->token != '{') { + error_set(error, lex, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if(!result) + return NULL; + + if(!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if(lex->token != TOKEN_EOF) { + error_set(error, lex, "end of file expected"); + json_decref(result); + return NULL; + } + } + + if(error) { + /* Save the position even though there was no error */ + error->position = lex->stream.position; + } + + return result; +} + +typedef struct +{ + const char *data; + int pos; +} string_data_t; + +static int string_get(void *data) +{ + char c; + string_data_t *stream = (string_data_t *)data; + c = stream->data[stream->pos]; + if(c == '\0') + return EOF; + else + { + stream->pos++; + return (unsigned char)c; + } +} + +json_t *json_loads(const char *string, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if(lex_init(&lex, string_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct +{ + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) +{ + char c; + buffer_data_t *stream = data; + if(stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + buffer_data_t stream_data; + + jsonp_error_init(error, ""); + + if (buffer == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; + + if(lex_init(&lex, buffer_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) +{ + lex_t lex; + const char *source; + json_t *result; + + if(input == stdin) + source = ""; + else + source = ""; + + jsonp_error_init(error, source); + + if (input == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)fgetc, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) +{ + json_t *result; + FILE *fp; + + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + fp = fopen(path, "rb"); + if(!fp) + { + error_set(error, NULL, "unable to open %s: %s", + path, strerror(errno)); + return NULL; + } + + result = json_loadf(fp, flags, error); + + fclose(fp); + return result; +} + +#define MAX_BUF_LEN 1024 + +typedef struct +{ + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) +{ + char c; + callback_data_t *stream = data; + + if(stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if(stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)callback_get, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/netloc/jansson/src/lookup3.h b/netloc/jansson/src/lookup3.h new file mode 100644 index 0000000000..c63ecbf216 --- /dev/null +++ b/netloc/jansson/src/lookup3.h @@ -0,0 +1,366 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include /* defines uint32_t etc */ +#endif + +#ifdef HAVE_SYS_PARAM_H +#include /* attempt to define endianness */ +#endif + +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} diff --git a/netloc/jansson/src/memory.c b/netloc/jansson/src/memory.c new file mode 100644 index 0000000000..ebd51b17cb --- /dev/null +++ b/netloc/jansson/src/memory.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * Copyright © 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) +{ + if(!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) +{ + if(!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) +{ + char *new_str; + size_t len; + + len = strlen(str); + if(len == (size_t)-1) + return NULL; + + new_str = jsonp_malloc(len + 1); + if(!new_str) + return NULL; + + memcpy(new_str, str, len + 1); + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) +{ + do_malloc = malloc_fn; + do_free = free_fn; +} diff --git a/netloc/jansson/src/pack_unpack.c b/netloc/jansson/src/pack_unpack.c new file mode 100644 index 0000000000..ef0bc5e2e7 --- /dev/null +++ b/netloc/jansson/src/pack_unpack.c @@ -0,0 +1,762 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * Copyright © 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { + "object", + "array", + "string", + "integer", + "real", + "true", + "false", + "null" +}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + + +static void scanner_init(scanner_t *s, json_error_t *error, + size_t flags, const char *fmt) +{ + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; +} + +static void next_token(scanner_t *s) +{ + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if(*t == '\n') { + s->line++; + s->column = 1; + } + else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + fmt, ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, + const char *purpose, int *ours) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + char *result; + + next_token(s); + t = token(s); + prev_token(s); + + if(t != '#' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + set_error(s, "", "NULL string argument"); + return NULL; + } + + if(!utf8_check_string(str, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 0; + return (char *)str; + } + + strbuffer_init(&strbuff); + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "", "NULL string argument"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + + if(token(s) == '#') { + length = va_arg(*ap, int); + } + else { + prev_token(s); + length = strlen(str); + } + + if(strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", "Out of memory"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + result = strbuffer_steal_value(&strbuff); + + if(!utf8_check_string(result, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 1; + return result; +} + +static json_t *pack_object(scanner_t *s, va_list *ap) +{ + json_t *object = json_object(); + next_token(s); + + while(token(s) != '}') { + char *key; + int ours; + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &ours); + if(!key) + goto error; + + next_token(s); + + value = pack(s, ap); + if(!value) + goto error; + + if(json_object_set_new_nocheck(object, key, value)) { + if(ours) + jsonp_free(key); + + set_error(s, "", "Unable to add key \"%s\"", key); + goto error; + } + + if(ours) + jsonp_free(key); + + next_token(s); + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) +{ + json_t *array = json_array(); + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + value = pack(s, ap); + if(!value) + goto error; + + if(json_array_append_new(array, value)) { + set_error(s, "", "Unable to append to array"); + goto error; + } + + next_token(s); + } + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack(scanner_t *s, va_list *ap) +{ + switch(token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': { /* string */ + char *str; + int ours; + json_t *result; + + str = read_string(s, ap, "string", &ours); + if(!str) + return NULL; + + result = json_string_nocheck(str); + if(ours) + jsonp_free(str); + + return result; + } + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return json_integer(va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return json_integer(va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return json_real(va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return json_incref(va_arg(*ap, json_t *)); + + case 'o': /* a json_t object; doesn't increment refcount */ + return va_arg(*ap, json_t *); + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) +{ + int ret = -1; + int strict = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if(hashtable_init(&key_set)) { + set_error(s, "", "Out of memory"); + return -1; + } + + if(root && !json_is_object(root)) { + set_error(s, "", "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while(token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if(strict != 0) { + set_error(s, "", "Expected '}' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), token(s)); + goto out; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto out; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if(!key) { + set_error(s, "", "NULL object key"); + goto out; + } + + next_token(s); + + if(token(s) == '?') { + opt = 1; + next_token(s); + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_object_get(root, key); + if(!value && !opt) { + set_error(s, "", "Object item not found: %s", key); + goto out; + } + } + + if(unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, 0, json_null()); + next_token(s); + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && key_set.size != json_object_size(root)) { + long diff = (long)json_object_size(root) - (long)key_set.size; + set_error(s, "", "%li object item(s) left unpacked", diff); + goto out; + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) +{ + size_t i = 0; + int strict = 0; + + if(root && !json_is_array(root)) { + set_error(s, "", "Expected array, got %s", type_name(root)); + return -1; + } + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(strict != 0) { + set_error(s, "", "Expected ']' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + return -1; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(!strchr(unpack_value_starters, token(s))) { + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_array_get(root, i); + if(!value) { + set_error(s, "", "Array index %lu out of range", + (unsigned long)i); + return -1; + } + } + + if(unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) +{ + switch(token(s)) + { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if(root && !json_is_string(root)) { + set_error(s, "", "Expected string, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + const char **target; + + target = va_arg(*ap, const char **); + if(!target) { + set_error(s, "", "NULL string argument"); + return -1; + } + + if(root) + *target = json_string_value(root); + } + return 0; + + case 'i': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t*); + if(root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if(root && !json_is_boolean(root)) { + set_error(s, "", "Expected true or false, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if(root && !json_is_real(root)) { + set_error(s, "", "Expected real, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if(root && !json_is_number(root)) { + set_error(s, "", "Expected real or integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if(root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t**); + if(root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if(root && !json_is_null(root)) { + set_error(s, "", "Expected null, got %s", + type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + json_t *value; + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + if(!value) + return NULL; + + next_token(&s); + if(token(&s)) { + json_decref(value); + set_error(&s, "", "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + + if(!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL root value"); + return -1; + } + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if(unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if(token(&s)) { + set_error(&s, "", "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/netloc/jansson/src/strbuffer.c b/netloc/jansson/src/strbuffer.c new file mode 100644 index 0000000000..9701c13694 --- /dev/null +++ b/netloc/jansson/src/strbuffer.c @@ -0,0 +1,116 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +#define STRBUFFER_MIN_SIZE 16 +#define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) + +int strbuffer_init(strbuffer_t *strbuff) +{ + strbuff->size = STRBUFFER_MIN_SIZE; + strbuff->length = 0; + + strbuff->value = jsonp_malloc(strbuff->size); + if(!strbuff->value) + return -1; + + /* initialize to empty */ + strbuff->value[0] = '\0'; + return 0; +} + +void strbuffer_close(strbuffer_t *strbuff) +{ + if(strbuff->value) + jsonp_free(strbuff->value); + + strbuff->size = 0; + strbuff->length = 0; + strbuff->value = NULL; +} + +void strbuffer_clear(strbuffer_t *strbuff) +{ + strbuff->length = 0; + strbuff->value[0] = '\0'; +} + +const char *strbuffer_value(const strbuffer_t *strbuff) +{ + return strbuff->value; +} + +char *strbuffer_steal_value(strbuffer_t *strbuff) +{ + char *result = strbuff->value; + strbuff->value = NULL; + return result; +} + +int strbuffer_append(strbuffer_t *strbuff, const char *string) +{ + return strbuffer_append_bytes(strbuff, string, strlen(string)); +} + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte) +{ + return strbuffer_append_bytes(strbuff, &byte, 1); +} + +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) +{ + if(size >= strbuff->size - strbuff->length) + { + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR + || size > STRBUFFER_SIZE_MAX - 1 + || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, + strbuff->length + size + 1); + + new_value = jsonp_malloc(new_size); + if(!new_value) + return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; + } + + memcpy(strbuff->value + strbuff->length, data, size); + strbuff->length += size; + strbuff->value[strbuff->length] = '\0'; + + return 0; +} + +char strbuffer_pop(strbuffer_t *strbuff) +{ + if(strbuff->length > 0) { + char c = strbuff->value[--strbuff->length]; + strbuff->value[strbuff->length] = '\0'; + return c; + } + else + return '\0'; +} diff --git a/netloc/jansson/src/strbuffer.h b/netloc/jansson/src/strbuffer.h new file mode 100644 index 0000000000..fccb1bd829 --- /dev/null +++ b/netloc/jansson/src/strbuffer.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STRBUFFER_H +#define STRBUFFER_H + +typedef struct { + char *value; + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ +} strbuffer_t; + +int strbuffer_init(strbuffer_t *strbuff); +void strbuffer_close(strbuffer_t *strbuff); + +void strbuffer_clear(strbuffer_t *strbuff); + +const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ +char *strbuffer_steal_value(strbuffer_t *strbuff); + +int strbuffer_append(strbuffer_t *strbuff, const char *string); +int strbuffer_append_byte(strbuffer_t *strbuff, char byte); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); + +char strbuffer_pop(strbuffer_t *strbuff); + +#endif diff --git a/netloc/jansson/src/strconv.c b/netloc/jansson/src/strconv.c new file mode 100644 index 0000000000..3e2cb7c4ce --- /dev/null +++ b/netloc/jansson/src/strconv.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +/* need config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if(pos) + *pos = *point; +} + +static void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) +{ + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if(errno == ERANGE && value != 0) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value) +{ + int ret; + char *start, *end; + size_t length; + + ret = snprintf(buffer, size, "%.17g", value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(buffer, '.') == NULL && + strchr(buffer, 'e') == NULL) + { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/netloc/jansson/src/utf.c b/netloc/jansson/src/utf.c new file mode 100644 index 0000000000..79b456b1f8 --- /dev/null +++ b/netloc/jansson/src/utf.c @@ -0,0 +1,190 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "utf.h" + +int utf8_encode(int32_t codepoint, char *buffer, int *size) +{ + if(codepoint < 0) + return -1; + else if(codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if(codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if(codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if(codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +int utf8_check_first(char byte) +{ + unsigned char u = (unsigned char)byte; + + if(u < 0x80) + return 1; + + if(0x80 <= u && u <= 0xBF) { + /* second, third or fourth byte of a multi-byte + sequence, i.e. a "continuation byte" */ + return 0; + } + else if(u == 0xC0 || u == 0xC1) { + /* overlong encoding of an ASCII byte */ + return 0; + } + else if(0xC2 <= u && u <= 0xDF) { + /* 2-byte sequence */ + return 2; + } + + else if(0xE0 <= u && u <= 0xEF) { + /* 3-byte sequence */ + return 3; + } + else if(0xF0 <= u && u <= 0xF4) { + /* 4-byte sequence */ + return 4; + } + else { /* u >= 0xF5 */ + /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid + UTF-8 */ + return 0; + } +} + +int utf8_check_full(const char *buffer, int size, int32_t *codepoint) +{ + int i; + int32_t value = 0; + unsigned char u = (unsigned char)buffer[0]; + + if(size == 2) + { + value = u & 0x1F; + } + else if(size == 3) + { + value = u & 0xF; + } + else if(size == 4) + { + value = u & 0x7; + } + else + return 0; + + for(i = 1; i < size; i++) + { + u = (unsigned char)buffer[i]; + + if(u < 0x80 || u > 0xBF) { + /* not a continuation byte */ + return 0; + } + + value = (value << 6) + (u & 0x3F); + } + + if(value > 0x10FFFF) { + /* not in Unicode range */ + return 0; + } + + else if(0xD800 <= value && value <= 0xDFFF) { + /* invalid code point (UTF-16 surrogate halves) */ + return 0; + } + + else if((size == 2 && value < 0x80) || + (size == 3 && value < 0x800) || + (size == 4 && value < 0x10000)) { + /* overlong encoding */ + return 0; + } + + if(codepoint) + *codepoint = value; + + return 1; +} + +const char *utf8_iterate(const char *buffer, int32_t *codepoint) +{ + int count; + int32_t value; + + if(!*buffer) + return buffer; + + count = utf8_check_first(buffer[0]); + if(count <= 0) + return NULL; + + if(count == 1) + value = (unsigned char)buffer[0]; + else + { + if(!utf8_check_full(buffer, count, &value)) + return NULL; + } + + if(codepoint) + *codepoint = value; + + return buffer + count; +} + +int utf8_check_string(const char *string, int length) +{ + int i; + + if(length == -1) + length = strlen(string); + + for(i = 0; i < length; i++) + { + int count = utf8_check_first(string[i]); + if(count == 0) + return 0; + else if(count > 1) + { + if(i + count > length) + return 0; + + if(!utf8_check_full(&string[i], count, NULL)) + return 0; + + i += count - 1; + } + } + + return 1; +} diff --git a/netloc/jansson/src/utf.h b/netloc/jansson/src/utf.h new file mode 100644 index 0000000000..ade81dbe3b --- /dev/null +++ b/netloc/jansson/src/utf.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTF_H +#define UTF_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +int utf8_encode(int codepoint, char *buffer, int *size); + +int utf8_check_first(char byte); +int utf8_check_full(const char *buffer, int size, int32_t *codepoint); +const char *utf8_iterate(const char *buffer, int32_t *codepoint); + +int utf8_check_string(const char *string, int length); + +#endif diff --git a/netloc/jansson/src/value.c b/netloc/jansson/src/value.c new file mode 100644 index 0000000000..a91a4ad940 --- /dev/null +++ b/netloc/jansson/src/value.c @@ -0,0 +1,966 @@ +/* + * Copyright © 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "jansson.h" +#include "hashtable.h" +#include "jansson_private.h" +#include "utf.h" + +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif + +static JSON_INLINE void json_init(json_t *json, json_type type) +{ + json->type = type; + json->refcount = 1; +} + + +/*** object ***/ + +extern volatile uint32_t hashtable_seed; + +json_t *json_object(void) +{ + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); + if(!object) + return NULL; + + if (!hashtable_seed) { + /* Autoseed */ + json_object_seed(0); + } + + json_init(&object->json, JSON_OBJECT); + + if(hashtable_init(&object->hashtable)) + { + jsonp_free(object); + return NULL; + } + + object->serial = 0; + object->visited = 0; + + return &object->json; +} + +static void json_delete_object(json_object_t *object) +{ + hashtable_close(&object->hashtable); + jsonp_free(object); +} + +size_t json_object_size(const json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return 0; + + object = json_to_object(json); + return object->hashtable.size; +} + +json_t *json_object_get(const json_t *json, const char *key) +{ + json_object_t *object; + + if(!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_get(&object->hashtable, key); +} + +int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) +{ + json_object_t *object; + + if(!value) + return -1; + + if(!key || !json_is_object(json) || json == value) + { + json_decref(value); + return -1; + } + object = json_to_object(json); + + if(hashtable_set(&object->hashtable, key, object->serial++, value)) + { + json_decref(value); + return -1; + } + + return 0; +} + +int json_object_set_new(json_t *json, const char *key, json_t *value) +{ + if(!key || !utf8_check_string(key, -1)) + { + json_decref(value); + return -1; + } + + return json_object_set_new_nocheck(json, key, value); +} + +int json_object_del(json_t *json, const char *key) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + return hashtable_del(&object->hashtable, key); +} + +int json_object_clear(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + + hashtable_clear(&object->hashtable); + object->serial = 0; + + return 0; +} + +int json_object_update(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_set_nocheck(object, key, value)) + return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(!json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +void *json_object_iter(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter(&object->hashtable); +} + +void *json_object_iter_at(json_t *json, const char *key) +{ + json_object_t *object; + + if(!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter_at(&object->hashtable, key); +} + +void *json_object_iter_next(json_t *json, void *iter) +{ + json_object_t *object; + + if(!json_is_object(json) || iter == NULL) + return NULL; + + object = json_to_object(json); + return hashtable_iter_next(&object->hashtable, iter); +} + +const char *json_object_iter_key(void *iter) +{ + if(!iter) + return NULL; + + return hashtable_iter_key(iter); +} + +json_t *json_object_iter_value(void *iter) +{ + if(!iter) + return NULL; + + return (json_t *)hashtable_iter_value(iter); +} + +int json_object_iter_set_new(json_t *json, void *iter, json_t *value) +{ + if(!json_is_object(json) || !iter || !value) + return -1; + + hashtable_iter_set(iter, value); + return 0; +} + +void *json_object_key_to_iter(const char *key) +{ + if(!key) + return NULL; + + return hashtable_key_to_iter(key); +} + +static int json_object_equal(json_t *object1, json_t *object2) +{ + const char *key; + json_t *value1, *value2; + + if(json_object_size(object1) != json_object_size(object2)) + return 0; + + json_object_foreach(object1, key, value1) { + value2 = json_object_get(object2, key); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_object_copy(json_t *object) +{ + json_t *result; + + const char *key; + json_t *value; + + result = json_object(); + if(!result) + return NULL; + + json_object_foreach(object, key, value) + json_object_set_nocheck(result, key, value); + + return result; +} + +static json_t *json_object_deep_copy(const json_t *object) +{ + json_t *result; + void *iter; + + result = json_object(); + if(!result) + return NULL; + + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { + const char *key; + const json_t *value; + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); + } + + return result; +} + + +/*** array ***/ + +json_t *json_array(void) +{ + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); + if(!array) + return NULL; + json_init(&array->json, JSON_ARRAY); + + array->entries = 0; + array->size = 8; + + array->table = jsonp_malloc(array->size * sizeof(json_t *)); + if(!array->table) { + jsonp_free(array); + return NULL; + } + + array->visited = 0; + + return &array->json; +} + +static void json_delete_array(json_array_t *array) +{ + size_t i; + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + jsonp_free(array->table); + jsonp_free(array); +} + +size_t json_array_size(const json_t *json) +{ + if(!json_is_array(json)) + return 0; + + return json_to_array(json)->entries; +} + +json_t *json_array_get(const json_t *json, size_t index) +{ + json_array_t *array; + if(!json_is_array(json)) + return NULL; + array = json_to_array(json); + + if(index >= array->entries) + return NULL; + + return array->table[index]; +} + +int json_array_set_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index >= array->entries) + { + json_decref(value); + return -1; + } + + json_decref(array->table[index]); + array->table[index] = value; + + return 0; +} + +static void array_move(json_array_t *array, size_t dest, + size_t src, size_t count) +{ + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, size_t dpos, + json_t **src, size_t spos, + size_t count) +{ + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, + size_t amount, + int copy) +{ + size_t new_size; + json_t **old_table, **new_table; + + if(array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); + if(!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if(copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + jsonp_free(old_table); + return array->table; + } + + return old_table; +} + +int json_array_append_new(json_t *json, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; + } + + array->table[array->entries] = value; + array->entries++; + + return 0; +} + +int json_array_insert_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + json_t **old_table; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if(!old_table) { + json_decref(value); + return -1; + } + + if(old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, + array->entries - index); + jsonp_free(old_table); + } + else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, size_t index) +{ + json_array_t *array; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + if(index >= array->entries) + return -1; + + json_decref(array->table[index]); + + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) +{ + json_array_t *array; + size_t i; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) +{ + json_array_t *array, *other; + size_t i; + + if(!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if(!json_array_grow(array, other->entries, 1)) + return -1; + + for(i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + +static int json_array_equal(json_t *array1, json_t *array2) +{ + size_t i, size; + + size = json_array_size(array1); + if(size != json_array_size(array2)) + return 0; + + for(i = 0; i < size; i++) + { + json_t *value1, *value2; + + value1 = json_array_get(array1, i); + value2 = json_array_get(array2, i); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_array_copy(json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append(result, json_array_get(array, i)); + + return result; +} + +static json_t *json_array_deep_copy(const json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append_new(result, json_deep_copy(json_array_get(array, i))); + + return result; +} + +/*** string ***/ + +json_t *json_string_nocheck(const char *value) +{ + json_string_t *string; + + if(!value) + return NULL; + + string = jsonp_malloc(sizeof(json_string_t)); + if(!string) + return NULL; + json_init(&string->json, JSON_STRING); + + string->value = jsonp_strdup(value); + if(!string->value) { + jsonp_free(string); + return NULL; + } + + return &string->json; +} + +json_t *json_string(const char *value) +{ + if(!value || !utf8_check_string(value, -1)) + return NULL; + + return json_string_nocheck(value); +} + +const char *json_string_value(const json_t *json) +{ + if(!json_is_string(json)) + return NULL; + + return json_to_string(json)->value; +} + +int json_string_set_nocheck(json_t *json, const char *value) +{ + char *dup; + json_string_t *string; + + if(!json_is_string(json) || !value) + return -1; + + dup = jsonp_strdup(value); + if(!dup) + return -1; + + string = json_to_string(json); + jsonp_free(string->value); + string->value = dup; + + return 0; +} + +int json_string_set(json_t *json, const char *value) +{ + if(!value || !utf8_check_string(value, -1)) + return -1; + + return json_string_set_nocheck(json, value); +} + +static void json_delete_string(json_string_t *string) +{ + jsonp_free(string->value); + jsonp_free(string); +} + +static int json_string_equal(json_t *string1, json_t *string2) +{ + return strcmp(json_string_value(string1), json_string_value(string2)) == 0; +} + +static json_t *json_string_copy(const json_t *string) +{ + return json_string_nocheck(json_string_value(string)); +} + + +/*** integer ***/ + +json_t *json_integer(json_int_t value) +{ + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); + if(!integer) + return NULL; + json_init(&integer->json, JSON_INTEGER); + + integer->value = value; + return &integer->json; +} + +json_int_t json_integer_value(const json_t *json) +{ + if(!json_is_integer(json)) + return 0; + + return json_to_integer(json)->value; +} + +int json_integer_set(json_t *json, json_int_t value) +{ + if(!json_is_integer(json)) + return -1; + + json_to_integer(json)->value = value; + + return 0; +} + +static void json_delete_integer(json_integer_t *integer) +{ + jsonp_free(integer); +} + +static int json_integer_equal(json_t *integer1, json_t *integer2) +{ + return json_integer_value(integer1) == json_integer_value(integer2); +} + +static json_t *json_integer_copy(const json_t *integer) +{ + return json_integer(json_integer_value(integer)); +} + + +/*** real ***/ + +json_t *json_real(double value) +{ + json_real_t *real; + + if(isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); + if(!real) + return NULL; + json_init(&real->json, JSON_REAL); + + real->value = value; + return &real->json; +} + +double json_real_value(const json_t *json) +{ + if(!json_is_real(json)) + return 0; + + return json_to_real(json)->value; +} + +int json_real_set(json_t *json, double value) +{ + if(!json_is_real(json) || isnan(value) || isinf(value)) + return -1; + + json_to_real(json)->value = value; + + return 0; +} + +static void json_delete_real(json_real_t *real) +{ + jsonp_free(real); +} + +static int json_real_equal(json_t *real1, json_t *real2) +{ + return json_real_value(real1) == json_real_value(real2); +} + +static json_t *json_real_copy(const json_t *real) +{ + return json_real(json_real_value(real)); +} + + +/*** number ***/ + +double json_number_value(const json_t *json) +{ + if(json_is_integer(json)) + return (double)json_integer_value(json); + else if(json_is_real(json)) + return json_real_value(json); + else + return 0.0; +} + + +/*** simple values ***/ + +json_t *json_true(void) +{ + static json_t the_true = {JSON_TRUE, (size_t)-1}; + return &the_true; +} + + +json_t *json_false(void) +{ + static json_t the_false = {JSON_FALSE, (size_t)-1}; + return &the_false; +} + + +json_t *json_null(void) +{ + static json_t the_null = {JSON_NULL, (size_t)-1}; + return &the_null; +} + + +/*** deletion ***/ + +void json_delete(json_t *json) +{ + if(json_is_object(json)) + json_delete_object(json_to_object(json)); + + else if(json_is_array(json)) + json_delete_array(json_to_array(json)); + + else if(json_is_string(json)) + json_delete_string(json_to_string(json)); + + else if(json_is_integer(json)) + json_delete_integer(json_to_integer(json)); + + else if(json_is_real(json)) + json_delete_real(json_to_real(json)); + + /* json_delete is not called for true, false or null */ +} + + +/*** equality ***/ + +int json_equal(json_t *json1, json_t *json2) +{ + if(!json1 || !json2) + return 0; + + if(json_typeof(json1) != json_typeof(json2)) + return 0; + + /* this covers true, false and null as they are singletons */ + if(json1 == json2) + return 1; + + if(json_is_object(json1)) + return json_object_equal(json1, json2); + + if(json_is_array(json1)) + return json_array_equal(json1, json2); + + if(json_is_string(json1)) + return json_string_equal(json1, json2); + + if(json_is_integer(json1)) + return json_integer_equal(json1, json2); + + if(json_is_real(json1)) + return json_real_equal(json1, json2); + + return 0; +} + + +/*** copying ***/ + +json_t *json_copy(json_t *json) +{ + if(!json) + return NULL; + + if(json_is_object(json)) + return json_object_copy(json); + + if(json_is_array(json)) + return json_array_copy(json); + + if(json_is_string(json)) + return json_string_copy(json); + + if(json_is_integer(json)) + return json_integer_copy(json); + + if(json_is_real(json)) + return json_real_copy(json); + + if(json_is_true(json) || json_is_false(json) || json_is_null(json)) + return json; + + return NULL; +} + +json_t *json_deep_copy(const json_t *json) +{ + if(!json) + return NULL; + + if(json_is_object(json)) + return json_object_deep_copy(json); + + if(json_is_array(json)) + return json_array_deep_copy(json); + + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + + if(json_is_string(json)) + return json_string_copy(json); + + if(json_is_integer(json)) + return json_integer_copy(json); + + if(json_is_real(json)) + return json_real_copy(json); + + if(json_is_true(json) || json_is_false(json) || json_is_null(json)) + return (json_t *)json; + + return NULL; +} diff --git a/netloc/lookup_table.c b/netloc/lookup_table.c new file mode 100644 index 0000000000..5a9626ef24 --- /dev/null +++ b/netloc/lookup_table.c @@ -0,0 +1,538 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include + +#define HASH_GROWS_BY 8 + +/** + * Constructor for netloc_lookup_table_entry_t + * + * User is responsible for calling the destructor on the handle returned. + * + * Returns + * A newly allocated pointer to the lookup table entry + */ +netloc_lookup_table_entry_t *netloc_lookup_table_entry_t_construct(); + +/** + * Do a -shallow copy- of the data in the table entry. + * + * User is responsible for calling the destructor on the handle returned. + * + * \param hte A valid pointer to a lookup table entry + * \param dup Set to 1 if keys are internally duplicated + * + * Returns + * NULL if an error occurs + * otherwise returns a newly allocated pointer to a lookup table entry. + */ +netloc_lookup_table_entry_t *netloc_copy_lookup_table_entry_t(netloc_lookup_table_entry_t* hte, int dup); + +/** + * Destructor for a netloc_lookup_table_entry_t + * + * \param hte A void pointer to a lookup table entry + * \param dup Set to 1 if keys are internally duplicated + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR on error + */ +int netloc_lookup_table_entry_t_destruct(netloc_lookup_table_entry_t* hte, int dup); + + +/********************************************************************** + * Function Definitions + **********************************************************************/ +struct netloc_dt_lookup_table_iterator *netloc_dt_lookup_table_iterator_t_construct(struct netloc_dt_lookup_table *ht) +{ + struct netloc_dt_lookup_table_iterator* hti = NULL; + + hti = (struct netloc_dt_lookup_table_iterator*)malloc(sizeof(struct netloc_dt_lookup_table_iterator)); + if( NULL == hti ) { + return NULL; + } + + hti->htp = ht; + hti->loc = 0; + hti->at_end = false; + + return hti; +} + +int netloc_dt_lookup_table_iterator_t_destruct(struct netloc_dt_lookup_table_iterator* hti) +{ + if( NULL == hti ) { + return NETLOC_SUCCESS; + } + + hti->htp = NULL; + hti->loc = 0; + hti->at_end = true; + + free(hti); + return NETLOC_SUCCESS; +} + +int netloc_lookup_table_size(struct netloc_dt_lookup_table *table) { + if( NULL == table ) { + return 0; + } else { + return table->ht_used_size; + } +} + +int netloc_lookup_table_size_alloc(struct netloc_dt_lookup_table *table) { + if( NULL == table ) { + return 0; + } else { + return table->ht_size; + } +} + +const char * netloc_lookup_table_iterator_next_key(struct netloc_dt_lookup_table_iterator* hti) +{ + size_t i; + + for(i = hti->loc; i < netloc_lookup_table_size(hti->htp); ++i) { + if( NULL != hti->htp->ht_entries[i] ) { + hti->loc = i+1; + return hti->htp->ht_entries[i]->key; + } + } + + hti->loc = netloc_lookup_table_size(hti->htp); + hti->at_end = true; + + return NULL; +} + +unsigned long netloc_lookup_table_iterator_next_key_int(struct netloc_dt_lookup_table_iterator* hti) +{ + size_t i; + + for(i = hti->loc; i < netloc_lookup_table_size(hti->htp); ++i) { + if( NULL != hti->htp->ht_entries[i] ) { + hti->loc = i+1; + return hti->htp->ht_entries[i]->__key__; + } + } + + hti->loc = netloc_lookup_table_size(hti->htp); + hti->at_end = true; + + return 0; +} + +void * netloc_lookup_table_iterator_next_entry(struct netloc_dt_lookup_table_iterator* hti) +{ + size_t i; + + for(i = hti->loc; i < netloc_lookup_table_size(hti->htp); ++i) { + if( NULL != hti->htp->ht_entries[i] ) { + hti->loc = i+1; + return hti->htp->ht_entries[i]->value; + } + } + + hti->loc = netloc_lookup_table_size(hti->htp); + hti->at_end = true; + + return NULL; +} + +bool netloc_lookup_table_iterator_at_end(struct netloc_dt_lookup_table_iterator *hti) { + return hti->at_end; +} + +void netloc_lookup_table_iterator_reset(struct netloc_dt_lookup_table_iterator *hti) { + hti->loc = 0; + hti->at_end = false; +} + +netloc_lookup_table_entry_t *netloc_lookup_table_entry_t_construct() +{ + netloc_lookup_table_entry_t* hte = NULL; + + hte = (netloc_lookup_table_entry_t*)malloc(sizeof(netloc_lookup_table_entry_t)); + if( NULL == hte ){ + return NULL; + } + + hte->__key__ = 0; + hte->key = NULL; + hte->value = NULL; + + return hte; +} + +netloc_lookup_table_entry_t *netloc_copy_lookup_table_entry_t(netloc_lookup_table_entry_t* orig, int dup) +{ + netloc_lookup_table_entry_t* hte = NULL; + hte = netloc_lookup_table_entry_t_construct(); + + hte->__key__ = orig->__key__; + hte->key = dup ? strdup(orig->key) : orig->key; + hte->value = orig->value; + + return hte; +} + +int netloc_lookup_table_entry_t_destruct(netloc_lookup_table_entry_t* hte, int dup) +{ + if( NULL == hte ) { + return NETLOC_SUCCESS; + } + + hte->__key__ = 0; + + if( NULL != hte->key ) { + if (dup) { + free((char*) hte->key); + } + hte->key = NULL; + } + hte->value = NULL; + + free(hte); + + return NETLOC_SUCCESS; +} + +int netloc_dt_lookup_table_t_copy(struct netloc_dt_lookup_table *from, struct netloc_dt_lookup_table *to) +{ + size_t i; + int dup = !(from->flags & NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + + if( NULL == from || NULL == to ) { + return NETLOC_ERROR; + } + + netloc_lookup_table_init(to, netloc_lookup_table_size(from), from->flags); + + for(i = 0; i < from->ht_size; ++i ) { + if( NULL != from->ht_entries[i] ) { + to->ht_entries[i] = netloc_copy_lookup_table_entry_t(from->ht_entries[i], dup); + } + } + + return NETLOC_SUCCESS; +} + +int netloc_lookup_table_init(struct netloc_dt_lookup_table *ht, size_t size, unsigned long flags) +{ + size_t i; + + if( NULL == ht ) { + fprintf(stderr, "Error: Hash Table handle is NULL!\n"); + return NETLOC_ERROR; + } + + ht->ht_entries = (netloc_lookup_table_entry_t**)malloc(sizeof(netloc_lookup_table_entry_t*) * size); + if( NULL == ht->ht_entries ) { + return NETLOC_ERROR; + } + ht->ht_size = size; + ht->ht_used_size = 0; + ht->flags = flags; + + for(i = 0; i < ht->ht_size; ++i ) { + ht->ht_entries[i] = NULL; + } + + return NETLOC_SUCCESS; +} + +int netloc_lookup_table_destroy(struct netloc_dt_lookup_table *ht) +{ + size_t i; + int dup; + + if( NULL == ht ) { + fprintf(stderr, "Error: Hash Table handle is NULL!\n"); + return NETLOC_ERROR; + } + + dup = !(ht->flags & NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + + for(i = 0; i < ht->ht_size; ++i) { + if( NULL != ht->ht_entries[i] ) { + netloc_lookup_table_entry_t_destruct(ht->ht_entries[i], dup); + } + } + free(ht->ht_entries); + ht->ht_entries = NULL; + ht->ht_size = 0; + ht->ht_used_size = 0; + + return NETLOC_SUCCESS; +} + +int netloc_lookup_table_append(struct netloc_dt_lookup_table *ht, const char *key, void *value) +{ + unsigned long hashed_key; + // JJH : Add hash function + hashed_key = 0; + + return netloc_lookup_table_append_with_int(ht, key, hashed_key, value); +} + +int netloc_lookup_table_append_with_int(struct netloc_dt_lookup_table *ht, const char *key, unsigned long key_int, void *value) +{ + int dup = !(ht->flags & NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + size_t i, a; + int len; + + // Check if key already exists! + // If not then we are looking at the next free entry + for(i = 0; i < ht->ht_size; ++i ) { + if( NULL == ht->ht_entries[i] ) { + break; + } + else { + if( 0 != key_int ) { + if( key_int == ht->ht_entries[i]->__key__ ) { + return NETLOC_ERROR_EXISTS; + } + } + else { + if( strlen(key) > strlen(ht->ht_entries[i]->key) ) { + len = strlen(key); + } else { + len = strlen(ht->ht_entries[i]->key); + } + if( 0 == strncmp(ht->ht_entries[i]->key, key, len) ) { + return NETLOC_ERROR_EXISTS; + } + } + } + } + + /* + * Grow the lookup table as needed + */ + if( i == ht->ht_size ) { + ht->ht_size += HASH_GROWS_BY; + ht->ht_entries = (netloc_lookup_table_entry_t**)realloc(ht->ht_entries, sizeof(netloc_lookup_table_entry_t*) * ht->ht_size); + for(a = i; a < ht->ht_size; ++a) { + ht->ht_entries[a] = NULL; + } + } + + ht->ht_entries[i] = netloc_lookup_table_entry_t_construct(); + ht->ht_entries[i]->key = dup ? strdup(key) : key; + ht->ht_entries[i]->value = value; + ht->ht_entries[i]->__key__ = key_int; + ht->ht_used_size += 1; + + return NETLOC_SUCCESS; +} + +void * netloc_lookup_table_access(struct netloc_dt_lookup_table *ht, const char *key) +{ + unsigned long hashed_key; + // JJH : Add hash function + hashed_key = 0; + + return netloc_lookup_table_access_with_int(ht, key, hashed_key); +} + +void * netloc_lookup_table_access_with_int(struct netloc_dt_lookup_table *ht, const char *key, unsigned long key_int) +{ + size_t i; + int len; + + for(i = 0; i < ht->ht_size; ++i ) { + if( NULL == ht->ht_entries[i] ) { + continue; + } + else { + if( 0 != key_int ) { + if( key_int == ht->ht_entries[i]->__key__ ) { + return ht->ht_entries[i]->value; + } + } + else { + if( strlen(key) > strlen(ht->ht_entries[i]->key) ) { + len = strlen(key); + } else { + len = strlen(ht->ht_entries[i]->key); + } + if( 0 == strncmp(ht->ht_entries[i]->key, key, len) ) { + return ht->ht_entries[i]->value; + } + } + } + } + + return NULL; +} + +int netloc_lookup_table_replace(struct netloc_dt_lookup_table *ht, const char *key, void *value) +{ + unsigned long hashed_key; + // JJH : Add hash function + hashed_key = 0; + + return netloc_lookup_table_replace_with_int(ht, key, hashed_key, value); +} + +int netloc_lookup_table_replace_with_int(struct netloc_dt_lookup_table *ht, const char *key, unsigned long key_int, void *value) +{ + size_t i; + int len; + + // Find this value + for(i = 0; i < ht->ht_size; ++i ) { + if( NULL == ht->ht_entries[i] ) { + break; + } + else { + if( 0 != key_int ) { + if( key_int == ht->ht_entries[i]->__key__ ) { + ht->ht_entries[i]->value = value; + } + } + else { + if( strlen(key) > strlen(ht->ht_entries[i]->key) ) { + len = strlen(key); + } else { + len = strlen(ht->ht_entries[i]->key); + } + if( 0 == strncmp(ht->ht_entries[i]->key, key, len) ) { + ht->ht_entries[i]->value = value; + } + } + } + } + + return NETLOC_SUCCESS; +} + +int netloc_lookup_table_remove(struct netloc_dt_lookup_table *ht, const char *key) +{ + unsigned long hashed_key; + // JJH : Add hash function + hashed_key = 0; + + return netloc_lookup_table_remove_with_int(ht, key, hashed_key); +} +int netloc_lookup_table_remove_with_int(struct netloc_dt_lookup_table *ht, const char *key, unsigned long key_int) +{ + size_t i; + int len; + int idx_to_remove = -1; + int dup = !(ht->flags & NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + + // Find this value + for(i = 0; i < ht->ht_size; ++i ) { + if( NULL == ht->ht_entries[i] ) { + break; + } + else { + if( 0 != key_int ) { + if( key_int == ht->ht_entries[i]->__key__ ) { + idx_to_remove = i; + break; + } + } + else { + if( strlen(key) > strlen(ht->ht_entries[i]->key) ) { + len = strlen(key); + } else { + len = strlen(ht->ht_entries[i]->key); + } + if( 0 == strncmp(ht->ht_entries[i]->key, key, len) ) { + idx_to_remove = i; + break; + } + } + } + } + + if( idx_to_remove < 0 ) { + return NETLOC_ERROR; + } + + netloc_lookup_table_entry_t_destruct(ht->ht_entries[idx_to_remove], dup); + for( i = idx_to_remove; i < ht->ht_size-1; ++i ) { + ht->ht_entries[i] = ht->ht_entries[i+1]; + } + ht->ht_entries[ht->ht_size-1] = NULL; + + ht->ht_used_size -= 1; + + return NETLOC_SUCCESS; +} + +void netloc_lookup_table_pretty_print(struct netloc_dt_lookup_table *ht) +{ + size_t i; + + for(i = 0; i < ht->ht_size; ++i ) { + printf("%3d) ", (int)i); + if( NULL != ht->ht_entries[i] ) { + printf("%4s [%p]", ht->ht_entries[i]->key, ht->ht_entries[i]->value); + } else { + printf("NULL"); + } + printf("\n"); + } +} + +json_t* netloc_dt_lookup_table_t_json_encode(struct netloc_dt_lookup_table *table, + json_t* (*func)(const char * key, void *value)) +{ + json_t *json_lt = NULL; + struct netloc_dt_lookup_table_iterator *hti = NULL; + const char * key = NULL; + void * value = NULL; + + json_lt = json_object(); + + hti = netloc_dt_lookup_table_iterator_t_construct(table); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + key = netloc_lookup_table_iterator_next_key(hti); + if( NULL == key ) { + break; + } + + value = netloc_lookup_table_access(table, key); + + json_object_set_new(json_lt, key, func(key, value)); + } + + netloc_dt_lookup_table_iterator_t_destruct(hti); + + return json_lt; +} + + +struct netloc_dt_lookup_table* netloc_dt_lookup_table_t_json_decode(json_t *json_lt, + void * (*func)(const char *key, json_t* json_obj)) +{ + struct netloc_dt_lookup_table *table = NULL; + const char * key = NULL; + json_t * value = NULL; + + table = calloc(1, sizeof(*table)); + netloc_lookup_table_init(table, json_object_size(json_lt), 0); + + json_object_foreach(json_lt, key, value) { + netloc_lookup_table_append(table, key, func(key, value)); + } + + return table; +} diff --git a/netloc/map.c b/netloc/map.c new file mode 100644 index 0000000000..5a546ce7ad --- /dev/null +++ b/netloc/map.c @@ -0,0 +1,1705 @@ +// +// Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. +// Copyright © 2013 Inria. All rights reserved. +// Copyright © 2013-2014 University of Wisconsin-La Crosse. +// +// See COPYING in top-level directory. +// +// $HEADER$ +// + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include +#include +#include + + +static void netloc_map__destroy_servers(struct netloc_map *map); +static void netloc_map__destroy_subnets(struct netloc_map *map); + +static struct netloc_map__server * netloc_map__get_server_by_name(struct netloc_map *map, const char *name); +static struct netloc_map__subnet * netloc_map__get_subnet_by_id(struct netloc_map *map, netloc_network_type_t type, const char *id); +static struct netloc_map__port * netloc_map__get_port_by_id(struct netloc_map__subnet *subnet, const char *id); + + +/***************************** + * Initializing a netloc_map + */ + +int +netloc_map_create(netloc_map_t *mapp) +{ + struct netloc_map *map; + + map = calloc(sizeof(*map), 1); + if (!map) + goto out; + + char *verbose_env; + verbose_env = getenv("NETLOC_MAP_VERBOSE"); + if (verbose_env) + map->verbose_flags = strtoul(verbose_env, NULL, 0); + + *mapp = map; + return 0; + + out: + return -1; +} + +int +netloc_map_load_hwloc_data(netloc_map_t _map, const char *data_dir) +{ + struct netloc_map *map = _map; + map->hwloc_xml_path = strdup(data_dir); + return 0; +} + +int +netloc_map_load_netloc_data(netloc_map_t _map, const char *data_dir) +{ + struct netloc_map *map = _map; + map->netloc_data_path = strdup(data_dir); + return 0; +} + + +/******************************** + * Managing hwloc topology diffs + */ + +static int +netloc_map__prepare_hwloc_topology(struct netloc_map *map, + struct netloc_map__server *server) +{ + if (map->flags & NETLOC_MAP_BUILD_FLAG_COMPRESS_HWLOC + && !server->topology) { + unsigned i; + int err; + if (map->verbose_flags & NETLOC_MAP_VERBOSE_FLAG_COMPRESS) + printf("uncompressing hwloc topology %s from %s\n", + server->name, server->topology_diff_refserver->name); + err = hwloc_topology_dup(&server->topology, server->topology_diff_refserver->topology); + if (err < 0) + return -1; + err = hwloc_topology_diff_apply(server->topology, server->topology_diff, 0); + if (err < 0) { + hwloc_topology_destroy(server->topology); + server->topology = NULL; + return -1; + } + for(i=0; inr_ports; i++) + server->ports[i]->hwloc_obj = hwloc_get_obj_by_depth(server->topology, server->ports[i]->hwloc_obj_depth, server->ports[i]->hwloc_obj_index); + } + return 0; +} + +static void +netloc_map__unprepare_hwloc_topology(struct netloc_map *map, + struct netloc_map__server *server) +{ + if (map->flags & NETLOC_MAP_BUILD_FLAG_COMPRESS_HWLOC + && server->topology_diff) { + unsigned i; + if (map->verbose_flags & NETLOC_MAP_VERBOSE_FLAG_COMPRESS) + printf("compressing hwloc topology %s on top of %s\n", + server->name, server->topology_diff_refserver->name); + hwloc_topology_destroy(server->topology); + server->topology = NULL; + for(i=0; inr_ports; i++) + server->ports[i]->hwloc_obj = NULL; + } +} + + +/************************* + * Building a netloc_map + */ + +static int +netloc_map__init_subnets(struct netloc_map *map) +{ + int err; + netloc_network_t **nets = NULL; + int nrnets = 0, i; + + if (!map->netloc_data_path) + return 0; + + netloc_foreach_network((const char * const *) &map->netloc_data_path, 1, NULL, map, &nrnets, &nets); + + err = netloc_lookup_table_init(&map->subnet_by_id[NETLOC_NETWORK_TYPE_ETHERNET], nrnets, + NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + if (NETLOC_SUCCESS != err) + goto out; + + err = netloc_lookup_table_init(&map->subnet_by_id[NETLOC_NETWORK_TYPE_INFINIBAND], nrnets, + NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + if (NETLOC_SUCCESS != err) + goto out_with_ltable_ethernet; + + for(i=0; isubnet_id)+1, 1); + if (!subnet) { + netloc_detach(netloc); + continue; + } + + strcpy(subnet->id, nets[i]->subnet_id); + subnet->topology = netloc; + subnet->type = nets[i]->network_type; + + err = netloc_lookup_table_append(&map->subnet_by_id[nets[i]->network_type], subnet->id, subnet); + if (NETLOC_SUCCESS != err) { + free(subnet); + netloc_detach(netloc); + continue; + } + + subnet->next = NULL; + subnet->prev = map->subnet_last; + if (map->subnet_last) + map->subnet_last->next = subnet; + else + map->subnet_first = subnet; + map->subnet_last = subnet; + map->subnets_nr++; + } + netloc_dt_network_t_destruct(nets[i]); + } + + free(nets); + return 0; + + out_with_ltable_ethernet: + netloc_lookup_table_destroy(&map->subnet_by_id[NETLOC_NETWORK_TYPE_ETHERNET]); + memset(&map->subnet_by_id, 0, sizeof(map->subnet_by_id)); + out: + return -1; +} + +static +void netloc_map__add_port(struct netloc_map *map, + struct netloc_map__server *server, + netloc_network_type_t type, + const char * gid, + hwloc_obj_t obj) +{ + struct netloc_map__port *port; + struct netloc_map__subnet *subnet; + const char *id; + size_t id_len; + + if (!gid) + return; + + if (type == NETLOC_NETWORK_TYPE_ETHERNET) { + subnet = netloc_map__get_subnet_by_id(map, type, "unknown"); + id = gid; + id_len = 17; + } else if (type == NETLOC_NETWORK_TYPE_INFINIBAND) { + char subnet_id[20]; + memcpy(subnet_id, gid, 19); + subnet_id[19] = '\0'; + subnet = netloc_map__get_subnet_by_id(map, type, subnet_id); + id = gid+20; + id_len = 19; + } + else { + subnet = NULL; + } + + if (!subnet) + return; + + if (server->nr_ports == server->nr_ports_allocated) { + unsigned new_nr_ports_allocated = server->nr_ports_allocated ? 2*server->nr_ports_allocated : 8; + struct netloc_map__port **new_ports; + new_ports = malloc(new_nr_ports_allocated * sizeof(*new_ports)); + if (!new_ports) + return; + memcpy(new_ports, server->ports, server->nr_ports * sizeof(*new_ports)); + free(server->ports); + server->ports = new_ports; + server->nr_ports_allocated = new_nr_ports_allocated; + } + + port = calloc(sizeof(*port) + id_len + 1, 1); + if (!port) + return; + strcpy(port->id, id); + port->server = server; + port->subnet = subnet; + + port->hwloc_obj = obj; + port->hwloc_obj_depth = obj->depth; + port->hwloc_obj_index = obj->logical_index; + + server->ports[server->nr_ports++] = port; + + map->server_ports_nr++; +} + +static void +netloc_map__add_ib_port(struct netloc_map *map, + struct netloc_map__server *server, + hwloc_obj_t obj) +{ + /* scan infos, and add valid ports using GIDs */ + int currentport = -1; + int currentportvalid = 1; + char * currentportgid = NULL; + unsigned i; + for(i=0; iinfos_count; i++) { + struct hwloc_obj_info_s *info = &obj->infos[i]; + unsigned newport, gid, pos; + + /* check port number */ + if (sscanf(info->name, "Port%u%n", &newport, &pos) >= 1) { + /* new port ? */ + if ((int) newport != currentport) { + /* try to add previous port */ + if (currentport != -1 && currentportvalid) + netloc_map__add_port(map, server, NETLOC_NETWORK_TYPE_INFINIBAND, currentportgid, obj); + /* reset new port */ + currentport = newport; currentportvalid = 1; currentportgid = NULL; + } + if (!strcmp(info->name+pos, "State")) { + /* active PortState defined in IB spec, section 14.2.5.6 "Port Info" */ + unsigned state = atoi(info->value); + if (state != 4) + currentportvalid = 0; + } else if (!strcmp(info->name+pos, "LID")) { + /* unicast lid range defined in IB spec, section 4.1.3 "Local Identifiers", rule 9 */ + unsigned lid = strtoul(info->value, NULL, 0); + if (lid < 0x1 || lid > 0xbfff) + currentportvalid = 0; + } else if (sscanf(info->name+pos, "GID%u", &gid) == 1) { + /* gid */ + currentportgid = info->value; + } + } + } + /* queue last port */ + if (currentport != -1 && currentportvalid) + netloc_map__add_port(map, server, NETLOC_NETWORK_TYPE_INFINIBAND, currentportgid, obj); +} + +static void +netloc_map__add_eth_port(struct netloc_map *map, + struct netloc_map__server *server, + hwloc_obj_t obj) +{ + unsigned i; + for(i=0; iinfos_count; i++) { + struct hwloc_obj_info_s *info = &obj->infos[i]; + + if (!strcmp(info->name, "Address")) { + netloc_map__add_port(map, server, NETLOC_NETWORK_TYPE_ETHERNET, info->value, obj); + break; + } + } +} + +static struct netloc_map__server * +netloc_map__init_server(struct netloc_map *map, hwloc_topology_t topo, const char *name) +{ + struct netloc_map__server *server; + hwloc_obj_t obj; + const char *infoname; + size_t namelen; + int err; + + /* setup a "HostName" info attr in the topology to recognize the name from the topology */ + obj = hwloc_get_root_obj(topo); + assert(obj); + infoname = hwloc_obj_get_info_by_name(obj, "HostName"); + if (!infoname) + hwloc_obj_add_info(obj, "HostName", name); + else + name = infoname; + namelen = strlen(name); + + server = calloc(sizeof(*server) + namelen+1, 1); + if (!server) + return NULL; + + strcpy(server->name, name); + server->topology = topo; + hwloc_topology_set_userdata(topo, server); + + if (netloc_lookup_table_access(&map->server_by_name, server->name)) { + fprintf(stderr, "Found duplicate server %s, ignoring the new one\n", server->name); + free(server); + return NULL; + } + + err = netloc_lookup_table_append(&map->server_by_name, server->name, server); + if (NETLOC_SUCCESS != err) { + free(server); + return NULL; + } + server->map = map; + + server->next = NULL; + server->prev = map->server_last; + if (map->server_last) + map->server_last->next = server; + else + map->server_first = server; + map->server_last = server; + map->servers_nr++; + + obj = NULL; + while ((obj = hwloc_get_next_osdev(topo, obj)) != NULL) { + if (obj->attr->osdev.type == HWLOC_OBJ_OSDEV_OPENFABRICS) { + netloc_map__add_ib_port(map, server, obj); + } else if (obj->attr->osdev.type == HWLOC_OBJ_OSDEV_NETWORK) { + netloc_map__add_eth_port(map, server, obj); + } + } + + return server; +} + +static int +netloc_map__init_servers(struct netloc_map *map) +{ + DIR *hwloc_xml_dir; + struct dirent *dirent; + unsigned nbxmls; + unsigned founddiffs = 0; + int err; + + if (!map->hwloc_xml_path) + return 0; + + hwloc_xml_dir = opendir(map->hwloc_xml_path); + if (!hwloc_xml_dir) + goto out; + + nbxmls=0; + while ((dirent = readdir(hwloc_xml_dir)) != NULL) + nbxmls++; + rewinddir(hwloc_xml_dir); + + err = netloc_lookup_table_init(&map->server_by_name, nbxmls, + NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + if (NETLOC_SUCCESS != err) + goto out_with_dir; + + /* load uncompressed topologies */ + while ((dirent = readdir(hwloc_xml_dir)) != NULL) { + struct netloc_map__server *server; + hwloc_topology_t topo; + char *name; + char *filepath; + size_t namelen; + int err; + + name = dirent->d_name; + namelen = strlen(name); + if (namelen < 4) + continue; + if (strcmp(".xml", name+namelen-4)) + continue; + namelen -= 4; + name[namelen] = '\0'; + + if (namelen >= 5 && !strcmp(".diff", name+namelen-5)) { + founddiffs++; + continue; + } + + err = asprintf(&filepath, "%s/%s.xml", map->hwloc_xml_path, name); + if (err < 0) + continue; + + hwloc_topology_init(&topo); + hwloc_topology_set_flags(topo, HWLOC_TOPOLOGY_FLAG_IO_DEVICES); + err = hwloc_topology_set_xml(topo, filepath); + free(filepath); + if (err < 0) { + hwloc_topology_destroy(topo); + continue; + } + hwloc_topology_load(topo); + + server = netloc_map__init_server(map, topo, name); + if (!server) + hwloc_topology_destroy(topo); + + /* FIXME: try to compress if the input directory isn't ? */ + } + + /* load compressed topologies now that the refs are ready */ + if (founddiffs) { + /* find one valid topology so that we can load diffs */ + if (!map->server_first) { + fprintf(stderr, "Found %u hwloc topology diffs, cannot load without any entire topology\n", + founddiffs); + } else { + hwloc_topology_t validtopo = map->server_first->topology; + + /* now reread the directory entries */ + rewinddir(hwloc_xml_dir); + while ((dirent = readdir(hwloc_xml_dir)) != NULL) { + struct netloc_map__server *server, *refserver; + hwloc_topology_t topo; + hwloc_topology_diff_t diff; + char *filepath; + char *refname; + size_t refnamelen; + char *name; + size_t namelen; + int err; + + name = dirent->d_name; + namelen = strlen(name); + if (namelen < 9) + continue; + if (strcmp(".diff.xml", name+namelen-9)) + continue; + namelen -= 9; + name[namelen] = '\0'; + + err = asprintf(&filepath, "%s/%s.diff.xml", map->hwloc_xml_path, name); + if (err < 0) + continue; + + if (map->verbose_flags & NETLOC_MAP_VERBOSE_FLAG_COMPRESS) + printf("loading topology diff %s\n", filepath); + + err = hwloc_topology_diff_load_xml(validtopo, filepath, &diff, &refname); + free(filepath); + if (err < 0) + continue; + if (!refname) { + hwloc_topology_diff_destroy(validtopo, diff); + continue; + } + refnamelen = strlen(refname); + if (strcmp(refname+refnamelen-4, ".xml")) { + free(refname); + hwloc_topology_diff_destroy(validtopo, diff); + continue; + } + refname[refnamelen-4] = '\0'; + + if (map->verbose_flags & NETLOC_MAP_VERBOSE_FLAG_COMPRESS) + printf(" applying diff on top of reference topology %s\n", refname); + + refserver = netloc_lookup_table_access(&map->server_by_name, refname); + if (!refserver) { + fprintf(stderr, "Could not find hwloc topology diff reference server %s\n", refname); + free(refname); + hwloc_topology_diff_destroy(validtopo, diff); + continue; + } + free(refname); + + /* make sure the ref isn't compressed */ + if (netloc_map__prepare_hwloc_topology(map, refserver) < 0) { + fprintf(stderr, "Failed to uncompress reference server %s topology\n", refname); + hwloc_topology_diff_destroy(validtopo, diff); + continue; + } + + err = hwloc_topology_dup(&topo, refserver->topology); + if (err < 0) { + hwloc_topology_diff_destroy(validtopo, diff); + continue; + } + + err = hwloc_topology_diff_apply(topo, diff, 0); + if (err < 0) { + hwloc_topology_diff_destroy(validtopo, diff); + hwloc_topology_destroy(topo); + continue; + } + + server = netloc_map__init_server(map, topo, name); + if (!server) { + hwloc_topology_diff_destroy(validtopo, diff); + hwloc_topology_destroy(topo); + } else { + /* ideally, we would walk up the chain of reference servers, but: + * - there shouldn't be any stack of multiple diffs if the compression is properly done. + * - things could fail above if the diffs are not loaded in the right order. + * so we don't bother. + */ + server->topology_diff_refserver = refserver; + refserver->usecount++; + server->topology_diff = diff; + /* compress the new server, there will likely be nobody depending on it */ + netloc_map__unprepare_hwloc_topology(map, server); + } + } + } + } + + closedir(hwloc_xml_dir); + return 0; + + out_with_dir: + closedir(hwloc_xml_dir); + out: + return -1; +} + +static int +netloc_map__prepare_subnet_port_hashes(struct netloc_map *map) +{ + struct netloc_map__subnet *subnet; + int err; + + subnet = map->subnet_first; + while (subnet) { + err = netloc_lookup_table_init(&subnet->port_by_id, map->server_ports_nr, + NETLOC_LOOKUP_TABLE_FLAG_NO_STRDUP_KEY); + if (NETLOC_SUCCESS != err) + return -1; + subnet->port_by_id_ready = 1; + subnet = subnet->next; + } + return 0; +} + +static int +netloc_map__hash_ports(struct netloc_map *map) +{ + struct netloc_map__server *server; + int err; + + server = map->server_first; + while (server) { + unsigned i; + for(i=0; inr_ports; i++) { + struct netloc_map__port *port = server->ports[i]; + struct netloc_map__subnet *subnet = port->subnet; + + err = netloc_lookup_table_append(&subnet->port_by_id, port->id, port); + if (NETLOC_SUCCESS != err) + return -1; + + port->next = NULL; + port->prev = subnet->port_last; + if (subnet->port_last) + subnet->port_last->next = port; + else + subnet->port_first = port; + subnet->port_last = port; + subnet->ports_nr++; + } + server = server->next; + } + + return 0; +} + +static int +netloc_map__map(struct netloc_map *map) +{ + struct netloc_map__subnet *subnet; + + subnet = map->subnet_first; + while (subnet) { + struct netloc_map__port *port = subnet->port_first; + while (port) { + netloc_node_t *node; + + node = netloc_get_node_by_physical_id(subnet->topology, port->id); + + if (node) { + netloc_edge_t **edges = NULL; + int nredges = 0; + int err; + + err = netloc_get_all_edges(subnet->topology, node, &nredges, &edges); + if (NETLOC_SUCCESS == err) { + assert(nredges == 1); + port->edge = edges[0]; + assert(!strcmp(port->edge->src_node_id, port->id)); + } + } + + port = port->next; + } + subnet = subnet->next; + } + return 0; +} + +int +netloc_map_build(netloc_map_t _map, unsigned long flags) +{ + struct netloc_map *map = _map; + int err; + + if (flags & ~NETLOC_MAP_BUILD_FLAG_COMPRESS_HWLOC) { + errno = EINVAL; + return -1; + } + + map->flags = flags; + + err = netloc_map__init_subnets(map); + if (err < 0) + goto out; + err = netloc_map__init_servers(map); + if (err < 0) + goto out; + err = netloc_map__prepare_subnet_port_hashes(map); + if (err < 0) + goto out; + err = netloc_map__hash_ports(map); + if (err < 0) + goto out; + err = netloc_map__map(map); + if (err < 0) + goto out; + + map->merged = true; + return 0; + + out: + netloc_map__destroy_subnets(map); + netloc_map__destroy_servers(map); + return -1; +} + + +/************************ + * Destroy a netloc_map + */ + +static void +netloc_map__destroy_servers(struct netloc_map *map) +{ + struct netloc_map__server *curserver, *nextserver; + unsigned i; + + curserver = map->server_first; + while (curserver) { + nextserver = curserver->next; + if (curserver->topology_diff_refserver) + hwloc_topology_diff_destroy(curserver->topology, curserver->topology_diff); + if (curserver->topology) + hwloc_topology_destroy(curserver->topology); + for(i=0; inr_ports; i++) + free(curserver->ports[i]); + free(curserver->ports); + free(curserver); + curserver = nextserver; + } + map->server_first = map->server_last = NULL; + map->servers_nr = 0; + + netloc_lookup_table_destroy(&map->server_by_name); + memset(&map->server_by_name, 0, sizeof(map->server_by_name)); +} + +static void +netloc_map__destroy_subnets(struct netloc_map *map) +{ + struct netloc_map__subnet *cursubnet, *nextsubnet; + + cursubnet = map->subnet_first; + while (cursubnet) { + nextsubnet = cursubnet->next; + netloc_detach(cursubnet->topology); + if (cursubnet->port_by_id_ready) + netloc_lookup_table_destroy(&cursubnet->port_by_id); + free(cursubnet); + cursubnet = nextsubnet; + } + map->subnet_first = map->subnet_last = NULL; + map->subnets_nr = 0; + + netloc_lookup_table_destroy(&map->subnet_by_id[NETLOC_NETWORK_TYPE_ETHERNET]); + netloc_lookup_table_destroy(&map->subnet_by_id[NETLOC_NETWORK_TYPE_INFINIBAND]); + memset(&map->subnet_by_id, 0, sizeof(map->subnet_by_id)); +} + +int +netloc_map_destroy(netloc_map_t _map) +{ + struct netloc_map *map = _map; + + free(map->netloc_data_path); + free(map->hwloc_xml_path); + + if (map->merged) { + netloc_map__destroy_subnets(map); + netloc_map__destroy_servers(map); + } + + free(map); + return 0; +} + + +/******************* + * Internal helpers + */ + +static struct netloc_map__server * +netloc_map__get_server_by_name(struct netloc_map *map, + const char *name) +{ + return (struct netloc_map__server *) netloc_lookup_table_access(&map->server_by_name, name); +} + +static struct netloc_map__server * +netloc_map__get_server_by_topology(struct netloc_map *map __netloc_attribute_unused, + hwloc_topology_t topology) +{ + return hwloc_topology_get_userdata(topology); +} + +static struct netloc_map__subnet * +netloc_map__get_subnet_by_id(struct netloc_map *map, + netloc_network_type_t type, + const char *id) +{ + return (struct netloc_map__subnet *) netloc_lookup_table_access(&map->subnet_by_id[type], id); +} + +static struct netloc_map__port * +netloc_map__get_port_by_id(struct netloc_map__subnet *subnet, + const char *id) +{ + return (struct netloc_map__port *) netloc_lookup_table_access(&subnet->port_by_id, id); +} + +static int +netloc_map__get_hwloc_topology(struct netloc_map__server *server) +{ + if (!server->usecount) + if (netloc_map__prepare_hwloc_topology(server->map, server) < 0) + return -1; + server->usecount++; + return 0; +} + +static void +netloc_map__put_hwloc_topology(struct netloc_map *map, + struct netloc_map__server *server) +{ + if (!--server->usecount) + netloc_map__unprepare_hwloc_topology(map, server); +} + +static int +netloc_map__check_port_locality(struct netloc_map__port *port, + hwloc_obj_t closeto_obj) +{ + hwloc_obj_t port_obj = port->hwloc_obj; + + assert(port_obj->type == HWLOC_OBJ_OS_DEVICE); + + if (!closeto_obj) + /* no closeto_obj specified, all objects match */ + return 1; + + /* if we want to be close to a OS device, it must be the exact port object */ + if (closeto_obj->type == HWLOC_OBJ_OS_DEVICE) + return closeto_obj == port_obj; + + /* if we want to be close to a PCI device or bridge, it must be a parent of the port object */ + if (closeto_obj->type == HWLOC_OBJ_PCI_DEVICE + || closeto_obj->type == HWLOC_OBJ_BRIDGE) { + while (port_obj) { + if (port_obj == closeto_obj) + return 1; + port_obj = port_obj->parent; + } + return 0; + } + + /* if we want to be close to something with no locality (multiple-node topology?!), all ports match */ + if (!closeto_obj->cpuset) + return 1; + + /* we want to be close to some PUs, check that the port locality intersects them */ + port_obj = hwloc_get_non_io_ancestor_obj(port->server->topology, port_obj); + return hwloc_bitmap_intersects(closeto_obj->cpuset, port_obj->cpuset); +} + + +/***************** + * Public queries + */ + +int netloc_map_hwloc2port(netloc_map_t _map, + hwloc_topology_t htopo, hwloc_obj_t hobj, + netloc_map_port_t *portsp, unsigned *nrp) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + unsigned i, found, room = *nrp; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + server = netloc_map__get_server_by_topology(map, htopo); + if (!server) { + errno = EINVAL; + return -1; + } + + found = 0; + for(i=0; inr_ports; i++) { + struct netloc_map__port *port = server->ports[i]; + if (!netloc_map__check_port_locality(port, hobj)) + continue; + + found++; + if (room) { + *(portsp++) = port; + room--; + } + } + + *nrp -= room; + return found; +} + +int +netloc_map_port2hwloc(netloc_map_port_t _port, + hwloc_topology_t *htopop, hwloc_obj_t *hobjp) +{ + struct netloc_map__port *port = _port; + + if (!port->server->map->merged || !htopop) { + errno = EINVAL; + return -1; + } + + *htopop = port->server->topology; + if (hobjp) + *hobjp = port->hwloc_obj; + return 0; +} + +int netloc_map_netloc2port(netloc_map_t _map, + netloc_topology_t ntopo __netloc_attribute_unused, netloc_node_t *nnode, netloc_edge_t *nedge, + netloc_map_port_t *portp) +{ + struct netloc_map *map = _map; + struct netloc_map__subnet *subnet; + struct netloc_map__port *port; + const char *physical_id = NULL; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + if (nedge) { + if (nnode) { + /* both node and edge: + * check they are connected, use node id. + */ + if ((NETLOC_NODE_TYPE_HOST == nedge->src_node_type && !strcmp(nedge->src_node_id, nnode->physical_id)) + || (NETLOC_NODE_TYPE_HOST == nedge->dest_node_type && !strcmp(nedge->dest_node_id, nnode->physical_id))) + physical_id = nnode->physical_id; + } else { + /* edge without node: + * find the node id from the edge, must have a single HOST vertex. + */ + if (NETLOC_NODE_TYPE_HOST == nedge->src_node_type + && NETLOC_NODE_TYPE_HOST != nedge->dest_node_type) + physical_id = nedge->src_node_id; + else if (NETLOC_NODE_TYPE_HOST != nedge->src_node_type + && NETLOC_NODE_TYPE_HOST == nedge->dest_node_type) + physical_id = nedge->dest_node_id; + } + } else { + if (nnode) { + /* node without edge: + * use the node id + */ + physical_id = nnode->physical_id; + } + } + if (!physical_id) { + errno = EINVAL; + return -1; + } + + subnet = netloc_map__get_subnet_by_id(map, nnode->network_type, nnode->subnet_id); + if (!subnet) + return -1; + + port = netloc_map__get_port_by_id(subnet, physical_id); + if (!port) + return -1; + + *portp = port; + return 0; +} + +int +netloc_map_port2netloc(netloc_map_port_t _port, + netloc_topology_t *ntopo, netloc_node_t **nnode, netloc_edge_t **nedge) +{ + struct netloc_map__port *port = _port; + + if (!port->server->map->merged) { + errno = EINVAL; + return -1; + } + + if (ntopo) + *ntopo = port->subnet->topology; + if (nedge) + *nedge = port->edge; + if (nnode) + *nnode = port->edge ? port->edge->src_node : NULL; + return 0; +} + +int +netloc_map_server2hwloc(netloc_map_server_t _server, + hwloc_topology_t *topologyp) +{ + struct netloc_map__server *server = _server; + + if (!server->map->merged || !topologyp) { + errno = EINVAL; + return -1; + } + + if (netloc_map__get_hwloc_topology(server) < 0) + return -1; + + *topologyp = server->topology; + return 0; +} + +int +netloc_map_hwloc2server(netloc_map_t _map, + hwloc_topology_t topology, + netloc_map_server_t *serverp) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + server = netloc_map__get_server_by_topology(map, topology); + if (!server) { + errno = EINVAL; + return -1; + } + + *serverp = server; + return 0; +} + +int +netloc_map_put_hwloc(netloc_map_t _map, + hwloc_topology_t topology) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + server = netloc_map__get_server_by_topology(map, topology); + if (!server) { + errno = EINVAL; + return -1; + } + + netloc_map__put_hwloc_topology(map, server); + return 0; +} + +int netloc_map_get_subnets(netloc_map_t _map, + unsigned *nr, + netloc_topology_t **toposp) +{ + struct netloc_map *map = _map; + netloc_topology_t *topos; + struct netloc_map__subnet *subnet; + unsigned i; + + topos = malloc(map->subnets_nr * sizeof(*topos)); + if (!topos) + return -1; + + i = 0; + subnet = map->subnet_first; + while (subnet) { + topos[i] = subnet->topology; + i++; + subnet = subnet->next; + } + + *toposp = topos; + *nr = map->subnets_nr; + return 0; +} + +int netloc_map_get_nbservers(netloc_map_t _map) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + unsigned i; + + server = map->server_first; + i=0; + while (server) { + server = server->next; + i++; + } + + return (int) i; +} + +int netloc_map_get_servers(netloc_map_t _map, + unsigned first, unsigned nr, + netloc_map_server_t servers[]) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + unsigned i; + + if (!nr) + return 0; + + server = map->server_first; + while (server && first) { + server = server->next; + first--; + } + if (!server) { + errno = ERANGE; + return -1; + } + + i = 0; + while (server && inext; + i++; + } + + return (int) i; +} + +int netloc_map_get_server_ports(netloc_map_server_t _server, + unsigned *nr, netloc_map_port_t **portsp) +{ + struct netloc_map__server *server = _server; + *nr = server->nr_ports; + *portsp = (netloc_map_port_t *) server->ports; + return 0; +} + +int netloc_map_port2server(netloc_map_port_t _port, + netloc_map_server_t *server) +{ + struct netloc_map__port *port = _port; + *server = port->server; + return 0; +} + +int netloc_map_server2map(netloc_map_server_t _server, + netloc_map_t *map) +{ + struct netloc_map__server *server = _server; + *map = server->map; + return 0; +} + +int netloc_map_server2name(netloc_map_server_t _server, + const char **namep) +{ + struct netloc_map__server *server = _server; + + if (!server->map->merged) { + errno = EINVAL; + return -1; + } + + *namep = server->name; + return 0; +} + +int netloc_map_name2server(netloc_map_t _map, + const char *name, netloc_map_server_t *serverp) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + server = netloc_map__get_server_by_name(map, name); + if (!server) { + errno = EINVAL; + return -1; + } + + *serverp = server; + return 0; +} + +/***************************** + * Paths + */ + +static int +netloc_map__paths_build_hwloc_edge_to_port(hwloc_topology_t topology, + hwloc_obj_t src, hwloc_obj_t port, + unsigned long flags, + struct netloc_map_edge_s **edgesp, unsigned *nr_edgesp) +{ + struct netloc_map_edge_s *edges = *edgesp; + unsigned nr_edges = *nr_edgesp; + unsigned i = nr_edges; + unsigned pcilength; + hwloc_obj_t portparent, srcparent, srccousin, ancestor; + + nr_edges += 4; + edges = realloc(edges, nr_edges * sizeof(*edges)); + if (!edges) { + *edgesp = NULL; + *nr_edgesp = 0; + return -1; + } + + /* hwloc_get_non_io_ancestor_obj(topology, port) with length */ + pcilength = 0; + portparent = port; + while (!portparent->cpuset) { + if (!portparent->parent) + break; + portparent = portparent->parent; + pcilength++; + } + /* ignore things like misc objects */ + while (portparent->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + portparent = portparent->parent; + + if (portparent->depth > src->depth) { + /* src ------ srccousin + | + portparent + | + port + */ + + /* find portparent cousin below src */ + srccousin = portparent; + while (srccousin->depth != src->depth) + srccousin = srccousin->parent; + if (srccousin != src) { + /* go horizontal to srccousin */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_HORIZONTAL; + edges[i].hwloc.src_obj = src; + edges[i].hwloc.dest_obj = srccousin; + /* find the weight through common ancestor */ + ancestor = hwloc_get_common_ancestor_obj(topology, src, srccousin); + /* ignore things like misc objects */ + while (ancestor->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + ancestor = ancestor->parent; + edges[i].hwloc.weight = (src->depth - ancestor->depth) * 2 - 1; + i++; + } + /* go down to portparent */ + if (portparent != srccousin && (flags & NETLOC_MAP_PATHS_FLAG_VERTICAL)) { + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_CHILD; + edges[i].hwloc.src_obj = srccousin; + edges[i].hwloc.dest_obj = portparent; + edges[i].hwloc.weight = src->depth - portparent->depth; + i++; + } + } else { + /* srcparent ----- portparent + | | + src | + port + */ + + /* find portparent cousin above src */ + srcparent = src; + while (srcparent->depth != portparent->depth) + srcparent = srcparent->parent; + if (srcparent != src && (flags & NETLOC_MAP_PATHS_FLAG_VERTICAL)) { + /* go up from src to srcparent */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_PARENT; + edges[i].hwloc.src_obj = src; + edges[i].hwloc.dest_obj = srcparent; + edges[i].hwloc.weight = src->depth - srcparent->depth; + i++; + } + if (srcparent != portparent) { + /* go horizontal from srcparent to portparent if different */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_HORIZONTAL; + edges[i].hwloc.src_obj = srcparent; + edges[i].hwloc.dest_obj = portparent; + /* find the weight through common ancestor */ + ancestor = hwloc_get_common_ancestor_obj(topology, portparent, srcparent); + /* ignore things like misc objects */ + while (ancestor->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + ancestor = ancestor->parent; + edges[i].hwloc.weight = (portparent->depth - ancestor->depth) * 2 - 1; + i++; + } + } + + if (flags & NETLOC_MAP_PATHS_FLAG_IO) { + /* now go down from portparent to port */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_PCI; + edges[i].hwloc.src_obj = portparent; + edges[i].hwloc.dest_obj = port; + edges[i].hwloc.weight = pcilength; + i++; + } + + *edgesp = edges; + *nr_edgesp = i; + return 0; +} + +static int +netloc_map__paths_build_hwloc_edge_from_port(hwloc_topology_t topology, + hwloc_obj_t port, hwloc_obj_t dst, + unsigned long flags, + struct netloc_map_edge_s **edgesp, unsigned *nr_edgesp) +{ + struct netloc_map_edge_s *edges = *edgesp; + unsigned nr_edges = *nr_edgesp; + unsigned i = nr_edges; + hwloc_obj_t portparent, dstparent, dstcousin, ancestor; + unsigned pcilength; + + nr_edges += 3; + edges = realloc(edges, nr_edges * sizeof(*edges)); + if (!edges) { + *edgesp = NULL; + *nr_edgesp = 0; + return -1; + } + + /* hwloc_get_non_io_ancestor_obj(topology, port) with length */ + pcilength = 0; + portparent = port; + while (!portparent->cpuset) { + if (!portparent->parent) + break; + portparent = portparent->parent; + pcilength++; + } + /* ignore things like misc objects */ + while (portparent->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + portparent = portparent->parent; + + if (flags & NETLOC_MAP_PATHS_FLAG_IO) { + /* go up from portparent to port */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_PCI; + edges[i].hwloc.src_obj = port; + edges[i].hwloc.dest_obj = portparent; + edges[i].hwloc.weight = pcilength; + i++; + } + + if (portparent->depth > dst->depth) { + /* dstcousin ------ dst + | + portparent + | + port + */ + + /* find portparent cousin below dst */ + dstcousin = portparent; + while (dstcousin->depth != dst->depth) + dstcousin = dstcousin->parent; + /* go up to dstcousin */ + if (portparent != dst && (flags & NETLOC_MAP_PATHS_FLAG_VERTICAL)) { + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_PARENT; + edges[i].hwloc.src_obj = portparent; + edges[i].hwloc.dest_obj = dstcousin; + edges[i].hwloc.weight = dst->depth - portparent->depth; + i++; + } + if (dstcousin != dst) { + /* go horizontal to dst */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_HORIZONTAL; + edges[i].hwloc.src_obj = dstcousin; + edges[i].hwloc.dest_obj = dst; + /* find the weight through common ancestor */ + ancestor = hwloc_get_common_ancestor_obj(topology, dstcousin, dst); + /* ignore things like misc objects */ + while (ancestor->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + ancestor = ancestor->parent; + edges[i].hwloc.weight = (dst->depth - ancestor->depth) * 2 - 1; + i++; + } + } else { + /* portparent ----- dstparent + | | + | dst + port + */ + + /* find portparent cousin above dst */ + dstparent = dst; + while (dstparent->depth != portparent->depth) + dstparent = dstparent->parent; + if (dstparent != portparent) { + /* go horizontal from portparent to dstparent if different */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_HORIZONTAL; + edges[i].hwloc.src_obj = portparent; + edges[i].hwloc.dest_obj = dstparent; + /* find the weight through common ancestor */ + ancestor = hwloc_get_common_ancestor_obj(topology, portparent, dstparent); + /* ignore things like misc objects */ + while (ancestor->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + ancestor = ancestor->parent; + edges[i].hwloc.weight = (portparent->depth - ancestor->depth) * 2 - 1; + i++; + } + if (dstparent != dst && (flags & NETLOC_MAP_PATHS_FLAG_VERTICAL)) { + /* go down from dstparent to dst */ + edges[i].type = NETLOC_MAP_EDGE_TYPE_HWLOC_CHILD; + edges[i].hwloc.src_obj = dstparent; + edges[i].hwloc.dest_obj = dst; + edges[i].hwloc.weight = dst->depth - dstparent->depth; + i++; + } + } + + *edgesp = edges; + *nr_edgesp = i; + return 0; +} + +int netloc_map_paths_build(netloc_map_t _map, + hwloc_topology_t srctopo, hwloc_obj_t srcobj, + hwloc_topology_t dsttopo, hwloc_obj_t dstobj, + unsigned long flags, + netloc_map_paths_t *_paths, unsigned *nr) +{ + struct netloc_map *map = _map; + struct netloc_map__paths *paths; + struct netloc_map__server *srcserver, *dstserver; + unsigned max,i,j; + int err; + + /* check flags */ + if (flags & ~(NETLOC_MAP_PATHS_FLAG_IO + |NETLOC_MAP_PATHS_FLAG_VERTICAL)) + return -1; + + /* don't let special objects be used, they would mess up the weights */ + if (srcobj->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN + || dstobj->depth == (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN) + return -1; + + srcserver = netloc_map__get_server_by_topology(map, srctopo); + if (!srcserver) + return -1; + dstserver = netloc_map__get_server_by_topology(map, dsttopo); + if (!dstserver) + return -1; + + /* preallocate the maximal number of paths */ + max = 0; + for(i=0; inr_ports; i++) { + struct netloc_map__port *srcport = srcserver->ports[i]; + for(j=0; jnr_ports; j++) { + struct netloc_map__port *dstport = dstserver->ports[j]; + if (srcport->subnet == dstport->subnet) + max++; + } + } + + paths = calloc(1, sizeof(*paths)); + if (!paths) + return -1; + paths->map = map; + paths->flags = flags; + + paths->nr_paths = 0; + paths->paths = calloc(max, sizeof(*paths->paths)); + if (!paths->paths) { + free(paths); + return -1; + } + + for(i=0; inr_ports; i++) { + struct netloc_map__port *srcport = srcserver->ports[i]; + netloc_topology_t netloc = srcport->subnet->topology; + netloc_node_t *srcnode; + srcnode = netloc_get_node_by_physical_id(netloc, srcport->id); + assert(srcnode); + + for(j=0; jnr_ports; j++) { + struct netloc_map__port *dstport = dstserver->ports[j]; + + if (srcport->subnet != dstport->subnet) + continue; + + netloc_node_t *dstnode; + dstnode = netloc_get_node_by_physical_id(netloc, dstport->id); + assert(dstnode); + + struct netloc_map__path *path = &paths->paths[paths->nr_paths]; + path->edges = NULL; + path->nr_edges = 0; + + /* hwloc edges in the source node */ + err = netloc_map__paths_build_hwloc_edge_to_port(srctopo, + srcobj, srcport->hwloc_obj, + flags, + &path->edges, &path->nr_edges); + if (err < 0) + continue; + + /* netloc edges */ + netloc_edge_t **nedges = NULL; + int nr_nedges = 0; + int res = netloc_get_path(netloc, srcnode, dstnode, &nr_nedges, &nedges, 0); + if (NETLOC_SUCCESS != res) + continue; + path->edges = realloc(path->edges, (path->nr_edges + nr_nedges) * sizeof(*path->edges)); + if (!path->edges) + goto out; + unsigned k; + for(k=0; k<(unsigned) nr_nedges; k++) { + struct netloc_map_edge_s *edge = &path->edges[path->nr_edges++]; + edge->type = NETLOC_MAP_EDGE_TYPE_NETLOC; + edge->netloc.topology = netloc; + edge->netloc.edge = nedges[k]; + } + + /* hwloc edges in the destination node */ + err = netloc_map__paths_build_hwloc_edge_from_port(dsttopo, + dstport->hwloc_obj, dstobj, + flags, + &path->edges, &path->nr_edges); + if (err < 0) + continue; + + paths->nr_paths++; + } + } + + out: + *_paths = paths; + *nr = paths->nr_paths; + return 0; +} + +int netloc_map_paths_get(netloc_map_paths_t _paths, unsigned idx, + struct netloc_map_edge_s **edges, unsigned *nr_edges) +{ + struct netloc_map__paths *paths = _paths; + + if (idx >= paths->nr_paths) { + errno = EINVAL; + return -1; + } + + *edges = paths->paths[idx].edges; + *nr_edges = paths->paths[idx].nr_edges; + return 0; +} + +int netloc_map_paths_destroy(netloc_map_paths_t _paths) +{ + struct netloc_map__paths *paths = _paths; + unsigned i; + for(i=0; inr_paths; i++) + free(paths->paths[i].edges); + free(paths->paths); + free(paths); + return 0; +} + +/****************** + * Debug + */ + +int +netloc_map_find_neighbors(netloc_map_t _map, + const char *hostname, unsigned maxdepth) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + unsigned i,j,k,l; + + if (!map->merged) { + errno = EINVAL; + return -1; + } + + server = netloc_map__get_server_by_name(map, hostname); + if (!server) + return -1; + + unsigned done_nr_allocated = 32; + const char **done_ids = malloc(done_nr_allocated * sizeof(*done_ids)); + unsigned prev_nr_allocated = 32; + const char **prev_ids = malloc(prev_nr_allocated * sizeof(*prev_ids)); + unsigned next_nr_allocated = 32; + const char **next_ids = malloc(next_nr_allocated * sizeof(*next_ids)); + + for(i=0; inr_ports; i++) { + struct netloc_map__port *port = server->ports[i]; + struct netloc_map__subnet *subnet = port->subnet; + netloc_topology_t netloc = subnet->topology; + unsigned depth; + + assert(netloc); + + unsigned done_nr = 1; + done_ids[0] = port->id; + unsigned prev_nr = 1; + prev_ids[0] = port->id; + unsigned next_nr = 0; + + printf("Starting from port %s in subnet type %d id %s\n", + port->id, subnet->type, subnet->id); + + for(depth = 1; depth <= maxdepth; depth++) { + printf("Looking at distance %u in subnet type %d id %s\n", + depth, subnet->type, subnet->id); + + for(j=0; jdest_node_id; + int done = 0; + for(l=0; ldest_node_type == NETLOC_NODE_TYPE_SWITCH) { + printf("Queueing switch %s\n", id); + if (next_nr == next_nr_allocated) { + //next_nr_allocated = next_nr_allocated; + next_ids = realloc(next_ids, next_nr_allocated * sizeof(*next_ids)); + if (!next_ids) + goto out; + } + next_ids[next_nr++] = id; + + } else { + const char *name = "unknown"; + struct netloc_map__port *port = netloc_map__get_port_by_id(subnet, id); + if (port) + name = port->server->name; + printf("Found server %s port %s\n", name, id); + } + + if (done_nr == done_nr_allocated) { + done_nr_allocated <<= 1; + done_ids = realloc(done_ids, done_nr_allocated * sizeof(*done_ids)); + if (!done_ids) + goto out; + } + done_ids[done_nr++] = id; + } + } + + if (!next_nr) + break; + + if (next_nr > prev_nr_allocated) { + prev_nr_allocated = next_nr_allocated; + prev_ids = realloc(prev_ids, prev_nr_allocated * sizeof(*prev_ids)); + if (!prev_ids) + goto out; + } + memcpy(prev_ids, next_ids, next_nr * sizeof(*prev_ids)); + prev_nr = next_nr; + next_nr = 0; + } + } + + out: + free(done_ids); + free(prev_ids); + free(next_ids); + return 0; +} + +int +netloc_map_dump(netloc_map_t _map) +{ + struct netloc_map *map = _map; + struct netloc_map__server *server; + struct netloc_map__subnet *subnet; + const char * tmp_str = NULL; + + printf("\n"); + printf("==== Dump of netloc map state ====\n"); + + printf("Subnets:\n"); + subnet = map->subnet_first; + while (subnet) { + tmp_str = netloc_decode_network_type_readable(subnet->type); + printf(" %s - %s\n", tmp_str, subnet->id ); + subnet = subnet->next; + tmp_str = NULL; + } + + printf("Servers:\n"); + server = map->server_first; + while (server) { + unsigned i; + printf(" %s (%d port(s))\n", server->name, server->nr_ports); + for(i=0; inr_ports; i++) { + struct netloc_map__port *port = server->ports[i]; + printf(" port %s in %s subnet %s\n", port->id, netloc_decode_network_type_readable(port->subnet->type), port->subnet->id); + } + server = server->next; + } + + printf("==== End of dump of netloc map state ====\n"); + printf("\n"); + + return 0; +} diff --git a/netloc/metadata.c b/netloc/metadata.c new file mode 100644 index 0000000000..4eced9a49a --- /dev/null +++ b/netloc/metadata.c @@ -0,0 +1,359 @@ +/* + * Copyright © 2013 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "support.h" + +/** + * Extract network information from a file + * + * Caller is responsible for calling destructor on the returned value. + * + * \param filename The file to extract information from + * + * Returns + * NULL if no network information was found, or a problem with the file. + * A newly allocated network handle. + */ +static netloc_network_t *extract_network_info(char *filename); + +/** + * Search a single URI for all networks. + * Works exactly like netloc_foreach_network() when it is provided only one search_uri. + */ +static int search_uri(const char * search_uri, + int (*func)(const netloc_network_t *network, void *funcdata), + void *funcdata, + int *num_networks, + netloc_network_t ***networks); + + +/*******************************************************************/ + +int netloc_find_network(const char * network_topo_uri, netloc_network_t* network) +{ + int ret, exit_status = NETLOC_SUCCESS; + netloc_network_t **all_networks = NULL; + int i, num_networks; + int num_found = 0; + netloc_network_t *last_found = NULL; + + /* + * Find all of the network information at this URI + */ + num_networks = 0; + ret = search_uri(network_topo_uri, NULL, NULL, &num_networks, &all_networks); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to search the uri: %s\n", network_topo_uri); + return ret; + } + + /* + * Compare the networks to see if they match + */ + num_found = 0; + for(i = 0; i < num_networks; ++i) { + if( NETLOC_NETWORK_TYPE_INVALID != network->network_type ) { + if(all_networks[i]->network_type != network->network_type) { + continue; + } + } + if( NULL != network->subnet_id ) { + if( 0 != strncmp(all_networks[i]->subnet_id, network->subnet_id, strlen(all_networks[i]->subnet_id)) ) { + continue; + } + } + + ++num_found; + last_found = all_networks[i]; + } + + /* + * Determine if we found too much or too little + */ + if( num_found == 0 ) { + exit_status = NETLOC_ERROR_EMPTY; + goto cleanup; + } + + if( num_found > 1 ) { + exit_status = NETLOC_ERROR_MULTIPLE; + goto cleanup; + } + + /* + * If we found exactly one then copy the information into the handle + */ + netloc_dt_network_t_copy(last_found, network); + + /* + * Cleanup + */ + cleanup: + for(i = 0; i < num_networks; ++i) { + if( NULL != all_networks[i] ) { + netloc_dt_network_t_destruct(all_networks[i]); + all_networks[i] = NULL; + } + } + free(all_networks); + + return exit_status; +} + +int netloc_foreach_network(const char * const * search_uris, + int num_uris, + int (*func)(const netloc_network_t *network, void *funcdata), + void *funcdata, + int *num_networks, + netloc_network_t ***networks) +{ + int i, ret; + + *num_networks = 0; + for(i = 0; i < num_uris; ++i ) { + ret = search_uri(search_uris[i], func, funcdata, num_networks, networks); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Processing networks at URI %s\n", search_uris[i]); + return ret; + } + } + + return NETLOC_SUCCESS; +} + +/******************************************************************* + * Support Functionality + *******************************************************************/ +static netloc_network_t *extract_network_info(char *filename) +{ + int ret; + json_t *json = NULL; + netloc_network_t *tmp_network = NULL; + + /* + * Load the JSON file + */ + ret = support_load_json_from_file(filename, &json); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the file %s\n", filename); + goto cleanup; + } + + if( !json_is_object(json) ) { + fprintf(stderr, "Error: json handle is not a valid object\n"); + goto cleanup; + } + + /* + * Extract the network information + */ + tmp_network = netloc_dt_network_t_json_decode( json_object_get(json, JSON_NODE_FILE_NETWORK_INFO)); + + cleanup: + if(NULL != json) { + json_decref(json); + json = NULL; + } + + return tmp_network; +} + +static int search_uri(const char * search_uri, + int (*func)(const netloc_network_t *network, void *funcdata), + void *funcdata, + int *num_networks, + netloc_network_t ***networks) +{ + int ret, i; + netloc_network_t *tmp_network = NULL; + netloc_network_t **all_networks = NULL; + int all_num_networks; + char * uri_str = NULL; + uri_type_t uri_type; + + char * filename = NULL; + DIR *dirp = NULL; + struct stat dstat; + struct dirent *dir_entry = NULL; + bool found; + + /* + * Process the URI + */ + ret = support_extract_filename_from_uri(search_uri, &uri_type, &uri_str); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Malformed URI <%s>.\n", search_uri); + return ret; + } + + if( URI_FILE != uri_type ) { + fprintf(stderr, "Error: Unsupported protocol in URI <%s>.\n", search_uri); + return NETLOC_ERROR; + } + + /* + * Check to make sure we are looking at a directory + */ + ret = stat(uri_str, &dstat); + if( 0 != ret ) { + fprintf(stderr, "Error: Cannot stat the directory <%s>.\n", uri_str); + return NETLOC_ERROR; + } + if( !(dstat.st_mode & S_IFDIR) ) { + fprintf(stderr, "Error: The URI does not point to a directory <%s>.\n", uri_str); + return NETLOC_ERROR_NOTDIR; + } + + /* + * Search the directory + */ + dirp = opendir(uri_str); + if( NULL == dirp ) { + fprintf(stderr, "Error: Cannot open the directory <%s>.\n", uri_str); + return NETLOC_ERROR_NOENT; + } + + all_num_networks = 0; + + while( NULL != (dir_entry = readdir(dirp)) ) { + /* + * Skip directories + */ + if( DT_DIR == dir_entry->d_type ) { + continue; + } + + /* + * Skip if does not end in .ndat extension + */ + if( NULL == strstr(dir_entry->d_name, ".ndat") ) { + continue; + } + + /* + * Extract the network metadata from the file + */ + asprintf(&filename, "%s%s", uri_str, dir_entry->d_name); + tmp_network = extract_network_info(filename); + if( NULL == tmp_network ) { + fprintf(stderr, "Error: Failed to extract network data from the file %s\n", filename); + continue; + } + + /* + * Determine file type: nodes or paths + */ + if( NULL != strstr(filename, "nodes.ndat") ) { + tmp_network->node_uri = strdup(filename); + } + else if( NULL != strstr(filename, "phy-paths.ndat") ) { + tmp_network->phy_path_uri = strdup(filename); + } + else if( NULL != strstr(filename, "log-paths.ndat") ) { + tmp_network->path_uri = strdup(filename); + } + + asprintf(&tmp_network->data_uri, "%s%s", URI_PREFIX_FILE, uri_str); + + /* + * Have we seen this network before? + */ + found = false; + for( i = 0; i < all_num_networks; ++i ) { + if( NETLOC_CMP_SAME == netloc_dt_network_t_compare(all_networks[i], tmp_network) ) { + found = true; + break; + } + } + + /* + * Append only the unique networks + */ + if( !found ) { + all_num_networks += 1; + all_networks = (netloc_network_t**)realloc(all_networks, sizeof(netloc_network_t*)*all_num_networks); + if( NULL == all_networks ) { + fprintf(stderr, "Error: Failed to allocate space for %d networks\n", all_num_networks); + return NETLOC_ERROR; + } + all_networks[all_num_networks-1] = tmp_network; + } else { + // If not unique, then we may still need to copy over the filenames + // Determine file type: nodes or paths + if( NULL != strstr(filename, "nodes.ndat") ) { + all_networks[i]->node_uri = strdup(filename); + } + else if( NULL != strstr(filename, "phy-paths.ndat") ) { + all_networks[i]->phy_path_uri = strdup(filename); + } + else if( NULL != strstr(filename, "log-paths.ndat") ) { + all_networks[i]->path_uri = strdup(filename); + } + netloc_dt_network_t_destruct(tmp_network); + } + + if( NULL != filename ) { + free(filename); + filename = NULL; + } + } + + /* + * From those unique networks, ask the user if they should be included + * in the final vector returned + */ + for( i = 0; i < all_num_networks; ++i ) { + ret = -1; + /* + * Call the user callback function to decide if we should + * include this in the vector returned. + */ + if( NULL != func ) { + ret = func(all_networks[i], funcdata); + } + if( 0 != ret ) { + // Note: we could be extending an existing networks array, so make sure not to clear that memory. + (*num_networks)++; + (*networks) = (netloc_network_t**)realloc((*networks), sizeof(netloc_network_t*)*(*num_networks)); + if( NULL == (*networks) ) { + return NETLOC_ERROR; + } + (*networks)[(*num_networks)-1] = all_networks[i]; + } + else { + netloc_dt_network_t_destruct(all_networks[i]); + all_networks[i] = NULL; + } + } + + /* + * Cleanup + */ + closedir(dirp); + dirp = NULL; + free(uri_str); + + if( NULL != all_networks ) { + free(all_networks); + all_networks = NULL; + } + + return NETLOC_SUCCESS; +} diff --git a/netloc/pathfinder.c b/netloc/pathfinder.c new file mode 100644 index 0000000000..43a829504c --- /dev/null +++ b/netloc/pathfinder.c @@ -0,0 +1,562 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include + +#include + +#include "support.h" + +/** + * Priority Queue support + */ +struct pq_element_t { + int priority; + void * data; +}; +typedef struct pq_element_t pq_element_t; + +struct pq_queue_t { + int size; + int alloc; + pq_element_t *data; +}; +typedef struct pq_queue_t pq_queue_t; + +static pq_queue_t * pq_queue_t_construct(); +static int pq_queue_t_destruct(pq_queue_t *pq); +static int pq_push(pq_queue_t *pq, int priority, void *data); +static void * pq_pop(pq_queue_t *pq); +static void pq_reorder(pq_queue_t *pq, int priority, void *data); +//static void pq_dump(pq_queue_t *pq); + +static inline bool pq_is_empty(pq_queue_t *pq) { + return pq->size == 0; +} + +/** + * Use Dijkstra's shortest path algorithm to calculate the + * path between the two nodes specified. + */ +static int compute_shortest_path_dijkstra(netloc_data_collection_handle_t *handle, + netloc_node_t *src_node, + netloc_node_t *dest_node, + int *num_edges, + netloc_edge_t ***edges); + +/*************************************************************/ + +int netloc_dc_compute_path_between_nodes(netloc_data_collection_handle_t *handle, + netloc_node_t *src_node, + netloc_node_t *dest_node, + int *num_edges, + netloc_edge_t ***edges, + bool is_logical) +{ + int ret, exit_status = NETLOC_SUCCESS; + + /* + * Sanity check + */ + if( NULL == src_node || NULL == dest_node ) { + fprintf(stderr, "Error: Source or Destination node is NULL\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + if( is_logical ) { + fprintf(stderr, "Error: Logical Pathfinding not supported\n"); + exit_status = NETLOC_ERROR_NOT_IMPL; + goto cleanup; + } + + /* + * Calculate path between these two nodes + */ + ret = compute_shortest_path_dijkstra(handle, + src_node, + dest_node, + num_edges, + edges); + if( NETLOC_SUCCESS != ret ) { + exit_status = ret; + goto cleanup; + } + + cleanup: + return exit_status; +} + +/************************************************************* + * Support Functionality + *************************************************************/ +static int compute_shortest_path_dijkstra(netloc_data_collection_handle_t *handle, + netloc_node_t *src_node, + netloc_node_t *dest_node, + int *num_edges, + netloc_edge_t ***edges) +{ + int exit_status = NETLOC_SUCCESS; + int i; + pq_queue_t *queue = NULL; + int *distance = NULL; + bool *not_seen = NULL; + netloc_node_t *node_u = NULL; + netloc_node_t *node_v = NULL; + netloc_node_t **prev_node = NULL; + netloc_edge_t **prev_edge = NULL; + int alt; + int idx_u, idx_v; + + int num_rev_edges; + netloc_edge_t **rev_edges = NULL; + + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_node_t *cur_node = NULL; + + unsigned long key_int; + + // Just in case things go poorly below + (*num_edges) = 0; + (*edges) = NULL; + + + /* + * Allocate some data structures + */ + queue = pq_queue_t_construct(); + if( NULL == queue ) { + fprintf(stderr, "Error: Failed to allocate the queue\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + distance = (int*)malloc(sizeof(int) * netloc_lookup_table_size(handle->node_list)); + if( NULL == distance ) { + fprintf(stderr, "Error: Failed to allocate the distance array\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + not_seen = (bool*)malloc(sizeof(bool) * netloc_lookup_table_size(handle->node_list)); + if( NULL == not_seen ) { + fprintf(stderr, "Error: Failed to allocate the 'not_seen' array\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + prev_node = (netloc_node_t**)malloc(sizeof(netloc_node_t*) * netloc_lookup_table_size(handle->node_list)); + if( NULL == prev_node ) { + fprintf(stderr, "Error: Failed to allocate the 'prev_node' array\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + prev_edge = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * netloc_lookup_table_size(handle->node_list)); + if( NULL == prev_edge ) { + fprintf(stderr, "Error: Failed to allocate the 'prev_edge' array\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + /* + * Initialize the data structures + */ + i = 0; + hti = netloc_dt_lookup_table_iterator_t_construct(handle->node_list); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_node = (netloc_node_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_node ) { + break; + } + + if( cur_node == src_node ) { + pq_push(queue, 0, cur_node); + distance[i] = 0; + } else { + pq_push(queue, INT_MAX, cur_node); + distance[i] = INT_MAX; + } + + not_seen[i] = true; + + prev_node[i] = NULL; + prev_edge[i] = NULL; + + cur_node->__uid__ = i; + ++i; + } + + /* + * Search + */ + while( !pq_is_empty(queue) ) { + //pq_dump(queue); + + // Grab the next hop + node_u = pq_pop(queue); + // Mark as seen + idx_u = -1; + i = 0; + idx_u = node_u->__uid__; + not_seen[idx_u] = false; + + // For all the edges from this node + for(i = 0; i < node_u->num_edges; ++i ) { + node_v = NULL; + idx_v = -1; + + // Lookup the "dest" node + node_v = node_u->edges[i]->dest_node; + idx_v = node_v->__uid__; + + // If the node has been seen, skip + if( !not_seen[idx_v] ) { + continue; + } + + // Otherwise check to see if we found a shorter path + // Future Work: Add a weight factor other than 1. + // Maybe calculated based on speed/width + alt = distance[idx_u] + 1; + if( alt < distance[idx_v] ) { + distance[idx_v] = alt; + prev_node[idx_v] = node_u; + prev_edge[idx_v] = node_u->edges[i]; + + // Adjust the priority queue as needed + pq_reorder(queue, alt, node_v); + } + } + } + + /* + * Reconstruct the path by picking up the edges + * The edges will be in reverse order (dest to source). + */ + num_rev_edges = 0; + rev_edges = NULL; + + // Find last hop + SUPPORT_CONVERT_ADDR_TO_INT(dest_node->physical_id, + handle->network->network_type, + key_int); + node_u = netloc_lookup_table_access_with_int( handle->node_list, + dest_node->physical_id, + key_int); + idx_u = node_u->__uid__; + + node_v = NULL; + idx_v = -1; + while( prev_node[idx_u] != NULL ) { + // Find the linking edge + if( node_u != dest_node) { + for(i = 0; i < node_u->num_edges; ++i ) { + if( node_v->physical_id_int == node_u->edges[i]->dest_node->physical_id_int ) { + ++num_rev_edges; + rev_edges = (netloc_edge_t**)realloc(rev_edges, sizeof(netloc_edge_t*) * num_rev_edges); + if( NULL == rev_edges ) { + fprintf(stderr, "Error: Failed to re-allocate the 'rev_edges' array with %d elements\n", + num_rev_edges); + exit_status = NETLOC_ERROR; + goto cleanup; + } + rev_edges[num_rev_edges-1] = node_u->edges[i]; + break; + } + } + } + node_v = node_u; + idx_v = idx_u; + + // Find the next node + SUPPORT_CONVERT_ADDR_TO_INT(prev_node[idx_u]->physical_id, + handle->network->network_type, + key_int); + node_u = netloc_lookup_table_access_with_int( handle->node_list, + prev_node[idx_u]->physical_id, + key_int); + idx_u = node_u->__uid__; + } + + for(i = 0; i < src_node->num_edges; ++i ) { + if( NULL == node_v ) { + fprintf(stderr, "Error: This should never happen, but node_v is NULL at line %d in file %s\n", + __LINE__, __FILE__); + exit_status = NETLOC_ERROR; + goto cleanup; + } + if( node_v->physical_id_int == src_node->edges[i]->dest_node->physical_id_int ) { + ++num_rev_edges; + rev_edges = (netloc_edge_t**)realloc(rev_edges, sizeof(netloc_edge_t*) * num_rev_edges); + if( NULL == rev_edges ) { + fprintf(stderr, "Error: Failed to re-allocate the 'rev_edges' array with %d elements\n", + num_rev_edges); + exit_status = NETLOC_ERROR; + goto cleanup; + } + rev_edges[num_rev_edges-1] = node_u->edges[i]; + + break; + } + } + + + /* + * Copy the edges back in correct order + */ + (*num_edges) = num_rev_edges; + (*edges) = (netloc_edge_t**)malloc(sizeof(netloc_edge_t*) * (*num_edges)); + if( NULL == (*edges) ) { + fprintf(stderr, "Error: Failed to allocate the edges array\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + for( i = 0; i < num_rev_edges; ++i ) { + (*edges)[i] = rev_edges[num_rev_edges-1-i]; + //printf("DEBUG: \t Edge: %s\n", netloc_pretty_print_edge_t( (*edges)[i] ) ); + } + + + /* + * Cleanup + */ + cleanup: + if( NULL != queue ) { + pq_queue_t_destruct(queue); + queue = NULL; + } + + if( NULL != rev_edges ) { + free(rev_edges); + rev_edges = NULL; + } + + if( NULL != distance ) { + free(distance); + distance = NULL; + } + + if( NULL != not_seen ) { + free(not_seen); + not_seen = NULL; + } + + if( NULL != prev_node ) { + free(prev_node); + prev_node = NULL; + } + + if( NULL != prev_edge ) { + free(prev_edge); + prev_edge = NULL; + } + + netloc_dt_lookup_table_iterator_t_destruct(hti); + + return exit_status; +} + +static pq_queue_t * pq_queue_t_construct() +{ + pq_queue_t *pq = NULL; + + pq = (pq_queue_t*)malloc(sizeof(pq_queue_t)); + if( NULL == pq ) { + return NULL; + } + + pq->size = 0; + pq->alloc = 4; // Increment by 4 + pq->data = (pq_element_t*)malloc(sizeof(pq_element_t) * pq->alloc); + if( NULL == pq->data ) { + free(pq); + return NULL; + } + + return pq; +} + +static int pq_queue_t_destruct(pq_queue_t *pq) +{ + if( NULL == pq ) { + return NETLOC_SUCCESS; + } + + if( NULL != pq->data ) { + free(pq->data); + pq->data = NULL; + } + + pq->size = 0; + pq->alloc = 0; + + free(pq); + + return NETLOC_SUCCESS; +} + +static int pq_push(pq_queue_t *pq, int priority, void *data) +{ + int i; + pq_element_t *elem = NULL; + + if( NULL == pq ) { + return NETLOC_ERROR; + } + + pq->size++; + + if( pq->size >= pq->alloc ) { + pq->alloc += 4; + pq->data = (pq_element_t*)realloc(pq->data, sizeof(pq_element_t) * pq->alloc); + if( NULL == pq->data ) { + return NETLOC_ERROR; + } + } + + if( 1 == pq->size ) { + elem = &pq->data[0]; + } + else { + elem = &pq->data[pq->size-1]; + // Make a hole in the array to place the new item + for( i = pq->size-2; i >= 0; --i ) { + if( pq->data[i].priority > priority ) { + // Move item backwards + pq->data[i+1].priority = pq->data[i].priority; + pq->data[i+1].data = pq->data[i].data; + + // Save this 'hole' + elem = &pq->data[i]; + elem->priority = INT_MAX; + elem->data = NULL; + } + } + } + + // Insert into the hole + elem->priority = priority; + elem->data = data; + + return NETLOC_SUCCESS; +} + +static void * pq_pop(pq_queue_t *pq) +{ + int i; + void *data = NULL; + + if( NULL == pq ) { + return NULL; + } + + data = pq->data[0].data; + + if( 0 == pq->size ) { + return NULL; + } + + // Remove top item, shift everyone up + for(i = 1; i < pq->size; ++i) { + pq->data[i-1].priority = pq->data[i].priority; + pq->data[i-1].data = pq->data[i].data; + } + pq->data[pq->size-1].priority = INT_MAX; + pq->data[pq->size-1].data = NULL; + + pq->size--; + + return data; +} + +static void pq_reorder(pq_queue_t *pq, int priority, void *data) +{ + int i, elem_idx; + pq_element_t *elem = NULL; + + // Find this element in this array + elem_idx = -1; + for(i = 0; i < pq->size; ++i) { + if( data == pq->data[i].data ) { + elem_idx = i; + break; + } + } + + if( 0 > elem_idx ) { + fprintf(stderr, "Error: Could not find item!\n"); + return; + } + + // Use the elem_idx as a pivot since we have the item information + // provided as a parameter + elem = &pq->data[elem_idx]; + elem->priority = INT_MAX; + elem->data = NULL; + + // Trivial case - do nothing + if( 1 == pq->size ) { + ; + } + // Move this item 'up' + else if( priority < elem->priority ) { + for(i = elem_idx-1; i >= 0; --i ) { + if( pq->data[i].priority > priority ) { + pq->data[i+1].priority = pq->data[i].priority; + pq->data[i+1].data = pq->data[i].data; + + elem = &pq->data[i]; + elem->priority = INT_MAX; + elem->data = NULL; + } + } + } + // Move this item 'down' + else { + for(i = elem_idx+1; i < pq->size; ++i ) { + if( pq->data[i].priority < priority ) { + pq->data[i-1].priority = pq->data[i].priority; + pq->data[i-1].data = pq->data[i].data; + + elem = &pq->data[i]; + elem->priority = INT_MAX; + elem->data = NULL; + } + } + } + + // Insert into the hole + elem->priority = priority; + elem->data = data; +} + +#if 0 +static void pq_dump(pq_queue_t *pq) +{ + int i; + for(i = 0; i < pq->size; ++i) { + printf("Dump: %3d) ", i); + if( NULL == pq->data[i].data ) { + printf("NULL\n"); + } else { + printf("%3d | %s\n", + pq->data[i].priority, + netloc_pretty_print_node_t((netloc_node_t*)pq->data[i].data)); + } + } + printf("---------------------------------------\n"); +} +#endif diff --git a/netloc/support.c b/netloc/support.c new file mode 100644 index 0000000000..5610d1494d --- /dev/null +++ b/netloc/support.c @@ -0,0 +1,345 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include "support.h" + +#include +#include +#include +#include +#include + +/** + * Decode an edge + */ +void * dc_decode_edge(const char * key, json_t* json_obj); + +/** + * Debugging function + */ +//void check_edge_data(struct netloc_dt_lookup_table *edges); + +int support_extract_filename_from_uri(const char * uri, uri_type_t *type, char **str) +{ + size_t len; + + *type = URI_INVALID; + + // Sanity check + if( strlen(uri) < strlen(URI_PREFIX_FILE) ) { + fprintf(stderr, "Error: URI too short. Must start with %s (Provided: %s)\n", URI_PREFIX_FILE, uri); + return NETLOC_ERROR; + } + + // The file uri is the only uri we support at the moment + if( 0 != strncmp(uri, URI_PREFIX_FILE, strlen(URI_PREFIX_FILE)) ) { + fprintf(stderr, "Error: Unsupported URI specifier. Must start with %s (Provided: %s)\n", URI_PREFIX_FILE, uri); + return NETLOC_ERROR; + } + *type = URI_FILE; + + // Strip of the file prefix + (*str) = strdup(&uri[strlen(URI_PREFIX_FILE)]); + + // Append a '/' if needed + len = strlen(*str); + if( (*str)[len-1] != '/' ) { + (*str) = (char *)realloc(*str, sizeof(char) * (len+2)); + (*str)[len] = '/'; + (*str)[len+1] = '\0'; + } + + return NETLOC_SUCCESS; +} + +int support_load_json(struct netloc_topology * topology) +{ + int ret, exit_status = NETLOC_SUCCESS; + int i; + json_t *json = NULL; + netloc_node_t *node = NULL; + + int cur_idx; + json_t *json_path_list = NULL; + json_t *json_path = NULL; + json_t *json_node_list = NULL; + json_t *json_node = NULL; + json_t *json_edge_list = NULL; + + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_edge_t *cur_edge = NULL; + + const char * key = NULL; + + if( topology->nodes_loaded ) { + return NETLOC_SUCCESS; + } + + /* + * Load the json object (nodes) + */ + ret = support_load_json_from_file(topology->network->node_uri, &json); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the node file %s\n", topology->network->node_uri); + exit_status = ret; + goto cleanup; + } + + if( !json_is_object(json) ) { + fprintf(stderr, "Error: json handle is not a valid object\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + /* + * Read in the edges + */ + json_edge_list = json_object_get(json, JSON_NODE_FILE_EDGE_INFO); + topology->edges = netloc_dt_lookup_table_t_json_decode(json_edge_list, &dc_decode_edge); + //netloc_lookup_table_pretty_print(topology->edges); + //check_edge_data(topology->edges); + + /* + * Read in the nodes + */ + json_node_list = json_object_get(json, JSON_NODE_FILE_NODE_INFO); + topology->num_nodes = (int) json_object_size(json_node_list); + topology->nodes = (netloc_node_t**)malloc(sizeof(netloc_node_t*) * (topology->num_nodes)); + if( NULL == topology->nodes ) { + exit_status = NETLOC_ERROR; + goto cleanup; + } + + cur_idx = 0; + json_object_foreach(json_node_list, key, json_node) { + topology->nodes[cur_idx] = netloc_dt_node_t_json_decode(topology->edges, json_object_get(json_node_list, key) ); + ++cur_idx; + } + + if(NULL != json) { + json_decref(json); + json = NULL; + } + + /* + * For each edge, find the correct pointer for the dest_node. + * Note: the src_node is filled in during the creation of a node in the + * netloc_dt_node_t_json_decode() operation, above. + */ + hti = netloc_dt_lookup_table_iterator_t_construct(topology->edges); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_edge = (netloc_edge_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_edge ) { + break; + } + + for(i = 0; i < topology->num_nodes; ++i ) { + if( NULL != topology->nodes[i] ) { + if( 0 == strncmp(cur_edge->dest_node_id, + topology->nodes[i]->physical_id, + strlen(cur_edge->dest_node_id)) ) { + cur_edge->dest_node = topology->nodes[i]; + break; + } + } + } + if( NULL == cur_edge->dest_node ) { + fprintf(stderr, "Error: Failed to find a node to match the following edge\n"); + char * tmp_str = NULL; + tmp_str = netloc_pretty_print_edge_t(cur_edge); + fprintf(stderr, " %s\n", tmp_str); + free(tmp_str); + } + } + + // for each edge + // find the corresponding node, and point to it. + + /* + * Load the json object (physical paths) + */ + ret = support_load_json_from_file(topology->network->phy_path_uri, &json); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the physical path file %s\n", topology->network->phy_path_uri); + exit_status = ret; + goto cleanup; + } + + if( !json_is_object(json) ) { + fprintf(stderr, "Error: json handle is not a valid object\n"); + exit_status = NETLOC_SUCCESS; + goto cleanup; + } + + /* + * Read in the paths + */ + json_path_list = json_object_get(json, JSON_NODE_FILE_PATH_INFO); + + cur_idx = 0; + json_object_foreach(json_path_list, key, json_path) { + node = NULL; + for(i = 0; i < topology->num_nodes; ++i) { + if( 0 == strncmp(topology->nodes[i]->physical_id, key, strlen(key) ) ) { + node = topology->nodes[i]; + break; + } + } + if( NULL == node ) { + fprintf(stderr, "Error: Failed to find the node with physical ID %s for physical path\n", key); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + if( NULL != node->physical_paths ) { + netloc_lookup_table_destroy(node->physical_paths); + free(node->physical_paths); + node->physical_paths = NULL; + } + node->physical_paths = netloc_dt_node_t_json_decode_paths(topology->edges, json_path); + if( NULL == node->physical_paths ) { + fprintf(stderr, "Error: Failed to decode the physical path for node\n"); + fprintf(stderr, "Error: Node: %s\n", netloc_pretty_print_node_t(node)); + exit_status = NETLOC_ERROR; + goto cleanup; + } + node->num_phy_paths = netloc_lookup_table_size(node->physical_paths); + } + + if(NULL != json) { + json_decref(json); + json = NULL; + } + + + /* + * Load the json object (logical paths) + */ + ret = support_load_json_from_file(topology->network->path_uri, &json); + if( NETLOC_SUCCESS != ret ) { + fprintf(stderr, "Error: Failed to load the path file %s\n", topology->network->path_uri); + exit_status = ret; + goto cleanup; + } + + if( !json_is_object(json) ) { + fprintf(stderr, "Error: json handle is not a valid object\n"); + exit_status = NETLOC_ERROR; + goto cleanup; + } + + /* + * Read in the paths + */ + json_path_list = json_object_get(json, JSON_NODE_FILE_PATH_INFO); + + cur_idx = 0; + json_object_foreach(json_path_list, key, json_path) { + node = NULL; + for(i = 0; i < topology->num_nodes; ++i) { + if( 0 == strncmp(topology->nodes[i]->physical_id, key, strlen(key) ) ) { + node = topology->nodes[i]; + break; + } + } + if( NULL == node ) { + fprintf(stderr, "Error: Failed to find the node with physical ID %s for logical path\n", key); + return NETLOC_ERROR; + } + + if( NULL != node->logical_paths ) { + netloc_lookup_table_destroy(node->logical_paths); + free(node->logical_paths); + node->logical_paths = NULL; + } + node->logical_paths = netloc_dt_node_t_json_decode_paths(topology->edges, json_path); + if( NULL == node->logical_paths ) { + fprintf(stderr, "Error: Failed to decode the logical path for node\n"); + fprintf(stderr, "Error: Node: %s\n", netloc_pretty_print_node_t(node)); + exit_status = NETLOC_ERROR; + goto cleanup; + } + node->num_log_paths = netloc_lookup_table_size(node->logical_paths); + } + + + topology->nodes_loaded = true; + + cleanup: + if(NULL != json) { + json_decref(json); + json = NULL; + } + + return exit_status; +} + +int support_load_json_from_file(const char * fname, json_t **json) +{ + const char *memblock = NULL; + int fd, filesize, pagesize, res; + struct stat sb; + + // Open file and get the needed file info + res = fd = open(fname, O_RDONLY); + if( 0 > res ) { + fprintf(stderr, "Error: Cannot open the file %s\n", fname); + goto CLEANUP; + } + res = fstat(fd, &sb); + if( 0 != res ) { + fprintf(stderr, "Error: Cannot stat the file %s\n", fname); + goto CLEANUP; + } + + // Set some useful values + filesize = sb.st_size; + pagesize = getpagesize(); + filesize = (filesize/pagesize)*pagesize + pagesize; + + // mmap the file + memblock = (const char *) mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0); + if (MAP_FAILED == memblock) { + fprintf(stderr, "Error: mmap failed\n"); + res = NETLOC_ERROR; + goto CLEANUP; + } + + // load the JSON from the file + (*json) = json_loads(memblock, 0, NULL); + if(NULL == (*json)) { + fprintf(stderr, "Error: json_loads on mmaped file failed\n"); + res = NETLOC_ERROR; + goto CLEANUP; + } + + // munmap the file and close it + CLEANUP: + if(NULL != memblock) { + res = munmap((char *)memblock, filesize); + if(0 != res) { + fprintf(stderr, "Error: munmap failed!\n"); + } + memblock = NULL; + } + if(0 <= fd) { + close(fd); + } + + return res; +} + +void * dc_decode_edge(const char * key, json_t* json_obj) +{ + return netloc_dt_edge_t_json_decode(json_obj); +} diff --git a/netloc/support.h b/netloc/support.h new file mode 100644 index 0000000000..b9d5460641 --- /dev/null +++ b/netloc/support.h @@ -0,0 +1,133 @@ +/* + * Copyright © 2013 Cisco Systems, Inc. All rights reserved. + * Copyright © 2013 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#ifndef NETLOC_SUPPORT_H +#define NETLOC_SUPPORT_H + +#include +#include + +#include + + +/*********************************************************************** + * JSON File Format Keywords + * nodes.ndat + * [metadata: [timestamp, version]], + * [network: [type, subnet, description], + * [node_uid: [node_type, phy_id, log_id, description, + * [edge_uid: src_id, src_type, src_port, dest_id, dest_type, dest_port, speed, width + ***********************************************************************/ +#define JSON_NODE_FILE_META_TIMESTAMP "timestamp" +#define JSON_NODE_FILE_META_VERSION "version" + +#define JSON_NODE_FILE_NETWORK_INFO "network_info" +#define JSON_NODE_FILE_NODE_INFO "node_info" +#define JSON_NODE_FILE_EDGE_INFO "edge_info" +#define JSON_NODE_FILE_PATH_INFO "path_info" + +#define JSON_NODE_FILE_NETWORK_TYPE "network_type" +#define JSON_NODE_FILE_NODE_TYPE "node_type" +#define JSON_NODE_FILE_SUBNET_ID "subnet_id" +#define JSON_NODE_FILE_DESCRIPTION "desc" +#define JSON_NODE_FILE_PHY_ID "phy_id" +#define JSON_NODE_FILE_LOG_ID "log_id" +#define JSON_NODE_FILE_EDGE_LIST "edges" +#define JSON_NODE_FILE_EDGE_ID_LIST "edge_ids" +#define JSON_NODE_FILE_LOG_PATH_LIST "log_paths" + +#define JSON_NODE_FILE_EDGE_UID "euid" +#define JSON_NODE_FILE_SRC_ID "src_node_id" +#define JSON_NODE_FILE_SRC_TYPE "src_node_type" +#define JSON_NODE_FILE_SRC_PORT "src_port_id" +#define JSON_NODE_FILE_DEST_ID "dest_node_id" +#define JSON_NODE_FILE_DEST_TYPE "dest_node_type" +#define JSON_NODE_FILE_DEST_PORT "dest_port_id" +#define JSON_NODE_FILE_EDGE_WIDTH "width" +#define JSON_NODE_FILE_EDGE_SPEED "speed" + + +/*********************************************************************** + * URI Support + ***********************************************************************/ +/** + * URI types + */ +typedef enum { + URI_FILE = 1, + URI_OTHER = 2, + URI_INVALID = 3, +} uri_type_t; + +#define URI_PREFIX_FILE "file://" + + +#define SUPPORT_CONVERT_ADDR_TO_INT(addr, type, v) { \ + if( NETLOC_NETWORK_TYPE_ETHERNET == type ) { \ + v = netloc_dt_convert_mac_str_to_int(addr); \ + } else { \ + v = netloc_dt_convert_guid_str_to_int(addr); \ + } \ +} + +#define SUPPORT_CONVERT_ADDR_TO_STR(addr, type, v) { \ + if( NETLOC_NETWORK_TYPE_ETHERNET == type ) { \ + v = netloc_dt_convert_mac_int_to_str(addr); \ + } else { \ + v = netloc_dt_convert_guid_int_to_str(addr); \ + } \ +} + +/*********************************************************************** + * Support Functions + ***********************************************************************/ +/** + * Extract the filename and URI information from a URI string + * + * \param uri URI to process + * \param type Type of the URI + * \param str String following the URI type prefix + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR otherwise + */ +int support_extract_filename_from_uri(const char * uri, uri_type_t *type, char **str); + +/** + * Load data onto the topology handle from a JSON file + * + * \param topology A valid pointer to a topology structure + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR otherwise + */ +int support_load_json(struct netloc_topology * topology); + +/** + * Returns "*json" as a representation of the JSON in "fname" + * + * Note that the user is responsible for decrementing the reference to the json_t + * pointer returned (via json_decref()) + * + * \param fname The file name to be loaded into json + * \param json Is presumed to be an unallocated reference to a json_t pointer. + * + * Returns + * NETLOC_SUCCESS on success + * NETLOC_ERROR otherwise + */ +int support_load_json_from_file(const char * fname, json_t **json); + +#endif /* NETLOC_SUPPORT_H */ diff --git a/netloc/topology.c b/netloc/topology.c new file mode 100644 index 0000000000..28e49d8648 --- /dev/null +++ b/netloc/topology.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2013-2014 University of Wisconsin-La Crosse. + * All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * See COPYING in top-level directory. + * + * $HEADER$ + */ + +#include +#include "support.h" + +int netloc_attach(struct netloc_topology ** topology_ptr, netloc_network_t network) +{ + struct netloc_topology *topology = NULL; + + /* + * Allocate Memory + */ + topology = (struct netloc_topology *)malloc(sizeof(struct netloc_topology) * 1); + if( NULL == topology ) { + return NETLOC_ERROR; + } + + /* + * Initialize the structure + */ + topology->network = netloc_dt_network_t_dup(&network); + + topology->nodes_loaded = false; + topology->num_nodes = 0; + topology->nodes = NULL; + topology->edges = NULL; + + /* + * Make the pointer live + */ + (*topology_ptr) = topology; + + return NETLOC_SUCCESS; +} + +int netloc_detach(struct netloc_topology * topology) +{ + int i; + struct netloc_dt_lookup_table_iterator *hti = NULL; + netloc_edge_t *cur_edge = NULL; + + /* + * Sanity Check + */ + if( NULL == topology ) { + fprintf(stderr, "Error: Detaching from a NULL pointer\n"); + return NETLOC_ERROR; + } + + /* + * Free Memory + */ + netloc_dt_network_t_destruct(topology->network); + + if( NULL != topology->edges ) { + hti = netloc_dt_lookup_table_iterator_t_construct(topology->edges); + while( !netloc_lookup_table_iterator_at_end(hti) ) { + cur_edge = (netloc_edge_t*)netloc_lookup_table_iterator_next_entry(hti); + if( NULL == cur_edge ) { + break; + } + netloc_dt_edge_t_destruct(cur_edge); + } + netloc_dt_lookup_table_iterator_t_destruct(hti); + netloc_lookup_table_destroy(topology->edges); + free(topology->edges); + topology->edges = NULL; + } + + if( NULL != topology->nodes ) { + for(i = 0; i < topology->num_nodes; ++i ) { + if( NULL != topology->nodes[i] ) { + netloc_dt_node_t_destruct(topology->nodes[i]); + topology->nodes[i] = NULL; + } + } + free(topology->nodes); + topology->nodes = NULL; + } + + free(topology); + + return NETLOC_SUCCESS; +} + +int netloc_refresh(struct netloc_topology *topology) +{ + return NETLOC_ERROR_NOT_IMPL; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index aa01af4df0..e8c1356a4e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,3 +3,6 @@ # See COPYING in top-level directory. SUBDIRS = hwloc +if BUILD_NETLOC +SUBDIRS += netloc +endif diff --git a/tests/netloc/Makefile.am b/tests/netloc/Makefile.am new file mode 100644 index 0000000000..b79d794688 --- /dev/null +++ b/tests/netloc/Makefile.am @@ -0,0 +1,34 @@ +# Copyright © 2013-2014 Cisco Systems, Inc. All rights reserved. +# Copyright © 2013-2014 University of Wisconsin-La Crosse. +# All rights reserved. +# +# See COPYING in top-level directory. +# +# $HEADER$ +# + +AM_CPPFLAGS = \ + $(JANSSON_CPPFLAGS) \ + -I$(top_builddir)/include \ + -I$(top_srcdir)/include \ + -DNETLOC_ABS_TOP_SRCDIR=\"$(abs_top_srcdir)/\" + +check_PROGRAMS = \ + test_API \ + test_ETH_API \ + test_ETH_verbose \ + test_find_neighbors \ + test_metadata \ + test_conv \ + test_map \ + test_map_hwloc \ + hwloc_compress \ + map_paths \ + netloc_hello \ + netloc_nodes \ + netloc_all + +LDADD = $(top_builddir)/netloc/libnetloc.la + +test_map_LDADD = $(LDADD) $(top_builddir)/hwloc/libhwloc.la +map_paths_LDADD = $(LDADD) $(top_builddir)/hwloc/libhwloc.la diff --git a/tests/netloc/README b/tests/netloc/README new file mode 100644 index 0000000000..55d53cb02b --- /dev/null +++ b/tests/netloc/README @@ -0,0 +1,18 @@ +Copyright © 2013 University of Wisconsin-La Crosse. + All rights reserved. + +$COPYRIGHT$ + +See COPYING in top-level directory. +Additional copyrights may follow + +$HEADER$ + +=========================================================================== + +Test data from: + - Ethernet: + A mininet simulated OpenFlow environment connected to an OpenDaylight + controller. + - InfiniBand: + The PlaFRIM system at INRIA diff --git a/tests/netloc/data/create-synthetic-hwloc.pl b/tests/netloc/data/create-synthetic-hwloc.pl new file mode 100755 index 0000000000..7933582396 --- /dev/null +++ b/tests/netloc/data/create-synthetic-hwloc.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl + +# +# Copyright © 2014 University of Wisconsin-La Crosse. +# All rights reserved. +# +# See COPYING in top-level directory. +# +# $HEADER$ +# +# ./create-synthetic-hwloc.pl -t node-template.xml -o hwloc/node02.xml -h node02 -e "00:00:00:00:00:01" +# + +use strict; +use warnings; + +use Getopt::Long; + +######################################################################## +# Process Command Line Arguments +######################################################################## +my $KEY_HOSTNAME = "TEMPLATE_HOSTNAME"; +my $KEY_MAC_ADDR = "TEMPLATE_MAC_ADDR"; + +my $template_arg; +my $output_arg; +my $hostname_arg; +my $eth_mac_arg; + +&Getopt::Long::Configure("bundling"); +my $ok = Getopt::Long::GetOptions( + "template|t=s" => \$template_arg, + "hostname|h=s" => \$hostname_arg, + "ethmac|e=s" => \$eth_mac_arg, + "output|o=s" => \$output_arg + ); + +if( !$ok ) { + print "Error: Must specify --template|-t, --output|-o, --hostname|-h, and --ethmac|-e\n"; + exit(-1); +} +elsif( !defined($template_arg) || length($template_arg) <= 0 ) { + print "Error: Must specify a template file name.\n"; + exit(-2); +} +elsif( !defined($hostname_arg) || length($hostname_arg) <= 0 ) { + print "Error: Must specify a string argument to --hostname|-h.\n"; + exit(-2); +} +elsif( !defined($eth_mac_arg) || length($eth_mac_arg) <= 0 ) { + print "Error: Must specify a string argument to --ethmac|-e.\n"; + exit(-2); +} +elsif( !defined($output_arg) || length($output_arg) <= 0 ) { + print "Error: Must specify a string argument to --output|-o.\n"; + exit(-2); +} + +if( $output_arg eq $template_arg ) { + print "Error: Cannot overwrite the template\n"; + exit(-3); +} + +die "Error: Can't read $template_arg" + unless(-r $template_arg); + +######################################################################## +# Create the output file +######################################################################## +my $line; + +#print "Hostname: <$hostname_arg>\n"; +#print "Output : <$output_arg>\n"; +#print "Eth Mac : <$eth_mac_arg>\n"; + +open(TEMPLATE, "<", $template_arg) + or die "Error: Failed to open $template_arg\n"; + +open(OUTPUT, ">", $output_arg) + or die "Error: Failed to open $output_arg\n"; + +while( $line =